summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChiao Cheng <chiaocheng@google.com>2012-11-28 18:10:43 -0800
committerChiao Cheng <chiaocheng@google.com>2012-11-30 10:38:30 -0800
commitaa690d4949b8105e5bcf10569b7cf4fae36741de (patch)
treeff88ad3311d5ec30fa21aadfc2a2e4122c9e50c2
parent7d98eb5067ec805aa4c05343b6320197b7632854 (diff)
downloadpackages_apps_Contacts-aa690d4949b8105e5bcf10569b7cf4fae36741de.tar.gz
packages_apps_Contacts-aa690d4949b8105e5bcf10569b7cf4fae36741de.tar.bz2
packages_apps_Contacts-aa690d4949b8105e5bcf10569b7cf4fae36741de.zip
Prefactor RawContactDelta.ValuesDelta into top level class.
Making ValuesDelta into top level class so we do not have to move RawContactDelta into ContactsCommon. ValuesDelta is used by CustomContactListFilterActivity which needs to be moved. Bug: 6993891 Change-Id: If7371cf08ac0e14218fb790c96856e971fa613ec
-rw-r--r--src/com/android/contacts/activities/AttachPhotoActivity.java3
-rw-r--r--src/com/android/contacts/activities/ConfirmAddDetailActivity.java2
-rw-r--r--src/com/android/contacts/detail/ContactDetailFragment.java2
-rw-r--r--src/com/android/contacts/detail/PhotoSelectionHandler.java2
-rw-r--r--src/com/android/contacts/editor/AggregationSuggestionEngine.java2
-rw-r--r--src/com/android/contacts/editor/BaseRawContactEditorView.java2
-rw-r--r--src/com/android/contacts/editor/ContactEditorFragment.java2
-rw-r--r--src/com/android/contacts/editor/Editor.java2
-rw-r--r--src/com/android/contacts/editor/EventFieldEditorView.java2
-rw-r--r--src/com/android/contacts/editor/GroupMembershipView.java2
-rw-r--r--src/com/android/contacts/editor/KindSectionView.java2
-rw-r--r--src/com/android/contacts/editor/LabeledEditorView.java2
-rw-r--r--src/com/android/contacts/editor/PhoneticNameEditorView.java2
-rw-r--r--src/com/android/contacts/editor/PhotoEditorView.java2
-rw-r--r--src/com/android/contacts/editor/RawContactEditorView.java2
-rw-r--r--src/com/android/contacts/editor/RawContactReadOnlyEditorView.java2
-rw-r--r--src/com/android/contacts/editor/StructuredNameEditorView.java2
-rw-r--r--src/com/android/contacts/editor/TextFieldsEditorView.java2
-rw-r--r--src/com/android/contacts/editor/ViewIdGenerator.java2
-rw-r--r--src/com/android/contacts/list/ContactListFilterView.java4
-rw-r--r--src/com/android/contacts/list/CustomContactListFilterActivity.java2
-rw-r--r--src/com/android/contacts/model/RawContactDelta.java550
-rw-r--r--src/com/android/contacts/model/RawContactDeltaList.java1
-rw-r--r--src/com/android/contacts/model/RawContactModifier.java1
-rw-r--r--src/com/android/contacts/model/ValuesDelta.java573
-rw-r--r--tests/src/com/android/contacts/RawContactDeltaListTests.java2
-rw-r--r--tests/src/com/android/contacts/RawContactDeltaTests.java45
-rw-r--r--tests/src/com/android/contacts/RawContactModifierTests.java2
-rw-r--r--tests/src/com/android/contacts/ValuesDeltaTests.java87
29 files changed, 687 insertions, 619 deletions
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 54f2de830..1eb77ddfc 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -39,6 +39,7 @@ import com.android.contacts.model.RawContactDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.util.ContactPhotoUtils;
import java.io.File;
@@ -195,7 +196,7 @@ public class AttachPhotoActivity extends ContactsActivity {
// 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);
- RawContactDelta.ValuesDelta values =
+ ValuesDelta values =
RawContactModifier.ensureKindExists(raw, account, Photo.CONTENT_ITEM_TYPE);
if (values == null) {
Log.w(TAG, "cannot attach photo to this account type");
diff --git a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
index f90ae7f11..99301c149 100644
--- a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
+++ b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
@@ -64,7 +64,7 @@ import com.android.contacts.editor.ViewIdGenerator;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 7701106cf..75cf1b385 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -86,7 +86,7 @@ import com.android.contacts.common.model.AccountTypeManager;
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.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
diff --git a/src/com/android/contacts/detail/PhotoSelectionHandler.java b/src/com/android/contacts/detail/PhotoSelectionHandler.java
index ec7637928..d004566dc 100644
--- a/src/com/android/contacts/detail/PhotoSelectionHandler.java
+++ b/src/com/android/contacts/detail/PhotoSelectionHandler.java
@@ -42,7 +42,7 @@ import com.android.contacts.editor.PhotoActionPopup;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.util.ContactPhotoUtils;
diff --git a/src/com/android/contacts/editor/AggregationSuggestionEngine.java b/src/com/android/contacts/editor/AggregationSuggestionEngine.java
index 0da05e883..4121d6aa4 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.Data;
import android.provider.ContactsContract.RawContacts;
import android.text.TextUtils;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
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 1ff9ac284..48ef96353 100644
--- a/src/com/android/contacts/editor/BaseRawContactEditorView.java
+++ b/src/com/android/contacts/editor/BaseRawContactEditorView.java
@@ -29,7 +29,7 @@ import android.widget.LinearLayout;
import com.android.contacts.R;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountType.EditType;
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 149f8216e..000a243d8 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -75,7 +75,7 @@ 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.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
diff --git a/src/com/android/contacts/editor/Editor.java b/src/com/android/contacts/editor/Editor.java
index ec816f7a9..bafffe126 100644
--- a/src/com/android/contacts/editor/Editor.java
+++ b/src/com/android/contacts/editor/Editor.java
@@ -19,7 +19,7 @@ package com.android.contacts.editor;
import android.provider.ContactsContract.Data;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
/**
diff --git a/src/com/android/contacts/editor/EventFieldEditorView.java b/src/com/android/contacts/editor/EventFieldEditorView.java
index 1f6cd4351..d2c4e4c0b 100644
--- a/src/com/android/contacts/editor/EventFieldEditorView.java
+++ b/src/com/android/contacts/editor/EventFieldEditorView.java
@@ -30,7 +30,7 @@ import com.android.contacts.datepicker.DatePicker;
import com.android.contacts.datepicker.DatePickerDialog;
import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType.EditField;
import com.android.contacts.common.model.account.AccountType.EventEditType;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/editor/GroupMembershipView.java b/src/com/android/contacts/editor/GroupMembershipView.java
index 97257f173..f14101170 100644
--- a/src/com/android/contacts/editor/GroupMembershipView.java
+++ b/src/com/android/contacts/editor/GroupMembershipView.java
@@ -41,7 +41,7 @@ import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.interactions.GroupCreationDialogFragment;
import com.android.contacts.interactions.GroupCreationDialogFragment.OnGroupCreatedListener;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.model.RawContactModifier;
import com.google.common.base.Objects;
diff --git a/src/com/android/contacts/editor/KindSectionView.java b/src/com/android/contacts/editor/KindSectionView.java
index 4f70cd414..985775ef7 100644
--- a/src/com/android/contacts/editor/KindSectionView.java
+++ b/src/com/android/contacts/editor/KindSectionView.java
@@ -30,7 +30,7 @@ import com.android.contacts.R;
import com.android.contacts.editor.Editor.EditorListener;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/editor/LabeledEditorView.java b/src/com/android/contacts/editor/LabeledEditorView.java
index 91339ae81..9b91d0dc4 100644
--- a/src/com/android/contacts/editor/LabeledEditorView.java
+++ b/src/com/android/contacts/editor/LabeledEditorView.java
@@ -47,7 +47,7 @@ import android.widget.TextView;
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType.EditType;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/editor/PhoneticNameEditorView.java b/src/com/android/contacts/editor/PhoneticNameEditorView.java
index 1ee7e217d..43050d9f9 100644
--- a/src/com/android/contacts/editor/PhoneticNameEditorView.java
+++ b/src/com/android/contacts/editor/PhoneticNameEditorView.java
@@ -22,7 +22,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.model.dataitem.StructuredNameDataItem;
diff --git a/src/com/android/contacts/editor/PhotoEditorView.java b/src/com/android/contacts/editor/PhotoEditorView.java
index e106eac6e..9e2036993 100644
--- a/src/com/android/contacts/editor/PhotoEditorView.java
+++ b/src/com/android/contacts/editor/PhotoEditorView.java
@@ -28,7 +28,7 @@ import android.widget.LinearLayout;
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.util.ContactPhotoUtils;
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index 27f2ce456..3d1cb85c5 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -42,7 +42,7 @@ import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountType.EditType;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.model.RawContactModifier;
import com.google.common.base.Objects;
diff --git a/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java b/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
index 8f9dcb986..1dc0a391d 100644
--- a/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
+++ b/src/com/android/contacts/editor/RawContactReadOnlyEditorView.java
@@ -41,7 +41,7 @@ import com.android.contacts.R;
import com.android.contacts.common.GeoUtil;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.model.dataitem.DataKind;
diff --git a/src/com/android/contacts/editor/StructuredNameEditorView.java b/src/com/android/contacts/editor/StructuredNameEditorView.java
index fcafe75f5..e6b9e157a 100644
--- a/src/com/android/contacts/editor/StructuredNameEditorView.java
+++ b/src/com/android/contacts/editor/StructuredNameEditorView.java
@@ -26,7 +26,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.model.dataitem.DataItem;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.model.dataitem.StructuredNameDataItem;
diff --git a/src/com/android/contacts/editor/TextFieldsEditorView.java b/src/com/android/contacts/editor/TextFieldsEditorView.java
index 970bbbfc8..fbaf68084 100644
--- a/src/com/android/contacts/editor/TextFieldsEditorView.java
+++ b/src/com/android/contacts/editor/TextFieldsEditorView.java
@@ -38,7 +38,7 @@ import android.widget.LinearLayout;
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType.EditField;
import com.android.contacts.common.model.dataitem.DataKind;
import com.android.contacts.common.util.PhoneNumberFormatter;
diff --git a/src/com/android/contacts/editor/ViewIdGenerator.java b/src/com/android/contacts/editor/ViewIdGenerator.java
index 9f4162320..6e26177a7 100644
--- a/src/com/android/contacts/editor/ViewIdGenerator.java
+++ b/src/com/android/contacts/editor/ViewIdGenerator.java
@@ -21,7 +21,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.dataitem.DataKind;
/**
diff --git a/src/com/android/contacts/list/ContactListFilterView.java b/src/com/android/contacts/list/ContactListFilterView.java
index d905683cc..5fa8e4d69 100644
--- a/src/com/android/contacts/list/ContactListFilterView.java
+++ b/src/com/android/contacts/list/ContactListFilterView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -11,7 +11,7 @@
* 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.
+ * limitations under the License
*/
package com.android.contacts.list;
diff --git a/src/com/android/contacts/list/CustomContactListFilterActivity.java b/src/com/android/contacts/list/CustomContactListFilterActivity.java
index 9750cf5c0..034f103c8 100644
--- a/src/com/android/contacts/list/CustomContactListFilterActivity.java
+++ b/src/com/android/contacts/list/CustomContactListFilterActivity.java
@@ -56,7 +56,7 @@ import android.widget.TextView;
import com.android.contacts.ContactsActivity;
import com.android.contacts.R;
import com.android.contacts.common.model.AccountTypeManager;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.model.account.GoogleAccountType;
diff --git a/src/com/android/contacts/model/RawContactDelta.java b/src/com/android/contacts/model/RawContactDelta.java
index 1a93cfbbd..34f039df4 100644
--- a/src/com/android/contacts/model/RawContactDelta.java
+++ b/src/com/android/contacts/model/RawContactDelta.java
@@ -24,11 +24,6 @@ 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;
@@ -39,13 +34,10 @@ import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.test.NeededForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+
/**
* Contains a {@link RawContact} and records any modifications separately so the
* original {@link RawContact} can be swapped out with a newer version and the
@@ -560,544 +552,4 @@ public class RawContactDelta implements Parcelable {
}
};
- /**
- * Type of {@link ContentValues} that maintains both an original state and a
- * modified version of that state. This allows us to build insert, update,
- * or delete operations based on a "before" {@link Entity} snapshot.
- */
- public static class ValuesDelta implements Parcelable {
- protected ContentValues mBefore;
- protected ContentValues mAfter;
- protected String mIdColumn = BaseColumns._ID;
- private boolean mFromTemplate;
-
- /**
- * Next value to assign to {@link #mIdColumn} when building an insert
- * operation through {@link #fromAfter(ContentValues)}. This is used so
- * we can concretely reference this {@link ValuesDelta} before it has
- * been persisted.
- */
- protected static int sNextInsertId = -1;
-
- protected ValuesDelta() {
- }
-
- /**
- * Create {@link ValuesDelta}, using the given object as the
- * "before" state, usually from an {@link Entity}.
- */
- public static ValuesDelta fromBefore(ContentValues before) {
- final ValuesDelta entry = new ValuesDelta();
- entry.mBefore = before;
- entry.mAfter = new ContentValues();
- return entry;
- }
-
- /**
- * Create {@link ValuesDelta}, using the given object as the "after"
- * state, usually when we are inserting a row instead of updating.
- */
- public static ValuesDelta fromAfter(ContentValues after) {
- final ValuesDelta entry = new ValuesDelta();
- entry.mBefore = null;
- entry.mAfter = after;
-
- // Assign temporary id which is dropped before insert.
- entry.mAfter.put(entry.mIdColumn, sNextInsertId--);
- return entry;
- }
-
- @NeededForTesting
- public ContentValues getAfter() {
- return mAfter;
- }
-
- public boolean containsKey(String key) {
- return ((mAfter != null && mAfter.containsKey(key)) ||
- (mBefore != null && mBefore.containsKey(key)));
- }
-
- public String getAsString(String key) {
- if (mAfter != null && mAfter.containsKey(key)) {
- return mAfter.getAsString(key);
- } else if (mBefore != null && mBefore.containsKey(key)) {
- return mBefore.getAsString(key);
- } else {
- return null;
- }
- }
-
- public byte[] getAsByteArray(String key) {
- if (mAfter != null && mAfter.containsKey(key)) {
- return mAfter.getAsByteArray(key);
- } else if (mBefore != null && mBefore.containsKey(key)) {
- return mBefore.getAsByteArray(key);
- } else {
- return null;
- }
- }
-
- public Long getAsLong(String key) {
- if (mAfter != null && mAfter.containsKey(key)) {
- return mAfter.getAsLong(key);
- } else if (mBefore != null && mBefore.containsKey(key)) {
- return mBefore.getAsLong(key);
- } else {
- return null;
- }
- }
-
- public Integer getAsInteger(String key) {
- return getAsInteger(key, null);
- }
-
- public Integer getAsInteger(String key, Integer defaultValue) {
- if (mAfter != null && mAfter.containsKey(key)) {
- return mAfter.getAsInteger(key);
- } else if (mBefore != null && mBefore.containsKey(key)) {
- return mBefore.getAsInteger(key);
- } else {
- return defaultValue;
- }
- }
-
- public boolean isChanged(String key) {
- if (mAfter == null || !mAfter.containsKey(key)) {
- return false;
- }
-
- Object newValue = mAfter.get(key);
- Object oldValue = mBefore.get(key);
-
- if (oldValue == null) {
- return newValue != null;
- }
-
- return !oldValue.equals(newValue);
- }
-
- public String getMimetype() {
- return getAsString(Data.MIMETYPE);
- }
-
- public Long getId() {
- return getAsLong(mIdColumn);
- }
-
- public void setIdColumn(String idColumn) {
- mIdColumn = idColumn;
- }
-
- public boolean isPrimary() {
- final Long isPrimary = getAsLong(Data.IS_PRIMARY);
- return isPrimary == null ? false : isPrimary != 0;
- }
-
- public void setFromTemplate(boolean isFromTemplate) {
- mFromTemplate = isFromTemplate;
- }
-
- public boolean isFromTemplate() {
- return mFromTemplate;
- }
-
- public boolean isSuperPrimary() {
- final Long isSuperPrimary = getAsLong(Data.IS_SUPER_PRIMARY);
- return isSuperPrimary == null ? false : isSuperPrimary != 0;
- }
-
- public boolean beforeExists() {
- return (mBefore != null && mBefore.containsKey(mIdColumn));
- }
-
- /**
- * When "after" is present, then visible
- */
- public boolean isVisible() {
- return (mAfter != null);
- }
-
- /**
- * When "after" is wiped, action is "delete"
- */
- public boolean isDelete() {
- return beforeExists() && (mAfter == null);
- }
-
- /**
- * When no "before" or "after", is transient
- */
- public boolean isTransient() {
- return (mBefore == null) && (mAfter == null);
- }
-
- /**
- * When "after" has some changes, action is "update"
- */
- public boolean isUpdate() {
- if (!beforeExists() || mAfter == null || mAfter.size() == 0) {
- return false;
- }
- for (String key : mAfter.keySet()) {
- Object newValue = mAfter.get(key);
- Object oldValue = mBefore.get(key);
- if (oldValue == null) {
- if (newValue != null) {
- return true;
- }
- } else if (!oldValue.equals(newValue)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * When "after" has no changes, action is no-op
- */
- public boolean isNoop() {
- return beforeExists() && (mAfter != null && mAfter.size() == 0);
- }
-
- /**
- * When no "before" id, and has "after", action is "insert"
- */
- public boolean isInsert() {
- return !beforeExists() && (mAfter != null);
- }
-
- public void markDeleted() {
- mAfter = null;
- }
-
- /**
- * Ensure that our internal structure is ready for storing updates.
- */
- private void ensureUpdate() {
- if (mAfter == null) {
- mAfter = new ContentValues();
- }
- }
-
- public void put(String key, String value) {
- ensureUpdate();
- mAfter.put(key, value);
- }
-
- public void put(String key, byte[] value) {
- ensureUpdate();
- mAfter.put(key, value);
- }
-
- public void put(String key, int value) {
- ensureUpdate();
- mAfter.put(key, value);
- }
-
- public void put(String key, long value) {
- ensureUpdate();
- mAfter.put(key, value);
- }
-
- public void putNull(String key) {
- ensureUpdate();
- mAfter.putNull(key);
- }
-
- public void copyStringFrom(ValuesDelta from, String key) {
- ensureUpdate();
- put(key, from.getAsString(key));
- }
-
- /**
- * Return set of all keys defined through this object.
- */
- public Set<String> keySet() {
- final HashSet<String> keys = Sets.newHashSet();
-
- if (mBefore != null) {
- for (Map.Entry<String, Object> entry : mBefore.valueSet()) {
- keys.add(entry.getKey());
- }
- }
-
- if (mAfter != null) {
- for (Map.Entry<String, Object> entry : mAfter.valueSet()) {
- keys.add(entry.getKey());
- }
- }
-
- return keys;
- }
-
- /**
- * Return complete set of "before" and "after" values mixed together,
- * giving full state regardless of edits.
- */
- public ContentValues getCompleteValues() {
- final ContentValues values = new ContentValues();
- if (mBefore != null) {
- values.putAll(mBefore);
- }
- if (mAfter != null) {
- values.putAll(mAfter);
- }
- if (values.containsKey(GroupMembership.GROUP_ROW_ID)) {
- // Clear to avoid double-definitions, and prefer rows
- values.remove(GroupMembership.GROUP_SOURCE_ID);
- }
-
- return values;
- }
-
- /**
- * Merge the "after" values from the given {@link ValuesDelta},
- * discarding any existing "after" state. This is typically used when
- * re-parenting changes onto an updated {@link Entity}.
- */
- public static ValuesDelta mergeAfter(ValuesDelta local, ValuesDelta remote) {
- // Bail early if trying to merge delete with missing local
- if (local == null && (remote.isDelete() || remote.isTransient())) return null;
-
- // Create local version if none exists yet
- if (local == null) local = new ValuesDelta();
-
- if (!local.beforeExists()) {
- // Any "before" record is missing, so take all values as "insert"
- local.mAfter = remote.getCompleteValues();
- } else {
- // Existing "update" with only "after" values
- local.mAfter = remote.mAfter;
- }
-
- return local;
- }
-
- @Override
- public boolean equals(Object object) {
- if (object instanceof ValuesDelta) {
- // Only exactly equal with both are identical subsets
- final ValuesDelta other = (ValuesDelta)object;
- return this.subsetEquals(other) && other.subsetEquals(this);
- }
- return false;
- }
-
- @Override
- public String toString() {
- final StringBuilder builder = new StringBuilder();
- toString(builder);
- return builder.toString();
- }
-
- /**
- * Helper for building string representation, leveraging the given
- * {@link StringBuilder} to minimize allocations.
- */
- public void toString(StringBuilder builder) {
- builder.append("{ ");
- builder.append("IdColumn=");
- builder.append(mIdColumn);
- builder.append(", FromTemplate=");
- builder.append(mFromTemplate);
- builder.append(", ");
- for (String key : this.keySet()) {
- builder.append(key);
- builder.append("=");
- builder.append(this.getAsString(key));
- builder.append(", ");
- }
- builder.append("}");
- }
-
- /**
- * Check if the given {@link ValuesDelta} is both a subset of this
- * object, and any defined keys have equal values.
- */
- public boolean subsetEquals(ValuesDelta other) {
- for (String key : this.keySet()) {
- final String ourValue = this.getAsString(key);
- final String theirValue = other.getAsString(key);
- if (ourValue == null) {
- // If they have value when we're null, no match
- if (theirValue != null) return false;
- } else {
- // If both values defined and aren't equal, no match
- if (!ourValue.equals(theirValue)) return false;
- }
- }
- // All values compared and matched
- return true;
- }
-
- /**
- * Build a {@link ContentProviderOperation} that will transform our
- * "before" state into our "after" state, using insert, update, or
- * delete as needed.
- */
- public ContentProviderOperation.Builder buildDiff(Uri targetUri) {
- Builder builder = null;
- if (isInsert()) {
- // Changed values are "insert" back-referenced to Contact
- mAfter.remove(mIdColumn);
- builder = ContentProviderOperation.newInsert(targetUri);
- builder.withValues(mAfter);
- } else if (isDelete()) {
- // When marked for deletion and "before" exists, then "delete"
- builder = ContentProviderOperation.newDelete(targetUri);
- builder.withSelection(mIdColumn + "=" + getId(), null);
- } else if (isUpdate()) {
- // When has changes and "before" exists, then "update"
- builder = ContentProviderOperation.newUpdate(targetUri);
- builder.withSelection(mIdColumn + "=" + getId(), null);
- builder.withValues(mAfter);
- }
- return builder;
- }
-
- /** {@inheritDoc} */
- public int describeContents() {
- // Nothing special about this parcel
- return 0;
- }
-
- /** {@inheritDoc} */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(mBefore, flags);
- dest.writeParcelable(mAfter, flags);
- dest.writeString(mIdColumn);
- }
-
- public void readFromParcel(Parcel source) {
- final ClassLoader loader = getClass().getClassLoader();
- mBefore = source.<ContentValues> readParcelable(loader);
- mAfter = source.<ContentValues> readParcelable(loader);
- mIdColumn = source.readString();
- }
-
- public static final Parcelable.Creator<ValuesDelta> CREATOR = new Parcelable.Creator<ValuesDelta>() {
- public ValuesDelta createFromParcel(Parcel in) {
- final ValuesDelta values = new ValuesDelta();
- values.readFromParcel(in);
- return values;
- }
-
- public ValuesDelta[] newArray(int size) {
- 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/RawContactDeltaList.java b/src/com/android/contacts/model/RawContactDeltaList.java
index 82dd4943d..3169c5d2d 100644
--- a/src/com/android/contacts/model/RawContactDeltaList.java
+++ b/src/com/android/contacts/model/RawContactDeltaList.java
@@ -30,7 +30,6 @@ import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.RawContacts;
import android.util.Log;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
import com.google.common.collect.Lists;
import java.util.ArrayList;
diff --git a/src/com/android/contacts/model/RawContactModifier.java b/src/com/android/contacts/model/RawContactModifier.java
index 27162a19d..d640f6b40 100644
--- a/src/com/android/contacts/model/RawContactModifier.java
+++ b/src/com/android/contacts/model/RawContactModifier.java
@@ -51,7 +51,6 @@ import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.util.CommonDateUtils;
import com.android.contacts.editor.EventFieldEditorView;
import com.android.contacts.editor.PhoneticNameEditorView;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountType.EditField;
import com.android.contacts.common.model.account.AccountType.EditType;
diff --git a/src/com/android/contacts/model/ValuesDelta.java b/src/com/android/contacts/model/ValuesDelta.java
new file mode 100644
index 000000000..d9ade773e
--- /dev/null
+++ b/src/com/android/contacts/model/ValuesDelta.java
@@ -0,0 +1,573 @@
+/*
+ * 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.ContentProviderOperation;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.provider.BaseColumns;
+import android.provider.ContactsContract;
+
+import com.android.contacts.common.test.NeededForTesting;
+import com.google.common.collect.Sets;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Type of {@link android.content.ContentValues} that maintains both an original state and a
+ * modified version of that state. This allows us to build insert, update,
+ * or delete operations based on a "before" {@link Entity} snapshot.
+ */
+public class ValuesDelta implements Parcelable {
+ protected ContentValues mBefore;
+ protected ContentValues mAfter;
+ protected String mIdColumn = BaseColumns._ID;
+ private boolean mFromTemplate;
+
+ /**
+ * Next value to assign to {@link #mIdColumn} when building an insert
+ * operation through {@link #fromAfter(android.content.ContentValues)}. This is used so
+ * we can concretely reference this {@link ValuesDelta} before it has
+ * been persisted.
+ */
+ protected static int sNextInsertId = -1;
+
+ protected ValuesDelta() {
+ }
+
+ /**
+ * Create {@link ValuesDelta}, using the given object as the
+ * "before" state, usually from an {@link Entity}.
+ */
+ public static ValuesDelta fromBefore(ContentValues before) {
+ final ValuesDelta entry = new ValuesDelta();
+ entry.mBefore = before;
+ entry.mAfter = new ContentValues();
+ return entry;
+ }
+
+ /**
+ * Create {@link ValuesDelta}, using the given object as the "after"
+ * state, usually when we are inserting a row instead of updating.
+ */
+ public static ValuesDelta fromAfter(ContentValues after) {
+ final ValuesDelta entry = new ValuesDelta();
+ entry.mBefore = null;
+ entry.mAfter = after;
+
+ // Assign temporary id which is dropped before insert.
+ entry.mAfter.put(entry.mIdColumn, sNextInsertId--);
+ return entry;
+ }
+
+ @NeededForTesting
+ public ContentValues getAfter() {
+ return mAfter;
+ }
+
+ public boolean containsKey(String key) {
+ return ((mAfter != null && mAfter.containsKey(key)) ||
+ (mBefore != null && mBefore.containsKey(key)));
+ }
+
+ public String getAsString(String key) {
+ if (mAfter != null && mAfter.containsKey(key)) {
+ return mAfter.getAsString(key);
+ } else if (mBefore != null && mBefore.containsKey(key)) {
+ return mBefore.getAsString(key);
+ } else {
+ return null;
+ }
+ }
+
+ public byte[] getAsByteArray(String key) {
+ if (mAfter != null && mAfter.containsKey(key)) {
+ return mAfter.getAsByteArray(key);
+ } else if (mBefore != null && mBefore.containsKey(key)) {
+ return mBefore.getAsByteArray(key);
+ } else {
+ return null;
+ }
+ }
+
+ public Long getAsLong(String key) {
+ if (mAfter != null && mAfter.containsKey(key)) {
+ return mAfter.getAsLong(key);
+ } else if (mBefore != null && mBefore.containsKey(key)) {
+ return mBefore.getAsLong(key);
+ } else {
+ return null;
+ }
+ }
+
+ public Integer getAsInteger(String key) {
+ return getAsInteger(key, null);
+ }
+
+ public Integer getAsInteger(String key, Integer defaultValue) {
+ if (mAfter != null && mAfter.containsKey(key)) {
+ return mAfter.getAsInteger(key);
+ } else if (mBefore != null && mBefore.containsKey(key)) {
+ return mBefore.getAsInteger(key);
+ } else {
+ return defaultValue;
+ }
+ }
+
+ public boolean isChanged(String key) {
+ if (mAfter == null || !mAfter.containsKey(key)) {
+ return false;
+ }
+
+ Object newValue = mAfter.get(key);
+ Object oldValue = mBefore.get(key);
+
+ if (oldValue == null) {
+ return newValue != null;
+ }
+
+ return !oldValue.equals(newValue);
+ }
+
+ public String getMimetype() {
+ return getAsString(ContactsContract.Data.MIMETYPE);
+ }
+
+ public Long getId() {
+ return getAsLong(mIdColumn);
+ }
+
+ public void setIdColumn(String idColumn) {
+ mIdColumn = idColumn;
+ }
+
+ public boolean isPrimary() {
+ final Long isPrimary = getAsLong(ContactsContract.Data.IS_PRIMARY);
+ return isPrimary == null ? false : isPrimary != 0;
+ }
+
+ public void setFromTemplate(boolean isFromTemplate) {
+ mFromTemplate = isFromTemplate;
+ }
+
+ public boolean isFromTemplate() {
+ return mFromTemplate;
+ }
+
+ public boolean isSuperPrimary() {
+ final Long isSuperPrimary = getAsLong(ContactsContract.Data.IS_SUPER_PRIMARY);
+ return isSuperPrimary == null ? false : isSuperPrimary != 0;
+ }
+
+ public boolean beforeExists() {
+ return (mBefore != null && mBefore.containsKey(mIdColumn));
+ }
+
+ /**
+ * When "after" is present, then visible
+ */
+ public boolean isVisible() {
+ return (mAfter != null);
+ }
+
+ /**
+ * When "after" is wiped, action is "delete"
+ */
+ public boolean isDelete() {
+ return beforeExists() && (mAfter == null);
+ }
+
+ /**
+ * When no "before" or "after", is transient
+ */
+ public boolean isTransient() {
+ return (mBefore == null) && (mAfter == null);
+ }
+
+ /**
+ * When "after" has some changes, action is "update"
+ */
+ public boolean isUpdate() {
+ if (!beforeExists() || mAfter == null || mAfter.size() == 0) {
+ return false;
+ }
+ for (String key : mAfter.keySet()) {
+ Object newValue = mAfter.get(key);
+ Object oldValue = mBefore.get(key);
+ if (oldValue == null) {
+ if (newValue != null) {
+ return true;
+ }
+ } else if (!oldValue.equals(newValue)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * When "after" has no changes, action is no-op
+ */
+ public boolean isNoop() {
+ return beforeExists() && (mAfter != null && mAfter.size() == 0);
+ }
+
+ /**
+ * When no "before" id, and has "after", action is "insert"
+ */
+ public boolean isInsert() {
+ return !beforeExists() && (mAfter != null);
+ }
+
+ public void markDeleted() {
+ mAfter = null;
+ }
+
+ /**
+ * Ensure that our internal structure is ready for storing updates.
+ */
+ private void ensureUpdate() {
+ if (mAfter == null) {
+ mAfter = new ContentValues();
+ }
+ }
+
+ public void put(String key, String value) {
+ ensureUpdate();
+ mAfter.put(key, value);
+ }
+
+ public void put(String key, byte[] value) {
+ ensureUpdate();
+ mAfter.put(key, value);
+ }
+
+ public void put(String key, int value) {
+ ensureUpdate();
+ mAfter.put(key, value);
+ }
+
+ public void put(String key, long value) {
+ ensureUpdate();
+ mAfter.put(key, value);
+ }
+
+ public void putNull(String key) {
+ ensureUpdate();
+ mAfter.putNull(key);
+ }
+
+ public void copyStringFrom(ValuesDelta from, String key) {
+ ensureUpdate();
+ put(key, from.getAsString(key));
+ }
+
+ /**
+ * Return set of all keys defined through this object.
+ */
+ public Set<String> keySet() {
+ final HashSet<String> keys = Sets.newHashSet();
+
+ if (mBefore != null) {
+ for (Map.Entry<String, Object> entry : mBefore.valueSet()) {
+ keys.add(entry.getKey());
+ }
+ }
+
+ if (mAfter != null) {
+ for (Map.Entry<String, Object> entry : mAfter.valueSet()) {
+ keys.add(entry.getKey());
+ }
+ }
+
+ return keys;
+ }
+
+ /**
+ * Return complete set of "before" and "after" values mixed together,
+ * giving full state regardless of edits.
+ */
+ public ContentValues getCompleteValues() {
+ final ContentValues values = new ContentValues();
+ if (mBefore != null) {
+ values.putAll(mBefore);
+ }
+ if (mAfter != null) {
+ values.putAll(mAfter);
+ }
+ if (values.containsKey(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID)) {
+ // Clear to avoid double-definitions, and prefer rows
+ values.remove(ContactsContract.CommonDataKinds.GroupMembership.GROUP_SOURCE_ID);
+ }
+
+ return values;
+ }
+
+ /**
+ * Merge the "after" values from the given {@link ValuesDelta},
+ * discarding any existing "after" state. This is typically used when
+ * re-parenting changes onto an updated {@link Entity}.
+ */
+ public static ValuesDelta mergeAfter(ValuesDelta local, ValuesDelta remote) {
+ // Bail early if trying to merge delete with missing local
+ if (local == null && (remote.isDelete() || remote.isTransient())) return null;
+
+ // Create local version if none exists yet
+ if (local == null) local = new ValuesDelta();
+
+ if (!local.beforeExists()) {
+ // Any "before" record is missing, so take all values as "insert"
+ local.mAfter = remote.getCompleteValues();
+ } else {
+ // Existing "update" with only "after" values
+ local.mAfter = remote.mAfter;
+ }
+
+ return local;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof ValuesDelta) {
+ // Only exactly equal with both are identical subsets
+ final ValuesDelta other = (ValuesDelta)object;
+ return this.subsetEquals(other) && other.subsetEquals(this);
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ toString(builder);
+ return builder.toString();
+ }
+
+ /**
+ * Helper for building string representation, leveraging the given
+ * {@link StringBuilder} to minimize allocations.
+ */
+ public void toString(StringBuilder builder) {
+ builder.append("{ ");
+ builder.append("IdColumn=");
+ builder.append(mIdColumn);
+ builder.append(", FromTemplate=");
+ builder.append(mFromTemplate);
+ builder.append(", ");
+ for (String key : this.keySet()) {
+ builder.append(key);
+ builder.append("=");
+ builder.append(this.getAsString(key));
+ builder.append(", ");
+ }
+ builder.append("}");
+ }
+
+ /**
+ * Check if the given {@link ValuesDelta} is both a subset of this
+ * object, and any defined keys have equal values.
+ */
+ public boolean subsetEquals(ValuesDelta other) {
+ for (String key : this.keySet()) {
+ final String ourValue = this.getAsString(key);
+ final String theirValue = other.getAsString(key);
+ if (ourValue == null) {
+ // If they have value when we're null, no match
+ if (theirValue != null) return false;
+ } else {
+ // If both values defined and aren't equal, no match
+ if (!ourValue.equals(theirValue)) return false;
+ }
+ }
+ // All values compared and matched
+ return true;
+ }
+
+ /**
+ * Build a {@link android.content.ContentProviderOperation} that will transform our
+ * "before" state into our "after" state, using insert, update, or
+ * delete as needed.
+ */
+ public ContentProviderOperation.Builder buildDiff(Uri targetUri) {
+ ContentProviderOperation.Builder builder = null;
+ if (isInsert()) {
+ // Changed values are "insert" back-referenced to Contact
+ mAfter.remove(mIdColumn);
+ builder = ContentProviderOperation.newInsert(targetUri);
+ builder.withValues(mAfter);
+ } else if (isDelete()) {
+ // When marked for deletion and "before" exists, then "delete"
+ builder = ContentProviderOperation.newDelete(targetUri);
+ builder.withSelection(mIdColumn + "=" + getId(), null);
+ } else if (isUpdate()) {
+ // When has changes and "before" exists, then "update"
+ builder = ContentProviderOperation.newUpdate(targetUri);
+ builder.withSelection(mIdColumn + "=" + getId(), null);
+ builder.withValues(mAfter);
+ }
+ return builder;
+ }
+
+ /** {@inheritDoc} */
+ public int describeContents() {
+ // Nothing special about this parcel
+ return 0;
+ }
+
+ /** {@inheritDoc} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mBefore, flags);
+ dest.writeParcelable(mAfter, flags);
+ dest.writeString(mIdColumn);
+ }
+
+ public void readFromParcel(Parcel source) {
+ final ClassLoader loader = getClass().getClassLoader();
+ mBefore = source.<ContentValues> readParcelable(loader);
+ mAfter = source.<ContentValues> readParcelable(loader);
+ mIdColumn = source.readString();
+ }
+
+ public static final Creator<ValuesDelta> CREATOR = new Creator<ValuesDelta>() {
+ public ValuesDelta createFromParcel(Parcel in) {
+ final ValuesDelta values = new ValuesDelta();
+ values.readFromParcel(in);
+ return values;
+ }
+
+ public ValuesDelta[] newArray(int size) {
+ return new ValuesDelta[size];
+ }
+ };
+
+ public void setGroupRowId(long groupId) {
+ put(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID, groupId);
+ }
+
+ public Long getGroupRowId() {
+ return getAsLong(ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID);
+ }
+
+ public void setPhoto(byte[] value) {
+ put(ContactsContract.CommonDataKinds.Photo.PHOTO, value);
+ }
+
+ public byte[] getPhoto() {
+ return getAsByteArray(ContactsContract.CommonDataKinds.Photo.PHOTO);
+ }
+
+ public void setSuperPrimary(boolean val) {
+ if (val) {
+ put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
+ } else {
+ put(ContactsContract.Data.IS_SUPER_PRIMARY, 0);
+ }
+ }
+
+ public void setPhoneticFamilyName(String value) {
+ put(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_FAMILY_NAME, value);
+ }
+
+ public void setPhoneticMiddleName(String value) {
+ put(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_MIDDLE_NAME, value);
+ }
+
+ public void setPhoneticGivenName(String value) {
+ put(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_GIVEN_NAME, value);
+ }
+
+ public String getPhoneticFamilyName() {
+ return getAsString(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_FAMILY_NAME);
+ }
+
+ public String getPhoneticMiddleName() {
+ return getAsString(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_MIDDLE_NAME);
+ }
+
+ public String getPhoneticGivenName() {
+ return getAsString(ContactsContract.CommonDataKinds.StructuredName.PHONETIC_GIVEN_NAME);
+ }
+
+ public String getDisplayName() {
+ return getAsString(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
+ }
+
+ public void setDisplayName(String name) {
+ if (name == null) {
+ putNull(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
+ } else {
+ put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);
+ }
+ }
+
+ public void copyStructuredNameFieldsFrom(ValuesDelta name) {
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
+
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.PREFIX);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.SUFFIX);
+
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.PHONETIC_GIVEN_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.PHONETIC_MIDDLE_NAME);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.PHONETIC_FAMILY_NAME);
+
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.FULL_NAME_STYLE);
+ copyStringFrom(name, ContactsContract.CommonDataKinds.StructuredName.PHONETIC_NAME_STYLE);
+ }
+
+ public String getPhoneNumber() {
+ return getAsString(ContactsContract.CommonDataKinds.Phone.NUMBER);
+ }
+
+ public String getPhoneNormalizedNumber() {
+ return getAsString(ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER);
+ }
+
+ public boolean phoneHasType() {
+ return containsKey(ContactsContract.CommonDataKinds.Phone.TYPE);
+ }
+
+ public int getPhoneType() {
+ return getAsInteger(ContactsContract.CommonDataKinds.Phone.TYPE);
+ }
+
+ public String getPhoneLabel() {
+ return getAsString(ContactsContract.CommonDataKinds.Phone.LABEL);
+ }
+
+ public String getEmailData() {
+ return getAsString(ContactsContract.CommonDataKinds.Email.DATA);
+ }
+
+ public boolean emailHasType() {
+ return containsKey(ContactsContract.CommonDataKinds.Email.TYPE);
+ }
+
+ public int getEmailType() {
+ return getAsInteger(ContactsContract.CommonDataKinds.Email.TYPE);
+ }
+
+ public String getEmailLabel() {
+ return getAsString(ContactsContract.CommonDataKinds.Email.LABEL);
+ }
+}
diff --git a/tests/src/com/android/contacts/RawContactDeltaListTests.java b/tests/src/com/android/contacts/RawContactDeltaListTests.java
index ef7667b30..a8a5d7be3 100644
--- a/tests/src/com/android/contacts/RawContactDeltaListTests.java
+++ b/tests/src/com/android/contacts/RawContactDeltaListTests.java
@@ -37,7 +37,7 @@ import android.test.suitebuilder.annotation.LargeTest;
import com.android.contacts.RawContactModifierTests.MockContactsSource;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
diff --git a/tests/src/com/android/contacts/RawContactDeltaTests.java b/tests/src/com/android/contacts/RawContactDeltaTests.java
index 751d41c41..62b7975de 100644
--- a/tests/src/com/android/contacts/RawContactDeltaTests.java
+++ b/tests/src/com/android/contacts/RawContactDeltaTests.java
@@ -34,7 +34,7 @@ import android.test.suitebuilder.annotation.LargeTest;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.google.common.collect.Lists;
import java.util.ArrayList;
@@ -143,49 +143,6 @@ public class RawContactDeltaTests extends AndroidTestCase {
assertEquals("Unexpected change when merging", source, merged);
}
- /**
- * Test that {@link ValuesDelta#buildDiff(android.net.Uri)} is correctly
- * built for insert, update, and delete cases. Note this only tests behavior
- * for individual {@link Data} rows.
- */
- public void testValuesDiffNone() {
- final ContentValues before = new ContentValues();
- before.put(Data._ID, TEST_PHONE_ID);
- before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
-
- final ValuesDelta values = ValuesDelta.fromBefore(before);
-
- // None action shouldn't produce a builder
- final Builder builder = values.buildDiff(Data.CONTENT_URI);
- assertNull("None action produced a builder", builder);
- }
-
- public void testValuesDiffInsert() {
- final ContentValues after = new ContentValues();
- after.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
-
- final ValuesDelta values = ValuesDelta.fromAfter(after);
-
- // Should produce an insert action
- final Builder builder = values.buildDiff(Data.CONTENT_URI);
- final int type = builder.build().getType();
- assertEquals("Didn't produce insert action", TYPE_INSERT, type);
- }
-
- public void testValuesDiffUpdate() {
- final ContentValues before = new ContentValues();
- before.put(Data._ID, TEST_PHONE_ID);
- before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
-
- final ValuesDelta values = ValuesDelta.fromBefore(before);
- values.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
-
- // Should produce an update action
- final Builder builder = values.buildDiff(Data.CONTENT_URI);
- final int type = builder.build().getType();
- assertEquals("Didn't produce update action", TYPE_UPDATE, type);
- }
-
public void testValuesDiffDelete() {
final ContentValues before = new ContentValues();
before.put(Data._ID, TEST_PHONE_ID);
diff --git a/tests/src/com/android/contacts/RawContactModifierTests.java b/tests/src/com/android/contacts/RawContactModifierTests.java
index d9f8f361b..382735dc5 100644
--- a/tests/src/com/android/contacts/RawContactModifierTests.java
+++ b/tests/src/com/android/contacts/RawContactModifierTests.java
@@ -41,7 +41,7 @@ import android.test.suitebuilder.annotation.LargeTest;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.model.RawContact;
import com.android.contacts.model.RawContactDelta;
-import com.android.contacts.model.RawContactDelta.ValuesDelta;
+import com.android.contacts.model.ValuesDelta;
import com.android.contacts.model.RawContactDeltaList;
import com.android.contacts.model.RawContactModifier;
import com.android.contacts.common.model.account.AccountType;
diff --git a/tests/src/com/android/contacts/ValuesDeltaTests.java b/tests/src/com/android/contacts/ValuesDeltaTests.java
new file mode 100644
index 000000000..e9e4648bf
--- /dev/null
+++ b/tests/src/com/android/contacts/ValuesDeltaTests.java
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import static android.content.ContentProviderOperation.TYPE_INSERT;
+import static android.content.ContentProviderOperation.TYPE_UPDATE;
+
+import android.content.ContentProviderOperation.Builder;
+import android.content.ContentValues;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Data;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.contacts.model.ValuesDelta;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link ValuesDelta}. These tests
+ * focus on passing changes across {@link android.os.Parcel}, and verifying that they
+ * correctly build expected "diff" operations.
+ */
+@SmallTest
+public class ValuesDeltaTests extends TestCase {
+
+ public static final long TEST_PHONE_ID = 24;
+
+ public static final String TEST_PHONE_NUMBER_1 = "218-555-1111";
+ public static final String TEST_PHONE_NUMBER_2 = "218-555-2222";
+
+ public void testValuesDiffInsert() {
+ final ContentValues after = new ContentValues();
+ after.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+
+ final ValuesDelta values = ValuesDelta.fromAfter(after);
+
+ // Should produce an insert action
+ final Builder builder = values.buildDiff(Data.CONTENT_URI);
+ final int type = builder.build().getType();
+ assertEquals("Didn't produce insert action", TYPE_INSERT, type);
+ }
+
+ /**
+ * Test that {@link ValuesDelta#buildDiff(android.net.Uri)} is correctly
+ * built for insert, update, and delete cases. Note this only tests behavior
+ * for individual {@link Data} rows.
+ */
+ public void testValuesDiffNone() {
+ final ContentValues before = new ContentValues();
+ before.put(Data._ID, TEST_PHONE_ID);
+ before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
+
+ final ValuesDelta values = ValuesDelta.fromBefore(before);
+
+ // None action shouldn't produce a builder
+ final Builder builder = values.buildDiff(Data.CONTENT_URI);
+ assertNull("None action produced a builder", builder);
+ }
+
+ public void testValuesDiffUpdate() {
+ final ContentValues before = new ContentValues();
+ before.put(Data._ID, TEST_PHONE_ID);
+ before.put(Phone.NUMBER, TEST_PHONE_NUMBER_1);
+
+ final ValuesDelta values = ValuesDelta.fromBefore(before);
+ values.put(Phone.NUMBER, TEST_PHONE_NUMBER_2);
+
+ // Should produce an update action
+ final Builder builder = values.buildDiff(Data.CONTENT_URI);
+ final int type = builder.build().getType();
+ assertEquals("Didn't produce update action", TYPE_UPDATE, type);
+ }
+}