Merge "Added thin object layer around contact data"
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 3acc34c..4333aa4 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -47,10 +47,10 @@
import android.widget.Toast;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.CallerInfoCacheUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -289,7 +289,7 @@
* @param rawContactId identifies a writable raw-contact whose photo is to be updated.
* @param updatedPhotoPath denotes a temporary file containing the contact's new photo.
*/
- public static Intent createSaveContactIntent(Context context, EntityDeltaList state,
+ public static Intent createSaveContactIntent(Context context, RawContactDeltaList state,
String saveModeExtraKey, int saveMode, boolean isProfile,
Class<? extends Activity> callbackActivity, String callbackAction, long rawContactId,
String updatedPhotoPath) {
@@ -306,7 +306,7 @@
* Contact Editor.
* @param updatedPhotos maps each raw-contact's ID to the file-path of the new photo.
*/
- public static Intent createSaveContactIntent(Context context, EntityDeltaList state,
+ public static Intent createSaveContactIntent(Context context, RawContactDeltaList state,
String saveModeExtraKey, int saveMode, boolean isProfile,
Class<? extends Activity> callbackActivity, String callbackAction,
Bundle updatedPhotos) {
@@ -332,13 +332,13 @@
}
private void saveContact(Intent intent) {
- EntityDeltaList state = intent.getParcelableExtra(EXTRA_CONTACT_STATE);
+ RawContactDeltaList state = intent.getParcelableExtra(EXTRA_CONTACT_STATE);
boolean isProfile = intent.getBooleanExtra(EXTRA_SAVE_IS_PROFILE, false);
Bundle updatedPhotos = intent.getParcelableExtra(EXTRA_UPDATED_PHOTOS);
// Trim any empty fields, and RawContacts, before persisting
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
- EntityModifier.trimEmpty(state, accountTypes);
+ RawContactModifier.trimEmpty(state, accountTypes);
Uri lookupUri = null;
@@ -427,16 +427,16 @@
throw new IllegalStateException("Version consistency failed for a new contact");
}
- final EntityDeltaList newState = EntityDeltaList.fromQuery(
+ final RawContactDeltaList newState = RawContactDeltaList.fromQuery(
isProfile
? RawContactsEntity.PROFILE_CONTENT_URI
: RawContactsEntity.CONTENT_URI,
resolver, sb.toString(), null, null);
- state = EntityDeltaList.mergeAfter(newState, state);
+ state = RawContactDeltaList.mergeAfter(newState, state);
// Update the new state to use profile URIs if appropriate.
if (isProfile) {
- for (EntityDelta delta : state) {
+ for (RawContactDelta delta : state) {
delta.setProfileQueryUri();
}
}
@@ -518,7 +518,7 @@
/**
* Find the ID of an existing or newly-inserted raw-contact. If none exists, return -1.
*/
- private long getRawContactId(EntityDeltaList state,
+ private long getRawContactId(RawContactDeltaList state,
final ArrayList<ContentProviderOperation> diff,
final ContentProviderResult[] results) {
long existingRawContactId = state.findRawContactId();
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 0b63345..e8aa1ae 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -33,9 +33,9 @@
import android.widget.TextView;
import com.android.contacts.activities.DialtactsActivity;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.test.NeededForTesting;
import com.android.contacts.util.Constants;
diff --git a/src/com/android/contacts/SplitAggregateView.java b/src/com/android/contacts/SplitAggregateView.java
index 834635c..1b42ca3 100644
--- a/src/com/android/contacts/SplitAggregateView.java
+++ b/src/com/android/contacts/SplitAggregateView.java
@@ -35,8 +35,8 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/src/com/android/contacts/TypePrecedence.java b/src/com/android/contacts/TypePrecedence.java
index b5e0777..b2d8a8f 100644
--- a/src/com/android/contacts/TypePrecedence.java
+++ b/src/com/android/contacts/TypePrecedence.java
@@ -23,14 +23,14 @@
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContactModifier;
import com.android.contacts.util.Constants;
/**
* This class contains utility functions for determining the precedence of
* different types associated with contact data items.
*
- * @deprecated use {@link EntityModifier#getTypePrecedence} instead, since this
+ * @deprecated use {@link RawContactModifier#getTypePrecedence} instead, since this
* list isn't {@link Account} based.
*/
@Deprecated
diff --git a/src/com/android/contacts/ViewNotificationService.java b/src/com/android/contacts/ViewNotificationService.java
index 584176d..3bc5ed2 100644
--- a/src/com/android/contacts/ViewNotificationService.java
+++ b/src/com/android/contacts/ViewNotificationService.java
@@ -23,7 +23,9 @@
import android.os.IBinder;
import android.util.Log;
-import com.android.contacts.ContactLoader.Result;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.ContactLoader;
+
/**
* Service that sends out a view notification for a contact. At the moment, this is only
@@ -41,9 +43,9 @@
// We simply need to start a Loader here. When its done, it will send out the
// View-Notification automatically.
final ContactLoader contactLoader = new ContactLoader(this, intent.getData(), true);
- contactLoader.registerListener(0, new OnLoadCompleteListener<ContactLoader.Result>() {
+ contactLoader.registerListener(0, new OnLoadCompleteListener<Contact>() {
@Override
- public void onLoadComplete(Loader<Result> loader, Result data) {
+ public void onLoadComplete(Loader<Contact> loader, Contact data) {
try {
loader.reset();
} catch (RuntimeException e) {
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 9ca9cfd..2f7651f 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -30,15 +30,15 @@
import android.provider.ContactsContract.DisplayPhoto;
import android.util.Log;
-import com.android.contacts.ContactLoader;
-import com.android.contacts.ContactLoader.Result;
import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsActivity;
import com.android.contacts.ContactsUtils;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.ContactLoader;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.model.account.AccountType;
import com.android.contacts.util.ContactPhotoUtils;
import java.io.File;
@@ -131,7 +131,7 @@
} else if (requestCode == REQUEST_CROP_PHOTO) {
loadContact(mContactUri, new Listener() {
@Override
- public void onContactLoaded(ContactLoader.Result contact) {
+ public void onContactLoaded(Contact contact) {
saveContact(contact);
}
});
@@ -144,10 +144,10 @@
// instance, the loader doesn't persist across Activity restarts.
private void loadContact(Uri contactUri, final Listener listener) {
final ContactLoader loader = new ContactLoader(this, contactUri, true);
- loader.registerListener(0, new OnLoadCompleteListener<ContactLoader.Result>() {
+ loader.registerListener(0, new OnLoadCompleteListener<Contact>() {
@Override
public void onLoadComplete(
- Loader<ContactLoader.Result> loader, ContactLoader.Result contact) {
+ Loader<Contact> loader, Contact contact) {
try {
loader.reset();
}
@@ -161,7 +161,7 @@
}
private interface Listener {
- public void onContactLoaded(Result contact);
+ public void onContactLoaded(Contact contact);
}
/**
@@ -170,11 +170,11 @@
* - photo has been cropped
* - contact has been loaded
*/
- private void saveContact(ContactLoader.Result contact) {
+ private void saveContact(Contact contact) {
// Obtain the raw-contact that we will save to.
- EntityDeltaList deltaList = contact.createEntityDeltaList();
- EntityDelta raw = deltaList.getFirstWritableRawContact(this);
+ RawContactDeltaList deltaList = contact.createRawContactDeltaList();
+ RawContactDelta raw = deltaList.getFirstWritableRawContact(this);
if (raw == null) {
Log.w(TAG, "no writable raw-contact found");
return;
@@ -195,13 +195,13 @@
// the ContactSaveService would not create the new contact, and the
// full-res photo would fail to be saved to the non-existent contact.
AccountType account = raw.getRawContactAccountType(this);
- EntityDelta.ValuesDelta values =
- EntityModifier.ensureKindExists(raw, account, Photo.CONTENT_ITEM_TYPE);
+ RawContactDelta.ValuesDelta values =
+ RawContactModifier.ensureKindExists(raw, account, Photo.CONTENT_ITEM_TYPE);
if (values == null) {
Log.w(TAG, "cannot attach photo to this account type");
return;
}
- values.put(Photo.PHOTO, compressed);
+ values.setPhoto(compressed);
// Finally, invoke the ContactSaveService.
Log.v(TAG, "all prerequisites met, about to save photo to contact");
diff --git a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
index 18e360f..c8adf95 100644
--- a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
+++ b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
@@ -24,7 +24,6 @@
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.OperationApplicationException;
@@ -62,14 +61,15 @@
import com.android.contacts.R;
import com.android.contacts.editor.Editor;
import com.android.contacts.editor.ViewIdGenerator;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContact;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.util.DialogManager;
import com.android.contacts.util.EmptyService;
@@ -124,11 +124,11 @@
private QueryHandler mQueryHandler;
- /** {@link EntityDeltaList} for the entire selected contact. */
- private EntityDeltaList mEntityDeltaList;
+ /** {@link RawContactDeltaList} for the entire selected contact. */
+ private RawContactDeltaList mEntityDeltaList;
- /** {@link EntityDeltaList} for the editable account */
- private EntityDelta mEntityDelta;
+ /** {@link RawContactDeltaList} for the editable account */
+ private RawContactDelta mRawContactDelta;
private String mMimetype = Phone.CONTENT_ITEM_TYPE;
@@ -357,7 +357,7 @@
new String[] { String.valueOf(mContactId) }, null);
}
- private static class QueryEntitiesTask extends AsyncTask<Intent, Void, EntityDeltaList> {
+ private static class QueryEntitiesTask extends AsyncTask<Intent, Void, RawContactDeltaList> {
private ConfirmAddDetailActivity activityTarget;
private String mSelection;
@@ -367,7 +367,7 @@
}
@Override
- protected EntityDeltaList doInBackground(Intent... params) {
+ protected RawContactDeltaList doInBackground(Intent... params) {
final Intent intent = params[0];
@@ -400,7 +400,7 @@
// Note that this query does not need to concern itself with whether the contact is
// the user's profile, since the profile does not show up in the picker.
- return EntityDeltaList.fromQuery(RawContactsEntity.CONTENT_URI,
+ return RawContactDeltaList.fromQuery(RawContactsEntity.CONTENT_URI,
activityTarget.getContentResolver(), mSelection,
new String[] { selectionArg }, null);
}
@@ -425,7 +425,7 @@
}
@Override
- protected void onPostExecute(EntityDeltaList entityList) {
+ protected void onPostExecute(RawContactDeltaList entityList) {
if (activityTarget.isFinishing()) {
return;
}
@@ -567,7 +567,7 @@
}
}
- private void setEntityDeltaList(EntityDeltaList entityList) {
+ private void setEntityDeltaList(RawContactDeltaList entityList) {
if (entityList == null) {
throw new IllegalStateException();
}
@@ -578,31 +578,33 @@
mEntityDeltaList = entityList;
// Find the editable raw_contact.
- mEntityDelta = mEntityDeltaList.getFirstWritableRawContact(this);
+ mRawContactDelta = mEntityDeltaList.getFirstWritableRawContact(this);
// If no editable raw_contacts are found, create one.
- if (mEntityDelta == null) {
- mEntityDelta = addEditableRawContact(this, mEntityDeltaList);
+ if (mRawContactDelta == null) {
+ mRawContactDelta = addEditableRawContact(this, mEntityDeltaList);
- if ((mEntityDelta != null) && VERBOSE_LOGGING) {
+ if ((mRawContactDelta != null) && VERBOSE_LOGGING) {
Log.v(TAG, "setEntityDeltaList: created editable raw_contact " + entityList);
}
}
- if (mEntityDelta == null) {
+ if (mRawContactDelta == null) {
// Selected contact is read-only, and there's no editable account.
mIsReadOnly = true;
mEditableAccountType = null;
} else {
mIsReadOnly = false;
- mEditableAccountType = mEntityDelta.getRawContactAccountType(this);
+ mEditableAccountType = mRawContactDelta.getRawContactAccountType(this);
// Handle any incoming values that should be inserted
final Bundle extras = getIntent().getExtras();
if (extras != null && extras.size() > 0) {
- // If there are any intent extras, add them as additional fields in the EntityDelta.
- EntityModifier.parseExtras(this, mEditableAccountType, mEntityDelta, extras);
+ // If there are any intent extras, add them as additional fields in the
+ // RawContactDelta.
+ RawContactModifier.parseExtras(this, mEditableAccountType, mRawContactDelta,
+ extras);
}
}
@@ -610,12 +612,12 @@
}
/**
- * Create an {@link EntityDelta} for a raw_contact on the first editable account found, and add
+ * Create an {@link RawContactDelta} for a raw_contact on the first editable account found, and add
* to the list. Also copy the structured name from an existing (read-only) raw_contact to the
* new one, if any of the read-only contacts has a name.
*/
- private static EntityDelta addEditableRawContact(Context context,
- EntityDeltaList entityDeltaList) {
+ private static RawContactDelta addEditableRawContact(Context context,
+ RawContactDeltaList entityDeltaList) {
// First, see if there's an editable account.
final AccountTypeManager accounts = AccountTypeManager.getInstance(context);
final List<AccountWithDataSet> editableAccounts = accounts.getAccounts(true);
@@ -627,44 +629,29 @@
final AccountType accountType = accounts.getAccountType(
editableAccount.type, editableAccount.dataSet);
- // Create a new EntityDelta for the new raw_contact.
- final ContentValues values = new ContentValues();
- values.put(RawContacts.ACCOUNT_NAME, editableAccount.name);
- values.put(RawContacts.ACCOUNT_TYPE, editableAccount.type);
- values.put(RawContacts.DATA_SET, editableAccount.dataSet);
+ // Create a new RawContactDelta for the new raw_contact.
+ final RawContact rawContact = new RawContact(context);
+ rawContact.setAccount(editableAccount);
- final EntityDelta entityDelta = new EntityDelta(ValuesDelta.fromAfter(values));
+ final RawContactDelta entityDelta = new RawContactDelta(ValuesDelta.fromAfter(
+ rawContact.getValues()));
// Then, copy the structure name from an existing (read-only) raw_contact.
- for (EntityDelta entity : entityDeltaList) {
+ for (RawContactDelta entity : entityDeltaList) {
final ArrayList<ValuesDelta> readOnlyNames =
entity.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
if ((readOnlyNames != null) && (readOnlyNames.size() > 0)) {
final ValuesDelta readOnlyName = readOnlyNames.get(0);
-
- final ValuesDelta newName = EntityModifier.ensureKindExists(entityDelta,
+ final ValuesDelta newName = RawContactModifier.ensureKindExists(entityDelta,
accountType, StructuredName.CONTENT_ITEM_TYPE);
// Copy all the data fields.
- newName.copyStringFrom(readOnlyName, StructuredName.DISPLAY_NAME);
-
- newName.copyStringFrom(readOnlyName, StructuredName.GIVEN_NAME);
- newName.copyStringFrom(readOnlyName, StructuredName.FAMILY_NAME);
- newName.copyStringFrom(readOnlyName, StructuredName.PREFIX);
- newName.copyStringFrom(readOnlyName, StructuredName.MIDDLE_NAME);
- newName.copyStringFrom(readOnlyName, StructuredName.SUFFIX);
-
- newName.copyStringFrom(readOnlyName, StructuredName.PHONETIC_GIVEN_NAME);
- newName.copyStringFrom(readOnlyName, StructuredName.PHONETIC_MIDDLE_NAME);
- newName.copyStringFrom(readOnlyName, StructuredName.PHONETIC_FAMILY_NAME);
-
- newName.copyStringFrom(readOnlyName, StructuredName.FULL_NAME_STYLE);
- newName.copyStringFrom(readOnlyName, StructuredName.PHONETIC_NAME_STYLE);
+ newName.copyStructuredNameFieldsFrom(readOnlyName);
break;
}
}
- // Add the new EntityDelta to the list.
+ // Add the new RawContactDelta to the list.
entityDeltaList.add(entityDelta);
return entityDelta;
@@ -695,11 +682,11 @@
// Skip kind that are not editable
if (!kind.editable) continue;
if (mMimetype.equals(kind.mimeType)) {
- for (ValuesDelta valuesDelta : mEntityDelta.getMimeEntries(mMimetype)) {
+ for (ValuesDelta valuesDelta : mRawContactDelta.getMimeEntries(mMimetype)) {
// Skip entries that aren't visible
if (!valuesDelta.isVisible()) continue;
if (valuesDelta.isInsert()) {
- inflateEditorView(kind, valuesDelta, mEntityDelta);
+ inflateEditorView(kind, valuesDelta, mRawContactDelta);
return;
}
}
@@ -712,7 +699,7 @@
* the views corresponding to the the object-model. The resulting EditorView is also added
* to the end of mEditors
*/
- private void inflateEditorView(DataKind dataKind, ValuesDelta valuesDelta, EntityDelta state) {
+ private void inflateEditorView(DataKind dataKind, ValuesDelta valuesDelta, RawContactDelta state) {
final View view = mInflater.inflate(dataKind.editorLayoutResourceId, mEditorContainerView,
false);
@@ -765,11 +752,11 @@
/**
* Background task for persisting edited contact data, using the changes
- * defined by a set of {@link EntityDelta}. This task starts
+ * defined by a set of {@link RawContactDelta}. This task starts
* {@link EmptyService} to make sure the background thread can finish
* persisting in cases where the system wants to reclaim our process.
*/
- private static class PersistTask extends AsyncTask<EntityDeltaList, Void, Integer> {
+ private static class PersistTask extends AsyncTask<RawContactDeltaList, Void, Integer> {
// In the future, use ContactSaver instead of WeakAsyncTask because of
// the danger of the activity being null during a save action
private static final int PERSIST_TRIES = 3;
@@ -799,18 +786,18 @@
}
@Override
- protected Integer doInBackground(EntityDeltaList... params) {
+ protected Integer doInBackground(RawContactDeltaList... params) {
final Context context = activityTarget;
final ContentResolver resolver = context.getContentResolver();
- EntityDeltaList state = params[0];
+ RawContactDeltaList state = params[0];
if (state == null) {
return RESULT_FAILURE;
}
// Trim any empty fields, and RawContacts, before persisting
- EntityModifier.trimEmpty(state, mAccountTypeManager);
+ RawContactModifier.trimEmpty(state, mAccountTypeManager);
// Attempt to persist changes
int tries = 0;
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index ace89df..811b904 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -36,7 +36,6 @@
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
-import com.android.contacts.ContactLoader;
import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
@@ -46,7 +45,8 @@
import com.android.contacts.detail.ContactLoaderFragment;
import com.android.contacts.detail.ContactLoaderFragment.ContactLoaderFragmentListener;
import com.android.contacts.interactions.ContactDeletionInteraction;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.PhoneCapabilityTester;
import java.util.ArrayList;
@@ -57,7 +57,7 @@
/** Shows a toogle button for hiding/showing updates. Don't submit with true */
private static final boolean DEBUG_TRANSITIONS = false;
- private ContactLoader.Result mContactData;
+ private Contact mContactData;
private Uri mLookupUri;
private ContactDetailLayoutController mContactDetailLayoutController;
@@ -208,7 +208,7 @@
}
@Override
- public void onDetailsLoaded(final ContactLoader.Result result) {
+ public void onDetailsLoaded(final Contact result) {
if (result == null) {
return;
}
diff --git a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
index 3e2a893..f5852e5 100644
--- a/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorAccountsChangedActivity.java
@@ -31,7 +31,7 @@
import com.android.contacts.R;
import com.android.contacts.editor.ContactEditorUtils;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountsListAdapter;
import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index 9639d97..77ed857 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -36,9 +36,9 @@
import com.android.contacts.R;
import com.android.contacts.editor.ContactEditorFragment;
import com.android.contacts.editor.ContactEditorFragment.SaveMode;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.DialogManager;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
index 9b3743f..492a2ff 100644
--- a/src/com/android/contacts/activities/GroupDetailActivity.java
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -33,8 +33,8 @@
import com.android.contacts.R;
import com.android.contacts.group.GroupDetailDisplayUtils;
import com.android.contacts.group.GroupDetailFragment;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
public class GroupDetailActivity extends ContactsActivity {
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 4ee5ea3..a99ac45 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -47,7 +47,6 @@
import android.view.ViewGroup;
import android.widget.Toast;
-import com.android.contacts.ContactLoader;
import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsActivity;
import com.android.contacts.ContactsUtils;
@@ -81,7 +80,8 @@
import com.android.contacts.list.OnContactsUnavailableActionListener;
import com.android.contacts.list.ProviderStatusWatcher;
import com.android.contacts.list.ProviderStatusWatcher.ProviderStatusListener;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.preference.ContactsPreferenceActivity;
import com.android.contacts.preference.DisplayOptionsPreferenceFragment;
import com.android.contacts.util.AccountFilterUtil;
@@ -1162,7 +1162,7 @@
}
@Override
- public void onDetailsLoaded(final ContactLoader.Result result) {
+ public void onDetailsLoaded(final Contact result) {
if (result == null) {
// Nothing is loaded. Show empty state.
mContactDetailLayoutController.showEmptyState();
diff --git a/src/com/android/contacts/activities/PhotoSelectionActivity.java b/src/com/android/contacts/activities/PhotoSelectionActivity.java
index a5ae7bd..6f3da00 100644
--- a/src/com/android/contacts/activities/PhotoSelectionActivity.java
+++ b/src/com/android/contacts/activities/PhotoSelectionActivity.java
@@ -38,7 +38,7 @@
import com.android.contacts.R;
import com.android.contacts.detail.PhotoSelectionHandler;
import com.android.contacts.editor.PhotoActionPopup;
-import com.android.contacts.model.EntityDeltaList;
+import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.util.ContactPhotoUtils;
import com.android.contacts.util.SchedulingUtils;
@@ -93,7 +93,7 @@
private Uri mPhotoUri;
/** Entity delta list of the contact. */
- private EntityDeltaList mState;
+ private RawContactDeltaList mState;
/** Whether the contact is the user's profile. */
private boolean mIsProfile;
@@ -167,7 +167,7 @@
// Pull data out of the intent.
final Intent intent = getIntent();
mPhotoUri = intent.getParcelableExtra(PHOTO_URI);
- mState = (EntityDeltaList) intent.getParcelableExtra(ENTITY_DELTA_LIST);
+ mState = (RawContactDeltaList) intent.getParcelableExtra(ENTITY_DELTA_LIST);
mIsProfile = intent.getBooleanExtra(IS_PROFILE, false);
mIsDirectoryContact = intent.getBooleanExtra(IS_DIRECTORY_CONTACT, false);
mExpandPhoto = intent.getBooleanExtra(EXPAND_PHOTO, false);
@@ -268,7 +268,7 @@
* @return An intent that can be used to invoke the photo selection activity.
*/
public static Intent buildIntent(Context context, Uri photoUri, Bitmap photoBitmap,
- byte[] photoBytes, Rect photoBounds, EntityDeltaList delta, boolean isProfile,
+ byte[] photoBytes, Rect photoBounds, RawContactDeltaList delta, boolean isProfile,
boolean isDirectoryContact, boolean expandPhotoOnClick) {
Intent intent = new Intent(context, PhotoSelectionActivity.class);
if (photoUri != null && photoBitmap != null && photoBytes != null) {
@@ -515,7 +515,7 @@
private final PhotoActionListener mListener;
private PhotoHandler(
- Context context, View photoView, int photoMode, EntityDeltaList state) {
+ Context context, View photoView, int photoMode, RawContactDeltaList state) {
super(context, photoView, photoMode, PhotoSelectionActivity.this.mIsDirectoryContact,
state);
mListener = new PhotoListener();
@@ -536,7 +536,7 @@
private final class PhotoListener extends PhotoActionListener {
@Override
public void onPhotoSelected(Bitmap bitmap) {
- EntityDeltaList delta = getDeltaForAttachingPhotoToContact();
+ RawContactDeltaList delta = getDeltaForAttachingPhotoToContact();
long rawContactId = getWritableEntityId();
final String croppedPath = ContactPhotoUtils.pathForCroppedPhoto(
PhotoSelectionActivity.this, mCurrentPhotoFile);
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index 67e8e4e..1908e96 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -17,10 +17,7 @@
package com.android.contacts.detail;
import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
-import android.content.Entity;
-import android.content.Entity.NamedContentValues;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
@@ -28,8 +25,6 @@
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.ContactsContract;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
-import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.DisplayNameSources;
import android.provider.ContactsContract.StreamItems;
import android.text.Html;
@@ -44,10 +39,12 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.contacts.ContactLoader;
-import com.android.contacts.ContactLoader.Result;
import com.android.contacts.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.preference.ContactsPreferences;
import com.android.contacts.util.ContactBadgeUtil;
import com.android.contacts.util.HtmlUtils;
@@ -55,13 +52,14 @@
import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemPhotoEntry;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Iterables;
import java.util.List;
/**
* This class contains utility methods to bind high-level contact details
* (meaning name, phonetic name, job, and attribution) from a
- * {@link ContactLoader.Result} data object to appropriate {@link View}s.
+ * {@link Contact} data object to appropriate {@link View}s.
*/
public class ContactDetailDisplayUtils {
private static final String TAG = "ContactDetailDisplayUtils";
@@ -95,7 +93,7 @@
* Returns the display name of the contact, using the current display order setting.
* Returns res/string/missing_name if there is no display name.
*/
- public static CharSequence getDisplayName(Context context, Result contactData) {
+ public static CharSequence getDisplayName(Context context, Contact contactData) {
CharSequence displayName = contactData.getDisplayName();
CharSequence altDisplayName = contactData.getAltDisplayName();
ContactsPreferences prefs = new ContactsPreferences(context);
@@ -115,7 +113,7 @@
/**
* Returns the phonetic name of the contact or null if there isn't one.
*/
- public static String getPhoneticName(Context context, Result contactData) {
+ public static String getPhoneticName(Context context, Contact contactData) {
String phoneticName = contactData.getPhoneticName();
if (!TextUtils.isEmpty(phoneticName)) {
return phoneticName;
@@ -127,7 +125,7 @@
* Returns the attribution string for the contact, which may specify the contact directory that
* the contact came from. Returns null if there is none applicable.
*/
- public static String getAttribution(Context context, Result contactData) {
+ public static String getAttribution(Context context, Contact contactData) {
if (contactData.isDirectoryEntry()) {
String directoryDisplayName = contactData.getDirectoryDisplayName();
String directoryType = contactData.getDirectoryType();
@@ -143,40 +141,37 @@
* Returns the organization of the contact. If several organizations are given,
* the first one is used. Returns null if not applicable.
*/
- public static String getCompany(Context context, Result contactData) {
+ public static String getCompany(Context context, Contact contactData) {
final boolean displayNameIsOrganization = contactData.getDisplayNameSource()
== DisplayNameSources.ORGANIZATION;
- for (Entity entity : contactData.getEntities()) {
- for (NamedContentValues subValue : entity.getSubValues()) {
- final ContentValues entryValues = subValue.values;
- final String mimeType = entryValues.getAsString(Data.MIMETYPE);
-
- if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
- final String company = entryValues.getAsString(Organization.COMPANY);
- final String title = entryValues.getAsString(Organization.TITLE);
- final String combined;
- // We need to show company and title in a combined string. However, if the
- // DisplayName is already the organization, it mirrors company or (if company
- // is empty title). Make sure we don't show what's already shown as DisplayName
- if (TextUtils.isEmpty(company)) {
- combined = displayNameIsOrganization ? null : title;
+ for (RawContact rawContact : contactData.getRawContacts()) {
+ for (DataItem dataItem : Iterables.filter(
+ rawContact.getDataItems(), OrganizationDataItem.class)) {
+ OrganizationDataItem organization = (OrganizationDataItem) dataItem;
+ final String company = organization.getCompany();
+ final String title = organization.getTitle();
+ final String combined;
+ // We need to show company and title in a combined string. However, if the
+ // DisplayName is already the organization, it mirrors company or (if company
+ // is empty title). Make sure we don't show what's already shown as DisplayName
+ if (TextUtils.isEmpty(company)) {
+ combined = displayNameIsOrganization ? null : title;
+ } else {
+ if (TextUtils.isEmpty(title)) {
+ combined = displayNameIsOrganization ? null : company;
} else {
- if (TextUtils.isEmpty(title)) {
- combined = displayNameIsOrganization ? null : company;
+ if (displayNameIsOrganization) {
+ combined = title;
} else {
- if (displayNameIsOrganization) {
- combined = title;
- } else {
- combined = context.getString(
- R.string.organization_company_and_title,
- company, title);
- }
+ combined = context.getString(
+ R.string.organization_company_and_title,
+ company, title);
}
}
+ }
- if (!TextUtils.isEmpty(combined)) {
- return combined;
- }
+ if (!TextUtils.isEmpty(combined)) {
+ return combined;
}
}
}
@@ -225,7 +220,7 @@
/**
* Set the social snippet text. If there isn't one, then set the view to gone.
*/
- public static void setSocialSnippet(Context context, Result contactData, TextView statusView,
+ public static void setSocialSnippet(Context context, Contact contactData, TextView statusView,
ImageView statusPhotoView) {
if (statusView == null) {
return;
@@ -378,7 +373,7 @@
* Sets the display name of this contact to the given {@link TextView}. If
* there is none, then set the view to gone.
*/
- public static void setDisplayName(Context context, Result contactData, TextView textView) {
+ public static void setDisplayName(Context context, Contact contactData, TextView textView) {
if (textView == null) {
return;
}
@@ -389,7 +384,7 @@
* Sets the company and job title of this contact to the given {@link TextView}. If
* there is none, then set the view to gone.
*/
- public static void setCompanyName(Context context, Result contactData, TextView textView) {
+ public static void setCompanyName(Context context, Contact contactData, TextView textView) {
if (textView == null) {
return;
}
@@ -400,7 +395,7 @@
* Sets the phonetic name of this contact to the given {@link TextView}. If
* there is none, then set the view to gone.
*/
- public static void setPhoneticName(Context context, Result contactData, TextView textView) {
+ public static void setPhoneticName(Context context, Contact contactData, TextView textView) {
if (textView == null) {
return;
}
@@ -411,7 +406,7 @@
* Sets the attribution contact to the given {@link TextView}. If
* there is none, then set the view to gone.
*/
- public static void setAttribution(Context context, Result contactData, TextView textView) {
+ public static void setAttribution(Context context, Contact contactData, TextView textView) {
if (textView == null) {
return;
}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 4fee26e..f66466d 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -22,8 +22,6 @@
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.Entity;
-import android.content.Entity.NamedContentValues;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -36,23 +34,13 @@
import android.os.ServiceManager;
import android.provider.ContactsContract;
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.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;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.DisplayNameSources;
-import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.StatusUpdates;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
@@ -83,7 +71,6 @@
import com.android.contacts.Collapser;
import com.android.contacts.Collapser.Collapsible;
-import com.android.contacts.ContactLoader;
import com.android.contacts.ContactPresenceIconUtil;
import com.android.contacts.ContactSaveService;
import com.android.contacts.ContactsUtils;
@@ -92,15 +79,31 @@
import com.android.contacts.TypePrecedence;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
import com.android.contacts.editor.SelectAccountDialogFragment;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.EditType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.RawContact;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountType.EditType;
+import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.dataitem.DataItem;
+import com.android.contacts.model.dataitem.DataKind;
+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.AccountsListAdapter.AccountListFilter;
import com.android.contacts.util.ClipboardUtils;
import com.android.contacts.util.Constants;
@@ -110,6 +113,7 @@
import com.android.contacts.util.StructuredPostalUtils;
import com.android.internal.telephony.ITelephony;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Collections;
@@ -137,7 +141,7 @@
private Uri mLookupUri;
private Listener mListener;
- private ContactLoader.Result mContactData;
+ private Contact mContactData;
private ViewGroup mStaticPhotoContainer;
private View mPhotoTouchOverlay;
private ListView mListView;
@@ -187,9 +191,8 @@
private Parcelable mListState;
/**
- * A list of distinct contact IDs included in the current contact.
+ * Lists of specific types of entries to be shown in contact details.
*/
- private ArrayList<Long> mRawContactIds = new ArrayList<Long>();
private ArrayList<DetailViewEntry> mPhoneEntries = new ArrayList<DetailViewEntry>();
private ArrayList<DetailViewEntry> mSmsEntries = new ArrayList<DetailViewEntry>();
private ArrayList<DetailViewEntry> mEmailEntries = new ArrayList<DetailViewEntry>();
@@ -335,7 +338,7 @@
return mListener;
}
- protected ContactLoader.Result getContactData() {
+ protected Contact getContactData() {
return mContactData;
}
@@ -362,7 +365,7 @@
setData(null, null);
}
- public void setData(Uri lookupUri, ContactLoader.Result result) {
+ public void setData(Uri lookupUri, Contact result) {
mLookupUri = lookupUri;
mContactData = result;
bindData();
@@ -530,65 +533,47 @@
// Clear out the old entries
mAllEntries.clear();
- mRawContactIds.clear();
-
mPrimaryPhoneUri = null;
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
-
// Build up method entries
if (mContactData == null) {
return;
}
ArrayList<String> groups = new ArrayList<String>();
- for (Entity entity: mContactData.getEntities()) {
- final ContentValues entValues = entity.getEntityValues();
- final String accountType = entValues.getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = entValues.getAsString(RawContacts.DATA_SET);
- final long rawContactId = entValues.getAsLong(RawContacts._ID);
+ for (RawContact rawContact: mContactData.getRawContacts()) {
+ final long rawContactId = rawContact.getId();
+ for (DataItem dataItem : rawContact.getDataItems()) {
+ dataItem.setRawContactId(rawContactId);
- if (!mRawContactIds.contains(rawContactId)) {
- mRawContactIds.add(rawContactId);
- }
+ if (dataItem.getMimeType() == null) continue;
- AccountType type = accountTypes.getAccountType(accountType, dataSet);
-
- for (NamedContentValues subValue : entity.getSubValues()) {
- final ContentValues entryValues = subValue.values;
- entryValues.put(Data.RAW_CONTACT_ID, rawContactId);
-
- final long dataId = entryValues.getAsLong(Data._ID);
- final String mimeType = entryValues.getAsString(Data.MIMETYPE);
- if (mimeType == null) continue;
-
- if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
- Long groupId = entryValues.getAsLong(GroupMembership.GROUP_ROW_ID);
+ if (dataItem instanceof GroupMembershipDataItem) {
+ GroupMembershipDataItem groupMembership =
+ (GroupMembershipDataItem) dataItem;
+ Long groupId = groupMembership.getGroupRowId();
if (groupId != null) {
handleGroupMembership(groups, mContactData.getGroupMetaData(), groupId);
}
continue;
}
- final DataKind kind = accountTypes.getKindOrFallback(
- accountType, dataSet, mimeType);
+ final DataKind kind = dataItem.getDataKind();
if (kind == null) continue;
- final DetailViewEntry entry = DetailViewEntry.fromValues(mContext, mimeType, kind,
- dataId, entryValues, mContactData.isDirectoryEntry(),
- mContactData.getDirectoryId());
+ final DetailViewEntry entry = DetailViewEntry.fromValues(mContext, dataItem,
+ mContactData.isDirectoryEntry(), mContactData.getDirectoryId());
entry.maxLines = kind.maxLinesForDisplay;
final boolean hasData = !TextUtils.isEmpty(entry.data);
- Integer superPrimary = entryValues.getAsInteger(Data.IS_SUPER_PRIMARY);
- final boolean isSuperPrimary = superPrimary != null && superPrimary != 0;
+ final boolean isSuperPrimary = dataItem.isSuperPrimary();
- if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ if (dataItem instanceof StructuredNameDataItem) {
// Always ignore the name. It is shown in the header if set
- } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof PhoneDataItem && hasData) {
+ PhoneDataItem phone = (PhoneDataItem) dataItem;
// Build phone entries
- String phoneNumberE164 =
- entryValues.getAsString(Phone.NORMALIZED_NUMBER);
+ String phoneNumberE164 = phone.getNormalizedNumber();
entry.data = PhoneNumberUtils.formatNumber(
entry.data, phoneNumberE164, mDefaultCountryIso);
final Intent phoneIntent = mHasPhone ?
@@ -623,7 +608,7 @@
// add to end of list
mPhoneEntries.add(entry);
}
- } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof EmailDataItem && hasData) {
// Build email entries
entry.intent = new Intent(Intent.ACTION_SENDTO,
Uri.fromParts(Constants.SCHEME_MAILTO, entry.data, null));
@@ -638,24 +623,23 @@
// When Email rows have status, create additional Im row
final DataStatus status = mContactData.getStatuses().get(entry.id);
if (status != null) {
- final String imMime = Im.CONTENT_ITEM_TYPE;
- final DataKind imKind = accountTypes.getKindOrFallback(accountType, dataSet,
- imMime);
- final DetailViewEntry imEntry = DetailViewEntry.fromValues(mContext, imMime,
- imKind, dataId, entryValues, mContactData.isDirectoryEntry(),
- mContactData.getDirectoryId());
- buildImActions(mContext, imEntry, entryValues);
+ EmailDataItem email = (EmailDataItem) dataItem;
+ ImDataItem im = ImDataItem.createFromEmail(email);
+
+ final DetailViewEntry imEntry = DetailViewEntry.fromValues(mContext, im,
+ mContactData.isDirectoryEntry(), mContactData.getDirectoryId());
+ buildImActions(mContext, imEntry, im);
imEntry.setPresence(status.getPresence());
- imEntry.maxLines = imKind.maxLinesForDisplay;
+ imEntry.maxLines = kind.maxLinesForDisplay;
mImEntries.add(imEntry);
}
- } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof StructuredPostalDataItem && hasData) {
// Build postal entries
entry.intent = StructuredPostalUtils.getViewPostalAddressIntent(entry.data);
mPostalEntries.add(entry);
- } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof ImDataItem && hasData) {
// Build IM entries
- buildImActions(mContext, entry, entryValues);
+ buildImActions(mContext, entry, (ImDataItem) dataItem);
// Apply presence when available
final DataStatus status = mContactData.getStatuses().get(entry.id);
@@ -663,10 +647,10 @@
entry.setPresence(status.getPresence());
}
mImEntries.add(entry);
- } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ } else if (dataItem instanceof OrganizationDataItem) {
// Organizations are not shown. The first one is shown in the header
// and subsequent ones are not supported anymore
- } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof NicknameDataItem && hasData) {
// Build nickname entries
final boolean isNameRawContact =
(mContactData.getNameRawContactId() == rawContactId);
@@ -679,11 +663,11 @@
entry.uri = null;
mNicknameEntries.add(entry);
}
- } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof NoteDataItem && hasData) {
// Build note entries
entry.uri = null;
mNoteEntries.add(entry);
- } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof WebsiteDataItem && hasData) {
// Build Website entries
entry.uri = null;
try {
@@ -694,7 +678,7 @@
Log.e(TAG, "Couldn't parse website: " + entry.data);
}
mWebsiteEntries.add(entry);
- } else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof SipAddressDataItem && hasData) {
// Build SipAddress entries
entry.uri = null;
if (mHasSip) {
@@ -710,11 +694,11 @@
// (Then, we'd also update FallbackAccountType.java to set
// secondary=false for this field, and tweak the weight
// of its DataKind.)
- } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof EventDataItem && hasData) {
entry.data = DateUtils.formatDate(mContext, entry.data);
entry.uri = null;
mEventEntries.add(entry);
- } else if (Relation.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
+ } else if (dataItem instanceof RelationDataItem && hasData) {
entry.intent = new Intent(Intent.ACTION_SEARCH);
entry.intent.putExtra(SearchManager.QUERY, entry.data);
entry.intent.setType(Contacts.CONTENT_TYPE);
@@ -724,14 +708,12 @@
entry.intent = new Intent(Intent.ACTION_VIEW);
entry.intent.setDataAndType(entry.uri, entry.mimetype);
- if (kind.actionBody != null) {
- CharSequence body = kind.actionBody.inflateUsing(mContext, entryValues);
- entry.data = (body == null) ? null : body.toString();
- }
+ entry.data = dataItem.buildDataString();
if (!TextUtils.isEmpty(entry.data)) {
// If the account type exists in the hash map, add it as another entry for
// that account type
+ AccountType type = dataItem.getAccountType();
if (mOtherEntriesMap.containsKey(type)) {
List<DetailViewEntry> listEntries = mOtherEntriesMap.get(type);
listEntries.add(entry);
@@ -960,37 +942,27 @@
}
}
- private static String buildDataString(DataKind kind, ContentValues values,
- Context context) {
- if (kind.actionBody == null) {
- return null;
- }
- CharSequence actionBody = kind.actionBody.inflateUsing(context, values);
- return actionBody == null ? null : actionBody.toString();
- }
-
/**
* Writes the Instant Messaging action into the given entry value.
*/
@VisibleForTesting
public static void buildImActions(Context context, DetailViewEntry entry,
- ContentValues values) {
- final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(values.getAsString(Data.MIMETYPE));
+ ImDataItem im) {
+ final boolean isEmail = im.isCreatedFromEmail();
- if (!isEmail && !isProtocolValid(values)) {
+ if (!isEmail && !im.isProtocolValid()) {
return;
}
- final String data = values.getAsString(isEmail ? Email.DATA : Im.DATA);
+ final String data = im.getData();
if (TextUtils.isEmpty(data)) {
return;
}
- final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : values.getAsInteger(Im.PROTOCOL);
+ final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : im.getProtocol();
if (protocol == Im.PROTOCOL_GOOGLE_TALK) {
- final Integer chatCapabilityObj = values.getAsInteger(Im.CHAT_CAPABILITY);
- final int chatCapability = chatCapabilityObj == null ? 0 : chatCapabilityObj;
+ final int chatCapability = im.getChatCapability();
entry.chatCapability = chatCapability;
entry.typeString = Im.getProtocolLabel(context.getResources(), Im.PROTOCOL_GOOGLE_TALK,
null).toString();
@@ -1011,7 +983,7 @@
}
} else {
// Build an IM Intent
- String host = values.getAsString(Im.CUSTOM_PROTOCOL);
+ String host = im.getCustomProtocol();
if (protocol != Im.PROTOCOL_CUSTOM) {
// Try bringing in a well-known host for specific protocols
@@ -1027,19 +999,6 @@
}
}
- private static boolean isProtocolValid(ContentValues values) {
- String protocolString = values.getAsString(Im.PROTOCOL);
- if (protocolString == null) {
- return false;
- }
- try {
- Integer.valueOf(protocolString);
- } catch (NumberFormatException e) {
- return false;
- }
- return true;
- }
-
/**
* Show a list popup. Used for "popup-able" entry, such as "More networks".
*/
@@ -1246,6 +1205,38 @@
private boolean mIsInSubSection = false;
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("== DetailViewEntry ==\n");
+ sb.append(" type: " + type + "\n");
+ sb.append(" kind: " + kind + "\n");
+ sb.append(" typeString: " + typeString + "\n");
+ sb.append(" data: " + data + "\n");
+ sb.append(" uri: " + uri.toString() + "\n");
+ sb.append(" maxLines: " + maxLines + "\n");
+ sb.append(" mimetype: " + mimetype + "\n");
+ sb.append(" isPrimary: " + (isPrimary ? "true" : "false") + "\n");
+ sb.append(" secondaryActionIcon: " + secondaryActionIcon + "\n");
+ sb.append(" secondaryActionDescription: " + secondaryActionDescription + "\n");
+ if (intent == null) {
+ sb.append(" intent: " + intent.toString() + "\n");
+ } else {
+ sb.append(" intent: " + intent.toString() + "\n");
+ }
+ if (secondaryIntent == null) {
+ sb.append(" secondaryIntent: (null)\n");
+ } else {
+ sb.append(" secondaryIntent: " + secondaryIntent.toString() + "\n");
+ }
+ sb.append(" ids: " + Iterables.toString(ids) + "\n");
+ sb.append(" collapseCount: " + collapseCount + "\n");
+ sb.append(" presence: " + presence + "\n");
+ sb.append(" chatCapability: " + chatCapability + "\n");
+ sb.append(" mIsInSubsection: " + (mIsInSubSection ? "true" : "false") + "\n");
+ return sb.toString();
+ }
+
DetailViewEntry() {
super(ViewAdapter.VIEW_TYPE_DETAIL_ENTRY);
isEnabled = true;
@@ -1254,34 +1245,34 @@
/**
* Build new {@link DetailViewEntry} and populate from the given values.
*/
- public static DetailViewEntry fromValues(Context context, String mimeType, DataKind kind,
- long dataId, ContentValues values, boolean isDirectoryEntry, long directoryId) {
+ public static DetailViewEntry fromValues(Context context, DataItem item,
+ boolean isDirectoryEntry, long directoryId) {
final DetailViewEntry entry = new DetailViewEntry();
- entry.id = dataId;
+ entry.id = item.getId();
entry.context = context;
entry.uri = ContentUris.withAppendedId(Data.CONTENT_URI, entry.id);
if (isDirectoryEntry) {
entry.uri = entry.uri.buildUpon().appendQueryParameter(
ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
}
- entry.mimetype = mimeType;
- entry.kind = (kind.titleRes == -1 || kind.titleRes == 0) ? ""
- : context.getString(kind.titleRes);
- entry.data = buildDataString(kind, values, context);
+ entry.mimetype = item.getMimeType();
+ entry.kind = item.getKindString();
+ entry.data = item.buildDataString();
- if (kind.typeColumn != null && values.containsKey(kind.typeColumn)) {
- entry.type = values.getAsInteger(kind.typeColumn);
+ if (item.hasKindTypeColumn()) {
+ entry.type = item.getKindTypeColumn();
// get type string
entry.typeString = "";
- for (EditType type : kind.typeList) {
+ for (EditType type : item.getDataKind().typeList) {
if (type.rawValue == entry.type) {
if (type.customColumn == null) {
// Non-custom type. Get its description from the resource
entry.typeString = context.getString(type.labelRes);
} else {
// Custom type. Read it from the database
- entry.typeString = values.getAsString(type.customColumn);
+ entry.typeString =
+ item.getContentValues().getAsString(type.customColumn);
}
break;
}
@@ -1996,7 +1987,7 @@
if (mContactData.isUserProfile()) return false;
// Only if exactly one raw contact
- if (mContactData.getEntities().size() != 1) return false;
+ if (mContactData.getRawContacts().size() != 1) return false;
// test if the default group is assigned
final List<GroupMetaData> groups = mContactData.getGroupMetaData();
@@ -2008,28 +1999,20 @@
final long defaultGroupId = getDefaultGroupId(groups);
if (defaultGroupId == -1) return false;
- final Entity rawContactEntity = mContactData.getEntities().get(0);
- ContentValues rawValues = rawContactEntity.getEntityValues();
- final String accountType = rawValues.getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = rawValues.getAsString(RawContacts.DATA_SET);
- final AccountTypeManager accountTypes =
- AccountTypeManager.getInstance(mContext);
- final AccountType type = accountTypes.getAccountType(accountType, dataSet);
+ final RawContact rawContact = (RawContact) mContactData.getRawContacts().get(0);
+ final AccountType type = rawContact.getAccountType();
// Offline or non-writeable account? Nothing to fix
if (type == null || !type.areContactsWritable()) return false;
// Check whether the contact is in the default group
boolean isInDefaultGroup = false;
- for (NamedContentValues subValue : rawContactEntity.getSubValues()) {
- final String mimeType = subValue.values.getAsString(Data.MIMETYPE);
-
- if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
- final Long groupId =
- subValue.values.getAsLong(GroupMembership.GROUP_ROW_ID);
- if (groupId == defaultGroupId) {
- isInDefaultGroup = true;
- break;
- }
+ for (DataItem dataItem : Iterables.filter(
+ rawContact.getDataItems(), GroupMembershipDataItem.class)) {
+ GroupMembershipDataItem groupMembership = (GroupMembershipDataItem) dataItem;
+ final Long groupId = groupMembership.getGroupRowId();
+ if (groupId == defaultGroupId) {
+ isInDefaultGroup = true;
+ break;
}
}
@@ -2049,19 +2032,16 @@
if (defaultGroupId == -1) return;
// add the group membership to the current state
- final EntityDeltaList contactDeltaList = mContactData.createEntityDeltaList();
- final EntityDelta rawContactEntityDelta = contactDeltaList.get(0);
+ final RawContactDeltaList contactDeltaList = mContactData.createRawContactDeltaList();
+ final RawContactDelta rawContactEntityDelta = contactDeltaList.get(0);
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
- final ValuesDelta values = rawContactEntityDelta.getValues();
- final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = values.getAsString(RawContacts.DATA_SET);
- final AccountType type = accountTypes.getAccountType(accountType, dataSet);
+ final AccountType type = rawContactEntityDelta.getAccountType(accountTypes);
final DataKind groupMembershipKind = type.getKindForMimetype(
GroupMembership.CONTENT_ITEM_TYPE);
- final ValuesDelta entry = EntityModifier.insertChild(rawContactEntityDelta,
+ final ValuesDelta entry = RawContactModifier.insertChild(rawContactEntityDelta,
groupMembershipKind);
- entry.put(GroupMembership.GROUP_ROW_ID, defaultGroupId);
+ entry.setGroupRowId(defaultGroupId);
// and fire off the intent. we don't need a callback, as the database listener
// should update the ui
@@ -2198,7 +2178,7 @@
private final LayoutInflater mInflater;
private final ArrayList<AccountType> mAccountTypes;
- public InvitableAccountTypesAdapter(Context context, ContactLoader.Result contactData) {
+ public InvitableAccountTypesAdapter(Context context, Contact contactData) {
mContext = context;
mInflater = LayoutInflater.from(context);
final List<AccountType> types = contactData.getInvitableAccountTypes();
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 8a87231..fca426c 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -34,10 +34,10 @@
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
-import com.android.contacts.ContactLoader;
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.util.PhoneCapabilityTester;
import com.android.contacts.util.UriUtils;
import com.android.contacts.widget.FrameLayoutWithOverlay;
@@ -102,7 +102,7 @@
private final ContactDetailFragment.Listener mContactDetailFragmentListener;
- private ContactLoader.Result mContactData;
+ private Contact mContactData;
private Uri mContactUri;
private boolean mTabCarouselIsAnimating;
@@ -270,7 +270,7 @@
}
}
- public void setContactData(ContactLoader.Result data) {
+ public void setContactData(Contact data) {
final boolean contactWasLoaded;
final boolean contactHadUpdates;
final boolean isDifferentContact;
diff --git a/src/com/android/contacts/detail/ContactDetailPhotoSetter.java b/src/com/android/contacts/detail/ContactDetailPhotoSetter.java
index 126c43a..eb832e9 100644
--- a/src/com/android/contacts/detail/ContactDetailPhotoSetter.java
+++ b/src/com/android/contacts/detail/ContactDetailPhotoSetter.java
@@ -25,10 +25,10 @@
import android.view.View.OnClickListener;
import android.widget.ImageView;
-import com.android.contacts.ContactLoader.Result;
import com.android.contacts.ContactPhotoManager;
import com.android.contacts.activities.PhotoSelectionActivity;
-import com.android.contacts.model.EntityDeltaList;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.util.ImageViewDrawableSetter;
/**
@@ -36,7 +36,7 @@
* photo.
*/
public class ContactDetailPhotoSetter extends ImageViewDrawableSetter {
- public OnClickListener setupContactPhotoForClick(Context context, Result contactData,
+ public OnClickListener setupContactPhotoForClick(Context context, Contact contactData,
ImageView photoView, boolean expandPhotoOnClick) {
setTarget(photoView);
Bitmap bitmap = setCompressedImage(contactData.getPhotoBinaryData());
@@ -46,12 +46,12 @@
private static final class PhotoClickListener implements OnClickListener {
private final Context mContext;
- private final Result mContactData;
+ private final Contact mContactData;
private final Bitmap mPhotoBitmap;
private final byte[] mPhotoBytes;
private final boolean mExpandPhotoOnClick;
- public PhotoClickListener(Context context, Result contactData, Bitmap photoBitmap,
+ public PhotoClickListener(Context context, Contact contactData, Bitmap photoBitmap,
byte[] photoBytes, boolean expandPhotoOnClick) {
mContext = context;
mContactData = contactData;
@@ -63,7 +63,7 @@
@Override
public void onClick(View v) {
// Assemble the intent.
- EntityDeltaList delta = mContactData.createEntityDeltaList();
+ RawContactDeltaList delta = mContactData.createRawContactDeltaList();
// Find location and bounds of target view, adjusting based on the
// assumed local density.
@@ -96,7 +96,7 @@
}
}
- private OnClickListener setupClickListener(Context context, Result contactData, Bitmap bitmap,
+ private OnClickListener setupClickListener(Context context, Contact contactData, Bitmap bitmap,
boolean expandPhotoOnClick) {
final ImageView target = getTarget();
if (target == null) return null;
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index 3191402..540f001 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -29,8 +29,8 @@
import android.widget.ImageView;
import android.widget.TextView;
-import com.android.contacts.ContactLoader;
import com.android.contacts.R;
+import com.android.contacts.model.Contact;
import com.android.contacts.util.MoreMath;
import com.android.contacts.util.SchedulingUtils;
@@ -464,7 +464,7 @@
* Loads the data from the Loader-Result. This is the only function that has to be called
* from the outside to fully setup the View
*/
- public void loadData(ContactLoader.Result contactData) {
+ public void loadData(Contact contactData) {
if (contactData == null) return;
// TODO: Move this into the {@link CarouselTab} class when the updates
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index 9ae614a..88c30c2 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -28,19 +28,19 @@
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
-import com.android.contacts.ContactLoader;
import com.android.contacts.R;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
import com.android.contacts.detail.ContactDetailDisplayUtils.StreamPhotoTag;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.account.AccountType;
import com.android.contacts.util.StreamItemEntry;
public class ContactDetailUpdatesFragment extends ListFragment implements FragmentKeyListener {
private static final String TAG = "ContactDetailUpdatesFragment";
- private ContactLoader.Result mContactData;
+ private Contact mContactData;
private Uri mLookupUri;
private LayoutInflater mInflater;
@@ -121,7 +121,7 @@
}
}
- public void setData(Uri lookupUri, ContactLoader.Result result) {
+ public void setData(Uri lookupUri, Contact result) {
if (result == null) {
return;
}
diff --git a/src/com/android/contacts/detail/ContactLoaderFragment.java b/src/com/android/contacts/detail/ContactLoaderFragment.java
index 787390c..6a69744 100644
--- a/src/com/android/contacts/detail/ContactLoaderFragment.java
+++ b/src/com/android/contacts/detail/ContactLoaderFragment.java
@@ -39,12 +39,13 @@
import android.view.ViewGroup;
import android.widget.Toast;
-import com.android.contacts.ContactLoader;
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
import com.android.contacts.list.ShortcutIntentBuilder;
import com.android.contacts.list.ShortcutIntentBuilder.OnShortcutIntentCreatedListener;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.ContactLoader;
import com.android.contacts.util.PhoneCapabilityTester;
import com.android.internal.util.Objects;
@@ -84,7 +85,7 @@
/**
* Contact details have finished loading.
*/
- public void onDetailsLoaded(ContactLoader.Result result);
+ public void onDetailsLoaded(Contact result);
/**
* User decided to go to Edit-Mode
@@ -107,7 +108,7 @@
private Uri mLookupUri;
private ContactLoaderFragmentListener mListener;
- private ContactLoader.Result mContactData;
+ private Contact mContactData;
public ContactLoaderFragment() {
}
@@ -179,10 +180,10 @@
/**
* The listener for the detail loader
*/
- private final LoaderManager.LoaderCallbacks<ContactLoader.Result> mDetailLoaderListener =
- new LoaderCallbacks<ContactLoader.Result>() {
+ private final LoaderManager.LoaderCallbacks<Contact> mDetailLoaderListener =
+ new LoaderCallbacks<Contact>() {
@Override
- public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
+ public Loader<Contact> onCreateLoader(int id, Bundle args) {
Uri lookupUri = args.getParcelable(LOADER_ARG_CONTACT_URI);
return new ContactLoader(mContext, lookupUri, true /* loadGroupMetaData */,
true /* loadStreamItems */, true /* load invitable account types */,
@@ -190,7 +191,7 @@
}
@Override
- public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
+ public void onLoadFinished(Loader<Contact> loader, Contact data) {
if (!mLookupUri.equals(data.getRequestedUri())) {
Log.e(TAG, "Different URI: requested=" + mLookupUri + " actual=" + data);
return;
@@ -219,7 +220,7 @@
}
@Override
- public void onLoaderReset(Loader<ContactLoader.Result> loader) {}
+ public void onLoaderReset(Loader<Contact> loader) {}
};
@Override
@@ -461,14 +462,14 @@
/** Toggles whether to load stream items. Just for debugging */
public void toggleLoadStreamItems() {
- Loader<ContactLoader.Result> loaderObj = getLoaderManager().getLoader(LOADER_DETAILS);
+ Loader<Contact> loaderObj = getLoaderManager().getLoader(LOADER_DETAILS);
ContactLoader loader = (ContactLoader) loaderObj;
loader.setLoadStreamItems(!loader.getLoadStreamItems());
}
/** Returns whether to load stream items. Just for debugging */
public boolean getLoadStreamItems() {
- Loader<ContactLoader.Result> loaderObj = getLoaderManager().getLoader(LOADER_DETAILS);
+ Loader<Contact> loaderObj = getLoaderManager().getLoader(LOADER_DETAILS);
ContactLoader loader = (ContactLoader) loaderObj;
return loader != null && loader.getLoadStreamItems();
}
diff --git a/src/com/android/contacts/detail/PhotoSelectionHandler.java b/src/com/android/contacts/detail/PhotoSelectionHandler.java
index 569012e..b5e406a 100644
--- a/src/com/android/contacts/detail/PhotoSelectionHandler.java
+++ b/src/com/android/contacts/detail/PhotoSelectionHandler.java
@@ -39,12 +39,12 @@
import com.android.contacts.R;
import com.android.contacts.editor.PhotoActionPopup;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.util.ContactPhotoUtils;
import java.io.File;
@@ -64,12 +64,12 @@
private final View mPhotoView;
private final int mPhotoMode;
private final int mPhotoPickSize;
- private final EntityDeltaList mState;
+ private final RawContactDeltaList mState;
private final boolean mIsDirectoryContact;
private ListPopupWindow mPopup;
public PhotoSelectionHandler(Context context, View photoView, int photoMode,
- boolean isDirectoryContact, EntityDeltaList state) {
+ boolean isDirectoryContact, RawContactDeltaList state) {
mContext = context;
mPhotoView = photoView;
mPhotoMode = photoMode;
@@ -162,12 +162,12 @@
* or null if the photo could not be parsed or none of the accounts associated with the
* contact are writable.
*/
- public EntityDeltaList getDeltaForAttachingPhotoToContact() {
+ public RawContactDeltaList getDeltaForAttachingPhotoToContact() {
// Find the first writable entity.
int writableEntityIndex = getWritableEntityIndex();
if (writableEntityIndex != -1) {
// We are guaranteed to have contact data if we have a writable entity index.
- final EntityDelta delta = mState.get(writableEntityIndex);
+ final RawContactDelta delta = mState.get(writableEntityIndex);
// Need to find the right account so that EntityModifier knows which fields to add
final ContentValues entityValues = delta.getValues().getCompleteValues();
@@ -176,10 +176,10 @@
final AccountType accountType = AccountTypeManager.getInstance(mContext).getAccountType(
type, dataSet);
- final ValuesDelta child = EntityModifier.ensureKindExists(
+ final ValuesDelta child = RawContactModifier.ensureKindExists(
delta, accountType, Photo.CONTENT_ITEM_TYPE);
child.setFromTemplate(false);
- child.put(Photo.IS_SUPER_PRIMARY, 1);
+ child.setSuperPrimary(true);
return mState;
}
diff --git a/src/com/android/contacts/detail/StreamItemAdapter.java b/src/com/android/contacts/detail/StreamItemAdapter.java
index 7564167..15219cd 100644
--- a/src/com/android/contacts/detail/StreamItemAdapter.java
+++ b/src/com/android/contacts/detail/StreamItemAdapter.java
@@ -23,8 +23,8 @@
import android.widget.BaseAdapter;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
import com.android.contacts.util.StreamItemEntry;
import com.google.common.collect.Lists;
diff --git a/src/com/android/contacts/editor/AggregationSuggestionEngine.java b/src/com/android/contacts/editor/AggregationSuggestionEngine.java
index 7c0e668..0da05e8 100644
--- a/src/com/android/contacts/editor/AggregationSuggestionEngine.java
+++ b/src/com/android/contacts/editor/AggregationSuggestionEngine.java
@@ -37,7 +37,7 @@
import android.provider.ContactsContract.RawContacts;
import android.text.TextUtils;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
import com.google.common.collect.Lists;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/editor/AggregationSuggestionView.java b/src/com/android/contacts/editor/AggregationSuggestionView.java
index 77b678a..7327a4c 100644
--- a/src/com/android/contacts/editor/AggregationSuggestionView.java
+++ b/src/com/android/contacts/editor/AggregationSuggestionView.java
@@ -28,8 +28,8 @@
import com.android.contacts.R;
import com.android.contacts.editor.AggregationSuggestionEngine.RawContact;
import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
import com.google.common.collect.Lists;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/editor/BaseRawContactEditorView.java b/src/com/android/contacts/editor/BaseRawContactEditorView.java
index 65395a8..66fc864 100644
--- a/src/com/android/contacts/editor/BaseRawContactEditorView.java
+++ b/src/com/android/contacts/editor/BaseRawContactEditorView.java
@@ -17,7 +17,6 @@
package com.android.contacts.editor;
import android.content.Context;
-import android.content.Entity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.provider.ContactsContract.CommonDataKinds.Photo;
@@ -29,20 +28,20 @@
import android.widget.LinearLayout;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.EditType;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountType.EditType;
/**
* Base view that provides common code for the editor interaction for a specific
- * RawContact represented through an {@link EntityDelta}.
+ * RawContact represented through an {@link RawContactDelta}.
* <p>
* Internal updates are performed against {@link ValuesDelta} so that the
- * source {@link Entity} can be swapped out. Any state-based changes, such as
+ * source {@link RawContact} can be swapped out. Any state-based changes, such as
* adding {@link Data} rows or changing {@link EditType}, are performed through
- * {@link EntityModifier} to ensure that {@link AccountType} are enforced.
+ * {@link RawContactModifier} to ensure that {@link AccountType} are enforced.
*/
public abstract class BaseRawContactEditorView extends LinearLayout {
@@ -78,7 +77,7 @@
/**
* Assign the given {@link Bitmap} to the internal {@link PhotoEditorView}
- * for the {@link EntityDelta} currently being edited.
+ * for the {@link RawContactDelta} currently being edited.
*/
public void setPhotoBitmap(Bitmap bitmap) {
mPhoto.setPhotoBitmap(bitmap);
@@ -115,10 +114,10 @@
/**
* Set the internal state for this view, given a current
- * {@link EntityDelta} state and the {@link AccountType} that
+ * {@link RawContactDelta} state and the {@link AccountType} that
* apply to that state.
*/
- public abstract void setState(EntityDelta state, AccountType source, ViewIdGenerator vig,
+ public abstract void setState(RawContactDelta state, AccountType source, ViewIdGenerator vig,
boolean isProfile);
/* package */ void setExpanded(boolean value) {
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 536c41d..780279e 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -29,7 +29,6 @@
import android.content.Context;
import android.content.CursorLoader;
import android.content.DialogInterface;
-import android.content.Entity;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
@@ -62,7 +61,6 @@
import android.widget.ListPopupWindow;
import android.widget.Toast;
-import com.android.contacts.ContactLoader;
import com.android.contacts.ContactSaveService;
import com.android.contacts.GroupMetaDataLoader;
import com.android.contacts.R;
@@ -72,18 +70,22 @@
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.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.model.EntityModifier;
-import com.android.contacts.model.GoogleAccountType;
+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.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.account.GoogleAccountType;
import com.android.contacts.util.AccountsListAdapter;
import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.util.ContactPhotoUtils;
import com.android.contacts.util.HelpUtils;
+import com.google.common.collect.ImmutableList;
import java.io.File;
import java.util.ArrayList;
@@ -224,7 +226,7 @@
private ContactEditorUtils mEditorUtils;
private LinearLayout mContent;
- private EntityDeltaList mState;
+ private RawContactDeltaList mState;
private ViewIdGenerator mViewIdGenerator;
@@ -420,7 +422,7 @@
mViewIdGenerator = new ViewIdGenerator();
} else {
// Read state from savedState. No loading involved here
- mState = savedState.<EntityDeltaList> getParcelable(KEY_EDIT_STATE);
+ mState = savedState.<RawContactDeltaList> getParcelable(KEY_EDIT_STATE);
mRawContactIdRequestingPhoto = savedState.getLong(
KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR);
@@ -436,7 +438,7 @@
}
}
- public void setData(ContactLoader.Result data) {
+ public void setData(Contact data) {
// If we have already loaded data, we do not want to change it here to not confuse the user
if (mState != null) {
Log.v(TAG, "Ignoring background change. This will have to be rebased later");
@@ -444,19 +446,17 @@
}
// See if this edit operation needs to be redirected to a custom editor
- ArrayList<Entity> entities = data.getEntities();
- if (entities.size() == 1) {
- Entity entity = entities.get(0);
- ContentValues entityValues = entity.getEntityValues();
- String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
- String dataSet = entityValues.getAsString(RawContacts.DATA_SET);
- AccountType accountType = AccountTypeManager.getInstance(mContext).getAccountType(
- type, dataSet);
+ ImmutableList<RawContact> rawContacts = data.getRawContacts();
+ if (rawContacts.size() == 1) {
+ RawContact rawContact = rawContacts.get(0);
+ String type = rawContact.getAccountTypeString();
+ String dataSet = rawContact.getDataSet();
+ AccountType accountType = rawContact.getAccountType();
if (accountType.getEditContactActivityClassName() != null &&
!accountType.areContactsWritable()) {
if (mListener != null) {
- String name = entityValues.getAsString(RawContacts.ACCOUNT_NAME);
- long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID);
+ String name = rawContact.getAccountName();
+ long rawContactId = rawContact.getId();
mListener.onCustomEditContactActivityRequested(
new AccountWithDataSet(name, type, dataSet),
ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId),
@@ -474,10 +474,10 @@
mListener.onCustomEditContactActivityRequested(account, uri, null, false);
}
- private void bindEditorsForExistingContact(ContactLoader.Result contact) {
+ private void bindEditorsForExistingContact(Contact contact) {
setEnabled(true);
- mState = contact.createEntityDeltaList();
+ mState = contact.createRawContactDeltaList();
setIntentExtras(mIntentExtras);
mIntentExtras = null;
@@ -486,7 +486,7 @@
boolean localProfileExists = false;
if (mIsUserProfile) {
- for (EntityDelta state : mState) {
+ for (RawContactDelta state : mState) {
// For profile contacts, we need a different query URI
state.setProfileQueryUri();
// Try to find a local profile contact
@@ -496,11 +496,11 @@
}
// Editor should always present a local profile for editing
if (!localProfileExists) {
- final ContentValues values = new ContentValues();
- values.putNull(RawContacts.ACCOUNT_NAME);
- values.putNull(RawContacts.ACCOUNT_TYPE);
- values.putNull(RawContacts.DATA_SET);
- EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values));
+ final RawContact rawContact = new RawContact(mContext);
+ rawContact.setAccountToLocal();
+
+ RawContactDelta insert = new RawContactDelta(ValuesDelta.fromAfter(
+ rawContact.getValues()));
insert.setProfileQueryUri();
mState.add(insert);
}
@@ -519,13 +519,11 @@
}
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
- for (EntityDelta state : mState) {
- final String accountType = state.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = state.getValues().getAsString(RawContacts.DATA_SET);
- final AccountType type = accountTypes.getAccountType(accountType, dataSet);
+ for (RawContactDelta state : mState) {
+ final AccountType type = state.getAccountType(accountTypes);
if (type.areContactsWritable()) {
// Apply extras to the first writable raw contact only
- EntityModifier.parseExtras(mContext, type, state, extras);
+ RawContactModifier.parseExtras(mContext, type, state, extras);
break;
}
}
@@ -604,7 +602,8 @@
* @param newAccount New account to be used.
*/
private void rebindEditorsForNewContact(
- EntityDelta oldState, AccountWithDataSet oldAccount, AccountWithDataSet newAccount) {
+ RawContactDelta oldState, AccountWithDataSet oldAccount,
+ AccountWithDataSet newAccount) {
AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
AccountType oldAccountType = accountTypes.getAccountType(
oldAccount.type, oldAccount.dataSet);
@@ -628,36 +627,34 @@
}
private void bindEditorsForNewContact(AccountWithDataSet newAccount,
- final AccountType newAccountType, EntityDelta oldState, AccountType oldAccountType) {
+ final AccountType newAccountType, RawContactDelta oldState,
+ AccountType oldAccountType) {
mStatus = Status.EDITING;
- final ContentValues values = new ContentValues();
+ final RawContact rawContact = new RawContact(mContext);
if (newAccount != null) {
- values.put(RawContacts.ACCOUNT_NAME, newAccount.name);
- values.put(RawContacts.ACCOUNT_TYPE, newAccount.type);
- values.put(RawContacts.DATA_SET, newAccount.dataSet);
+ rawContact.setAccount(newAccount);
} else {
- values.putNull(RawContacts.ACCOUNT_NAME);
- values.putNull(RawContacts.ACCOUNT_TYPE);
- values.putNull(RawContacts.DATA_SET);
+ rawContact.setAccountToLocal();
}
- EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values));
+ RawContactDelta insert = new RawContactDelta(ValuesDelta.fromAfter(rawContact.getValues()));
if (oldState == null) {
// Parse any values from incoming intent
- EntityModifier.parseExtras(mContext, newAccountType, insert, mIntentExtras);
+ RawContactModifier.parseExtras(mContext, newAccountType, insert, mIntentExtras);
} else {
- EntityModifier.migrateStateForNewContact(mContext, oldState, insert,
+ RawContactModifier.migrateStateForNewContact(mContext, oldState, insert,
oldAccountType, newAccountType);
}
// Ensure we have some default fields (if the account type does not support a field,
// ensureKind will not add it, so it is safe to add e.g. Event)
- EntityModifier.ensureKindExists(insert, newAccountType, Phone.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, newAccountType, Email.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, newAccountType, Organization.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, newAccountType, Event.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(insert, newAccountType, StructuredPostal.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(insert, newAccountType, Phone.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(insert, newAccountType, Email.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(insert, newAccountType, Organization.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(insert, newAccountType, Event.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(insert, newAccountType,
+ StructuredPostal.CONTENT_ITEM_TYPE);
// Set the correct URI for saving the contact as a profile
if (mNewLocalProfile) {
@@ -666,7 +663,7 @@
if (mState == null) {
// Create state if none exists yet
- mState = EntityDeltaList.fromSingle(insert);
+ mState = RawContactDeltaList.fromSingle(insert);
} else {
// Add contact onto end of existing state
mState.add(insert);
@@ -690,14 +687,11 @@
int numRawContacts = mState.size();
for (int i = 0; i < numRawContacts; i++) {
// TODO ensure proper ordering of entities in the list
- final EntityDelta entity = mState.get(i);
- final ValuesDelta values = entity.getValues();
- if (!values.isVisible()) continue;
+ final RawContactDelta rawContactDelta = mState.get(i);
+ if (!rawContactDelta.isVisible()) continue;
- final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = values.getAsString(RawContacts.DATA_SET);
- final AccountType type = accountTypes.getAccountType(accountType, dataSet);
- final long rawContactId = values.getAsLong(RawContacts._ID);
+ final AccountType type = rawContactDelta.getAccountType(accountTypes);
+ final long rawContactId = rawContactDelta.getRawContactId();
final BaseRawContactEditorView editor;
if (!type.areContactsWritable()) {
@@ -724,7 +718,7 @@
mContent.addView(editor);
- editor.setState(entity, type, mViewIdGenerator, isEditingUserProfile());
+ editor.setState(rawContactDelta, type, mViewIdGenerator, isEditingUserProfile());
// Set up the photo handler.
bindPhotoHandler(editor, type, mState);
@@ -797,7 +791,7 @@
}
private void bindPhotoHandler(BaseRawContactEditorView editor, AccountType type,
- EntityDeltaList state) {
+ RawContactDeltaList state) {
final int mode;
if (type.areContactsWritable()) {
if (editor.hasSetPhoto()) {
@@ -852,11 +846,10 @@
// Find the associated account for this contact (retrieve it here because there are
// multiple paths to creating a contact and this ensures we always have the correct
// account).
- final EntityDelta entity = mState.get(0);
- final ValuesDelta values = entity.getValues();
- String name = values.getAsString(RawContacts.ACCOUNT_NAME);
- String type = values.getAsString(RawContacts.ACCOUNT_TYPE);
- String dataSet = values.getAsString(RawContacts.DATA_SET);
+ final RawContactDelta rawContactDelta = mState.get(0);
+ String name = rawContactDelta.getAccountName();
+ String type = rawContactDelta.getAccountType();
+ String dataSet = rawContactDelta.getDataSet();
AccountWithDataSet account = (name == null || type == null) ? null :
new AccountWithDataSet(name, type, dataSet);
@@ -864,12 +857,11 @@
}
private void addAccountSwitcher(
- final EntityDelta currentState, BaseRawContactEditorView editor) {
- ValuesDelta values = currentState.getValues();
+ final RawContactDelta currentState, BaseRawContactEditorView editor) {
final AccountWithDataSet currentAccount = new AccountWithDataSet(
- values.getAsString(RawContacts.ACCOUNT_NAME),
- values.getAsString(RawContacts.ACCOUNT_TYPE),
- values.getAsString(RawContacts.DATA_SET));
+ currentState.getAccountName(),
+ currentState.getAccountType(),
+ currentState.getDataSet());
final View accountView = editor.findViewById(R.id.account);
final View anchorView = editor.findViewById(R.id.account_container);
accountView.setOnClickListener(new View.OnClickListener() {
@@ -1005,7 +997,7 @@
*/
private boolean hasPendingChanges() {
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
- return EntityModifier.hasChanges(mState, accountTypes);
+ return RawContactModifier.hasChanges(mState, accountTypes);
}
/**
@@ -1209,10 +1201,8 @@
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
int size = mState.size();
for (int i = 0; i < size; i++) {
- ValuesDelta values = mState.get(i).getValues();
- final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = values.getAsString(RawContacts.DATA_SET);
- final AccountType type = accountTypes.getAccountType(accountType, dataSet);
+ RawContactDelta entity = mState.get(i);
+ final AccountType type = entity.getAccountType(accountTypes);
if (type.areContactsWritable()) {
return true;
}
@@ -1273,12 +1263,12 @@
Bundle intentExtras, boolean redirect);
}
- private class EntityDeltaComparator implements Comparator<EntityDelta> {
+ private class EntityDeltaComparator implements Comparator<RawContactDelta> {
/**
* Compare EntityDeltas for sorting the stack of editors.
*/
@Override
- public int compare(EntityDelta one, EntityDelta two) {
+ public int compare(RawContactDelta one, RawContactDelta two) {
// Check direct equality
if (one.equals(two)) {
return 0;
@@ -1333,11 +1323,9 @@
}
// Check account name
- ValuesDelta oneValues = one.getValues();
- String oneAccount = oneValues.getAsString(RawContacts.ACCOUNT_NAME);
+ String oneAccount = one.getAccountName();
if (oneAccount == null) oneAccount = "";
- ValuesDelta twoValues = two.getValues();
- String twoAccount = twoValues.getAsString(RawContacts.ACCOUNT_NAME);
+ String twoAccount = two.getAccountName();
if (twoAccount == null) twoAccount = "";
value = oneAccount.compareTo(twoAccount);
if (value != 0) {
@@ -1345,8 +1333,8 @@
}
// Both are in the same account, fall back to contact ID
- Long oneId = oneValues.getAsLong(RawContacts._ID);
- Long twoId = twoValues.getAsLong(RawContacts._ID);
+ Long oneId = one.getRawContactId();
+ Long twoId = two.getRawContactId();
if (oneId == null) {
return -1;
} else if (twoId == null) {
@@ -1362,7 +1350,7 @@
*/
protected long getContactId() {
if (mState != null) {
- for (EntityDelta rawContact : mState) {
+ for (RawContactDelta rawContact : mState) {
Long contactId = rawContact.getValues().getAsLong(RawContacts.CONTACT_ID);
if (contactId != null) {
return contactId;
@@ -1662,14 +1650,13 @@
int countWithPicture = 0;
final int numEntities = mState.size();
for (int i = 0; i < numEntities; i++) {
- final EntityDelta entity = mState.get(i);
- final ValuesDelta values = entity.getValues();
- if (values.isVisible()) {
+ final RawContactDelta entity = mState.get(i);
+ if (entity.isVisible()) {
final ValuesDelta primary = entity.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
- if (primary != null && primary.getAsByteArray(Photo.PHOTO) != null) {
+ if (primary != null && primary.getPhoto() != null) {
countWithPicture++;
} else {
- final long rawContactId = values.getAsLong(RawContacts._ID);
+ final long rawContactId = entity.getRawContactId();
final String path = mUpdatedPhotos.getString(String.valueOf(rawContactId));
if (path != null) {
final File file = new File(path);
@@ -1690,16 +1677,16 @@
/**
* The listener for the data loader
*/
- private final LoaderManager.LoaderCallbacks<ContactLoader.Result> mDataLoaderListener =
- new LoaderCallbacks<ContactLoader.Result>() {
+ private final LoaderManager.LoaderCallbacks<Contact> mDataLoaderListener =
+ new LoaderCallbacks<Contact>() {
@Override
- public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
+ public Loader<Contact> onCreateLoader(int id, Bundle args) {
mLoaderStartTime = SystemClock.elapsedRealtime();
return new ContactLoader(mContext, mLookupUri, true);
}
@Override
- public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
+ public void onLoadFinished(Loader<Contact> loader, Contact data) {
final long loaderCurrentTime = SystemClock.elapsedRealtime();
Log.v(TAG, "Time needed for loading: " + (loaderCurrentTime-mLoaderStartTime));
if (!data.isLoaded()) {
@@ -1719,7 +1706,7 @@
}
@Override
- public void onLoaderReset(Loader<ContactLoader.Result> loader) {
+ public void onLoaderReset(Loader<Contact> loader) {
}
};
@@ -1772,7 +1759,7 @@
private final PhotoActionListener mPhotoEditorListener;
public PhotoHandler(Context context, BaseRawContactEditorView editor, int photoMode,
- EntityDeltaList state) {
+ RawContactDeltaList state) {
super(context, editor.getPhotoEditor(), photoMode, false, state);
mEditor = editor;
mRawContactId = editor.getRawContactId();
diff --git a/src/com/android/contacts/editor/ContactEditorUtils.java b/src/com/android/contacts/editor/ContactEditorUtils.java
index 0029b14..2791c2d 100644
--- a/src/com/android/contacts/editor/ContactEditorUtils.java
+++ b/src/com/android/contacts/editor/ContactEditorUtils.java
@@ -26,9 +26,9 @@
import android.text.TextUtils;
import android.util.Log;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.test.NeededForTesting;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
diff --git a/src/com/android/contacts/editor/Editor.java b/src/com/android/contacts/editor/Editor.java
index 025f092..05336f2 100644
--- a/src/com/android/contacts/editor/Editor.java
+++ b/src/com/android/contacts/editor/Editor.java
@@ -18,9 +18,9 @@
import android.provider.ContactsContract.Data;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.dataitem.DataKind;
/**
* Generic definition of something that edits a {@link Data} row through an
@@ -60,7 +60,7 @@
* builds any needed views. Any changes performed by the user will be
* written back to that same object.
*/
- public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly,
+ public void setValues(DataKind kind, ValuesDelta values, RawContactDelta state, boolean readOnly,
ViewIdGenerator vig);
public void setDeletable(boolean deletable);
diff --git a/src/com/android/contacts/editor/EventFieldEditorView.java b/src/com/android/contacts/editor/EventFieldEditorView.java
index ff2622f..ca1bf64 100644
--- a/src/com/android/contacts/editor/EventFieldEditorView.java
+++ b/src/com/android/contacts/editor/EventFieldEditorView.java
@@ -29,11 +29,11 @@
import com.android.contacts.datepicker.DatePicker;
import com.android.contacts.datepicker.DatePickerDialog;
import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener;
-import com.android.contacts.model.AccountType.EditField;
-import com.android.contacts.model.AccountType.EventEditType;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.account.AccountType.EditField;
+import com.android.contacts.model.account.AccountType.EventEditType;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.util.DateUtils;
import java.text.ParsePosition;
@@ -108,7 +108,7 @@
}
@Override
- public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
+ public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly,
ViewIdGenerator vig) {
if (kind.fieldList.size() != 1) throw new IllegalStateException("kind must have 1 field");
super.setValues(kind, entry, state, readOnly, vig);
diff --git a/src/com/android/contacts/editor/GroupMembershipView.java b/src/com/android/contacts/editor/GroupMembershipView.java
index f405e4d..b84e22b 100644
--- a/src/com/android/contacts/editor/GroupMembershipView.java
+++ b/src/com/android/contacts/editor/GroupMembershipView.java
@@ -21,7 +21,6 @@
import android.content.res.Resources;
import android.database.Cursor;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.RawContacts;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
@@ -40,10 +39,10 @@
import com.android.contacts.R;
import com.android.contacts.interactions.GroupCreationDialogFragment;
import com.android.contacts.interactions.GroupCreationDialogFragment.OnGroupCreatedListener;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.internal.util.Objects;
import java.util.ArrayList;
@@ -127,7 +126,7 @@
}
}
- private EntityDelta mState;
+ private RawContactDelta mState;
private Cursor mGroupMetaData;
private String mAccountName;
private String mAccountType;
@@ -197,12 +196,11 @@
}
}
- public void setState(EntityDelta state) {
+ public void setState(RawContactDelta state) {
mState = state;
- ValuesDelta values = state.getValues();
- mAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
- mAccountName = values.getAsString(RawContacts.ACCOUNT_NAME);
- mDataSet = values.getAsString(RawContacts.DATA_SET);
+ mAccountType = mState.getAccountType();
+ mAccountName = mState.getAccountName();
+ mDataSet = mState.getDataSet();
mDefaultGroupVisibilityKnown = false;
mCreatedNewGroup = false;
updateView();
@@ -357,7 +355,7 @@
if (entries != null) {
for (ValuesDelta entry : entries) {
if (!entry.isDelete()) {
- Long groupId = entry.getAsLong(GroupMembership.GROUP_ROW_ID);
+ Long groupId = entry.getGroupRowId();
if (groupId != null && groupId != mFavoritesGroupId
&& (groupId != mDefaultGroupId || mDefaultGroupVisible)
&& !isGroupChecked(groupId)) {
@@ -372,8 +370,8 @@
GroupSelectionItem item = mAdapter.getItem(i);
long groupId = item.getGroupId();
if (item.isChecked() && !hasMembership(groupId)) {
- ValuesDelta entry = EntityModifier.insertChild(mState, mKind);
- entry.put(GroupMembership.GROUP_ROW_ID, groupId);
+ ValuesDelta entry = RawContactModifier.insertChild(mState, mKind);
+ entry.setGroupRowId(groupId);
}
}
@@ -400,7 +398,7 @@
if (entries != null) {
for (ValuesDelta values : entries) {
if (!values.isDelete()) {
- Long id = values.getAsLong(GroupMembership.GROUP_ROW_ID);
+ Long id = values.getGroupRowId();
if (id != null && id == groupId) {
return true;
}
diff --git a/src/com/android/contacts/editor/KindSectionView.java b/src/com/android/contacts/editor/KindSectionView.java
index ae0262a..2d4263b 100644
--- a/src/com/android/contacts/editor/KindSectionView.java
+++ b/src/com/android/contacts/editor/KindSectionView.java
@@ -28,10 +28,10 @@
import com.android.contacts.R;
import com.android.contacts.editor.Editor.EditorListener;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.dataitem.DataKind;
import java.util.ArrayList;
import java.util.List;
@@ -50,7 +50,7 @@
private String mTitleString;
private DataKind mKind;
- private EntityDelta mState;
+ private RawContactDelta mState;
private boolean mReadOnly;
private ViewIdGenerator mViewIdGenerator;
@@ -136,7 +136,7 @@
}
}
- public void setState(DataKind kind, EntityDelta state, boolean readOnly, ViewIdGenerator vig) {
+ public void setState(DataKind kind, RawContactDelta state, boolean readOnly, ViewIdGenerator vig) {
mKind = kind;
mState = state;
mReadOnly = readOnly;
@@ -237,7 +237,7 @@
updateEmptyEditors();
// If there are no existing empty editors and it's possible to add
// another field, then make the "add footer" field visible.
- if (!hasEmptyEditor() && EntityModifier.canInsert(mState, mKind)) {
+ if (!hasEmptyEditor() && RawContactModifier.canInsert(mState, mKind)) {
if (animate) {
EditorAnimator.getInstance().showAddFieldFooter(mAddFieldFooter);
} else {
@@ -364,7 +364,7 @@
// Insert a new child, create its view and set its focus
if (values == null) {
- values = EntityModifier.insertChild(mState, mKind);
+ values = RawContactModifier.insertChild(mState, mKind);
}
final View newField = createEditorView(values);
diff --git a/src/com/android/contacts/editor/LabeledEditorView.java b/src/com/android/contacts/editor/LabeledEditorView.java
index 288e915..789f425 100644
--- a/src/com/android/contacts/editor/LabeledEditorView.java
+++ b/src/com/android/contacts/editor/LabeledEditorView.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnShowListener;
-import android.content.Entity;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
@@ -47,11 +46,11 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType.EditType;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.account.AccountType.EditType;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.util.DialogManager;
import com.android.contacts.util.DialogManager.DialogShowingView;
@@ -59,7 +58,7 @@
/**
* Base class for editors that handles labels and values. Uses
- * {@link ValuesDelta} to read any existing {@link Entity} values, and to
+ * {@link ValuesDelta} to read any existing {@link RawContact} values, and to
* correctly write any changes values.
*/
public abstract class LabeledEditorView extends LinearLayout implements Editor, DialogShowingView {
@@ -76,7 +75,7 @@
private DataKind mKind;
private ValuesDelta mEntry;
- private EntityDelta mState;
+ private RawContactDelta mState;
private boolean mReadOnly;
private boolean mWasEmpty = true;
private boolean mIsDeletable = true;
@@ -342,7 +341,7 @@
* structure and {@link ValuesDelta} describing the content to edit.
*/
@Override
- public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
+ public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly,
ViewIdGenerator vig) {
mKind = kind;
mEntry = entry;
@@ -359,11 +358,11 @@
setVisibility(View.VISIBLE);
// Display label selector if multiple types available
- final boolean hasTypes = EntityModifier.hasEditTypes(kind);
+ final boolean hasTypes = RawContactModifier.hasEditTypes(kind);
setupLabelButton(hasTypes);
mLabel.setEnabled(!readOnly && isEnabled());
if (hasTypes) {
- mType = EntityModifier.getCurrentType(entry, kind);
+ mType = RawContactModifier.getCurrentType(entry, kind);
rebuildLabel();
}
}
@@ -398,7 +397,7 @@
final String customText = editText.getText().toString().trim();
if (ContactsUtils.isGraphic(customText)) {
final List<EditType> allTypes =
- EntityModifier.getValidTypes(mState, mKind, null);
+ RawContactModifier.getValidTypes(mState, mKind, null);
mType = null;
for (EditType editType : allTypes) {
if (editType.customColumn != null) {
@@ -534,7 +533,7 @@
}
}
- addAll(EntityModifier.getValidTypes(mState, mKind, mType));
+ addAll(RawContactModifier.getValidTypes(mState, mKind, mType));
}
public boolean hasCustomSelection() {
diff --git a/src/com/android/contacts/editor/PhoneticNameEditorView.java b/src/com/android/contacts/editor/PhoneticNameEditorView.java
index 1700817..8cbb921 100644
--- a/src/com/android/contacts/editor/PhoneticNameEditorView.java
+++ b/src/com/android/contacts/editor/PhoneticNameEditorView.java
@@ -16,15 +16,15 @@
package com.android.contacts.editor;
-import android.content.ContentValues;
import android.content.Context;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.text.TextUtils;
import android.util.AttributeSet;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.dataitem.DataKind;
+import com.android.contacts.model.dataitem.StructuredNameDataItem;
/**
* A dedicated editor for phonetic name. It is similar to {@link StructuredNameEditorView}.
@@ -61,19 +61,16 @@
}
private void parsePhoneticName(String value) {
- ContentValues values = PhoneticNameEditorView.parsePhoneticName(value, null);
- mValues.put(StructuredName.PHONETIC_FAMILY_NAME,
- values.getAsString(StructuredName.PHONETIC_FAMILY_NAME));
- mValues.put(StructuredName.PHONETIC_MIDDLE_NAME,
- values.getAsString(StructuredName.PHONETIC_MIDDLE_NAME));
- mValues.put(StructuredName.PHONETIC_GIVEN_NAME,
- values.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
+ StructuredNameDataItem dataItem = PhoneticNameEditorView.parsePhoneticName(value, null);
+ mValues.setPhoneticFamilyName(dataItem.getPhoneticFamilyName());
+ mValues.setPhoneticMiddleName(dataItem.getPhoneticMiddleName());
+ mValues.setPhoneticGivenName(dataItem.getPhoneticGivenName());
}
private void buildPhoneticName() {
- String family = mValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
- String middle = mValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
- String given = mValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
+ String family = mValues.getPhoneticFamilyName();
+ String middle = mValues.getPhoneticMiddleName();
+ String given = mValues.getPhoneticGivenName();
mPhoneticName = PhoneticNameEditorView.buildPhoneticName(family, middle, given);
}
@@ -100,7 +97,8 @@
* created.
* @return ContentValues with parsed data. Those data can be null.
*/
- public static ContentValues parsePhoneticName(String phoneticName, ContentValues values) {
+ public static StructuredNameDataItem parsePhoneticName(String phoneticName,
+ StructuredNameDataItem item) {
String family = null;
String middle = null;
String given = null;
@@ -123,13 +121,13 @@
}
}
- if (values == null) {
- values = new ContentValues();
+ if (item == null) {
+ item = new StructuredNameDataItem();
}
- values.put(StructuredName.PHONETIC_FAMILY_NAME, family);
- values.put(StructuredName.PHONETIC_MIDDLE_NAME, middle);
- values.put(StructuredName.PHONETIC_GIVEN_NAME, given);
- return values;
+ item.setPhoneticFamilyName(family);
+ item.setPhoneticMiddleName(middle);
+ item.setPhoneticGivenName(given);
+ return item;
}
/**
@@ -172,7 +170,7 @@
}
@Override
- public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
+ public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly,
ViewIdGenerator vig) {
if (!(entry instanceof PhoneticValuesDelta)) {
entry = new PhoneticValuesDelta(entry);
@@ -213,9 +211,9 @@
public boolean hasData() {
ValuesDelta entry = getEntry();
- String family = entry.getAsString(StructuredName.PHONETIC_FAMILY_NAME);
- String middle = entry.getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
- String given = entry.getAsString(StructuredName.PHONETIC_GIVEN_NAME);
+ String family = entry.getPhoneticFamilyName();
+ String middle = entry.getPhoneticMiddleName();
+ String given = entry.getPhoneticGivenName();
return !TextUtils.isEmpty(family) || !TextUtils.isEmpty(middle)
|| !TextUtils.isEmpty(given);
diff --git a/src/com/android/contacts/editor/PhotoEditorView.java b/src/com/android/contacts/editor/PhotoEditorView.java
index 71a4197..30c3bb4 100644
--- a/src/com/android/contacts/editor/PhotoEditorView.java
+++ b/src/com/android/contacts/editor/PhotoEditorView.java
@@ -27,9 +27,9 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.util.ContactPhotoUtils;
/**
@@ -92,7 +92,7 @@
/** {@inheritDoc} */
@Override
- public void setValues(DataKind kind, ValuesDelta values, EntityDelta state, boolean readOnly,
+ public void setValues(DataKind kind, ValuesDelta values, RawContactDelta state, boolean readOnly,
ViewIdGenerator vig) {
mEntry = values;
mReadOnly = readOnly;
@@ -143,7 +143,7 @@
mEntry.setFromTemplate(false);
// When the user chooses a new photo mark it as super primary
- mEntry.put(Photo.IS_SUPER_PRIMARY, 1);
+ mEntry.setSuperPrimary(true);
// Even though high-res photos cannot be saved by passing them via
// an EntityDeltaList (since they cause the Bundle size limit to be
@@ -154,7 +154,7 @@
final int size = ContactsUtils.getThumbnailSize(getContext());
final Bitmap scaled = Bitmap.createScaledBitmap(photo, size, size, false);
final byte[] compressed = ContactPhotoUtils.compressBitmap(scaled);
- if (compressed != null) mEntry.put(Photo.PHOTO, compressed);
+ if (compressed != null) mEntry.setPhoto(compressed);
}
/**
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index 51ba400..daccdd8 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -17,7 +17,6 @@
package com.android.contacts.editor;
import android.content.Context;
-import android.content.Entity;
import android.database.Cursor;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
import android.provider.ContactsContract.CommonDataKinds.Organization;
@@ -25,7 +24,6 @@
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
-import android.provider.ContactsContract.RawContacts;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -40,26 +38,26 @@
import com.android.contacts.GroupMetaDataLoader;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.EditType;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountType.EditType;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.internal.util.Objects;
import java.util.ArrayList;
/**
* Custom view that provides all the editor interaction for a specific
- * {@link Contacts} represented through an {@link EntityDelta}. Callers can
+ * {@link Contacts} represented through an {@link RawContactDelta}. Callers can
* reuse this view and quickly rebuild its contents through
- * {@link #setState(EntityDelta, AccountType, ViewIdGenerator)}.
+ * {@link #setState(RawContactDelta, AccountType, ViewIdGenerator)}.
* <p>
* Internal updates are performed against {@link ValuesDelta} so that the
- * source {@link Entity} can be swapped out. Any state-based changes, such as
+ * source {@link RawContact} can be swapped out. Any state-based changes, such as
* adding {@link Data} rows or changing {@link EditType}, are performed through
- * {@link EntityModifier} to ensure that {@link AccountType} are enforced.
+ * {@link RawContactModifier} to ensure that {@link AccountType} are enforced.
*/
public class RawContactEditorView extends BaseRawContactEditorView {
private LayoutInflater mInflater;
@@ -80,7 +78,7 @@
private boolean mAutoAddToDefaultGroup = true;
private Cursor mGroupMetaData;
private DataKind mGroupMembershipKind;
- private EntityDelta mState;
+ private RawContactDelta mState;
private boolean mPhoneticNameAdded;
@@ -152,11 +150,11 @@
/**
* Set the internal state for this view, given a current
- * {@link EntityDelta} state and the {@link AccountType} that
+ * {@link RawContactDelta} state and the {@link AccountType} that
* apply to that state.
*/
@Override
- public void setState(EntityDelta state, AccountType type, ViewIdGenerator vig,
+ public void setState(RawContactDelta state, AccountType type, ViewIdGenerator vig,
boolean isProfile) {
mState = state;
@@ -170,15 +168,14 @@
setId(vig.getId(state, null, null, ViewIdGenerator.NO_VIEW_INDEX));
// Make sure we have a StructuredName and Organization
- EntityModifier.ensureKindExists(state, type, StructuredName.CONTENT_ITEM_TYPE);
- EntityModifier.ensureKindExists(state, type, Organization.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(state, type, StructuredName.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(state, type, Organization.CONTENT_ITEM_TYPE);
- ValuesDelta values = state.getValues();
- mRawContactId = values.getAsLong(RawContacts._ID);
+ mRawContactId = state.getRawContactId();
// Fill in the account info
if (isProfile) {
- String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
+ String accountName = state.getAccountName();
if (TextUtils.isEmpty(accountName)) {
mAccountNameTextView.setVisibility(View.GONE);
mAccountTypeTextView.setText(R.string.local_profile_title);
@@ -189,7 +186,7 @@
mAccountNameTextView.setText(accountName);
}
} else {
- String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
+ String accountName = state.getAccountName();
CharSequence accountType = type.getDisplayLabel(mContext);
if (TextUtils.isEmpty(accountType)) {
accountType = mContext.getString(R.string.account_phone);
@@ -208,7 +205,7 @@
mAccountIcon.setImageDrawable(type.getDisplayIcon(mContext));
// Show photo editor when supported
- EntityModifier.ensureKindExists(state, type, Photo.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(state, type, Photo.CONTENT_ITEM_TYPE);
setHasPhotoEditor((type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null));
getPhotoEditor().setEnabled(isEnabled());
mName.setEnabled(isEnabled());
@@ -341,7 +338,7 @@
ArrayList<ValuesDelta> entries = mState.getMimeEntries(GroupMembership.CONTENT_ITEM_TYPE);
if (entries != null) {
for (ValuesDelta values : entries) {
- Long id = values.getAsLong(GroupMembership.GROUP_ROW_ID);
+ Long id = values.getGroupRowId();
if (id != null && id.longValue() != 0) {
hasGroupMembership = true;
break;
@@ -352,8 +349,8 @@
if (!hasGroupMembership) {
long defaultGroupId = getDefaultGroupId();
if (defaultGroupId != -1) {
- ValuesDelta entry = EntityModifier.insertChild(mState, mGroupMembershipKind);
- entry.put(GroupMembership.GROUP_ROW_ID, defaultGroupId);
+ ValuesDelta entry = RawContactModifier.insertChild(mState, mGroupMembershipKind);
+ entry.setGroupRowId(defaultGroupId);
}
}
}
@@ -363,9 +360,9 @@
* account. Returns -1 if there is no such group.
*/
private long getDefaultGroupId() {
- String accountType = mState.getValues().getAsString(RawContacts.ACCOUNT_TYPE);
- String accountName = mState.getValues().getAsString(RawContacts.ACCOUNT_NAME);
- String accountDataSet = mState.getValues().getAsString(RawContacts.DATA_SET);
+ String accountType = mState.getAccountType();
+ String accountName = mState.getAccountName();
+ String accountDataSet = mState.getDataSet();
mGroupMetaData.moveToPosition(-1);
while (mGroupMetaData.moveToNext()) {
String name = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_NAME);
diff --git a/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java b/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
index 25edca9..8e51d18 100644
--- a/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
+++ b/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
@@ -39,12 +39,12 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountWithDataSet;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.dataitem.DataKind;
import java.util.ArrayList;
@@ -108,11 +108,11 @@
/**
* Set the internal state for this view, given a current
- * {@link EntityDelta} state and the {@link AccountType} that
+ * {@link RawContactDelta} state and the {@link AccountType} that
* apply to that state.
*/
@Override
- public void setState(EntityDelta state, AccountType type, ViewIdGenerator vig,
+ public void setState(RawContactDelta state, AccountType type, ViewIdGenerator vig,
boolean isProfile) {
// Remove any existing sections
mGeneral.removeAllViews();
@@ -121,13 +121,12 @@
if (state == null || type == null) return;
// Make sure we have StructuredName
- EntityModifier.ensureKindExists(state, type, StructuredName.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(state, type, StructuredName.CONTENT_ITEM_TYPE);
// Fill in the header info
- ValuesDelta values = state.getValues();
- mAccountName = values.getAsString(RawContacts.ACCOUNT_NAME);
- mAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
- mDataSet = values.getAsString(RawContacts.DATA_SET);
+ mAccountName = state.getAccountName();
+ mAccountType = state.getAccountType();
+ mDataSet = state.getDataSet();
if (isProfile) {
if (TextUtils.isEmpty(mAccountName)) {
@@ -162,14 +161,14 @@
mAccountIcon.setImageDrawable(type.getDisplayIcon(mContext));
- mRawContactId = values.getAsLong(RawContacts._ID);
+ mRawContactId = state.getRawContactId();
ValuesDelta primary;
// Photo
DataKind kind = type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE);
if (kind != null) {
- EntityModifier.ensureKindExists(state, type, Photo.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(state, type, Photo.CONTENT_ITEM_TYPE);
boolean hasPhotoEditor = type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null;
setHasPhotoEditor(hasPhotoEditor);
primary = state.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
@@ -203,13 +202,13 @@
for (int i = 0; i < phones.size(); i++) {
ValuesDelta phone = phones.get(i);
final String phoneNumber = PhoneNumberUtils.formatNumber(
- phone.getAsString(Phone.NUMBER),
- phone.getAsString(Phone.NORMALIZED_NUMBER),
+ phone.getPhoneNumber(),
+ phone.getPhoneNormalizedNumber(),
ContactsUtils.getCurrentCountryIso(getContext()));
final CharSequence phoneType;
- if (phone.containsKey(Phone.TYPE)) {
+ if (phone.phoneHasType()) {
phoneType = Phone.getTypeLabel(
- res, phone.getAsInteger(Phone.TYPE), phone.getAsString(Phone.LABEL));
+ res, phone.getPhoneType(), phone.getPhoneLabel());
} else {
phoneType = null;
}
@@ -223,11 +222,11 @@
if (emails != null) {
for (int i = 0; i < emails.size(); i++) {
ValuesDelta email = emails.get(i);
- final String emailAddress = email.getAsString(Email.DATA);
+ final String emailAddress = email.getEmailData();
final CharSequence emailType;
- if (email.containsKey(Email.TYPE)) {
+ if (email.emailHasType()) {
emailType = Email.getTypeLabel(
- res, email.getAsInteger(Email.TYPE), email.getAsString(Email.LABEL));
+ res, email.getEmailType(), email.getEmailLabel());
} else {
emailType = null;
}
diff --git a/src/com/android/contacts/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
index b9b9f7b..3e7ad0e 100644
--- a/src/com/android/contacts/editor/SelectAccountDialogFragment.java
+++ b/src/com/android/contacts/editor/SelectAccountDialogFragment.java
@@ -24,7 +24,7 @@
import android.content.DialogInterface;
import android.os.Bundle;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountsListAdapter;
import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
diff --git a/src/com/android/contacts/editor/StructuredNameEditorView.java b/src/com/android/contacts/editor/StructuredNameEditorView.java
index ac25f22..3c4476d 100644
--- a/src/com/android/contacts/editor/StructuredNameEditorView.java
+++ b/src/com/android/contacts/editor/StructuredNameEditorView.java
@@ -25,9 +25,11 @@
import android.text.TextUtils;
import android.util.AttributeSet;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.dataitem.DataItem;
+import com.android.contacts.model.dataitem.DataKind;
+import com.android.contacts.model.dataitem.StructuredNameDataItem;
import com.android.contacts.util.NameConverter;
import java.util.HashMap;
@@ -45,7 +47,7 @@
*/
public class StructuredNameEditorView extends TextFieldsEditorView {
- private ContentValues mSnapshot;
+ private StructuredNameDataItem mSnapshot;
private boolean mChanged;
public StructuredNameEditorView(Context context) {
@@ -61,11 +63,12 @@
}
@Override
- public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
+ public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly,
ViewIdGenerator vig) {
super.setValues(kind, entry, state, readOnly, vig);
if (mSnapshot == null) {
- mSnapshot = new ContentValues(getValues().getCompleteValues());
+ mSnapshot = (StructuredNameDataItem) DataItem.createFrom(null,
+ new ContentValues(getValues().getCompleteValues()));
mChanged = entry.isInsert();
} else {
mChanged = false;
@@ -114,12 +117,12 @@
if (!mChanged) {
for (String field : NameConverter.STRUCTURED_NAME_FIELDS) {
- values.put(field, mSnapshot.getAsString(field));
+ values.put(field, mSnapshot.getContentValues().getAsString(field));
}
return;
}
- String displayName = values.getAsString(StructuredName.DISPLAY_NAME);
+ String displayName = values.getDisplayName();
Map<String, String> structuredNameMap = NameConverter.displayNameToStructuredName(
getContext(), displayName);
if (!structuredNameMap.isEmpty()) {
@@ -129,17 +132,16 @@
}
}
- mSnapshot.clear();
- mSnapshot.putAll(values.getCompleteValues());
- mSnapshot.put(StructuredName.DISPLAY_NAME, displayName);
+ mSnapshot.getContentValues().clear();
+ mSnapshot.getContentValues().putAll(values.getCompleteValues());
+ mSnapshot.setDisplayName(displayName);
}
private void switchFromStructuredNameToFullName() {
ValuesDelta values = getValues();
if (!mChanged) {
- values.put(StructuredName.DISPLAY_NAME,
- mSnapshot.getAsString(StructuredName.DISPLAY_NAME));
+ values.setDisplayName(mSnapshot.getDisplayName());
return;
}
@@ -151,10 +153,10 @@
values.put(StructuredName.DISPLAY_NAME, displayName);
}
- mSnapshot.clear();
- mSnapshot.put(StructuredName.DISPLAY_NAME, values.getAsString(StructuredName.DISPLAY_NAME));
+ mSnapshot.getContentValues().clear();
+ mSnapshot.setDisplayName(values.getDisplayName());
for (String field : structuredNameMap.keySet()) {
- mSnapshot.put(field, structuredNameMap.get(field));
+ mSnapshot.getContentValues().put(field, structuredNameMap.get(field));
}
}
@@ -167,14 +169,14 @@
}
private void eraseFullName(ValuesDelta values) {
- values.putNull(StructuredName.DISPLAY_NAME);
+ values.setDisplayName(null);
}
private void rebuildFullName(ValuesDelta values) {
Map<String, String> structuredNameMap = valuesToStructuredNameMap(values);
String displayName = NameConverter.structuredNameToDisplayName(getContext(),
structuredNameMap);
- values.put(StructuredName.DISPLAY_NAME, displayName);
+ values.setDisplayName(displayName);
}
private void eraseStructuredName(ValuesDelta values) {
@@ -184,7 +186,7 @@
}
private void rebuildStructuredName(ValuesDelta values) {
- String displayName = values.getAsString(StructuredName.DISPLAY_NAME);
+ String displayName = values.getDisplayName();
Map<String, String> structuredNameMap = NameConverter.displayNameToStructuredName(
getContext(), displayName);
for (String field : structuredNameMap.keySet()) {
@@ -202,7 +204,7 @@
protected Parcelable onSaveInstanceState() {
SavedState state = new SavedState(super.onSaveInstanceState());
state.mChanged = mChanged;
- state.mSnapshot = mSnapshot;
+ state.mSnapshot = mSnapshot.getContentValues();
return state;
}
@@ -212,7 +214,7 @@
super.onRestoreInstanceState(ss.mSuperState);
mChanged = ss.mChanged;
- mSnapshot = ss.mSnapshot;
+ mSnapshot = (StructuredNameDataItem) DataItem.createFrom(null, ss.mSnapshot);
}
private static class SavedState implements Parcelable {
diff --git a/src/com/android/contacts/editor/TextFieldsEditorView.java b/src/com/android/contacts/editor/TextFieldsEditorView.java
index b558a4b..8558b11 100644
--- a/src/com/android/contacts/editor/TextFieldsEditorView.java
+++ b/src/com/android/contacts/editor/TextFieldsEditorView.java
@@ -17,7 +17,6 @@
package com.android.contacts.editor;
import android.content.Context;
-import android.content.Entity;
import android.graphics.Rect;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,15 +37,15 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType.EditField;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.account.AccountType.EditField;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.util.PhoneNumberFormatter;
/**
* Simple editor that handles labels and any {@link EditField} defined for the
- * entry. Uses {@link ValuesDelta} to read any existing {@link Entity} values,
+ * entry. Uses {@link ValuesDelta} to read any existing {@link RawContact} values,
* and to correctly write any changes values.
*/
public class TextFieldsEditorView extends LabeledEditorView {
@@ -171,7 +170,7 @@
}
@Override
- public void setValues(DataKind kind, ValuesDelta entry, EntityDelta state, boolean readOnly,
+ public void setValues(DataKind kind, ValuesDelta entry, RawContactDelta state, boolean readOnly,
ViewIdGenerator vig) {
super.setValues(kind, entry, state, readOnly, vig);
// Remove edit texts that we currently have
diff --git a/src/com/android/contacts/editor/ViewIdGenerator.java b/src/com/android/contacts/editor/ViewIdGenerator.java
index 4ab9279..55a42a7 100644
--- a/src/com/android/contacts/editor/ViewIdGenerator.java
+++ b/src/com/android/contacts/editor/ViewIdGenerator.java
@@ -20,9 +20,9 @@
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.dataitem.DataKind;
/**
* A class that provides unique view ids for {@link ContentEditorView}, {@link KindSectionView},
@@ -62,13 +62,13 @@
/**
* Returns an id for a view associated with specified contact field.
*
- * @param entity {@link EntityDelta} associated with the view
+ * @param entity {@link RawContactDelta} associated with the view
* @param kind {@link DataKind} associated with the view, or null if none exists.
* @param values {@link ValuesDelta} associated with the view, or null if none exists.
* @param viewIndex index of the view in the parent {@link Editor}, if it's a leave view.
* Otherwise, pass {@link #NO_VIEW_INDEX}.
*/
- public int getId(EntityDelta entity, DataKind kind, ValuesDelta values,
+ public int getId(RawContactDelta entity, DataKind kind, ValuesDelta values,
int viewIndex) {
final String k = getMapKey(entity, kind, values, viewIndex);
@@ -81,7 +81,7 @@
return id;
}
- private static String getMapKey(EntityDelta entity, DataKind kind, ValuesDelta values,
+ private static String getMapKey(RawContactDelta entity, DataKind kind, ValuesDelta values,
int viewIndex) {
sWorkStringBuilder.setLength(0);
if (entity != null) {
diff --git a/src/com/android/contacts/group/GroupBrowseListAdapter.java b/src/com/android/contacts/group/GroupBrowseListAdapter.java
index ae58f73..acea625 100644
--- a/src/com/android/contacts/group/GroupBrowseListAdapter.java
+++ b/src/com/android/contacts/group/GroupBrowseListAdapter.java
@@ -29,8 +29,8 @@
import com.android.contacts.GroupListLoader;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
import com.android.internal.util.Objects;
/**
diff --git a/src/com/android/contacts/group/GroupDetailDisplayUtils.java b/src/com/android/contacts/group/GroupDetailDisplayUtils.java
index 4865196..d4e43a0 100644
--- a/src/com/android/contacts/group/GroupDetailDisplayUtils.java
+++ b/src/com/android/contacts/group/GroupDetailDisplayUtils.java
@@ -23,8 +23,8 @@
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
public class GroupDetailDisplayUtils {
diff --git a/src/com/android/contacts/group/GroupDetailFragment.java b/src/com/android/contacts/group/GroupDetailFragment.java
index 5f07c64..6294b40 100644
--- a/src/com/android/contacts/group/GroupDetailFragment.java
+++ b/src/com/android/contacts/group/GroupDetailFragment.java
@@ -53,8 +53,8 @@
import com.android.contacts.list.ContactTileAdapter;
import com.android.contacts.list.ContactTileAdapter.DisplayType;
import com.android.contacts.list.ContactTileView;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
/**
* Displays the details of a group and shows a list of actions possible for the group.
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 5f9beb3..762867c 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -66,9 +66,9 @@
import com.android.contacts.activities.GroupEditorActivity;
import com.android.contacts.editor.SelectAccountDialogFragment;
import com.android.contacts.group.SuggestedMemberListAdapter.SuggestedMember;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.util.ViewUtil;
import com.android.internal.util.Objects;
diff --git a/src/com/android/contacts/interactions/ContactDeletionInteraction.java b/src/com/android/contacts/interactions/ContactDeletionInteraction.java
index ead7010..ea6e6dc 100644
--- a/src/com/android/contacts/interactions/ContactDeletionInteraction.java
+++ b/src/com/android/contacts/interactions/ContactDeletionInteraction.java
@@ -35,8 +35,8 @@
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets;
diff --git a/src/com/android/contacts/interactions/GroupCreationDialogFragment.java b/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
index 9eb4de9..5731bc1 100644
--- a/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
+++ b/src/com/android/contacts/interactions/GroupCreationDialogFragment.java
@@ -23,7 +23,7 @@
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
/**
* A dialog for creating a new group.
diff --git a/src/com/android/contacts/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
index 94c0616..f63f84c 100644
--- a/src/com/android/contacts/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
@@ -40,7 +40,7 @@
import com.android.contacts.R;
import com.android.contacts.editor.SelectAccountDialogFragment;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountSelectionUtil;
import com.android.contacts.util.AccountsListAdapter.AccountListFilter;
import com.android.contacts.vcard.ExportVCardActivity;
diff --git a/src/com/android/contacts/interactions/PhoneNumberInteraction.java b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
index 22cbd7d..207ceea 100644
--- a/src/com/android/contacts/interactions/PhoneNumberInteraction.java
+++ b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
@@ -53,10 +53,10 @@
import com.android.contacts.R;
import com.android.contacts.activities.DialtactsActivity;
import com.android.contacts.activities.TransactionSafeActivity;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.StringInflater;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountType.StringInflater;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.DataKind;
import com.google.common.annotations.VisibleForTesting;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/list/AccountFilterActivity.java b/src/com/android/contacts/list/AccountFilterActivity.java
index b9e5b03..c5a21ba 100644
--- a/src/com/android/contacts/list/AccountFilterActivity.java
+++ b/src/com/android/contacts/list/AccountFilterActivity.java
@@ -36,9 +36,9 @@
import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.google.common.collect.Lists;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/list/ContactListFilterController.java b/src/com/android/contacts/list/ContactListFilterController.java
index aec670f..ddcb1ae 100644
--- a/src/com/android/contacts/list/ContactListFilterController.java
+++ b/src/com/android/contacts/list/ContactListFilterController.java
@@ -20,7 +20,7 @@
import android.preference.PreferenceManager;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/contacts/list/ContactListFilterView.java b/src/com/android/contacts/list/ContactListFilterView.java
index 7763846..d0ecfe4 100644
--- a/src/com/android/contacts/list/ContactListFilterView.java
+++ b/src/com/android/contacts/list/ContactListFilterView.java
@@ -26,8 +26,8 @@
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.account.AccountType;
/**
* Contact list filter parameters.
diff --git a/src/com/android/contacts/list/CustomContactListFilterActivity.java b/src/com/android/contacts/list/CustomContactListFilterActivity.java
index a113f0c..8842a1d 100644
--- a/src/com/android/contacts/list/CustomContactListFilterActivity.java
+++ b/src/com/android/contacts/list/CustomContactListFilterActivity.java
@@ -27,7 +27,6 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.EntityIterator;
import android.content.Intent;
import android.content.Loader;
import android.content.OperationApplicationException;
@@ -56,11 +55,11 @@
import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.GoogleAccountType;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.account.GoogleAccountType;
import com.android.contacts.util.EmptyService;
import com.android.contacts.util.LocalizedNameResolver;
import com.android.contacts.util.WeakAsyncTask;
@@ -146,7 +145,8 @@
if (account.dataSet != null) {
groupsUri.appendQueryParameter(Groups.DATA_SET, account.dataSet).build();
}
- EntityIterator iterator = ContactsContract.Groups.newEntityIterator(resolver.query(
+ android.content.EntityIterator iterator =
+ ContactsContract.Groups.newEntityIterator(resolver.query(
groupsUri.build(), null, null, null, null));
try {
boolean hasGroups = false;
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index 7c56e15..64f3a91 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -45,6 +45,14 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.list.ContactListFilterController;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountTypeWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.account.ExchangeAccountType;
+import com.android.contacts.model.account.ExternalAccountType;
+import com.android.contacts.model.account.FallbackAccountType;
+import com.android.contacts.model.account.GoogleAccountType;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.util.Constants;
import com.android.internal.util.Objects;
import com.google.common.annotations.VisibleForTesting;
diff --git a/src/com/android/contacts/model/Contact.java b/src/com/android/contacts/model/Contact.java
new file mode 100644
index 0000000..ede2101
--- /dev/null
+++ b/src/com/android/contacts/model/Contact.java
@@ -0,0 +1,495 @@
+/*
+ * 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.model.account.AccountType;
+import com.android.contacts.model.dataitem.DataItem;
+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;
+
+/**
+ * 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 ImmutableList<StreamItemEntry> mStreamItems;
+ 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;
+ mStreamItems = 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;
+ mStreamItems = 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;
+ mStreamItems = from.mStreamItems;
+ 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 mStreamItems;
+ }
+
+ 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();
+ 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 = new ArrayList<ContentValues>();
+ for (DataItem dataItem : rawContact.getDataItems()) {
+ result.add(dataItem.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;
+ }
+
+ /* package */ void setStreamItems(ImmutableList<StreamItemEntry> streamItems) {
+ mStreamItems = streamItems;
+ }
+}
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/model/ContactLoader.java
similarity index 63%
rename from src/com/android/contacts/ContactLoader.java
rename to src/com/android/contacts/model/ContactLoader.java
index c0aacae..6db997e 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/model/ContactLoader.java
@@ -14,15 +14,13 @@
* limitations under the License
*/
-package com.android.contacts;
+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.Entity;
-import android.content.Entity.NamedContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -32,11 +30,9 @@
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Directory;
-import android.provider.ContactsContract.DisplayNameSources;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.StreamItemPhotos;
@@ -45,17 +41,18 @@
import android.util.Log;
import android.util.LongSparseArray;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountTypeWithDataSet;
-import com.android.contacts.model.EntityDeltaList;
+import com.android.contacts.GroupMetaData;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountTypeWithDataSet;
+import com.android.contacts.model.dataitem.DataItem;
+import com.android.contacts.model.dataitem.PhotoDataItem;
import com.android.contacts.util.ContactLoaderUtils;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.StreamItemEntry;
import com.android.contacts.util.StreamItemPhotoEntry;
import com.android.contacts.util.UriUtils;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -64,20 +61,19 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
-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<ContactLoader.Result> {
+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 Result sCachedResult = null;
+ private static Contact sCachedResult = null;
private final Uri mRequestedUri;
private Uri mLookupUri;
@@ -85,7 +81,7 @@
private boolean mLoadStreamItems;
private boolean mLoadInvitableAccountTypes;
private boolean mPostViewNotification;
- private Result mContact;
+ private Contact mContact;
private ForceLoadContentObserver mObserver;
private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
@@ -106,433 +102,6 @@
}
/**
- * The result of a load operation. Contains all data necessary to display the contact.
- */
- public static final class Result {
- 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 final ArrayList<Entity> mEntities;
- private ArrayList<StreamItemEntry> mStreamItems;
- private final LongSparseArray<DataStatus> mStatuses;
- private ArrayList<AccountType> mInvitableAccountTypes;
-
- private String mDirectoryDisplayName;
- private String mDirectoryType;
- private String mDirectoryAccountType;
- private String mDirectoryAccountName;
- private int mDirectoryExportSupport;
-
- private ArrayList<GroupMetaData> mGroups;
-
- private byte[] mPhotoBinaryData;
- private final boolean mSendToVoicemail;
- private final String mCustomRingtone;
- private final boolean mIsUserProfile;
-
- private final Status mStatus;
- private final Exception mException;
-
- /**
- * Constructor for special results, namely "no contact found" and "error".
- */
- private Result(Uri requestedUri, 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;
- mEntities = null;
- mStreamItems = 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;
- }
-
- private static Result forError(Uri requestedUri, Exception exception) {
- return new Result(requestedUri, Status.ERROR, exception);
- }
-
- private static Result forNotFound(Uri requestedUri) {
- return new Result(requestedUri, Status.NOT_FOUND, null);
- }
-
- /**
- * Constructor to call when contact was found
- */
- private Result(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;
- mEntities = new ArrayList<Entity>();
- mStreamItems = null;
- mStatuses = new LongSparseArray<DataStatus>();
- 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;
- }
-
- private Result(Uri requestedUri, Result 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;
- mEntities = from.mEntities;
- mStreamItems = from.mStreamItems;
- 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}.
- */
- private void setDirectoryMetaData(String displayName, String directoryType,
- String accountType, String accountName, int exportSupport) {
- mDirectoryDisplayName = displayName;
- mDirectoryType = directoryType;
- mDirectoryAccountType = accountType;
- mDirectoryAccountName = accountName;
- mDirectoryExportSupport = exportSupport;
- }
-
- private 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 EntityDeltaList for this contact.
- */
- public EntityDeltaList createEntityDeltaList() {
- return EntityDeltaList.fromIterator(getEntities().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;
- }
-
- public ArrayList<AccountType> getInvitableAccountTypes() {
- return mInvitableAccountTypes;
- }
-
- public ArrayList<Entity> getEntities() {
- return mEntities;
- }
-
- public ArrayList<StreamItemEntry> getStreamItems() {
- return mStreamItems;
- }
-
- public LongSparseArray<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.
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
- for (Entity entity : getEntities()) {
- ContentValues values = entity.getEntityValues();
- String type = values.getAsString(RawContacts.ACCOUNT_TYPE);
- String dataSet = values.getAsString(RawContacts.DATA_SET);
-
- AccountType accountType = accountTypes.getAccountType(type, dataSet);
- if (accountType != null && accountType.areContactsWritable()) {
- return values.getAsLong(RawContacts._ID);
- }
- }
- // 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 (mEntities.size() != 1) {
- throw new IllegalStateException(
- "Cannot extract content values from an aggregated contact");
- }
-
- Entity entity = mEntities.get(0);
- ArrayList<ContentValues> result = new ArrayList<ContentValues>();
- ArrayList<NamedContentValues> subValues = entity.getSubValues();
- if (subValues != null) {
- int size = subValues.size();
- for (int i = 0; i < size; i++) {
- NamedContentValues pair = subValues.get(i);
- if (Data.CONTENT_URI.equals(pair.uri)) {
- result.add(pair.values);
- }
- }
- }
-
- // 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;
- }
-
- public List<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 + "}";
- }
- }
-
- /**
* Projection used for the query that loads all data for the entire contact (except for
* social stream items).
*/
@@ -726,21 +295,21 @@
}
@Override
- public Result loadInBackground() {
+ public Contact loadInBackground() {
try {
final ContentResolver resolver = getContext().getContentResolver();
final Uri uriCurrentFormat = ContactLoaderUtils.ensureIsContactUri(
resolver, mLookupUri);
- final Result cachedResult = sCachedResult;
+ final Contact cachedResult = sCachedResult;
sCachedResult = null;
// Is this the same Uri as what we had before already? In that case, reuse that result
- final Result 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 Result(mRequestedUri, cachedResult);
+ result = new Contact(mRequestedUri, cachedResult);
resultIsCached = true;
} else {
result = loadContactEntity(resolver, uriCurrentFormat);
@@ -769,57 +338,62 @@
return result;
} catch (Exception e) {
Log.e(TAG, "Error loading the contact: " + mLookupUri, e);
- return Result.forError(mRequestedUri, e);
+ return Contact.forError(mRequestedUri, e);
}
}
- private Result loadContactEntity(ContentResolver resolver, Uri contactUri) {
+ 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 Result.forNotFound(mRequestedUri);
+ return Contact.forNotFound(mRequestedUri);
}
try {
if (!cursor.moveToFirst()) {
cursor.close();
- return Result.forNotFound(mRequestedUri);
+ return Contact.forNotFound(mRequestedUri);
}
- // Create the loaded result starting with the Contact data.
- Result result = loadContactHeaderData(cursor, contactUri);
+ // 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;
- Entity entity = null;
- ArrayList<Entity> entities = result.getEntities();
- LongSparseArray<DataStatus> statuses = result.getStatuses();
- for (; !cursor.isAfterLast(); cursor.moveToNext()) {
+ 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;
- entity = new android.content.Entity(loadRawContact(cursor));
- entities.add(entity);
+ rawContact = new RawContact(getContext(), loadRawContactValues(cursor));
+ rawContactsBuilder.add(rawContact);
}
if (!cursor.isNull(ContactQuery.DATA_ID)) {
- ContentValues data = loadData(cursor);
- entity.addSubValue(ContactsContract.Data.CONTENT_URI, data);
+ 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);
- statuses.put(dataId, status);
+ statusesBuilder.put(dataId, status);
}
}
- }
+ } while (cursor.moveToNext());
- return result;
+ contact.setRawContacts(rawContactsBuilder.build());
+ contact.setStatuses(statusesBuilder.build());
+
+ return contact;
} finally {
cursor.close();
}
@@ -829,7 +403,7 @@
* Looks for the photo data item in entities. If found, creates a new Bitmap instance. If
* not found, returns null
*/
- private void loadPhotoBinaryData(Result contactData) {
+ private void loadPhotoBinaryData(Contact contactData) {
// If we have a photo URI, try loading that first.
String photoUri = contactData.getPhotoUri();
@@ -863,17 +437,15 @@
return;
}
- for (Entity entity : contactData.getEntities()) {
- for (NamedContentValues subValue : entity.getSubValues()) {
- final ContentValues entryValues = subValue.values;
- final long dataId = entryValues.getAsLong(Data._ID);
- if (dataId == photoId) {
- final String mimeType = entryValues.getAsString(Data.MIMETYPE);
- // Correct Data Id but incorrect MimeType? Don't load
- if (!Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
- return;
+ for (RawContact rawContact : contactData.getRawContacts()) {
+ for (DataItem dataItem : rawContact.getDataItems()) {
+ if (dataItem.getId() == photoId) {
+ if (!(dataItem instanceof PhotoDataItem)) {
+ break;
}
- contactData.setPhotoBinaryData(entryValues.getAsByteArray(Photo.PHOTO));
+
+ final PhotoDataItem photo = (PhotoDataItem) dataItem;
+ contactData.setPhotoBinaryData(photo.getPhoto());
break;
}
}
@@ -881,10 +453,11 @@
}
/**
- * Sets the "invitable" account types to {@link Result#mInvitableAccountTypes}.
+ * Sets the "invitable" account types to {@link Contact#mInvitableAccountTypes}.
*/
- private void loadInvitableAccountTypes(Result contactData) {
- final ArrayList<AccountType> resultList = Lists.newArrayList();
+ 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();
@@ -893,26 +466,25 @@
Maps.newHashMap(invitables);
// Remove the ones that already have a raw contact in the current contact
- for (Entity entity : contactData.getEntities()) {
- final ContentValues values = entity.getEntityValues();
+ for (RawContact rawContact : contactData.getRawContacts()) {
final AccountTypeWithDataSet type = AccountTypeWithDataSet.get(
- values.getAsString(RawContacts.ACCOUNT_TYPE),
- values.getAsString(RawContacts.DATA_SET));
+ rawContact.getAccountTypeString(),
+ rawContact.getDataSet());
resultMap.remove(type);
}
- resultList.addAll(resultMap.values());
+ resultListBuilder.addAll(resultMap.values());
}
}
// Set to mInvitableAccountTypes
- contactData.mInvitableAccountTypes = resultList;
+ contactData.setInvitableAccountTypes(resultListBuilder.build());
}
/**
* Extracts Contact level columns from the cursor.
*/
- private Result loadContactHeaderData(final Cursor cursor, Uri contactUri) {
+ private Contact loadContactHeaderData(final Cursor cursor, Uri contactUri) {
final String directoryParameter =
contactUri.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY);
final long directoryId = directoryParameter == null
@@ -943,7 +515,7 @@
lookupUri = contactUri;
}
- return new Result(mRequestedUri, contactUri, lookupUri, directoryId, lookupKey,
+ return new Contact(mRequestedUri, contactUri, lookupUri, directoryId, lookupKey,
contactId, nameRawContactId, displayNameSource, photoId, photoUri, displayName,
altDisplayName, phoneticName, starred, presence, sendToVoicemail,
customRingtone, isUserProfile);
@@ -952,7 +524,7 @@
/**
* Extracts RawContact level columns from the cursor.
*/
- private ContentValues loadRawContact(Cursor cursor) {
+ private ContentValues loadRawContactValues(Cursor cursor) {
ContentValues cv = new ContentValues();
cv.put(RawContacts._ID, cursor.getLong(ContactQuery.RAW_CONTACT_ID));
@@ -979,7 +551,7 @@
/**
* Extracts Data level columns from the cursor.
*/
- private ContentValues loadData(Cursor cursor) {
+ private ContentValues loadDataValues(Cursor cursor) {
ContentValues cv = new ContentValues();
cv.put(Data._ID, cursor.getLong(ContactQuery.DATA_ID));
@@ -1034,7 +606,7 @@
}
}
- private void loadDirectoryMetaData(Result result) {
+ private void loadDirectoryMetaData(Contact result) {
long directoryId = result.getDirectoryId();
Cursor cursor = getContext().getContentResolver().query(
@@ -1075,14 +647,13 @@
* Loads groups meta-data for all groups associated with all constituent raw contacts'
* accounts.
*/
- private void loadGroupMetaData(Result result) {
+ private void loadGroupMetaData(Contact result) {
StringBuilder selection = new StringBuilder();
ArrayList<String> selectionArgs = new ArrayList<String>();
- for (Entity entity : result.mEntities) {
- ContentValues values = entity.getEntityValues();
- String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
- String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
- String dataSet = values.getAsString(RawContacts.DATA_SET);
+ 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 ");
@@ -1101,7 +672,8 @@
selection.append(")");
}
}
- final ArrayList<GroupMetaData> groupList = new ArrayList<GroupMetaData>();
+ 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);
@@ -1119,28 +691,28 @@
? false
: cursor.getInt(GroupQuery.FAVORITES) != 0;
- groupList.add(new GroupMetaData(
+ groupListBuilder.add(new GroupMetaData(
accountName, accountType, dataSet, groupId, title, defaultGroup,
favorites));
}
} finally {
cursor.close();
}
- result.mGroups = groupList;
+ result.setGroupMetaData(groupListBuilder.build());
}
/**
* Loads all stream items and stream item photos belonging to this contact.
*/
- private void loadStreamItems(Result result) {
- Cursor cursor = getContext().getContentResolver().query(
+ private void loadStreamItems(Contact result) {
+ final Cursor cursor = getContext().getContentResolver().query(
Contacts.CONTENT_LOOKUP_URI.buildUpon()
.appendPath(result.getLookupKey())
.appendPath(Contacts.StreamItems.CONTENT_DIRECTORY).build(),
null, null, null, null);
- LongSparseArray<StreamItemEntry> streamItemsById =
+ final LongSparseArray<StreamItemEntry> streamItemsById =
new LongSparseArray<StreamItemEntry>();
- ArrayList<StreamItemEntry> streamItems = new ArrayList<StreamItemEntry>();
+ final ArrayList<StreamItemEntry> streamItems = new ArrayList<StreamItemEntry>();
try {
while (cursor.moveToNext()) {
StreamItemEntry streamItem = new StreamItemEntry(cursor);
@@ -1213,11 +785,13 @@
// Set the sorted stream items on the result.
Collections.sort(streamItems);
- result.mStreamItems = streamItems;
+ result.setStreamItems(new ImmutableList.Builder<StreamItemEntry>()
+ .addAll(streamItems.iterator())
+ .build());
}
@Override
- public void deliverResult(Result result) {
+ public void deliverResult(Contact result) {
unregisterObserver();
// The creator isn't interested in any further updates
@@ -1254,17 +828,13 @@
*/
private void postViewNotificationToSyncAdapter() {
Context context = getContext();
- for (Entity entity : mContact.getEntities()) {
- final ContentValues entityValues = entity.getEntityValues();
- final long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID);
+ 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 String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = entityValues.getAsString(RawContacts.DATA_SET);
- final AccountType accountType = AccountTypeManager.getInstance(context).getAccountType(
- type, dataSet);
+ final AccountType accountType = rawContact.getAccountType();
final String serviceName = accountType.getViewContactNotifyServiceClassName();
final String servicePackageName = accountType.getViewContactNotifyServicePackageName();
if (!TextUtils.isEmpty(serviceName) && !TextUtils.isEmpty(servicePackageName)) {
diff --git a/src/com/android/contacts/model/RawContact.java b/src/com/android/contacts/model/RawContact.java
new file mode 100644
index 0000000..3a193b4
--- /dev/null
+++ b/src/com/android/contacts/model/RawContact.java
@@ -0,0 +1,261 @@
+/*
+ * 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.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.dataitem.DataItem;
+
+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.).
+ */
+public class RawContact {
+
+ private final Context mContext;
+ private AccountTypeManager mAccountTypeManager;
+ private final ContentValues mValues;
+ private final ArrayList<NamedDataItem> mDataItems;
+
+ public static class NamedDataItem {
+ public final Uri uri;
+ public final DataItem dataItem;
+
+ public NamedDataItem(Uri uri, DataItem dataItem) {
+ this.uri = uri;
+ this.dataItem = dataItem;
+ }
+ }
+
+ public static RawContact createFrom(Entity entity) {
+ final ContentValues values = entity.getEntityValues();
+ final ArrayList<Entity.NamedContentValues> subValues = entity.getSubValues();
+
+ RawContact rawContact = new RawContact(null, 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.
+ *
+ * The context is used for the buildString() member function in DataItem objects,
+ * specifically for retrieving an instance of AccountTypeManager. It is okay to
+ * pass in null for the context in which case, you will not be able to call buildString(),
+ * getDataKind(), or getAccountType() from a DataItem object.
+ */
+ public RawContact(Context context) {
+ this(context, new ContentValues());
+ }
+
+ public RawContact(Context context, ContentValues values) {
+ mContext = context;
+ mValues = values;
+ mDataItems = new ArrayList<NamedDataItem>();
+ }
+
+ public AccountTypeManager getAccountTypeManager() {
+ if (mAccountTypeManager == null) {
+ mAccountTypeManager = AccountTypeManager.getInstance(mContext);
+ }
+ return mAccountTypeManager;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ 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 long getVersion() {
+ return getValues().getAsLong(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() {
+ return getAccountTypeManager().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);
+ }
+ }
+ }
+ 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);
+ }
+
+ public void addDataItemValues(ContentValues values) {
+ addNamedDataItemValues(Data.CONTENT_URI, values);
+ }
+
+ public void addNamedDataItemValues(Uri uri, ContentValues values) {
+ mDataItems.add(new NamedDataItem(uri, DataItem.createFrom(this, values)));
+ }
+
+ public List<DataItem> getDataItems() {
+ final ArrayList<DataItem> list = new ArrayList<DataItem>();
+ for (NamedDataItem dataItem : mDataItems) {
+ if (Data.CONTENT_URI.equals(dataItem.uri)) {
+ list.add(dataItem.dataItem);
+ }
+ }
+ return list;
+ }
+
+ public List<NamedDataItem> getNamedDataItems() {
+ return mDataItems;
+ }
+
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("RawContact: ").append(mValues);
+ for (RawContact.NamedDataItem namedDataItem : mDataItems) {
+ sb.append("\n ").append(namedDataItem.uri);
+ sb.append("\n -> ").append(namedDataItem.dataItem.getContentValues());
+ }
+ return sb.toString();
+ }
+}
diff --git a/src/com/android/contacts/model/EntityDelta.java b/src/com/android/contacts/model/RawContactDelta.java
similarity index 83%
rename from src/com/android/contacts/model/EntityDelta.java
rename to src/com/android/contacts/model/RawContactDelta.java
index 31b5306..2ee9d5c 100644
--- a/src/com/android/contacts/model/EntityDelta.java
+++ b/src/com/android/contacts/model/RawContactDelta.java
@@ -20,18 +20,22 @@
import android.content.ContentProviderOperation.Builder;
import android.content.ContentValues;
import android.content.Context;
-import android.content.Entity;
-import android.content.Entity.NamedContentValues;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.BaseColumns;
+import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Profile;
import android.provider.ContactsContract.RawContacts;
import android.util.Log;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.dataitem.DataItem;
import com.android.contacts.test.NeededForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -42,21 +46,20 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-
/**
- * Contains an {@link Entity} and records any modifications separately so the
- * original {@link Entity} can be swapped out with a newer version and the
+ * 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 Entity}, which then becomes an insert {@link RawContacts} case.
+ * empty {@link RawContact}, which then becomes an insert {@link RawContacts} case.
* <p>
- * When applying modifications over an {@link Entity}, we try finding the
+ * 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 Entity}, we know the original data must
+ * 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 EntityDelta implements Parcelable {
+public class RawContactDelta implements Parcelable {
// TODO: optimize by using contentvalues pool, since we allocate so many of them
private static final String TAG = "EntityDelta";
@@ -79,40 +82,40 @@
*/
private final HashMap<String, ArrayList<ValuesDelta>> mEntries = Maps.newHashMap();
- public EntityDelta() {
+ public RawContactDelta() {
}
- public EntityDelta(ValuesDelta values) {
+ public RawContactDelta(ValuesDelta values) {
mValues = values;
}
/**
- * Build an {@link EntityDelta} using the given {@link Entity} as a
+ * Build an {@link RawContactDelta} using the given {@link RawContact} as a
* starting point; the "before" snapshot.
*/
- public static EntityDelta fromBefore(Entity before) {
- final EntityDelta entity = new EntityDelta();
- entity.mValues = ValuesDelta.fromBefore(before.getEntityValues());
- entity.mValues.setIdColumn(RawContacts._ID);
- for (NamedContentValues namedValues : before.getSubValues()) {
- entity.addEntry(ValuesDelta.fromBefore(namedValues.values));
+ public static RawContactDelta fromBefore(RawContact before) {
+ final RawContactDelta rawContactDelta = new RawContactDelta();
+ rawContactDelta.mValues = ValuesDelta.fromBefore(before.getValues());
+ rawContactDelta.mValues.setIdColumn(RawContacts._ID);
+ for (DataItem dataItem : before.getDataItems()) {
+ rawContactDelta.addEntry(ValuesDelta.fromBefore(dataItem.getContentValues()));
}
- return entity;
+ return rawContactDelta;
}
/**
- * Merge the "after" values from the given {@link EntityDelta} onto the
- * "before" state represented by this {@link EntityDelta}, discarding any
+ * 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 EntityDelta mergeAfter(EntityDelta local, EntityDelta remote) {
+ 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 EntityDelta();
+ if (local == null) local = new RawContactDelta();
if (LOGV) {
final Long localVersion = (local.mValues == null) ? null : local.mValues
@@ -223,6 +226,26 @@
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.
@@ -308,8 +331,8 @@
@Override
public boolean equals(Object object) {
- if (object instanceof EntityDelta) {
- final EntityDelta other = (EntityDelta)object;
+ if (object instanceof RawContactDelta) {
+ final RawContactDelta other = (RawContactDelta)object;
// Equality failed if parent values different
if (!other.mValues.equals(mValues)) return false;
@@ -403,7 +426,7 @@
/**
* Build a list of {@link ContentProviderOperation} that will transform the
* current "before" {@link Entity} state into the modified state which this
- * {@link EntityDelta} represents.
+ * {@link RawContactDelta} represents.
*/
public void buildDiff(ArrayList<ContentProviderOperation> buildInto) {
final int firstIndex = buildInto.size();
@@ -524,15 +547,16 @@
mContactsQueryUri = Profile.CONTENT_RAW_CONTACTS_URI;
}
- public static final Parcelable.Creator<EntityDelta> CREATOR = new Parcelable.Creator<EntityDelta>() {
- public EntityDelta createFromParcel(Parcel in) {
- final EntityDelta state = new EntityDelta();
+ 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 EntityDelta[] newArray(int size) {
- return new EntityDelta[size];
+ public RawContactDelta[] newArray(int size) {
+ return new RawContactDelta[size];
}
};
@@ -962,5 +986,118 @@
return new ValuesDelta[size];
}
};
+
+ public void setGroupRowId(long groupId) {
+ put(GroupMembership.GROUP_ROW_ID, groupId);
+ }
+
+ public Long getGroupRowId() {
+ return getAsLong(GroupMembership.GROUP_ROW_ID);
+ }
+
+ public void setPhoto(byte[] value) {
+ put(Photo.PHOTO, value);
+ }
+
+ public byte[] getPhoto() {
+ return getAsByteArray(Photo.PHOTO);
+ }
+
+ public void setSuperPrimary(boolean val) {
+ if (val) {
+ put(Data.IS_SUPER_PRIMARY, 1);
+ } else {
+ put(Data.IS_SUPER_PRIMARY, 0);
+ }
+ }
+
+ public void setPhoneticFamilyName(String value) {
+ put(StructuredName.PHONETIC_FAMILY_NAME, value);
+ }
+
+ public void setPhoneticMiddleName(String value) {
+ put(StructuredName.PHONETIC_MIDDLE_NAME, value);
+ }
+
+ public void setPhoneticGivenName(String value) {
+ put(StructuredName.PHONETIC_GIVEN_NAME, value);
+ }
+
+ public String getPhoneticFamilyName() {
+ return getAsString(StructuredName.PHONETIC_FAMILY_NAME);
+ }
+
+ public String getPhoneticMiddleName() {
+ return getAsString(StructuredName.PHONETIC_MIDDLE_NAME);
+ }
+
+ public String getPhoneticGivenName() {
+ return getAsString(StructuredName.PHONETIC_GIVEN_NAME);
+ }
+
+ public String getDisplayName() {
+ return getAsString(StructuredName.DISPLAY_NAME);
+ }
+
+ public void setDisplayName(String name) {
+ if (name == null) {
+ putNull(StructuredName.DISPLAY_NAME);
+ } else {
+ put(StructuredName.DISPLAY_NAME, name);
+ }
+ }
+
+ public void copyStructuredNameFieldsFrom(ValuesDelta name) {
+ copyStringFrom(name, StructuredName.DISPLAY_NAME);
+
+ copyStringFrom(name, StructuredName.GIVEN_NAME);
+ copyStringFrom(name, StructuredName.FAMILY_NAME);
+ copyStringFrom(name, StructuredName.PREFIX);
+ copyStringFrom(name, StructuredName.MIDDLE_NAME);
+ copyStringFrom(name, StructuredName.SUFFIX);
+
+ copyStringFrom(name, StructuredName.PHONETIC_GIVEN_NAME);
+ copyStringFrom(name, StructuredName.PHONETIC_MIDDLE_NAME);
+ copyStringFrom(name, StructuredName.PHONETIC_FAMILY_NAME);
+
+ copyStringFrom(name, StructuredName.FULL_NAME_STYLE);
+ copyStringFrom(name, StructuredName.PHONETIC_NAME_STYLE);
+ }
+
+ public String getPhoneNumber() {
+ return getAsString(Phone.NUMBER);
+ }
+
+ public String getPhoneNormalizedNumber() {
+ return getAsString(Phone.NORMALIZED_NUMBER);
+ }
+
+ public boolean phoneHasType() {
+ return containsKey(Phone.TYPE);
+ }
+
+ public int getPhoneType() {
+ return getAsInteger(Phone.TYPE);
+ }
+
+ public String getPhoneLabel() {
+ return getAsString(Phone.LABEL);
+ }
+
+ public String getEmailData() {
+ return getAsString(Email.DATA);
+ }
+
+ public boolean emailHasType() {
+ return containsKey(Email.TYPE);
+ }
+
+ public int getEmailType() {
+ return getAsInteger(Email.TYPE);
+ }
+
+ public String getEmailLabel() {
+ return getAsString(Email.LABEL);
+ }
}
}
diff --git a/src/com/android/contacts/model/EntityDeltaList.java b/src/com/android/contacts/model/RawContactDeltaList.java
similarity index 78%
rename from src/com/android/contacts/model/EntityDeltaList.java
rename to src/com/android/contacts/model/RawContactDeltaList.java
index cf074ef..82dd494 100644
--- a/src/com/android/contacts/model/EntityDeltaList.java
+++ b/src/com/android/contacts/model/RawContactDeltaList.java
@@ -30,7 +30,7 @@
import android.provider.ContactsContract.RawContacts;
import android.util.Log;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
import com.google.common.collect.Lists;
import java.util.ArrayList;
@@ -38,40 +38,39 @@
import java.util.Iterator;
/**
- * Container for multiple {@link EntityDelta} objects, usually when editing
+ * Container for multiple {@link RawContactDelta} objects, usually when editing
* together as an entire aggregate. Provides convenience methods for parceling
- * and applying another {@link EntityDeltaList} over it.
+ * and applying another {@link RawContactDeltaList} over it.
*/
-public class EntityDeltaList extends ArrayList<EntityDelta> implements Parcelable {
- private static final String TAG = "EntityDeltaList";
+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;
- private EntityDeltaList() {
+ private RawContactDeltaList() {
}
/**
- * Create an {@link EntityDeltaList} that contains the given {@link EntityDelta},
+ * Create an {@link RawContactDeltaList} that contains the given {@link RawContactDelta},
* usually when inserting a new {@link Contacts} entry.
*/
- public static EntityDeltaList fromSingle(EntityDelta delta) {
- final EntityDeltaList state = new EntityDeltaList();
+ public static RawContactDeltaList fromSingle(RawContactDelta delta) {
+ final RawContactDeltaList state = new RawContactDeltaList();
state.add(delta);
return state;
}
/**
- * Create an {@link EntityDeltaList} based on {@link Contacts} specified by the
+ * 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 EntityDeltaList fromQuery(Uri entityUri, ContentResolver resolver,
+ 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));
+ final EntityIterator iterator = RawContacts.newEntityIterator(
+ resolver.query(entityUri, null, selection, selectionArgs, sortOrder));
try {
return fromIterator(iterator);
} finally {
@@ -80,36 +79,41 @@
}
/**
- * Create an {@link EntityDeltaList} that contains the entities of the Iterator as before
- * values.
+ * 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 EntityDeltaList fromIterator(Iterator<Entity> iterator) {
- final EntityDeltaList state = new EntityDeltaList();
+ public static RawContactDeltaList fromIterator(Iterator<?> iterator) {
+ final RawContactDeltaList state = new RawContactDeltaList();
// Perform background query to pull contact details
while (iterator.hasNext()) {
// Read all contacts into local deltas to prepare for edits
- final Entity before = iterator.next();
- final EntityDelta entity = EntityDelta.fromBefore(before);
- state.add(entity);
+ Object nextObject = iterator.next();
+ final RawContact before = nextObject instanceof Entity
+ ? RawContact.createFrom((Entity) nextObject)
+ : (RawContact) nextObject;
+ final RawContactDelta rawContactDelta = RawContactDelta.fromBefore(before);
+ state.add(rawContactDelta);
}
return state;
}
/**
- * Merge the "after" values from the given {@link EntityDeltaList}, discarding any
+ * 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 EntityDeltaList}.
+ * edits onto an updated {@link RawContactDeltaList}.
*/
- public static EntityDeltaList mergeAfter(EntityDeltaList local, EntityDeltaList remote) {
- if (local == null) local = new EntityDeltaList();
+ 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 (EntityDelta remoteEntity : remote) {
+ for (RawContactDelta remoteEntity : remote) {
final Long rawContactId = remoteEntity.getValues().getId();
// Find or create local match and merge
- final EntityDelta localEntity = local.getByRawContactId(rawContactId);
- final EntityDelta merged = EntityDelta.mergeAfter(localEntity, remoteEntity);
+ final RawContactDelta localEntity = local.getByRawContactId(rawContactId);
+ final RawContactDelta merged = RawContactDelta.mergeAfter(localEntity, remoteEntity);
if (localEntity == null && merged != null) {
// No local entry before, so insert
@@ -123,7 +127,7 @@
/**
* Build a list of {@link ContentProviderOperation} that will transform all
* the "before" {@link Entity} states into the modified state which all
- * {@link EntityDelta} objects represent. This method specifically creates
+ * {@link RawContactDelta} objects represent. This method specifically creates
* any {@link AggregationExceptions} rules needed to groups edits together.
*/
public ArrayList<ContentProviderOperation> buildDiff() {
@@ -136,7 +140,7 @@
int firstInsertRow = -1;
// First pass enforces versions remain consistent
- for (EntityDelta delta : this) {
+ for (RawContactDelta delta : this) {
delta.buildAssert(diff);
}
@@ -146,7 +150,7 @@
int rawContactIndex = 0;
// Second pass builds actual operations
- for (EntityDelta delta : this) {
+ for (RawContactDelta delta : this) {
final int firstBatch = diff.size();
final boolean isInsert = delta.isContactInsert();
backRefs[rawContactIndex++] = isInsert ? firstBatch : -1;
@@ -281,12 +285,12 @@
}
/**
- * Search all contained {@link EntityDelta} for the first one with an
+ * 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 (EntityDelta delta : this) {
+ for (RawContactDelta delta : this) {
final Long rawContactId = delta.getValues().getAsLong(RawContacts._ID);
if (rawContactId != null && rawContactId >= 0) {
return rawContactId;
@@ -296,11 +300,11 @@
}
/**
- * Find {@link RawContacts#_ID} of the requested {@link EntityDelta}.
+ * Find {@link RawContacts#_ID} of the requested {@link RawContactDelta}.
*/
public Long getRawContactId(int index) {
if (index >= 0 && index < this.size()) {
- final EntityDelta delta = this.get(index);
+ final RawContactDelta delta = this.get(index);
final ValuesDelta values = delta.getValues();
if (values.isVisible()) {
return values.getAsLong(RawContacts._ID);
@@ -310,9 +314,9 @@
}
/**
- * Find the raw-contact (an {@link EntityDelta}) with the specified ID.
+ * Find the raw-contact (an {@link RawContactDelta}) with the specified ID.
*/
- public EntityDelta getByRawContactId(Long rawContactId) {
+ public RawContactDelta getByRawContactId(Long rawContactId) {
final int index = this.indexOfRawContactId(rawContactId);
return (index == -1) ? null : this.get(index);
}
@@ -332,19 +336,21 @@
return -1;
}
- /** Return the index of the first EntityDelta corresponding to a writable raw-contact, or -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 (EntityDelta delta : this) {
+ for (RawContactDelta delta : this) {
if (delta.getRawContactAccountType(context).areContactsWritable()) return entityIndex;
entityIndex++;
}
return -1;
}
- /** Return the first EntityDelta corresponding to a writable raw-contact, or null. */
- public EntityDelta getFirstWritableRawContact(Context context) {
+ /** 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);
}
@@ -352,7 +358,7 @@
public ValuesDelta getSuperPrimaryEntry(final String mimeType) {
ValuesDelta primary = null;
ValuesDelta randomEntry = null;
- for (EntityDelta delta : this) {
+ for (RawContactDelta delta : this) {
final ArrayList<ValuesDelta> mimeEntries = delta.getMimeEntries(mimeType);
if (mimeEntries == null) return null;
@@ -404,7 +410,7 @@
public void writeToParcel(Parcel dest, int flags) {
final int size = this.size();
dest.writeInt(size);
- for (EntityDelta delta : this) {
+ for (RawContactDelta delta : this) {
dest.writeParcelable(delta, flags);
}
dest.writeLongArray(mJoinWithRawContactIds);
@@ -416,24 +422,24 @@
final ClassLoader loader = getClass().getClassLoader();
final int size = source.readInt();
for (int i = 0; i < size; i++) {
- this.add(source.<EntityDelta> readParcelable(loader));
+ this.add(source.<RawContactDelta> readParcelable(loader));
}
mJoinWithRawContactIds = source.createLongArray();
mSplitRawContacts = source.readInt() != 0;
}
- public static final Parcelable.Creator<EntityDeltaList> CREATOR =
- new Parcelable.Creator<EntityDeltaList>() {
+ public static final Parcelable.Creator<RawContactDeltaList> CREATOR =
+ new Parcelable.Creator<RawContactDeltaList>() {
@Override
- public EntityDeltaList createFromParcel(Parcel in) {
- final EntityDeltaList state = new EntityDeltaList();
+ public RawContactDeltaList createFromParcel(Parcel in) {
+ final RawContactDeltaList state = new RawContactDeltaList();
state.readFromParcel(in);
return state;
}
@Override
- public EntityDeltaList[] newArray(int size) {
- return new EntityDeltaList[size];
+ public RawContactDeltaList[] newArray(int size) {
+ return new RawContactDeltaList[size];
}
};
diff --git a/src/com/android/contacts/model/EntityModifier.java b/src/com/android/contacts/model/RawContactModifier.java
similarity index 91%
rename from src/com/android/contacts/model/EntityModifier.java
rename to src/com/android/contacts/model/RawContactModifier.java
index a26ceca..c397e5f 100644
--- a/src/com/android/contacts/model/EntityModifier.java
+++ b/src/com/android/contacts/model/RawContactModifier.java
@@ -49,10 +49,14 @@
import com.android.contacts.ContactsUtils;
import com.android.contacts.editor.EventFieldEditorView;
import com.android.contacts.editor.PhoneticNameEditorView;
-import com.android.contacts.model.AccountType.EditField;
-import com.android.contacts.model.AccountType.EditType;
-import com.android.contacts.model.AccountType.EventEditType;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountType.EditField;
+import com.android.contacts.model.account.AccountType.EditType;
+import com.android.contacts.model.account.AccountType.EventEditType;
+import com.android.contacts.model.account.GoogleAccountType;
+import com.android.contacts.model.dataitem.DataKind;
+import com.android.contacts.model.dataitem.StructuredNameDataItem;
import com.android.contacts.util.DateUtils;
import com.android.contacts.util.NameConverter;
@@ -68,21 +72,21 @@
import java.util.Set;
/**
- * Helper methods for modifying an {@link EntityDelta}, such as inserting
+ * Helper methods for modifying an {@link RawContactDelta}, such as inserting
* new rows, or enforcing {@link AccountType}.
*/
-public class EntityModifier {
- private static final String TAG = "EntityModifier";
+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 EntityDelta}, determine if the given
+ * For the given {@link RawContactDelta}, determine if the given
* {@link DataKind} could be inserted under specific
* {@link AccountType}.
*/
- public static boolean canInsert(EntityDelta state, DataKind kind) {
+ 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);
@@ -91,8 +95,8 @@
return (validTypes && validOverall);
}
- public static boolean hasValidTypes(EntityDelta state, DataKind kind) {
- if (EntityModifier.hasEditTypes(kind)) {
+ public static boolean hasValidTypes(RawContactDelta state, DataKind kind) {
+ if (RawContactModifier.hasEditTypes(kind)) {
return (getValidTypes(state, kind).size() > 0);
} else {
return true;
@@ -101,12 +105,12 @@
/**
* Ensure that at least one of the given {@link DataKind} exists in the
- * given {@link EntityDelta} state, and try creating one if none exist.
+ * 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(
- EntityDelta state, AccountType accountType, String mimeType) {
+ RawContactDelta state, AccountType accountType, String mimeType) {
final DataKind kind = accountType.getKindForMimetype(mimeType);
final boolean hasChild = state.getMimeEntriesCount(mimeType, true) > 0;
@@ -127,16 +131,16 @@
}
/**
- * For the given {@link EntityDelta} and {@link DataKind}, return the
+ * 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(EntityDelta state, DataKind kind) {
+ public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind) {
return getValidTypes(state, kind, null, true, null);
}
/**
- * For the given {@link EntityDelta} and {@link DataKind}, return the
+ * For the given {@link RawContactDelta} and {@link DataKind}, return the
* list possible {@link EditType} options available based on
* {@link AccountType}.
*
@@ -144,13 +148,13 @@
* list, even when an otherwise-invalid choice. This is useful
* when showing a dialog that includes the current type.
*/
- public static ArrayList<EditType> getValidTypes(EntityDelta state, DataKind kind,
+ public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind,
EditType forceInclude) {
return getValidTypes(state, kind, forceInclude, true, null);
}
/**
- * For the given {@link EntityDelta} and {@link DataKind}, return the
+ * For the given {@link RawContactDelta} and {@link DataKind}, return the
* list possible {@link EditType} options available based on
* {@link AccountType}.
*
@@ -161,9 +165,9 @@
* {@link EditType#secondary}.
* @param typeCount When provided, will be used for the frequency count of
* each {@link EditType}, otherwise built using
- * {@link #getTypeFrequencies(EntityDelta, DataKind)}.
+ * {@link #getTypeFrequencies(RawContactDelta, DataKind)}.
*/
- private static ArrayList<EditType> getValidTypes(EntityDelta state, DataKind kind,
+ private static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind,
EditType forceInclude, boolean includeSecondary, SparseIntArray typeCount) {
final ArrayList<EditType> validTypes = new ArrayList<EditType>();
@@ -197,11 +201,11 @@
/**
* Count up the frequency that each {@link EditType} appears in the given
- * {@link EntityDelta}. The returned {@link SparseIntArray} maps from
+ * {@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(EntityDelta state, DataKind kind) {
+ private static SparseIntArray getTypeFrequencies(RawContactDelta state, DataKind kind) {
final SparseIntArray typeCount = new SparseIntArray();
// Find all entries for this kind, bailing early if none found
@@ -297,7 +301,7 @@
* first primary type that doesn't already exist. When all valid types
* exist, we pick the last valid option.
*/
- public static EditType getBestValidType(EntityDelta state, DataKind kind,
+ public static EditType getBestValidType(RawContactDelta state, DataKind kind,
boolean includeSecondary, int exactValue) {
// Shortcut when no types
if (kind.typeColumn == null) return null;
@@ -338,10 +342,10 @@
/**
* Insert a new child of kind {@link DataKind} into the given
- * {@link EntityDelta}. Tries using the best {@link EditType} found using
- * {@link #getBestValidType(EntityDelta, DataKind, boolean, int)}.
+ * {@link RawContactDelta}. Tries using the best {@link EditType} found using
+ * {@link #getBestValidType(RawContactDelta, DataKind, boolean, int)}.
*/
- public static ValuesDelta insertChild(EntityDelta state, DataKind kind) {
+ 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) {
@@ -353,9 +357,9 @@
/**
* Insert a new child of kind {@link DataKind} into the given
- * {@link EntityDelta}, marked with the given {@link EditType}.
+ * {@link RawContactDelta}, marked with the given {@link EditType}.
*/
- public static ValuesDelta insertChild(EntityDelta state, DataKind kind, EditType type) {
+ 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();
@@ -379,13 +383,13 @@
}
/**
- * Processing to trim any empty {@link ValuesDelta} and {@link EntityDelta}
- * from the given {@link EntityDeltaList}, assuming the given {@link AccountTypeManager}
+ * 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(EntityDeltaList set, AccountTypeManager accountTypes) {
- for (EntityDelta state : set) {
+ 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);
@@ -394,12 +398,12 @@
}
}
- public static boolean hasChanges(EntityDeltaList set, AccountTypeManager accountTypes) {
+ public static boolean hasChanges(RawContactDeltaList set, AccountTypeManager accountTypes) {
if (set.isMarkedForSplitting() || set.isMarkedForJoining()) {
return true;
}
- for (EntityDelta state : set) {
+ for (RawContactDelta state : set) {
ValuesDelta values = state.getValues();
final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
final String dataSet = values.getAsString(RawContacts.DATA_SET);
@@ -413,11 +417,11 @@
/**
* Processing to trim any empty {@link ValuesDelta} rows from the given
- * {@link EntityDelta}, assuming the given {@link AccountType} dictates
+ * {@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(EntityDelta state, AccountType accountType) {
+ public static void trimEmpty(RawContactDelta state, AccountType accountType) {
boolean hasValues = false;
// Walk through entries for each well-known kind
@@ -440,7 +444,7 @@
final boolean isPhoto = TextUtils.equals(Photo.CONTENT_ITEM_TYPE, kind.mimeType);
final boolean isGooglePhoto = isPhoto && isGoogleAccount;
- if (EntityModifier.isEmpty(entry, kind) && !isGooglePhoto) {
+ if (RawContactModifier.isEmpty(entry, kind) && !isGooglePhoto) {
if (DEBUG) {
Log.v(TAG, "Trimming: " + entry.toString());
}
@@ -456,7 +460,7 @@
}
}
- private static boolean hasChanges(EntityDelta state, AccountType accountType) {
+ 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);
@@ -516,10 +520,10 @@
}
/**
- * Parse the given {@link Bundle} into the given {@link EntityDelta} state,
+ * 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, EntityDelta state,
+ public static void parseExtras(Context context, AccountType accountType, RawContactDelta state,
Bundle extras) {
if (extras == null || extras.size() == 0) {
// Bail early if no useful data
@@ -560,8 +564,8 @@
final boolean hasOrg = extras.containsKey(Insert.COMPANY)
|| extras.containsKey(Insert.JOB_TITLE);
final DataKind kindOrg = accountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
- if (hasOrg && EntityModifier.canInsert(state, kindOrg)) {
- final ValuesDelta child = EntityModifier.insertChild(state, kindOrg);
+ if (hasOrg && RawContactModifier.canInsert(state, kindOrg)) {
+ final ValuesDelta child = RawContactModifier.insertChild(state, kindOrg);
final String company = extras.getString(Insert.COMPANY);
if (ContactsUtils.isGraphic(company)) {
@@ -577,8 +581,8 @@
// Notes
final boolean hasNotes = extras.containsKey(Insert.NOTES);
final DataKind kindNotes = accountType.getKindForMimetype(Note.CONTENT_ITEM_TYPE);
- if (hasNotes && EntityModifier.canInsert(state, kindNotes)) {
- final ValuesDelta child = EntityModifier.insertChild(state, kindNotes);
+ if (hasNotes && RawContactModifier.canInsert(state, kindNotes)) {
+ final ValuesDelta child = RawContactModifier.insertChild(state, kindNotes);
final String notes = extras.getString(Insert.NOTES);
if (ContactsUtils.isGraphic(notes)) {
@@ -594,9 +598,9 @@
}
private static void parseStructuredNameExtra(
- Context context, AccountType accountType, EntityDelta state, Bundle extras) {
+ Context context, AccountType accountType, RawContactDelta state, Bundle extras) {
// StructuredName
- EntityModifier.ensureKindExists(state, accountType, StructuredName.CONTENT_ITEM_TYPE);
+ RawContactModifier.ensureKindExists(state, accountType, StructuredName.CONTENT_ITEM_TYPE);
final ValuesDelta child = state.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
final String name = extras.getString(Insert.NAME);
@@ -649,7 +653,7 @@
}
private static void parseStructuredPostalExtra(
- AccountType accountType, EntityDelta state, Bundle extras) {
+ 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,
@@ -675,7 +679,8 @@
}
private static void parseValues(
- EntityDelta state, AccountType accountType, ArrayList<ContentValues> dataValueList) {
+ RawContactDelta state, AccountType accountType,
+ ArrayList<ContentValues> dataValueList) {
for (ContentValues values : dataValueList) {
String mimeType = values.getAsString(Data.MIMETYPE);
if (TextUtils.isEmpty(mimeType)) {
@@ -873,7 +878,7 @@
/**
* Parse a specific entry from the given {@link Bundle} and insert into the
- * given {@link EntityDelta}. Silently skips the insert when missing value
+ * 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
@@ -881,7 +886,7 @@
* @param valueExtra {@link Bundle} key that holds the incoming value.
* @param valueColumn Column to write value into {@link ValuesDelta}.
*/
- public static ValuesDelta parseExtras(EntityDelta state, DataKind kind, Bundle extras,
+ public static ValuesDelta parseExtras(RawContactDelta state, DataKind kind, Bundle extras,
String typeExtra, String valueExtra, String valueColumn) {
final CharSequence value = extras.getCharSequence(valueExtra);
@@ -889,7 +894,7 @@
if (kind == null) return null;
// Bail when can't insert type, or value missing
- final boolean canInsert = EntityModifier.canInsert(state, kind);
+ final boolean canInsert = RawContactModifier.canInsert(state, kind);
final boolean validValue = (value != null && TextUtils.isGraphic(value));
if (!validValue || !canInsert) return null;
@@ -897,10 +902,10 @@
final boolean hasType = extras.containsKey(typeExtra);
final int typeValue = extras.getInt(typeExtra, hasType ? BaseTypes.TYPE_CUSTOM
: Integer.MIN_VALUE);
- final EditType editType = EntityModifier.getBestValidType(state, kind, true, typeValue);
+ final EditType editType = RawContactModifier.getBestValidType(state, kind, true, typeValue);
// Create data row and fill with value
- final ValuesDelta child = EntityModifier.insertChild(state, kind, editType);
+ final ValuesDelta child = RawContactModifier.insertChild(state, kind, editType);
child.put(valueColumn, value.toString());
if (editType != null && editType.customColumn != null) {
@@ -937,13 +942,13 @@
private static final int TYPE_CUSTOM = Phone.TYPE_CUSTOM;
/**
- * Migrates old EntityDelta to newly created one with a new restriction supplied from
+ * 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,
- EntityDelta oldState, EntityDelta newState,
+ 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
@@ -996,8 +1001,8 @@
* Checks {@link DataKind#isList} and {@link DataKind#typeOverallMax}, and restricts
* the number of entries (ValuesDelta) inside newState.
*/
- private static ArrayList<ValuesDelta> ensureEntryMaxSize(EntityDelta newState, DataKind kind,
- ArrayList<ValuesDelta> mimeEntries) {
+ private static ArrayList<ValuesDelta> ensureEntryMaxSize(RawContactDelta newState,
+ DataKind kind, ArrayList<ValuesDelta> mimeEntries) {
if (mimeEntries == null) {
return null;
}
@@ -1015,7 +1020,8 @@
/** @hide Public only for testing. */
public static void migrateStructuredName(
- Context context, EntityDelta oldState, EntityDelta newState, DataKind newDataKind) {
+ Context context, RawContactDelta oldState, RawContactDelta newState,
+ DataKind newDataKind) {
final ContentValues values =
oldState.getPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE).getAfter();
if (values == null) {
@@ -1071,24 +1077,24 @@
if (!TextUtils.isEmpty(phoneticFullName)) {
if (!supportPhoneticFullName) {
// Old data has a phonetic (full) name, while the new account doesn't allow it.
- final ContentValues tmpValues =
+ final StructuredNameDataItem tmpItem =
PhoneticNameEditorView.parsePhoneticName(phoneticFullName, null);
values.remove(DataKind.PSEUDO_COLUMN_PHONETIC_NAME);
if (supportPhoneticFamilyName) {
values.put(StructuredName.PHONETIC_FAMILY_NAME,
- tmpValues.getAsString(StructuredName.PHONETIC_FAMILY_NAME));
+ tmpItem.getPhoneticFamilyName());
} else {
values.remove(StructuredName.PHONETIC_FAMILY_NAME);
}
if (supportPhoneticMiddleName) {
values.put(StructuredName.PHONETIC_MIDDLE_NAME,
- tmpValues.getAsString(StructuredName.PHONETIC_MIDDLE_NAME));
+ tmpItem.getPhoneticMiddleName());
} else {
values.remove(StructuredName.PHONETIC_MIDDLE_NAME);
}
if (supportPhoneticGivenName) {
values.put(StructuredName.PHONETIC_GIVEN_NAME,
- tmpValues.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
+ tmpItem.getPhoneticGivenName());
} else {
values.remove(StructuredName.PHONETIC_GIVEN_NAME);
}
@@ -1117,7 +1123,7 @@
}
/** @hide Public only for testing. */
- public static void migratePostal(EntityDelta oldState, EntityDelta newState,
+ public static void migratePostal(RawContactDelta oldState, RawContactDelta newState,
DataKind newDataKind) {
final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind,
oldState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE));
@@ -1228,7 +1234,7 @@
}
/** @hide Public only for testing. */
- public static void migrateEvent(EntityDelta oldState, EntityDelta newState,
+ 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));
@@ -1285,7 +1291,7 @@
/** @hide Public only for testing. */
public static void migrateGenericWithoutTypeColumn(
- EntityDelta oldState, EntityDelta newState, DataKind newDataKind) {
+ RawContactDelta oldState, RawContactDelta newState, DataKind newDataKind) {
final ArrayList<ValuesDelta> mimeEntries = ensureEntryMaxSize(newState, newDataKind,
oldState.getMimeEntries(newDataKind.mimeType));
if (mimeEntries == null || mimeEntries.isEmpty()) {
@@ -1302,7 +1308,7 @@
/** @hide Public only for testing. */
public static void migrateGenericWithTypeColumn(
- EntityDelta oldState, EntityDelta newState, DataKind newDataKind) {
+ RawContactDelta oldState, RawContactDelta newState, DataKind newDataKind) {
final ArrayList<ValuesDelta> mimeEntries = oldState.getMimeEntries(newDataKind.mimeType);
if (mimeEntries == null || mimeEntries.isEmpty()) {
return;
diff --git a/src/com/android/contacts/model/AccountType.java b/src/com/android/contacts/model/account/AccountType.java
similarity index 98%
rename from src/com/android/contacts/model/AccountType.java
rename to src/com/android/contacts/model/account/AccountType.java
index f3aa868..edd17a0 100644
--- a/src/com/android/contacts/model/AccountType.java
+++ b/src/com/android/contacts/model/account/AccountType.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.content.ContentValues;
import android.content.Context;
@@ -28,6 +28,8 @@
import android.widget.EditText;
import com.android.contacts.R;
+import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.dataitem.DataKind;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
diff --git a/src/com/android/contacts/model/AccountTypeWithDataSet.java b/src/com/android/contacts/model/account/AccountTypeWithDataSet.java
similarity index 98%
rename from src/com/android/contacts/model/AccountTypeWithDataSet.java
rename to src/com/android/contacts/model/account/AccountTypeWithDataSet.java
index 8d55758..ab0a891 100644
--- a/src/com/android/contacts/model/AccountTypeWithDataSet.java
+++ b/src/com/android/contacts/model/account/AccountTypeWithDataSet.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.content.Context;
import android.database.Cursor;
diff --git a/src/com/android/contacts/model/AccountWithDataSet.java b/src/com/android/contacts/model/account/AccountWithDataSet.java
similarity index 99%
rename from src/com/android/contacts/model/AccountWithDataSet.java
rename to src/com/android/contacts/model/account/AccountWithDataSet.java
index 2a8fac7..03fcc02 100644
--- a/src/com/android/contacts/model/AccountWithDataSet.java
+++ b/src/com/android/contacts/model/account/AccountWithDataSet.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.accounts.Account;
import android.content.Context;
diff --git a/src/com/android/contacts/model/BaseAccountType.java b/src/com/android/contacts/model/account/BaseAccountType.java
similarity index 99%
rename from src/com/android/contacts/model/BaseAccountType.java
rename to src/com/android/contacts/model/account/BaseAccountType.java
index f67ad53..7f9e1ef 100644
--- a/src/com/android/contacts/model/BaseAccountType.java
+++ b/src/com/android/contacts/model/account/BaseAccountType.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.content.ContentValues;
import android.content.Context;
@@ -39,6 +39,7 @@
import android.view.inputmethod.EditorInfo;
import com.android.contacts.R;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.test.NeededForTesting;
import com.android.contacts.util.DateUtils;
import com.google.common.collect.Lists;
diff --git a/src/com/android/contacts/model/ExchangeAccountType.java b/src/com/android/contacts/model/account/ExchangeAccountType.java
similarity index 99%
rename from src/com/android/contacts/model/ExchangeAccountType.java
rename to src/com/android/contacts/model/account/ExchangeAccountType.java
index 6c73568..5ca3308 100644
--- a/src/com/android/contacts/model/ExchangeAccountType.java
+++ b/src/com/android/contacts/model/account/ExchangeAccountType.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.content.ContentValues;
import android.content.Context;
@@ -32,6 +32,7 @@
import android.util.Log;
import com.android.contacts.R;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.util.DateUtils;
import com.google.common.collect.Lists;
diff --git a/src/com/android/contacts/model/ExternalAccountType.java b/src/com/android/contacts/model/account/ExternalAccountType.java
similarity index 99%
rename from src/com/android/contacts/model/ExternalAccountType.java
rename to src/com/android/contacts/model/account/ExternalAccountType.java
index 3aca24f..71dbebf 100644
--- a/src/com/android/contacts/model/ExternalAccountType.java
+++ b/src/com/android/contacts/model/account/ExternalAccountType.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.content.Context;
import android.content.pm.PackageInfo;
@@ -31,6 +31,7 @@
import android.util.Log;
import android.util.Xml;
+import com.android.contacts.model.dataitem.DataKind;
import com.google.common.annotations.VisibleForTesting;
import org.xmlpull.v1.XmlPullParser;
diff --git a/src/com/android/contacts/model/FallbackAccountType.java b/src/com/android/contacts/model/account/FallbackAccountType.java
similarity index 96%
rename from src/com/android/contacts/model/FallbackAccountType.java
rename to src/com/android/contacts/model/account/FallbackAccountType.java
index 21eb9e7..dae288d 100644
--- a/src/com/android/contacts/model/FallbackAccountType.java
+++ b/src/com/android/contacts/model/account/FallbackAccountType.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.content.Context;
import android.util.Log;
import com.android.contacts.R;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.test.NeededForTesting;
public class FallbackAccountType extends BaseAccountType {
diff --git a/src/com/android/contacts/model/GoogleAccountType.java b/src/com/android/contacts/model/account/GoogleAccountType.java
similarity index 98%
rename from src/com/android/contacts/model/GoogleAccountType.java
rename to src/com/android/contacts/model/account/GoogleAccountType.java
index d7360ee..192c3d0 100644
--- a/src/com/android/contacts/model/GoogleAccountType.java
+++ b/src/com/android/contacts/model/account/GoogleAccountType.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.content.ContentValues;
import android.content.Context;
@@ -25,6 +25,7 @@
import android.util.Log;
import com.android.contacts.R;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.util.DateUtils;
import com.google.common.collect.Lists;
diff --git a/src/com/android/contacts/model/dataitem/DataItem.java b/src/com/android/contacts/model/dataitem/DataItem.java
new file mode 100644
index 0000000..25c44cb
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/DataItem.java
@@ -0,0 +1,214 @@
+/*
+ * 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.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.model.AccountTypeManager;
+import com.android.contacts.model.RawContact;
+import com.android.contacts.model.account.AccountType;
+
+/**
+ * This is the base class for data items, which represents a row from the Data table.
+ */
+public class DataItem {
+
+ private final ContentValues mContentValues;
+
+ /**
+ * The raw contact that this data item is associated with. This can be null.
+ */
+ private final RawContact mRawContact;
+ private DataKind mDataKind;
+
+ protected DataItem(RawContact rawContact, ContentValues values) {
+ mContentValues = values;
+ mRawContact = rawContact;
+ }
+
+ /**
+ * 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(RawContact rawContact, ContentValues values) {
+ final String mimeType = values.getAsString(Data.MIMETYPE);
+ if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new GroupMembershipDataItem(rawContact, values);
+ } else if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new StructuredNameDataItem(rawContact, values);
+ } else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new PhoneDataItem(rawContact, values);
+ } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new EmailDataItem(rawContact, values);
+ } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new StructuredPostalDataItem(rawContact, values);
+ } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new ImDataItem(rawContact, values);
+ } else if (Organization.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new OrganizationDataItem(rawContact, values);
+ } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new NicknameDataItem(rawContact, values);
+ } else if (Note.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new NoteDataItem(rawContact, values);
+ } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new WebsiteDataItem(rawContact, values);
+ } else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new SipAddressDataItem(rawContact, values);
+ } else if (Event.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new EventDataItem(rawContact, values);
+ } else if (Relation.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new RelationDataItem(rawContact, values);
+ } else if (Identity.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new IdentityDataItem(rawContact, values);
+ } else if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ return new PhotoDataItem(rawContact, values);
+ }
+
+ // generic
+ return new DataItem(rawContact, values);
+ }
+
+ public ContentValues getContentValues() {
+ return mContentValues;
+ }
+
+ protected RawContact getRawContact() {
+ return mRawContact;
+ }
+
+ public void setRawContactId(long rawContactId) {
+ mContentValues.put(Data.RAW_CONTACT_ID, rawContactId);
+ }
+
+ /**
+ * Returns the data id.
+ */
+ public long getId() {
+ return mContentValues.getAsLong(Data._ID);
+ }
+
+ public long getRawContactId() {
+ return mContentValues.getAsLong(Data.RAW_CONTACT_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 int getDataVersion() {
+ return mContentValues.getAsInteger(Data.DATA_VERSION);
+ }
+
+ public AccountTypeManager getAccountTypeManager() {
+ if (mRawContact == null) {
+ return null;
+ } else {
+ return mRawContact.getAccountTypeManager();
+ }
+ }
+
+ public AccountType getAccountType() {
+ if (mRawContact == null) {
+ return null;
+ } else {
+ return mRawContact.getAccountType();
+ }
+ }
+
+ /**
+ * This method can only be invoked if the raw contact is non-null.
+ */
+ public DataKind getDataKind() {
+ if (mRawContact == null) {
+ throw new IllegalStateException("mRawContact must be non-null to call getDataKind()");
+ }
+
+ if (mDataKind == null) {
+ mDataKind = getAccountTypeManager().getKindOrFallback(
+ mRawContact.getAccountTypeString(), mRawContact.getDataSet(), getMimeType());
+ }
+
+ return mDataKind;
+ }
+
+ public boolean hasKindTypeColumn() {
+ final String key = getDataKind().typeColumn;
+ return key != null && mContentValues.containsKey(key);
+ }
+
+ public int getKindTypeColumn() {
+ final String key = getDataKind().typeColumn;
+ return mContentValues.getAsInteger(key);
+ }
+
+ /**
+ * This builds the data string depending on the type of data item by using the generic
+ * DataKind object underneath. This DataItem object must be associated with a raw contact
+ * for this function to work.
+ */
+ public String buildDataString() {
+ if (mRawContact == null) {
+ throw new IllegalStateException("mRawContact must be non-null to call getDataKind()");
+ }
+ final DataKind kind = getDataKind();
+
+ if (kind.actionBody == null) {
+ return null;
+ }
+ CharSequence actionBody = kind.actionBody.inflateUsing(mRawContact.getContext(),
+ mContentValues);
+ return actionBody == null ? null : actionBody.toString();
+ }
+
+ public String getKindString() {
+ final DataKind kind = getDataKind();
+ return (kind.titleRes == -1 || kind.titleRes == 0) ? ""
+ : mRawContact.getContext().getString(kind.titleRes);
+ }
+}
diff --git a/src/com/android/contacts/model/DataKind.java b/src/com/android/contacts/model/dataitem/DataKind.java
similarity index 95%
rename from src/com/android/contacts/model/DataKind.java
rename to src/com/android/contacts/model/dataitem/DataKind.java
index bae9836..8707012 100644
--- a/src/com/android/contacts/model/DataKind.java
+++ b/src/com/android/contacts/model/dataitem/DataKind.java
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.dataitem;
import android.content.ContentValues;
import android.provider.ContactsContract.Data;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType.EditField;
-import com.android.contacts.model.AccountType.EditType;
-import com.android.contacts.model.AccountType.StringInflater;
+import com.android.contacts.model.account.AccountType.EditField;
+import com.android.contacts.model.account.AccountType.EditType;
+import com.android.contacts.model.account.AccountType.StringInflater;
import com.google.common.collect.Iterators;
import java.text.SimpleDateFormat;
diff --git a/src/com/android/contacts/model/dataitem/EmailDataItem.java b/src/com/android/contacts/model/dataitem/EmailDataItem.java
new file mode 100644
index 0000000..a535c73
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/EmailDataItem.java
@@ -0,0 +1,57 @@
+/*
+ * 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 com.android.contacts.model.RawContact;
+
+/**
+ * Represents an email data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Email}.
+ */
+public class EmailDataItem extends DataItem {
+
+ /* package */ EmailDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, 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);
+ }
+
+ /**
+ * Values is one of Email.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(Email.TYPE);
+ }
+
+ 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
new file mode 100644
index 0000000..2114279
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/EventDataItem.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents an event data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Event}.
+ */
+public class EventDataItem extends DataItem {
+
+ /* package */ EventDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, values);
+ }
+
+ public String getStartDate() {
+ return getContentValues().getAsString(Event.START_DATE);
+ }
+
+ /**
+ * Values are one of Event.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(Event.TYPE);
+ }
+
+ 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
new file mode 100644
index 0000000..aea9bca
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/GroupMembershipDataItem.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a group memebership data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.GroupMembership}.
+ */
+public class GroupMembershipDataItem extends DataItem {
+
+ /* package */ GroupMembershipDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, 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
new file mode 100644
index 0000000..fd4b836
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/IdentityDataItem.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents an identity data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Identity}.
+ */
+public class IdentityDataItem extends DataItem {
+
+ /* package */ IdentityDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, 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
new file mode 100644
index 0000000..3a08325
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/ImDataItem.java
@@ -0,0 +1,94 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents an IM data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Im}.
+ */
+public class ImDataItem extends DataItem {
+
+ private final boolean mCreatedFromEmail;
+
+ /* package */ ImDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, values);
+ mCreatedFromEmail = false;
+ }
+
+ private ImDataItem(RawContact rawContact, ContentValues values,
+ boolean createdFromEmail) {
+ super(rawContact, values);
+ mCreatedFromEmail = createdFromEmail;
+ }
+
+ public static ImDataItem createFromEmail(EmailDataItem item) {
+ ImDataItem im = new ImDataItem(item.getRawContact(),
+ 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);
+ }
+ }
+
+ /**
+ * Values are one of Im.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(Im.TYPE);
+ }
+
+ 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
new file mode 100644
index 0000000..7b52510
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/NicknameDataItem.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a nickname data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Nickname}.
+ */
+public class NicknameDataItem extends DataItem {
+
+ public NicknameDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, values);
+ }
+
+ public String getName() {
+ return getContentValues().getAsString(Nickname.NAME);
+ }
+
+ /**
+ * Types are defined as Nickname.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(Nickname.TYPE);
+ }
+
+ 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
new file mode 100644
index 0000000..0d0fa24
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/NoteDataItem.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a note data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Note}.
+ */
+public class NoteDataItem extends DataItem {
+
+ /* package */ NoteDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, 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
new file mode 100644
index 0000000..1326bdb
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/OrganizationDataItem.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents an organization data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Organization}.
+ */
+public class OrganizationDataItem extends DataItem {
+
+ /* package */ OrganizationDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, values);
+ }
+
+ public String getCompany() {
+ return getContentValues().getAsString(Organization.COMPANY);
+ }
+
+ /**
+ * Values are one of Organization.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(Organization.TYPE);
+ }
+
+ 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
new file mode 100644
index 0000000..94a0054
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/PhoneDataItem.java
@@ -0,0 +1,57 @@
+/*
+ * 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.Phone;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a phone data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Phone}.
+ */
+public class PhoneDataItem extends DataItem {
+
+ /* package */ PhoneDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, 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);
+ }
+
+ /**
+ * Values are Phone.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(Phone.TYPE);
+ }
+
+ public String getLabel() {
+ return getContentValues().getAsString(Phone.LABEL);
+ }
+
+}
diff --git a/src/com/android/contacts/model/dataitem/PhotoDataItem.java b/src/com/android/contacts/model/dataitem/PhotoDataItem.java
new file mode 100644
index 0000000..5e355fa
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/PhotoDataItem.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a photo data item, wrapping the columns in
+ * {@link ContactsContract.Contacts.Photo}.
+ */
+public class PhotoDataItem extends DataItem {
+
+ /* package */ PhotoDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, 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
new file mode 100644
index 0000000..7c22cf5
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/RelationDataItem.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a relation data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Relation}.
+ */
+public class RelationDataItem extends DataItem {
+
+ /* package */ RelationDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, values);
+ }
+
+ public String getName() {
+ return getContentValues().getAsString(Relation.NAME);
+ }
+
+ /**
+ * Values are one of Relation.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(Relation.TYPE);
+ }
+
+ 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
new file mode 100644
index 0000000..6b8e93d
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/SipAddressDataItem.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a sip address data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.SipAddress}.
+ */
+public class SipAddressDataItem extends DataItem {
+
+ /* package */ SipAddressDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, values);
+ }
+
+ public String getSipAddress() {
+ return getContentValues().getAsString(SipAddress.SIP_ADDRESS);
+ }
+
+ /**
+ * Value is one of SipAddress.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(SipAddress.TYPE);
+ }
+
+ 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
new file mode 100644
index 0000000..4654a6f
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/StructuredNameDataItem.java
@@ -0,0 +1,100 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a structured name data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.StructuredName}.
+ */
+public class StructuredNameDataItem extends DataItem {
+
+ public StructuredNameDataItem() {
+ super(null, new ContentValues());
+ getContentValues().put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ }
+
+ /* package */ StructuredNameDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, 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
new file mode 100644
index 0000000..cc2cf56
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/StructuredPostalDataItem.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a structured postal data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.StructuredPostal}.
+ */
+public class StructuredPostalDataItem extends DataItem {
+
+ /* package */ StructuredPostalDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, values);
+ }
+
+ public String getFormattedAddress() {
+ return getContentValues().getAsString(StructuredPostal.FORMATTED_ADDRESS);
+ }
+
+ /**
+ * Values are one of StructuredPostal.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(StructuredPostal.TYPE);
+ }
+
+ 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
new file mode 100644
index 0000000..c3aadf3
--- /dev/null
+++ b/src/com/android/contacts/model/dataitem/WebsiteDataItem.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import com.android.contacts.model.RawContact;
+
+/**
+ * Represents a website data item, wrapping the columns in
+ * {@link ContactsContract.CommonDataKinds.Website}.
+ */
+public class WebsiteDataItem extends DataItem {
+
+ /* package */ WebsiteDataItem(RawContact rawContact, ContentValues values) {
+ super(rawContact, values);
+ }
+
+ public String getUrl() {
+ return getContentValues().getAsString(Website.URL);
+ }
+
+ /**
+ * Value is one of Website.TYPE_*
+ */
+ public int getType() {
+ return getContentValues().getAsInteger(Website.TYPE);
+ }
+
+ 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 ec6bf4c..c10c338 100644
--- a/src/com/android/contacts/quickcontact/DataAction.java
+++ b/src/com/android/contacts/quickcontact/DataAction.java
@@ -17,27 +17,28 @@
package com.android.contacts.quickcontact;
import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.WebAddress;
-import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.provider.ContactsContract.CommonDataKinds.SipAddress;
-import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
-import android.provider.ContactsContract.CommonDataKinds.Website;
import android.provider.ContactsContract.Data;
import android.text.TextUtils;
import android.util.Log;
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType.EditType;
-import com.android.contacts.model.DataKind;
+import com.android.contacts.model.account.AccountType.EditType;
+import com.android.contacts.model.dataitem.DataItem;
+import com.android.contacts.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.util.Constants;
import com.android.contacts.util.PhoneCapabilityTester;
import com.android.contacts.util.StructuredPostalUtils;
@@ -68,51 +69,45 @@
/**
* Create an action from common {@link Data} elements.
*/
- public DataAction(Context context, String mimeType, DataKind kind, long dataId,
- ContentValues entryValues) {
+ public DataAction(Context context, DataItem item) {
mContext = context;
- mKind = kind;
- mMimeType = mimeType;
+ mKind = item.getDataKind();
+ mMimeType = item.getMimeType();
// Determine type for subtitle
mSubtitle = "";
- if (kind.typeColumn != null) {
- if (entryValues.containsKey(kind.typeColumn)) {
- final int typeValue = entryValues.getAsInteger(kind.typeColumn);
+ if (item.hasKindTypeColumn()) {
+ final int typeValue = item.getKindTypeColumn();
- // get type string
- for (EditType type : kind.typeList) {
- if (type.rawValue == typeValue) {
- if (type.customColumn == null) {
- // Non-custom type. Get its description from the resource
- mSubtitle = context.getString(type.labelRes);
- } else {
- // Custom type. Read it from the database
- mSubtitle = entryValues.getAsString(type.customColumn);
- }
- break;
+ // get type string
+ for (EditType type : item.getDataKind().typeList) {
+ if (type.rawValue == typeValue) {
+ if (type.customColumn == null) {
+ // Non-custom type. Get its description from the resource
+ mSubtitle = context.getString(type.labelRes);
+ } else {
+ // Custom type. Read it from the database
+ mSubtitle = item.getContentValues().getAsString(type.customColumn);
}
+ break;
}
}
}
- final Integer superPrimary = entryValues.getAsInteger(Data.IS_SUPER_PRIMARY);
- mIsPrimary = superPrimary != null && superPrimary != 0;
+ mIsPrimary = item.isSuperPrimary();
+ mBody = item.buildDataString();
- if (mKind.actionBody != null) {
- mBody = mKind.actionBody.inflateUsing(context, entryValues);
- }
-
- mDataId = dataId;
- mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, dataId);
+ mDataId = item.getId();
+ mDataUri = ContentUris.withAppendedId(Data.CONTENT_URI, mDataId);
final boolean hasPhone = PhoneCapabilityTester.isPhone(mContext);
final boolean hasSms = PhoneCapabilityTester.isSmsIntentRegistered(mContext);
// Handle well-known MIME-types with special care
- if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ if (item instanceof PhoneDataItem) {
if (PhoneCapabilityTester.isPhone(mContext)) {
- final String number = entryValues.getAsString(Phone.NUMBER);
+ PhoneDataItem phone = (PhoneDataItem) item;
+ final String number = phone.getNumber();
if (!TextUtils.isEmpty(number)) {
final Intent phoneIntent = hasPhone ? ContactsUtils.getCallIntent(number)
@@ -124,8 +119,8 @@
if (hasPhone && hasSms) {
mIntent = phoneIntent;
mAlternateIntent = smsIntent;
- mAlternateIconRes = kind.iconAltRes;
- mAlternateIconDescriptionRes = kind.iconAltDescriptionRes;
+ mAlternateIconRes = phone.getDataKind().iconAltRes;
+ mAlternateIconDescriptionRes = phone.getDataKind().iconAltDescriptionRes;
} else if (hasPhone) {
mIntent = phoneIntent;
} else if (hasSms) {
@@ -133,9 +128,10 @@
}
}
}
- } else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ } else if (item instanceof SipAddressDataItem) {
if (PhoneCapabilityTester.isSipPhone(mContext)) {
- final String address = entryValues.getAsString(SipAddress.SIP_ADDRESS);
+ final SipAddressDataItem sip = (SipAddressDataItem) item;
+ final String address = sip.getSipAddress();
if (!TextUtils.isEmpty(address)) {
final Uri callUri = Uri.fromParts(Constants.SCHEME_SIP, address, null);
mIntent = ContactsUtils.getCallIntent(callUri);
@@ -147,26 +143,27 @@
// for the SIP-related intent-filters in its manifest.
}
}
- } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
- final String address = entryValues.getAsString(Email.DATA);
+ } else if (item instanceof EmailDataItem) {
+ final EmailDataItem email = (EmailDataItem) item;
+ final String address = email.getData();
if (!TextUtils.isEmpty(address)) {
final Uri mailUri = Uri.fromParts(Constants.SCHEME_MAILTO, address, null);
mIntent = new Intent(Intent.ACTION_SENDTO, mailUri);
}
- } else if (Website.CONTENT_ITEM_TYPE.equals(mimeType)) {
- final String url = entryValues.getAsString(Website.URL);
+ } else if (item instanceof WebsiteDataItem) {
+ final WebsiteDataItem website = (WebsiteDataItem) item;
+ final String url = website.getUrl();
if (!TextUtils.isEmpty(url)) {
WebAddress webAddress = new WebAddress(url);
mIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webAddress.toString()));
}
- } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
- final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(
- entryValues.getAsString(Data.MIMETYPE));
- if (isEmail || isProtocolValid(entryValues)) {
- final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK :
- entryValues.getAsInteger(Im.PROTOCOL);
+ } else if (item instanceof ImDataItem) {
+ ImDataItem im = (ImDataItem) item;
+ final boolean isEmail = im.isCreatedFromEmail();
+ if (isEmail || im.isProtocolValid()) {
+ final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : im.getProtocol();
if (isEmail) {
// Use Google Talk string when using Email, and clear data
@@ -176,8 +173,8 @@
mDataUri = null;
}
- String host = entryValues.getAsString(Im.CUSTOM_PROTOCOL);
- String data = entryValues.getAsString(isEmail ? Email.DATA : Im.DATA);
+ String host = im.getCustomProtocol();
+ String data = im.getData();
if (protocol != Im.PROTOCOL_CUSTOM) {
// Try bringing in a well-known host for specific protocols
host = ContactsUtils.lookupProviderNameFromId(protocol);
@@ -191,8 +188,7 @@
// If the address is also available for a video chat, we'll show the capability
// as a secondary action.
- final Integer chatCapabilityObj = entryValues.getAsInteger(Im.CHAT_CAPABILITY);
- final int chatCapability = chatCapabilityObj == null ? 0 : chatCapabilityObj;
+ final int chatCapability = im.getChatCapability();
final boolean isVideoChatCapable =
(chatCapability & Im.CAPABILITY_HAS_CAMERA) != 0;
final boolean isAudioChatCapable =
@@ -210,9 +206,9 @@
}
}
}
- } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(mimeType)) {
- final String postalAddress =
- entryValues.getAsString(StructuredPostal.FORMATTED_ADDRESS);
+ } else if (item instanceof StructuredPostalDataItem) {
+ StructuredPostalDataItem postal = (StructuredPostalDataItem) item;
+ final String postalAddress = postal.getFormattedAddress();
if (!TextUtils.isEmpty(postalAddress)) {
mIntent = StructuredPostalUtils.getViewPostalAddressIntent(postalAddress);
}
@@ -221,7 +217,7 @@
if (mIntent == null) {
// Otherwise fall back to default VIEW action
mIntent = new Intent(Intent.ACTION_VIEW);
- mIntent.setDataAndType(mDataUri, mimeType);
+ mIntent.setDataAndType(mDataUri, item.getMimeType());
}
mIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
@@ -236,19 +232,6 @@
mPresence = presence;
}
- private boolean isProtocolValid(ContentValues entryValues) {
- final String protocol = entryValues.getAsString(Im.PROTOCOL);
- if (protocol == null) {
- return false;
- }
- try {
- Integer.valueOf(protocol);
- } catch (NumberFormatException e) {
- return false;
- }
- return true;
- }
-
@Override
public CharSequence getSubtitle() {
return mSubtitle;
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 4587f1d..25fb3f4 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -22,10 +22,7 @@
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ActivityNotFoundException;
import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
-import android.content.Entity;
-import android.content.Entity.NamedContentValues;
import android.content.Intent;
import android.content.Loader;
import android.content.pm.PackageManager;
@@ -35,13 +32,11 @@
import android.os.Bundle;
import android.os.Handler;
import android.provider.ContactsContract.CommonDataKinds.Email;
-import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsContract.RawContacts;
import android.support.v13.app.FragmentPagerAdapter;
@@ -62,10 +57,14 @@
import android.widget.Toast;
import com.android.contacts.Collapser;
-import com.android.contacts.ContactLoader;
import com.android.contacts.R;
-import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.DataKind;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.ContactLoader;
+import com.android.contacts.model.RawContact;
+import com.android.contacts.model.dataitem.DataItem;
+import com.android.contacts.model.dataitem.DataKind;
+import com.android.contacts.model.dataitem.EmailDataItem;
+import com.android.contacts.model.dataitem.ImDataItem;
import com.android.contacts.util.Constants;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.ImageViewDrawableSetter;
@@ -330,7 +329,7 @@
/**
* Handle the result from the ContactLoader
*/
- private void bindData(ContactLoader.Result data) {
+ private void bindData(Contact data) {
final ResolveCache cache = ResolveCache.getInstance(this);
final Context context = this;
@@ -339,42 +338,29 @@
mDefaultsMap.clear();
- mStopWatch.lap("atm"); // AccountTypeManager initialization start
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(
- context.getApplicationContext());
- mStopWatch.lap("fatm"); // AccountTypeManager initialization finished
+ mStopWatch.lap("sph"); // Start photo setting
final ImageView photoView = (ImageView) mPhotoContainer.findViewById(R.id.photo);
mPhotoSetter.setupContactPhoto(data, photoView);
mStopWatch.lap("ph"); // Photo set
- for (Entity entity : data.getEntities()) {
- final ContentValues entityValues = entity.getEntityValues();
- final String accountType = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
- final String dataSet = entityValues.getAsString(RawContacts.DATA_SET);
- for (NamedContentValues subValue : entity.getSubValues()) {
- final ContentValues entryValues = subValue.values;
- final String mimeType = entryValues.getAsString(Data.MIMETYPE);
+ for (RawContact rawContact : data.getRawContacts()) {
+ for (DataItem dataItem : rawContact.getDataItems()) {
+ final String mimeType = dataItem.getMimeType();
// Skip this data item if MIME-type excluded
if (isMimeExcluded(mimeType)) continue;
- final long dataId = entryValues.getAsLong(Data._ID);
- final Integer primary = entryValues.getAsInteger(Data.IS_PRIMARY);
- final boolean isPrimary = primary != null && primary != 0;
- final Integer superPrimary = entryValues.getAsInteger(Data.IS_SUPER_PRIMARY);
- final boolean isSuperPrimary = superPrimary != null && superPrimary != 0;
+ final long dataId = dataItem.getId();
+ final boolean isPrimary = dataItem.isPrimary();
+ final boolean isSuperPrimary = dataItem.isSuperPrimary();
- final DataKind kind =
- accountTypes.getKindOrFallback(accountType, dataSet, mimeType);
-
- if (kind != null) {
+ if (dataItem.getDataKind() != null) {
// Build an action for this data entry, find a mapping to a UI
// element, build its summary from the cursor, and collect it
// along with all others of this MIME-type.
- final Action action = new DataAction(context, mimeType, kind, dataId,
- entryValues);
+ final Action action = new DataAction(context, dataItem);
final boolean wasAdded = considerAdd(action, cache, isSuperPrimary);
if (wasAdded) {
// Remember the default
@@ -386,12 +372,11 @@
// Handle Email rows with presence data as Im entry
final DataStatus status = data.getStatuses().get(dataId);
- if (status != null && Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
- final DataKind imKind = accountTypes.getKindOrFallback(accountType, dataSet,
- Im.CONTENT_ITEM_TYPE);
- if (imKind != null) {
- final DataAction action = new DataAction(context, Im.CONTENT_ITEM_TYPE,
- imKind, dataId, entryValues);
+ if (status != null && dataItem instanceof EmailDataItem) {
+ final EmailDataItem email = (EmailDataItem) dataItem;
+ final ImDataItem im = ImDataItem.createFromEmail(email);
+ if (im.getDataKind() != null) {
+ final DataAction action = new DataAction(context, im);
action.setPresence(status.getPresence());
considerAdd(action, cache, isSuperPrimary);
}
@@ -505,14 +490,14 @@
listFragment.setListener(mListFragmentListener);
}
- private LoaderCallbacks<ContactLoader.Result> mLoaderCallbacks =
- new LoaderCallbacks<ContactLoader.Result>() {
+ private LoaderCallbacks<Contact> mLoaderCallbacks =
+ new LoaderCallbacks<Contact>() {
@Override
- public void onLoaderReset(Loader<ContactLoader.Result> loader) {
+ public void onLoaderReset(Loader<Contact> loader) {
}
@Override
- public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
+ public void onLoadFinished(Loader<Contact> loader, Contact data) {
mStopWatch.lap("lf"); // onLoadFinished
if (isFinishing()) {
close(false);
@@ -558,7 +543,7 @@
}
@Override
- public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
+ public Loader<Contact> onCreateLoader(int id, Bundle args) {
if (mLookupUri == null) {
Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early");
}
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index b80169b..03517d4 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -37,10 +37,11 @@
import android.view.View;
import android.widget.RemoteViews;
-import com.android.contacts.ContactLoader;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.ContactLoader;
+import com.android.contacts.model.account.AccountType;
import com.android.contacts.quickcontact.QuickContactBroadcastReceiver;
import com.android.contacts.util.ContactBadgeUtil;
import com.android.contacts.util.HtmlUtils;
@@ -115,10 +116,10 @@
final ContactLoader contactLoader = new ContactLoader(context, contactUri, false, true,
false, true);
contactLoader.registerListener(0,
- new ContactLoader.OnLoadCompleteListener<ContactLoader.Result>() {
+ new ContactLoader.OnLoadCompleteListener<Contact>() {
@Override
- public void onLoadComplete(Loader<ContactLoader.Result> loader,
- ContactLoader.Result contactData) {
+ public void onLoadComplete(Loader<Contact> loader,
+ Contact contactData) {
bindRemoteViews(context, widgetId, appWidgetManager, contactData);
}
});
@@ -127,7 +128,7 @@
}
private static void bindRemoteViews(final Context context, final int widgetId,
- final AppWidgetManager widgetManager, ContactLoader.Result contactData) {
+ final AppWidgetManager widgetManager, Contact contactData) {
Log.d(TAG, "Loaded " + contactData.getLookupKey()
+ " for widget with id=" + widgetId);
final RemoteViews views = new RemoteViews(context.getPackageName(),
diff --git a/src/com/android/contacts/util/AccountPromptUtils.java b/src/com/android/contacts/util/AccountPromptUtils.java
index 8c8c305..cdefda0 100644
--- a/src/com/android/contacts/util/AccountPromptUtils.java
+++ b/src/com/android/contacts/util/AccountPromptUtils.java
@@ -30,7 +30,7 @@
import android.util.Log;
import com.android.contacts.R;
-import com.android.contacts.model.GoogleAccountType;
+import com.android.contacts.model.account.GoogleAccountType;
import java.io.IOException;
diff --git a/src/com/android/contacts/util/AccountSelectionUtil.java b/src/com/android/contacts/util/AccountSelectionUtil.java
index 312dd16..d83cb41 100644
--- a/src/com/android/contacts/util/AccountSelectionUtil.java
+++ b/src/com/android/contacts/util/AccountSelectionUtil.java
@@ -31,9 +31,9 @@
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
import java.util.List;
diff --git a/src/com/android/contacts/util/AccountsListAdapter.java b/src/com/android/contacts/util/AccountsListAdapter.java
index 5f17cee..4355cba 100644
--- a/src/com/android/contacts/util/AccountsListAdapter.java
+++ b/src/com/android/contacts/util/AccountsListAdapter.java
@@ -26,9 +26,9 @@
import android.widget.TextView;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/contacts/util/ImageViewDrawableSetter.java b/src/com/android/contacts/util/ImageViewDrawableSetter.java
index 4c7869b..b231572 100644
--- a/src/com/android/contacts/util/ImageViewDrawableSetter.java
+++ b/src/com/android/contacts/util/ImageViewDrawableSetter.java
@@ -26,8 +26,8 @@
import android.util.Log;
import android.widget.ImageView;
-import com.android.contacts.ContactLoader.Result;
import com.android.contacts.ContactPhotoManager;
+import com.android.contacts.model.Contact;
import java.util.Arrays;
@@ -49,7 +49,7 @@
mTarget = target;
}
- public void setupContactPhoto(Result contactData, ImageView photoView) {
+ public void setupContactPhoto(Contact contactData, ImageView photoView) {
setTarget(photoView);
setCompressedImage(contactData.getPhotoBinaryData());
}
diff --git a/src/com/android/contacts/vcard/ImportVCardActivity.java b/src/com/android/contacts/vcard/ImportVCardActivity.java
index 48d6e83..a9566ef 100644
--- a/src/com/android/contacts/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/ImportVCardActivity.java
@@ -49,7 +49,7 @@
import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountSelectionUtil;
import com.android.vcard.VCardEntryCounter;
import com.android.vcard.VCardParser;
diff --git a/src/com/android/contacts/vcard/NfcImportVCardActivity.java b/src/com/android/contacts/vcard/NfcImportVCardActivity.java
index f427358..035be60 100644
--- a/src/com/android/contacts/vcard/NfcImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/NfcImportVCardActivity.java
@@ -33,7 +33,7 @@
import com.android.contacts.R;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.vcard.VCardEntry;
import com.android.vcard.VCardEntryCounter;
import com.android.vcard.VCardParser;
diff --git a/src/com/android/contacts/vcard/SelectAccountActivity.java b/src/com/android/contacts/vcard/SelectAccountActivity.java
index 1226385..0e9c5a8 100644
--- a/src/com/android/contacts/vcard/SelectAccountActivity.java
+++ b/src/com/android/contacts/vcard/SelectAccountActivity.java
@@ -24,7 +24,7 @@
import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.util.AccountSelectionUtil;
import java.util.List;
diff --git a/tests/src/com/android/contacts/EntityDeltaListTests.java b/tests/src/com/android/contacts/RawContactDeltaListTests.java
similarity index 70%
rename from tests/src/com/android/contacts/EntityDeltaListTests.java
rename to tests/src/com/android/contacts/RawContactDeltaListTests.java
index fd2fcb1..165e689 100644
--- a/tests/src/com/android/contacts/EntityDeltaListTests.java
+++ b/tests/src/com/android/contacts/RawContactDeltaListTests.java
@@ -23,7 +23,7 @@
import android.content.ContentProviderOperation;
import android.content.ContentValues;
-import android.content.Entity;
+import android.content.Context;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.ContactsContract.AggregationExceptions;
@@ -34,24 +34,25 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import com.android.contacts.EntityModifierTests.MockContactsSource;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.model.EntityModifier;
+import com.android.contacts.RawContactModifierTests.MockContactsSource;
+import com.android.contacts.model.RawContact;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.account.AccountType;
import com.google.common.collect.Lists;
import java.lang.reflect.Field;
import java.util.ArrayList;
/**
- * Tests for {@link EntityDeltaList} which focus on "diff" operations that should
+ * Tests for {@link RawContactDeltaList} which focus on "diff" operations that should
* create {@link AggregationExceptions} in certain cases.
*/
@LargeTest
-public class EntityDeltaListTests extends AndroidTestCase {
- public static final String TAG = "EntityDeltaListTests";
+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;
@@ -71,7 +72,7 @@
public static final String TEST_PHONE = "555-1212";
public static final String TEST_ACCOUNT = "org.example.test";
- public EntityDeltaListTests() {
+ public RawContactDeltaListTests() {
super();
}
@@ -95,47 +96,47 @@
return (ContentValues) field.get(operation);
}
- static EntityDelta getUpdate(long rawContactId) {
- final Entity before = EntityDeltaTests.getEntity(rawContactId,
- EntityDeltaTests.TEST_PHONE_ID);
- return EntityDelta.fromBefore(before);
+ static RawContactDelta getUpdate(Context context, long rawContactId) {
+ final RawContact before = RawContactDeltaTests.getRawContact(context, rawContactId,
+ RawContactDeltaTests.TEST_PHONE_ID);
+ return RawContactDelta.fromBefore(before);
}
- static EntityDelta getInsert() {
+ static RawContactDelta getInsert() {
final ContentValues after = new ContentValues();
- after.put(RawContacts.ACCOUNT_NAME, EntityDeltaTests.TEST_ACCOUNT_NAME);
+ after.put(RawContacts.ACCOUNT_NAME, RawContactDeltaTests.TEST_ACCOUNT_NAME);
after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
final ValuesDelta values = ValuesDelta.fromAfter(after);
- return new EntityDelta(values);
+ return new RawContactDelta(values);
}
- static EntityDeltaList buildSet(EntityDelta... deltas) {
- final EntityDeltaList set = EntityDeltaList.fromSingle(deltas[0]);
+ static RawContactDeltaList buildSet(RawContactDelta... deltas) {
+ final RawContactDeltaList set = RawContactDeltaList.fromSingle(deltas[0]);
for (int i = 1; i < deltas.length; i++) {
set.add(deltas[i]);
}
return set;
}
- static EntityDelta buildBeforeEntity(long rawContactId, long version,
+ 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 Entity before = new Entity(contact);
+ final RawContact before = new RawContact(context, contact);
for (ContentValues entry : entries) {
- before.addSubValue(Data.CONTENT_URI, entry);
+ before.addDataItemValues(entry);
}
- return EntityDelta.fromBefore(before);
+ return RawContactDelta.fromBefore(before);
}
- static EntityDelta buildAfterEntity(ContentValues... entries) {
+ 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 EntityDelta after = new EntityDelta(ValuesDelta.fromAfter(contact));
+ final RawContactDelta after = new RawContactDelta(ValuesDelta.fromAfter(contact));
for (ContentValues entry : entries) {
after.addEntry(ValuesDelta.fromAfter(entry));
}
@@ -164,24 +165,24 @@
return values;
}
- static void insertPhone(EntityDeltaList set, long rawContactId, ContentValues values) {
- final EntityDelta match = set.getByRawContactId(rawContactId);
+ static void insertPhone(RawContactDeltaList set, long rawContactId, ContentValues values) {
+ final RawContactDelta match = set.getByRawContactId(rawContactId);
match.addEntry(ValuesDelta.fromAfter(values));
}
- static ValuesDelta getPhone(EntityDeltaList set, long rawContactId, long dataId) {
- final EntityDelta match = set.getByRawContactId(rawContactId);
+ static ValuesDelta getPhone(RawContactDeltaList set, long rawContactId, long dataId) {
+ final RawContactDelta match = set.getByRawContactId(rawContactId);
return match.getEntry(dataId);
}
- static void assertDiffPattern(EntityDelta delta, ContentProviderOperation... pattern) {
+ 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(EntityDeltaList set, ContentProviderOperation... pattern) {
+ static void assertDiffPattern(RawContactDeltaList set, ContentProviderOperation... pattern) {
assertDiffPattern(set.buildDiff(), pattern);
}
@@ -281,7 +282,7 @@
return null;
}
- static Long getVersion(EntityDeltaList set, Long rawContactId) {
+ static Long getVersion(RawContactDeltaList set, Long rawContactId) {
return set.getByRawContactId(rawContactId).getValues().getAsLong(RawContacts.VERSION);
}
@@ -301,8 +302,8 @@
}
public void testInsert() {
- final EntityDelta insert = getInsert();
- final EntityDeltaList set = buildSet(insert);
+ final RawContactDelta insert = getInsert();
+ final RawContactDeltaList set = buildSet(insert);
// Inserting single shouldn't create rules
final ArrayList<ContentProviderOperation> diff = set.buildDiff();
@@ -311,9 +312,9 @@
}
public void testUpdateUpdate() {
- final EntityDelta updateFirst = getUpdate(CONTACT_FIRST);
- final EntityDelta updateSecond = getUpdate(CONTACT_SECOND);
- final EntityDeltaList set = buildSet(updateFirst, updateSecond);
+ 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();
@@ -322,9 +323,9 @@
}
public void testUpdateInsert() {
- final EntityDelta update = getUpdate(CONTACT_FIRST);
- final EntityDelta insert = getInsert();
- final EntityDeltaList set = buildSet(update, insert);
+ 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();
@@ -333,10 +334,10 @@
}
public void testInsertUpdateInsert() {
- final EntityDelta insertFirst = getInsert();
- final EntityDelta update = getUpdate(CONTACT_FIRST);
- final EntityDelta insertSecond = getInsert();
- final EntityDeltaList set = buildSet(insertFirst, update, insertSecond);
+ 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();
@@ -345,10 +346,10 @@
}
public void testInsertInsertInsert() {
- final EntityDelta insertFirst = getInsert();
- final EntityDelta insertSecond = getInsert();
- final EntityDelta insertThird = getInsert();
- final EntityDeltaList set = buildSet(insertFirst, insertSecond, insertThird);
+ 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();
@@ -357,21 +358,21 @@
}
public void testMergeDataRemoteInsert() {
- final EntityDeltaList first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
- buildPhone(PHONE_RED)));
- final EntityDeltaList second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
- buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
+ 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 EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertEquals("Unexpected change when merging", second, merged);
}
public void testMergeDataLocalUpdateRemoteInsert() {
- final EntityDeltaList first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
- buildPhone(PHONE_RED)));
- final EntityDeltaList second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
- buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
+ 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);
@@ -384,7 +385,7 @@
buildUpdateAggregationDefault());
// Merge in the second version, verify diff matches
- final EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertDiffPattern(merged,
buildAssertVersion(VER_SECOND),
buildUpdateAggregationSuspended(),
@@ -393,10 +394,10 @@
}
public void testMergeDataLocalUpdateRemoteDelete() {
- final EntityDeltaList first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
- buildPhone(PHONE_RED)));
- final EntityDeltaList second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
- buildPhone(PHONE_GREEN)));
+ 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);
@@ -410,7 +411,7 @@
// Merge in the second version, verify that our update changed to
// insert, since RED was deleted on remote side
- final EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertDiffPattern(merged,
buildAssertVersion(VER_SECOND),
buildUpdateAggregationSuspended(),
@@ -419,10 +420,10 @@
}
public void testMergeDataLocalDeleteRemoteUpdate() {
- final EntityDeltaList first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
- buildPhone(PHONE_RED)));
- final EntityDeltaList second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
- buildPhone(PHONE_RED, TEST_PHONE)));
+ 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);
@@ -435,7 +436,7 @@
buildUpdateAggregationDefault());
// Merge in the second version, verify that our delete remains
- final EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertDiffPattern(merged,
buildAssertVersion(VER_SECOND),
buildUpdateAggregationSuspended(),
@@ -444,10 +445,10 @@
}
public void testMergeDataLocalInsertRemoteInsert() {
- final EntityDeltaList first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
- buildPhone(PHONE_RED)));
- final EntityDeltaList second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
- buildPhone(PHONE_RED), buildPhone(PHONE_GREEN)));
+ 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));
@@ -459,7 +460,7 @@
buildUpdateAggregationDefault());
// Merge in the second version, verify that our insert remains
- final EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertDiffPattern(merged,
buildAssertVersion(VER_SECOND),
buildUpdateAggregationSuspended(),
@@ -468,15 +469,15 @@
}
public void testMergeRawContactLocalInsertRemoteInsert() {
- final EntityDeltaList first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
- buildPhone(PHONE_RED)));
- final EntityDeltaList second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
- buildPhone(PHONE_RED)), buildBeforeEntity(CONTACT_MARY, VER_SECOND,
- buildPhone(PHONE_RED)));
+ 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 EntityDelta joeContact = buildAfterEntity(joePhoneInsert);
+ final RawContactDelta joeContact = buildAfterEntity(joePhoneInsert);
final ContentValues joeContactInsert = joeContact.getValues().getCompleteValues();
joeContactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
first.add(joeContact);
@@ -488,7 +489,7 @@
buildUpdateAggregationKeepTogether(CONTACT_BOB));
// Merge in the second version, verify that our insert remains
- final EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertDiffPattern(merged,
buildAssertVersion(VER_SECOND),
buildAssertVersion(VER_SECOND),
@@ -499,11 +500,11 @@
}
public void testMergeRawContactLocalDeleteRemoteDelete() {
- final EntityDeltaList first = buildSet(
- buildBeforeEntity(CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
- buildBeforeEntity(CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
- final EntityDeltaList second = buildSet(
- buildBeforeEntity(CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
+ 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();
@@ -513,16 +514,16 @@
buildDelete(RawContacts.CONTENT_URI));
// Merge in the second version, verify that our delete isn't needed
- final EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertDiffPattern(merged);
}
public void testMergeRawContactLocalUpdateRemoteDelete() {
- final EntityDeltaList first = buildSet(
- buildBeforeEntity(CONTACT_BOB, VER_FIRST, buildPhone(PHONE_RED)),
- buildBeforeEntity(CONTACT_MARY, VER_FIRST, buildPhone(PHONE_RED)));
- final EntityDeltaList second = buildSet(
- buildBeforeEntity(CONTACT_BOB, VER_SECOND, buildPhone(PHONE_RED)));
+ 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);
@@ -540,7 +541,7 @@
contactInsert.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_SUSPENDED);
// Merge and verify that update turned into insert
- final EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertDiffPattern(merged,
buildAssertVersion(VER_SECOND),
buildOper(RawContacts.CONTENT_URI, TYPE_INSERT, contactInsert),
@@ -550,28 +551,28 @@
}
public void testMergeUsesNewVersion() {
- final EntityDeltaList first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
- buildPhone(PHONE_RED)));
- final EntityDeltaList second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
- buildPhone(PHONE_RED)));
+ 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 EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertEquals((Long)VER_SECOND, getVersion(merged, CONTACT_BOB));
}
public void testMergeAfterEnsureAndTrim() {
- final EntityDeltaList first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
- buildEmail(EMAIL_YELLOW)));
- final EntityDeltaList second = buildSet(buildBeforeEntity(CONTACT_BOB, VER_SECOND,
- buildEmail(EMAIL_YELLOW)));
+ 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 EntityDelta bobContact = first.getByRawContactId(CONTACT_BOB);
- EntityModifier.ensureKindExists(bobContact, source, Phone.CONTENT_ITEM_TYPE);
+ 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
@@ -582,11 +583,11 @@
buildUpdateAggregationDefault());
// Trim values and ensure that we don't insert things
- EntityModifier.trimEmpty(bobContact, source);
+ RawContactModifier.trimEmpty(bobContact, source);
assertDiffPattern(first);
// Now re-parent the change, which should remain no-op
- final EntityDeltaList merged = EntityDeltaList.mergeAfter(second, first);
+ final RawContactDeltaList merged = RawContactDeltaList.mergeAfter(second, first);
assertDiffPattern(merged);
}
}
diff --git a/tests/src/com/android/contacts/EntityDeltaTests.java b/tests/src/com/android/contacts/RawContactDeltaTests.java
similarity index 82%
rename from tests/src/com/android/contacts/EntityDeltaTests.java
rename to tests/src/com/android/contacts/RawContactDeltaTests.java
index d873748..80e4c20 100644
--- a/tests/src/com/android/contacts/EntityDeltaTests.java
+++ b/tests/src/com/android/contacts/RawContactDeltaTests.java
@@ -24,7 +24,7 @@
import android.content.ContentProviderOperation;
import android.content.ContentProviderOperation.Builder;
import android.content.ContentValues;
-import android.content.Entity;
+import android.content.Context;
import android.os.Parcel;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data;
@@ -32,19 +32,20 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.RawContact;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
import com.google.common.collect.Lists;
import java.util.ArrayList;
/**
- * Tests for {@link EntityDelta} and {@link ValuesDelta}. These tests
+ * 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 EntityDeltaTests extends AndroidTestCase {
+public class RawContactDeltaTests extends AndroidTestCase {
public static final String TAG = "EntityDeltaTests";
public static final long TEST_CONTACT_ID = 12;
@@ -55,7 +56,7 @@
public static final String TEST_ACCOUNT_NAME = "TEST";
- public EntityDeltaTests() {
+ public RawContactDeltaTests() {
super();
}
@@ -64,7 +65,7 @@
mContext = getContext();
}
- public static Entity getEntity(long contactId, long phoneId) {
+ 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);
@@ -76,31 +77,31 @@
phone.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
phone.put(Phone.TYPE, Phone.TYPE_HOME);
- final Entity before = new Entity(contact);
- before.addSubValue(Data.CONTENT_URI, phone);
+ final RawContact before = new RawContact(context, contact);
+ before.addDataItemValues(phone);
return before;
}
/**
- * Test that {@link EntityDelta#mergeAfter(EntityDelta)} correctly passes
+ * Test that {@link RawContactDelta#mergeAfter(RawContactDelta)} correctly passes
* any changes through the {@link Parcel} object. This enforces that
- * {@link EntityDelta} should be identical when serialized against the same
- * "before" {@link Entity}.
+ * {@link RawContactDelta} should be identical when serialized against the same
+ * "before" {@link RawContact}.
*/
public void testParcelChangesNone() {
- final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
- final EntityDelta source = EntityDelta.fromBefore(before);
- final EntityDelta dest = EntityDelta.fromBefore(before);
+ 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 EntityDelta merged = EntityDelta.mergeAfter(dest, source);
+ final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
assertEquals("Unexpected change when merging", source, merged);
}
public void testParcelChangesInsert() {
- final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
- final EntityDelta source = EntityDelta.fromBefore(before);
- final EntityDelta dest = EntityDelta.fromBefore(before);
+ 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();
@@ -110,35 +111,35 @@
source.addEntry(ValuesDelta.fromAfter(phone));
// Merge modified values and assert they match
- final EntityDelta merged = EntityDelta.mergeAfter(dest, source);
+ 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 Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
- final EntityDelta source = EntityDelta.fromBefore(before);
- final EntityDelta dest = EntityDelta.fromBefore(before);
+ 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 EntityDelta merged = EntityDelta.mergeAfter(dest, source);
+ 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 Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
- final EntityDelta source = EntityDelta.fromBefore(before);
- final EntityDelta dest = EntityDelta.fromBefore(before);
+ 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 EntityDelta merged = EntityDelta.mergeAfter(dest, source);
+ final RawContactDelta merged = RawContactDelta.mergeAfter(dest, source);
assertEquals("Unexpected change when merging", source, merged);
}
@@ -200,13 +201,13 @@
}
/**
- * Test that {@link EntityDelta#buildDiff(ArrayList)} is correctly built for
+ * 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 Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
- final EntityDelta source = EntityDelta.fromBefore(before);
+ 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();
@@ -216,8 +217,8 @@
}
public void testEntityDiffNoneInsert() {
- final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
- final EntityDelta source = EntityDelta.fromBefore(before);
+ 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();
@@ -253,8 +254,8 @@
}
public void testEntityDiffUpdateInsert() {
- final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
- final EntityDelta source = EntityDelta.fromBefore(before);
+ 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);
@@ -298,8 +299,8 @@
}
public void testEntityDiffNoneUpdate() {
- final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
- final EntityDelta source = EntityDelta.fromBefore(before);
+ 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);
@@ -332,8 +333,8 @@
}
public void testEntityDiffDelete() {
- final Entity before = getEntity(TEST_CONTACT_ID, TEST_PHONE_ID);
- final EntityDelta source = EntityDelta.fromBefore(before);
+ final RawContact before = getRawContact(mContext, TEST_CONTACT_ID, TEST_PHONE_ID);
+ final RawContactDelta source = RawContactDelta.fromBefore(before);
// Delete entire entity
source.getValues().markDeleted();
@@ -361,7 +362,7 @@
after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
final ValuesDelta values = ValuesDelta.fromAfter(after);
- final EntityDelta source = new EntityDelta(values);
+ final RawContactDelta source = new RawContactDelta(values);
// Assert two operations: delete Contact and enforce version
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -382,7 +383,7 @@
after.put(RawContacts.SEND_TO_VOICEMAIL, 1);
final ValuesDelta values = ValuesDelta.fromAfter(after);
- final EntityDelta source = new EntityDelta(values);
+ final RawContactDelta source = new RawContactDelta(values);
// Insert a new phone number
final ContentValues phone = new ContentValues();
diff --git a/tests/src/com/android/contacts/EntityModifierTests.java b/tests/src/com/android/contacts/RawContactModifierTests.java
similarity index 80%
rename from tests/src/com/android/contacts/EntityModifierTests.java
rename to tests/src/com/android/contacts/RawContactModifierTests.java
index 6a68baf..9254a7e 100644
--- a/tests/src/com/android/contacts/EntityModifierTests.java
+++ b/tests/src/com/android/contacts/RawContactModifierTests.java
@@ -22,7 +22,6 @@
import android.content.ContentProviderOperation;
import android.content.ContentValues;
-import android.content.Entity;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
@@ -39,16 +38,17 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.EditType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.DataKind;
-import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.EntityDeltaList;
-import com.android.contacts.model.EntityModifier;
-import com.android.contacts.model.ExchangeAccountType;
-import com.android.contacts.model.GoogleAccountType;
+import com.android.contacts.model.RawContact;
+import com.android.contacts.model.RawContactDelta;
+import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.RawContactDeltaList;
+import com.android.contacts.model.RawContactModifier;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountType.EditType;
+import com.android.contacts.model.account.ExchangeAccountType;
+import com.android.contacts.model.account.GoogleAccountType;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.tests.mocks.ContactsMockContext;
import com.android.contacts.tests.mocks.MockAccountTypeManager;
import com.android.contacts.tests.mocks.MockContentProvider;
@@ -58,11 +58,11 @@
import java.util.List;
/**
- * Tests for {@link EntityModifier} to verify that {@link AccountType}
+ * Tests for {@link RawContactModifier} to verify that {@link AccountType}
* constraints are being enforced correctly.
*/
@LargeTest
-public class EntityModifierTests extends AndroidTestCase {
+public class RawContactModifierTests extends AndroidTestCase {
public static final String TAG = "EntityModifierTests";
public static final long VER_FIRST = 100;
@@ -168,9 +168,9 @@
}
/**
- * Build an {@link Entity} with the requested set of phone numbers.
+ * Build an {@link RawContact} with the requested set of phone numbers.
*/
- protected EntityDelta getEntity(Long existingId, ContentValues... entries) {
+ protected RawContactDelta getRawContact(Long existingId, ContentValues... entries) {
final ContentValues contact = new ContentValues();
if (existingId != null) {
contact.put(RawContacts._ID, existingId);
@@ -178,11 +178,11 @@
contact.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE);
- final Entity before = new Entity(contact);
+ final RawContact before = new RawContact(mContext, contact);
for (ContentValues values : entries) {
- before.addSubValue(Data.CONTENT_URI, values);
+ before.addDataItemValues(values);
}
- return EntityDelta.fromBefore(before);
+ return RawContactDelta.fromBefore(before);
}
/**
@@ -201,116 +201,116 @@
/**
* Insert various rows to test
- * {@link EntityModifier#getValidTypes(EntityDelta, DataKind, EditType)}
+ * {@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 = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
- final EditType typeWork = EntityModifier.getType(kindPhone, Phone.TYPE_WORK);
- final EditType typeOther = EntityModifier.getType(kindPhone, Phone.TYPE_OTHER);
+ 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 EntityDelta state = getEntity(TEST_ID);
- EntityModifier.insertChild(state, kindPhone, typeHome);
- EntityModifier.insertChild(state, kindPhone, typeWork);
+ final RawContactDelta state = getRawContact(TEST_ID);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeWork);
// Expecting home, other
- validTypes = EntityModifier.getValidTypes(state, kindPhone, null);
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
assertContains(validTypes, typeHome);
assertNotContains(validTypes, typeWork);
assertContains(validTypes, typeOther);
// Add second home
- EntityModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
// Expecting other
- validTypes = EntityModifier.getValidTypes(state, kindPhone, null);
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
assertNotContains(validTypes, typeHome);
assertNotContains(validTypes, typeWork);
assertContains(validTypes, typeOther);
// Add third and fourth home (invalid, but possible)
- EntityModifier.insertChild(state, kindPhone, typeHome);
- EntityModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
// Expecting none
- validTypes = EntityModifier.getValidTypes(state, kindPhone, null);
+ validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
assertNotContains(validTypes, typeHome);
assertNotContains(validTypes, typeWork);
assertNotContains(validTypes, typeOther);
}
/**
- * Test {@link EntityModifier#canInsert(EntityDelta, DataKind)} by
+ * 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 = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
- final EditType typeWork = EntityModifier.getType(kindPhone, Phone.TYPE_WORK);
- final EditType typeOther = EntityModifier.getType(kindPhone, Phone.TYPE_OTHER);
+ 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 EntityDelta state = getEntity(TEST_ID);
- EntityModifier.insertChild(state, kindPhone, typeHome);
- EntityModifier.insertChild(state, kindPhone, typeWork);
- assertTrue("Unable to insert", EntityModifier.canInsert(state, kindPhone));
+ 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
- EntityModifier.insertChild(state, kindPhone, typeOther);
- EntityModifier.insertChild(state, kindPhone, typeOther);
- assertTrue("Unable to insert", EntityModifier.canInsert(state, kindPhone));
+ 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
- EntityModifier.insertChild(state, kindPhone, typeHome);
- assertFalse("Able to insert", EntityModifier.canInsert(state, kindPhone));
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ assertFalse("Able to insert", RawContactModifier.canInsert(state, kindPhone));
}
/**
* Test
- * {@link EntityModifier#getBestValidType(EntityDelta, DataKind, boolean, int)}
+ * {@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 = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
- final EditType typeWork = EntityModifier.getType(kindPhone, Phone.TYPE_WORK);
- final EditType typeFaxWork = EntityModifier.getType(kindPhone, Phone.TYPE_FAX_WORK);
- final EditType typeOther = EntityModifier.getType(kindPhone, Phone.TYPE_OTHER);
+ 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 EntityDelta state = getEntity(TEST_ID);
- suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ 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
- EntityModifier.insertChild(state, kindPhone, typeHome);
- suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ 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
- EntityModifier.insertChild(state, kindPhone, typeFaxWork);
- suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ 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
- EntityModifier.insertChild(state, kindPhone, typeOther);
- suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ 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
- EntityModifier.insertChild(state, kindPhone, typeWork);
- suggested = EntityModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
+ RawContactModifier.insertChild(state, kindPhone, typeWork);
+ suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
assertEquals("Unexpected suggestion", typeOther, suggested);
}
@@ -322,34 +322,34 @@
final ContentValues after = new ContentValues();
final ValuesDelta values = ValuesDelta.fromAfter(after);
- assertTrue("Expected empty", EntityModifier.isEmpty(values, kindPhone));
+ 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 = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Test row that has type values, but core fields are empty
- final EntityDelta state = getEntity(TEST_ID);
- final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+ final RawContactDelta state = getRawContact(TEST_ID);
+ final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
- assertTrue("Expected empty", EntityModifier.isEmpty(values, kindPhone));
+ 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", EntityModifier.isEmpty(values, kindPhone));
+ 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 = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Test row that has type values, but core fields are empty
- final EntityDelta state = getEntity(TEST_ID);
- EntityModifier.insertChild(state, kindPhone, typeHome);
+ 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();
@@ -372,7 +372,7 @@
}
// Trim empty rows and try again, expecting delete of overall contact
- EntityModifier.trimEmpty(state, source);
+ RawContactModifier.trimEmpty(state, source);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 1, diff.size());
@@ -386,63 +386,65 @@
public void testTrimEmptySpaces() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Test row that has type values, but values are spaces
- final EntityDelta state = EntityDeltaListTests.buildBeforeEntity(TEST_ID, VER_FIRST);
- final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+ 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
- EntityDeltaListTests.assertDiffPattern(state,
- EntityDeltaListTests.buildAssertVersion(VER_FIRST),
- EntityDeltaListTests.buildUpdateAggregationSuspended(),
- EntityDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
- EntityDeltaListTests.buildDataInsert(values, TEST_ID)),
- EntityDeltaListTests.buildUpdateAggregationDefault());
+ 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
- EntityModifier.trimEmpty(state, source);
- EntityDeltaListTests.assertDiffPattern(state,
- EntityDeltaListTests.buildAssertVersion(VER_FIRST),
- EntityDeltaListTests.buildDelete(RawContacts.CONTENT_URI));
+ 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 = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Test row that has type values with valid number
- final EntityDelta state = EntityDeltaListTests.buildBeforeEntity(TEST_ID, VER_FIRST);
- final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+ 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
- EntityDeltaListTests.assertDiffPattern(state,
- EntityDeltaListTests.buildAssertVersion(VER_FIRST),
- EntityDeltaListTests.buildUpdateAggregationSuspended(),
- EntityDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
- EntityDeltaListTests.buildDataInsert(values, TEST_ID)),
- EntityDeltaListTests.buildUpdateAggregationDefault());
+ 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
- EntityModifier.trimEmpty(state, source);
- EntityDeltaListTests.assertDiffPattern(state,
- EntityDeltaListTests.buildAssertVersion(VER_FIRST),
- EntityDeltaListTests.buildUpdateAggregationSuspended(),
- EntityDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
- EntityDeltaListTests.buildDataInsert(values, TEST_ID)),
- EntityDeltaListTests.buildUpdateAggregationDefault());
+ 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);
- EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Build "before" that has empty row
- final EntityDelta state = getEntity(TEST_ID);
+ 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);
@@ -454,7 +456,7 @@
assertEquals("Unexpected operations", 0, diff.size());
// Try trimming existing empty, which we shouldn't touch
- EntityModifier.trimEmpty(state, source);
+ RawContactModifier.trimEmpty(state, source);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
@@ -463,7 +465,7 @@
public void testTrimEmptyAfterUpdate() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Build "before" that has row with some phone number
final ContentValues before = new ContentValues();
@@ -471,7 +473,7 @@
before.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
before.put(kindPhone.typeColumn, typeHome.rawValue);
before.put(Phone.NUMBER, TEST_PHONE);
- final EntityDelta state = getEntity(TEST_ID, before);
+ final RawContactDelta state = getRawContact(TEST_ID, before);
// Build diff, expecting no changes
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -501,7 +503,7 @@
}
// Now run trim, which should turn that update into delete
- EntityModifier.trimEmpty(state, source);
+ RawContactModifier.trimEmpty(state, source);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 1, diff.size());
@@ -516,11 +518,11 @@
final AccountType accountType = getAccountType();
final AccountTypeManager accountTypes = getAccountTypes(accountType);
final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Try creating a contact without any child entries
- final EntityDelta state = getEntity(null);
- final EntityDeltaList set = EntityDeltaList.fromSingle(state);
+ final RawContactDelta state = getRawContact(null);
+ final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
// Build diff, expecting single insert
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -533,7 +535,7 @@
}
// Trim empty rows and try again, expecting no insert
- EntityModifier.trimEmpty(set, accountTypes);
+ RawContactModifier.trimEmpty(set, accountTypes);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
@@ -543,12 +545,12 @@
final AccountType accountType = getAccountType();
final AccountTypeManager accountTypes = getAccountTypes(accountType);
final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Try creating a contact with single empty entry
- final EntityDelta state = getEntity(null);
- EntityModifier.insertChild(state, kindPhone, typeHome);
- final EntityDeltaList set = EntityDeltaList.fromSingle(state);
+ final RawContactDelta state = getRawContact(null);
+ RawContactModifier.insertChild(state, kindPhone, typeHome);
+ final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
// Build diff, expecting two insert operations
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -566,7 +568,7 @@
}
// Trim empty rows and try again, expecting silence
- EntityModifier.trimEmpty(set, accountTypes);
+ RawContactModifier.trimEmpty(set, accountTypes);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
@@ -576,7 +578,7 @@
final AccountType accountType = getAccountType();
final AccountTypeManager accountTypes = getAccountTypes(accountType);
final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Build "before" with two phone numbers
final ContentValues first = new ContentValues();
@@ -591,8 +593,8 @@
second.put(kindPhone.typeColumn, typeHome.rawValue);
second.put(Phone.NUMBER, TEST_PHONE);
- final EntityDelta state = getEntity(TEST_ID, first, second);
- final EntityDeltaList set = EntityDeltaList.fromSingle(state);
+ final RawContactDelta state = getRawContact(TEST_ID, first, second);
+ final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
// Build diff, expecting no changes
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -622,7 +624,7 @@
}
// Now run trim, which should turn that update into delete
- EntityModifier.trimEmpty(set, accountTypes);
+ RawContactModifier.trimEmpty(set, accountTypes);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 3, diff.size());
@@ -647,7 +649,7 @@
final AccountType accountType = getAccountType();
final AccountTypeManager accountTypes = getAccountTypes(accountType);
final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
- final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+ final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Build "before" with two phone numbers
final ContentValues first = new ContentValues();
@@ -656,8 +658,8 @@
first.put(kindPhone.typeColumn, typeHome.rawValue);
first.put(Phone.NUMBER, TEST_PHONE);
- final EntityDelta state = getEntity(TEST_ID, first);
- final EntityDeltaList set = EntityDeltaList.fromSingle(state);
+ final RawContactDelta state = getRawContact(TEST_ID, first);
+ final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
// Build diff, expecting no changes
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -687,7 +689,7 @@
}
// Now run trim, which should turn into deleting the whole contact
- EntityModifier.trimEmpty(set, accountTypes);
+ RawContactModifier.trimEmpty(set, accountTypes);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 1, diff.size());
@@ -708,10 +710,10 @@
first.put(StructuredName.GIVEN_NAME, TEST_NAME);
// Parse extras, making sure we keep single name
- final EntityDelta state = getEntity(TEST_ID, first);
+ final RawContactDelta state = getRawContact(TEST_ID, first);
final Bundle extras = new Bundle();
extras.putString(Insert.NAME, TEST_NAME2);
- EntityModifier.parseExtras(mContext, accountType, state, extras);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
final int nameCount = state.getMimeEntriesCount(StructuredName.CONTENT_ITEM_TYPE, true);
assertEquals("Unexpected names", 1, nameCount);
@@ -726,7 +728,7 @@
first.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
first.put(Im.DATA, TEST_IM);
- final EntityDelta state = getEntity(TEST_ID, first);
+ 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
@@ -734,7 +736,7 @@
final Bundle extras = new Bundle();
extras.putInt(Insert.IM_PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
extras.putString(Insert.IM_HANDLE, TEST_IM);
- EntityModifier.parseExtras(mContext, accountType, state, extras);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
final int afterCount = state.getMimeEntries(Im.CONTENT_ITEM_TYPE).size();
assertEquals("Broke account type rules", beforeCount, afterCount);
@@ -742,12 +744,12 @@
public void testParseExtrasIgnoreUnhandled() {
final AccountType accountType = getAccountType();
- final EntityDelta state = getEntity(TEST_ID);
+ 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);
- EntityModifier.parseExtras(mContext, accountType, state, extras);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
assertNull("Broke accoun type rules",
state.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE));
@@ -755,12 +757,12 @@
public void testParseExtrasJobTitle() {
final AccountType accountType = getAccountType();
- final EntityDelta state = getEntity(TEST_ID);
+ 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);
- EntityModifier.parseExtras(mContext, accountType, state, extras);
+ RawContactModifier.parseExtras(mContext, accountType, state, extras);
final int count = state.getMimeEntries(Organization.CONTENT_ITEM_TYPE).size();
assertEquals("Expected to create organization", 1, count);
@@ -773,7 +775,7 @@
ContactsMockContext context = new ContactsMockContext(getContext());
- EntityDelta oldState = new EntityDelta();
+ RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
mockNameValues.put(StructuredName.PREFIX, "prefix");
@@ -786,8 +788,8 @@
mockNameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "PHONETIC_GIVEN");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migrateStructuredName(context, oldState, newState, kind);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
assertEquals(1, list.size());
@@ -824,14 +826,14 @@
StructuredName.MIDDLE_NAME, StructuredName.FAMILY_NAME,
StructuredName.SUFFIX);
- EntityDelta oldState = new EntityDelta();
+ 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));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migrateStructuredName(context, oldState, newState, kind);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
assertEquals(1, list.size());
@@ -866,7 +868,7 @@
.returnRow("prefix given middle family suffix")
.withProjection(StructuredName.DISPLAY_NAME);
- EntityDelta oldState = new EntityDelta();
+ RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
mockNameValues.put(StructuredName.PREFIX, "prefix");
@@ -876,8 +878,8 @@
mockNameValues.put(StructuredName.SUFFIX, "suffix");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migrateStructuredName(context, oldState, newState, kind);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
assertNotNull(list);
@@ -892,14 +894,14 @@
AccountType newAccountType = new ExchangeAccountType(getContext(), "");
DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
- EntityDelta oldState = new EntityDelta();
+ 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));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migratePostal(oldState, newState, kind);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migratePostal(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
assertNotNull(list);
@@ -915,7 +917,7 @@
AccountType newAccountType = new GoogleAccountType(getContext(), "");
DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
- EntityDelta oldState = new EntityDelta();
+ RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
mockNameValues.put(StructuredPostal.COUNTRY, "country");
@@ -925,8 +927,8 @@
mockNameValues.put(StructuredPostal.STREET, "street");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migratePostal(oldState, newState, kind);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migratePostal(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
assertNotNull(list);
@@ -957,15 +959,15 @@
private void testMigrateEventCommon(AccountType oldAccountType, AccountType newAccountType) {
DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
- EntityDelta oldState = new EntityDelta();
+ 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));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migrateEvent(oldState, newState, kind, 1990);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
assertNotNull(list);
@@ -981,7 +983,7 @@
AccountType newAccountType = new ExchangeAccountType(getContext(), "");
DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
- EntityDelta oldState = new EntityDelta();
+ RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
// No year format is not supported by Exchange.
@@ -995,8 +997,8 @@
mockNameValues.put(Event.TYPE, Event.TYPE_ANNIVERSARY);
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migrateEvent(oldState, newState, kind, 1990);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
assertNotNull(list);
@@ -1013,7 +1015,7 @@
AccountType newAccountType = new ExchangeAccountType(getContext(), "");
DataKind kind = newAccountType.getKindForMimetype(Email.CONTENT_ITEM_TYPE);
- EntityDelta oldState = new EntityDelta();
+ RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
mockNameValues.put(Email.TYPE, Email.TYPE_CUSTOM);
@@ -1037,8 +1039,8 @@
mockNameValues.put(Email.ADDRESS, "address4");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(Email.CONTENT_ITEM_TYPE);
assertNotNull(list);
@@ -1063,7 +1065,7 @@
AccountType newAccountType = new ExchangeAccountType(getContext(), "");
DataKind kind = newAccountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
- EntityDelta oldState = new EntityDelta();
+ RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
// Exchange doesn't support TYPE_HOME
@@ -1096,8 +1098,8 @@
mockNameValues.put(Im.DATA, "im4");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(Im.CONTENT_ITEM_TYPE);
assertNotNull(list);
@@ -1149,7 +1151,7 @@
// - "3" -- MOBILE
// - "4" -- WORK
- EntityDelta oldState = new EntityDelta();
+ RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
mockNameValues.put(Phone.TYPE, Phone.TYPE_HOME);
@@ -1179,8 +1181,8 @@
mockNameValues.put(Phone.NUMBER, "5");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
assertNotNull(list);
@@ -1208,15 +1210,15 @@
AccountType newAccountType = new ExchangeAccountType(getContext(), "");
DataKind kind = newAccountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
- EntityDelta oldState = new EntityDelta();
+ 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));
- EntityDelta newState = new EntityDelta();
- EntityModifier.migrateGenericWithoutTypeColumn(oldState, newState, kind);
+ RawContactDelta newState = new RawContactDelta();
+ RawContactModifier.migrateGenericWithoutTypeColumn(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(Organization.CONTENT_ITEM_TYPE);
assertNotNull(list);
diff --git a/tests/src/com/android/contacts/activities/PeopleActivityTest.java b/tests/src/com/android/contacts/activities/PeopleActivityTest.java
index c0648a7..11fccd1 100644
--- a/tests/src/com/android/contacts/activities/PeopleActivityTest.java
+++ b/tests/src/com/android/contacts/activities/PeopleActivityTest.java
@@ -38,10 +38,10 @@
import com.android.contacts.detail.ContactDetailFragment;
import com.android.contacts.interactions.TestLoaderManager;
import com.android.contacts.list.ContactBrowseListFragment;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
-import com.android.contacts.model.BaseAccountType;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.account.BaseAccountType;
import com.android.contacts.test.InjectedServices;
import com.android.contacts.tests.mocks.ContactsMockContext;
import com.android.contacts.tests.mocks.MockAccountTypeManager;
diff --git a/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java b/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
index b252c9c..b1d1daa 100644
--- a/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
+++ b/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
@@ -25,6 +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;
/**
* Tests for {@link ContactDetailFragment}.
@@ -41,9 +44,10 @@
values.put(Im.TYPE, Im.TYPE_HOME);
values.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
values.put(Im.DATA, TEST_ADDRESS);
+ ImDataItem im = (ImDataItem) DataItem.createFrom(null, values);
DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
- ContactDetailFragment.buildImActions(mContext, entry, values);
+ ContactDetailFragment.buildImActions(mContext, entry, im);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
@@ -58,9 +62,10 @@
values.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
values.put(Im.DATA, TEST_ADDRESS);
values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO);
+ ImDataItem im = (ImDataItem) DataItem.createFrom(null, values);
DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
- ContactDetailFragment.buildImActions(mContext, entry, values);
+ ContactDetailFragment.buildImActions(mContext, entry, im);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
@@ -77,9 +82,10 @@
values.put(Im.DATA, TEST_ADDRESS);
values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
Im.CAPABILITY_HAS_VOICE);
+ ImDataItem im = (ImDataItem) DataItem.createFrom(null, values);
DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
- ContactDetailFragment.buildImActions(mContext, entry, values);
+ ContactDetailFragment.buildImActions(mContext, entry, im);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
@@ -96,9 +102,10 @@
values.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM);
values.put(Im.CUSTOM_PROTOCOL, TEST_PROTOCOL);
values.put(Im.DATA, TEST_ADDRESS);
+ ImDataItem im = (ImDataItem) DataItem.createFrom(null, values);
DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
- ContactDetailFragment.buildImActions(mContext, entry, values);
+ ContactDetailFragment.buildImActions(mContext, entry, im);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
final Uri data = entry.intent.getData();
@@ -119,9 +126,11 @@
values.put(Email.DATA, TEST_ADDRESS);
values.put(Email.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
Im.CAPABILITY_HAS_VOICE);
+ ImDataItem im = ImDataItem.createFromEmail(
+ (EmailDataItem) DataItem.createFrom(null, values));
DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
- ContactDetailFragment.buildImActions(mContext, entry, values);
+ ContactDetailFragment.buildImActions(mContext, entry, im);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
diff --git a/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java b/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java
index a60f2c8..9f2d49b 100644
--- a/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java
+++ b/tests/src/com/android/contacts/editor/ContactEditorUtilsTest.java
@@ -20,8 +20,8 @@
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.android.contacts.tests.mocks.MockAccountTypeManager;
import com.google.common.collect.Sets;
diff --git a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
index 8bcebcd..fcbd83d 100644
--- a/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactDeletionInteractionTest.java
@@ -26,9 +26,9 @@
import com.android.contacts.ContactsApplication;
import com.android.contacts.R;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.BaseAccountType;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.BaseAccountType;
import com.android.contacts.test.FragmentTestActivity;
import com.android.contacts.test.InjectedServices;
import com.android.contacts.tests.mocks.ContactsMockContext;
diff --git a/tests/src/com/android/contacts/model/AccountTypeManagerTest.java b/tests/src/com/android/contacts/model/AccountTypeManagerTest.java
index c3b9e22..c8db85e 100644
--- a/tests/src/com/android/contacts/model/AccountTypeManagerTest.java
+++ b/tests/src/com/android/contacts/model/AccountTypeManagerTest.java
@@ -20,6 +20,9 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountTypeWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
diff --git a/tests/src/com/android/contacts/model/AccountWithDataSetTest.java b/tests/src/com/android/contacts/model/AccountWithDataSetTest.java
index 30ada1b..1818c38 100644
--- a/tests/src/com/android/contacts/model/AccountWithDataSetTest.java
+++ b/tests/src/com/android/contacts/model/AccountWithDataSetTest.java
@@ -21,6 +21,7 @@
import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.google.common.collect.Lists;
import java.util.List;
diff --git a/tests/src/com/android/contacts/ContactLoaderTest.java b/tests/src/com/android/contacts/model/ContactLoaderTest.java
similarity index 92%
rename from tests/src/com/android/contacts/ContactLoaderTest.java
rename to tests/src/com/android/contacts/model/ContactLoaderTest.java
index b1d9d86..54d220f 100644
--- a/tests/src/com/android/contacts/ContactLoaderTest.java
+++ b/tests/src/com/android/contacts/model/ContactLoaderTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts;
+package com.android.contacts.model;
import android.content.ContentUris;
import android.net.Uri;
@@ -28,9 +28,10 @@
import android.test.LoaderTestCase;
import android.test.suitebuilder.annotation.LargeTest;
-import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountWithDataSet;
-import com.android.contacts.model.BaseAccountType;
+import com.android.contacts.model.Contact;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountWithDataSet;
+import com.android.contacts.model.account.BaseAccountType;
import com.android.contacts.test.InjectedServices;
import com.android.contacts.tests.mocks.ContactsMockContext;
import com.android.contacts.tests.mocks.MockAccountTypeManager;
@@ -74,23 +75,23 @@
super.tearDown();
}
- private ContactLoader.Result assertLoadContact(Uri uri) {
+ private Contact assertLoadContact(Uri uri) {
final ContactLoader loader = new ContactLoader(mMockContext, uri, true);
return getLoaderResultSynchronously(loader);
}
public void testNullUri() {
- ContactLoader.Result result = assertLoadContact(null);
+ Contact result = assertLoadContact(null);
assertTrue(result.isError());
}
public void testEmptyUri() {
- ContactLoader.Result result = assertLoadContact(Uri.EMPTY);
+ Contact result = assertLoadContact(Uri.EMPTY);
assertTrue(result.isError());
}
public void testInvalidUri() {
- ContactLoader.Result result = assertLoadContact(Uri.parse("content://wtf"));
+ Contact result = assertLoadContact(Uri.parse("content://wtf"));
assertTrue(result.isError());
}
@@ -111,14 +112,14 @@
mContactsProvider.expectTypeQuery(baseUri, Contacts.CONTENT_ITEM_TYPE);
queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
- ContactLoader.Result contact = assertLoadContact(baseUri);
+ 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.getEntities().size());
+ assertEquals(1, contact.getRawContacts().size());
assertEquals(1, contact.getStatuses().size());
mContactsProvider.verify();
}
@@ -143,14 +144,14 @@
queries.fetchContactIdAndLookupFromRawContactUri(rawContactUri, contactId, lookupKey);
queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
- ContactLoader.Result contact = assertLoadContact(legacyUri);
+ 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.getEntities().size());
+ assertEquals(1, contact.getRawContacts().size());
assertEquals(1, contact.getStatuses().size());
mContactsProvider.verify();
}
@@ -174,14 +175,14 @@
queries.fetchContactIdAndLookupFromRawContactUri(rawContactUri, contactId, lookupKey);
queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
- ContactLoader.Result contact = assertLoadContact(rawContactUri);
+ 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.getEntities().size());
+ assertEquals(1, contact.getRawContacts().size());
assertEquals(1, contact.getStatuses().size());
mContactsProvider.verify();
}
@@ -203,14 +204,14 @@
mContactsProvider.expectTypeQuery(lookupNoIdUri, Contacts.CONTENT_ITEM_TYPE);
queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
- ContactLoader.Result contact = assertLoadContact(lookupNoIdUri);
+ 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.getEntities().size());
+ assertEquals(1, contact.getRawContacts().size());
assertEquals(1, contact.getStatuses().size());
mContactsProvider.verify();
}
@@ -232,14 +233,14 @@
mContactsProvider.expectTypeQuery(lookupUri, Contacts.CONTENT_ITEM_TYPE);
queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
- ContactLoader.Result contact = assertLoadContact(lookupUri);
+ 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.getEntities().size());
+ assertEquals(1, contact.getRawContacts().size());
assertEquals(1, contact.getStatuses().size());
mContactsProvider.verify();
}
@@ -271,14 +272,14 @@
mContactsProvider.expectTypeQuery(lookupWithWrongIdUri, Contacts.CONTENT_ITEM_TYPE);
queries.fetchAllData(entityUri, contactId, rawContactId, dataId, lookupKey);
- ContactLoader.Result contact = assertLoadContact(lookupWithWrongIdUri);
+ 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.getEntities().size());
+ assertEquals(1, contact.getRawContacts().size());
assertEquals(1, contact.getStatuses().size());
mContactsProvider.verify();
diff --git a/tests/src/com/android/contacts/model/AccountTypeTest.java b/tests/src/com/android/contacts/model/account/AccountTypeTest.java
similarity index 97%
rename from tests/src/com/android/contacts/model/AccountTypeTest.java
rename to tests/src/com/android/contacts/model/account/AccountTypeTest.java
index 5ed46f5..ad111d9 100644
--- a/tests/src/com/android/contacts/model/AccountTypeTest.java
+++ b/tests/src/com/android/contacts/model/account/AccountTypeTest.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.content.Context;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.contacts.model.account.AccountType;
import com.android.contacts.tests.R;
/**
diff --git a/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java b/tests/src/com/android/contacts/model/account/ExternalAccountTypeTest.java
similarity index 96%
rename from tests/src/com/android/contacts/model/ExternalAccountTypeTest.java
rename to tests/src/com/android/contacts/model/account/ExternalAccountTypeTest.java
index e4a94e0..9545bc1 100644
--- a/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java
+++ b/tests/src/com/android/contacts/model/account/ExternalAccountTypeTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.contacts.model;
+package com.android.contacts.model.account;
import android.content.Context;
import android.provider.ContactsContract.CommonDataKinds.Email;
@@ -31,6 +31,11 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.BaseAccountType;
+import com.android.contacts.model.account.ExternalAccountType;
+import com.android.contacts.model.account.FallbackAccountType;
+import com.android.contacts.model.dataitem.DataKind;
import com.android.contacts.tests.R;
import java.util.List;
diff --git a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java b/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
index 635607a..d774252 100644
--- a/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
+++ b/tests/src/com/android/contacts/tests/mocks/MockAccountTypeManager.java
@@ -15,10 +15,10 @@
*/
package com.android.contacts.tests.mocks;
-import com.android.contacts.model.AccountType;
import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountTypeWithDataSet;
-import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.account.AccountType;
+import com.android.contacts.model.account.AccountTypeWithDataSet;
+import com.android.contacts.model.account.AccountWithDataSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
diff --git a/tests/src/com/android/contacts/tests/streamitems/StreamItemPopulatorActivity.java b/tests/src/com/android/contacts/tests/streamitems/StreamItemPopulatorActivity.java
index bc54e5b..20229d2 100644
--- a/tests/src/com/android/contacts/tests/streamitems/StreamItemPopulatorActivity.java
+++ b/tests/src/com/android/contacts/tests/streamitems/StreamItemPopulatorActivity.java
@@ -32,7 +32,7 @@
import android.widget.Button;
import android.widget.Toast;
-import com.android.contacts.model.GoogleAccountType;
+import com.android.contacts.model.account.GoogleAccountType;
import com.android.contacts.tests.R;
import com.google.common.collect.Lists;