blob: 8046ed6e72b3fb270a5deccd0484867bed01297e [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.contacts;
import static android.content.ContentProviderOperation.TYPE_DELETE;
import static android.content.ContentProviderOperation.TYPE_INSERT;
import static android.content.ContentProviderOperation.TYPE_UPDATE;
import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Intents.Insert;
import android.provider.ContactsContract.RawContacts;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import com.android.contacts.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.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;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for {@link RawContactModifier} to verify that {@link AccountType}
* constraints are being enforced correctly.
*/
@LargeTest
public class RawContactModifierTests extends AndroidTestCase {
public static final String TAG = "EntityModifierTests";
public static final long VER_FIRST = 100;
private static final long TEST_ID = 4;
private static final String TEST_PHONE = "218-555-1212";
private static final String TEST_NAME = "Adam Young";
private static final String TEST_NAME2 = "Breanne Duren";
private static final String TEST_IM = "example@example.com";
private static final String TEST_POSTAL = "1600 Amphitheatre Parkway";
private static final String TEST_ACCOUNT_NAME = "unittest@example.com";
private static final String TEST_ACCOUNT_TYPE = "com.example.unittest";
private static final String EXCHANGE_ACCT_TYPE = "com.android.exchange";
@Override
public void setUp() {
mContext = getContext();
}
public static class MockContactsSource extends AccountType {
MockContactsSource() {
try {
this.accountType = TEST_ACCOUNT_TYPE;
final DataKind nameKind = new DataKind(StructuredName.CONTENT_ITEM_TYPE,
R.string.nameLabelsGroup, -1, true, -1);
nameKind.typeOverallMax = 1;
addKind(nameKind);
// Phone allows maximum 2 home, 1 work, and unlimited other, with
// constraint of 5 numbers maximum.
final DataKind phoneKind = new DataKind(
Phone.CONTENT_ITEM_TYPE, -1, 10, true, -1);
phoneKind.typeOverallMax = 5;
phoneKind.typeColumn = Phone.TYPE;
phoneKind.typeList = Lists.newArrayList();
phoneKind.typeList.add(new EditType(Phone.TYPE_HOME, -1).setSpecificMax(2));
phoneKind.typeList.add(new EditType(Phone.TYPE_WORK, -1).setSpecificMax(1));
phoneKind.typeList.add(new EditType(Phone.TYPE_FAX_WORK, -1).setSecondary(true));
phoneKind.typeList.add(new EditType(Phone.TYPE_OTHER, -1));
phoneKind.fieldList = Lists.newArrayList();
phoneKind.fieldList.add(new EditField(Phone.NUMBER, -1, -1));
phoneKind.fieldList.add(new EditField(Phone.LABEL, -1, -1));
addKind(phoneKind);
// Email is unlimited
final DataKind emailKind = new DataKind(
Email.CONTENT_ITEM_TYPE, -1, 10, true, -1);
emailKind.typeOverallMax = -1;
emailKind.fieldList = Lists.newArrayList();
emailKind.fieldList.add(new EditField(Email.DATA, -1, -1));
addKind(emailKind);
// IM is only one
final DataKind imKind = new DataKind(Im.CONTENT_ITEM_TYPE, -1, 10,
true, -1);
imKind.typeOverallMax = 1;
imKind.fieldList = Lists.newArrayList();
imKind.fieldList.add(new EditField(Im.DATA, -1, -1));
addKind(imKind);
// Organization is only one
final DataKind orgKind = new DataKind(
Organization.CONTENT_ITEM_TYPE, -1, 10, true, -1);
orgKind.typeOverallMax = 1;
orgKind.fieldList = Lists.newArrayList();
orgKind.fieldList.add(new EditField(Organization.COMPANY, -1, -1));
orgKind.fieldList.add(new EditField(Organization.TITLE, -1, -1));
addKind(orgKind);
} catch (DefinitionException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean isGroupMembershipEditable() {
return false;
}
@Override
public boolean areContactsWritable() {
return true;
}
}
/**
* Build a {@link AccountType} that has various odd constraints for
* testing purposes.
*/
protected AccountType getAccountType() {
return new MockContactsSource();
}
/**
* Build {@link AccountTypeManager} instance.
*/
protected AccountTypeManager getAccountTypes(AccountType... types) {
return new MockAccountTypeManager(types, null);
}
/**
* Build an {@link RawContact} with the requested set of phone numbers.
*/
protected RawContactDelta getRawContact(Long existingId, ContentValues... entries) {
final ContentValues contact = new ContentValues();
if (existingId != null) {
contact.put(RawContacts._ID, existingId);
}
contact.put(RawContacts.ACCOUNT_NAME, TEST_ACCOUNT_NAME);
contact.put(RawContacts.ACCOUNT_TYPE, TEST_ACCOUNT_TYPE);
final RawContact before = new RawContact(mContext, contact);
for (ContentValues values : entries) {
before.addDataItemValues(values);
}
return RawContactDelta.fromBefore(before);
}
/**
* Assert this {@link List} contains the given {@link Object}.
*/
protected void assertContains(List<?> list, Object object) {
assertTrue("Missing expected value", list.contains(object));
}
/**
* Assert this {@link List} does not contain the given {@link Object}.
*/
protected void assertNotContains(List<?> list, Object object) {
assertFalse("Contained unexpected value", list.contains(object));
}
/**
* Insert various rows to test
* {@link RawContactModifier#getValidTypes(RawContactDelta, DataKind, EditType)}
*/
public void testValidTypes() {
// Build a source and pull specific types
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
List<EditType> validTypes;
// Add first home, first work
final RawContactDelta state = getRawContact(TEST_ID);
RawContactModifier.insertChild(state, kindPhone, typeHome);
RawContactModifier.insertChild(state, kindPhone, typeWork);
// Expecting home, other
validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
assertContains(validTypes, typeHome);
assertNotContains(validTypes, typeWork);
assertContains(validTypes, typeOther);
// Add second home
RawContactModifier.insertChild(state, kindPhone, typeHome);
// Expecting other
validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
assertNotContains(validTypes, typeHome);
assertNotContains(validTypes, typeWork);
assertContains(validTypes, typeOther);
// Add third and fourth home (invalid, but possible)
RawContactModifier.insertChild(state, kindPhone, typeHome);
RawContactModifier.insertChild(state, kindPhone, typeHome);
// Expecting none
validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
assertNotContains(validTypes, typeHome);
assertNotContains(validTypes, typeWork);
assertNotContains(validTypes, typeOther);
}
/**
* Test {@link RawContactModifier#canInsert(RawContactDelta, DataKind)} by
* inserting various rows.
*/
public void testCanInsert() {
// Build a source and pull specific types
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
// Add first home, first work
final RawContactDelta state = getRawContact(TEST_ID);
RawContactModifier.insertChild(state, kindPhone, typeHome);
RawContactModifier.insertChild(state, kindPhone, typeWork);
assertTrue("Unable to insert", RawContactModifier.canInsert(state, kindPhone));
// Add two other, which puts us just under "5" overall limit
RawContactModifier.insertChild(state, kindPhone, typeOther);
RawContactModifier.insertChild(state, kindPhone, typeOther);
assertTrue("Unable to insert", RawContactModifier.canInsert(state, kindPhone));
// Add second home, which should push to snug limit
RawContactModifier.insertChild(state, kindPhone, typeHome);
assertFalse("Able to insert", RawContactModifier.canInsert(state, kindPhone));
}
/**
* Test
* {@link RawContactModifier#getBestValidType(RawContactDelta, DataKind, boolean, int)}
* by asserting expected best options in various states.
*/
public void testBestValidType() {
// Build a source and pull specific types
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
final EditType typeFaxWork = RawContactModifier.getType(kindPhone, Phone.TYPE_FAX_WORK);
final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
EditType suggested;
// Default suggestion should be home
final RawContactDelta state = getRawContact(TEST_ID);
suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
assertEquals("Unexpected suggestion", typeHome, suggested);
// Add first home, should now suggest work
RawContactModifier.insertChild(state, kindPhone, typeHome);
suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
assertEquals("Unexpected suggestion", typeWork, suggested);
// Add work fax, should still suggest work
RawContactModifier.insertChild(state, kindPhone, typeFaxWork);
suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
assertEquals("Unexpected suggestion", typeWork, suggested);
// Add other, should still suggest work
RawContactModifier.insertChild(state, kindPhone, typeOther);
suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
assertEquals("Unexpected suggestion", typeWork, suggested);
// Add work, now should suggest other
RawContactModifier.insertChild(state, kindPhone, typeWork);
suggested = RawContactModifier.getBestValidType(state, kindPhone, false, Integer.MIN_VALUE);
assertEquals("Unexpected suggestion", typeOther, suggested);
}
public void testIsEmptyEmpty() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
// Test entirely empty row
final ContentValues after = new ContentValues();
final ValuesDelta values = ValuesDelta.fromAfter(after);
assertTrue("Expected empty", RawContactModifier.isEmpty(values, kindPhone));
}
public void testIsEmptyDirectFields() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Test row that has type values, but core fields are empty
final RawContactDelta state = getRawContact(TEST_ID);
final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
assertTrue("Expected empty", RawContactModifier.isEmpty(values, kindPhone));
// Insert some data to trigger non-empty state
values.put(Phone.NUMBER, TEST_PHONE);
assertFalse("Expected non-empty", RawContactModifier.isEmpty(values, kindPhone));
}
public void testTrimEmptySingle() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Test row that has type values, but core fields are empty
final RawContactDelta state = getRawContact(TEST_ID);
RawContactModifier.insertChild(state, kindPhone, typeHome);
// Build diff, expecting insert for data row and update enforcement
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
state.buildDiff(diff);
assertEquals("Unexpected operations", 3, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(1);
assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(2);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
// Trim empty rows and try again, expecting delete of overall contact
RawContactModifier.trimEmpty(state, source);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 1, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
}
public void testTrimEmptySpaces() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Test row that has type values, but values are spaces
final RawContactDelta state = RawContactDeltaListTests.buildBeforeEntity(mContext, TEST_ID,
VER_FIRST);
final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
values.put(Phone.NUMBER, " ");
// Build diff, expecting insert for data row and update enforcement
RawContactDeltaListTests.assertDiffPattern(state,
RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
RawContactDeltaListTests.buildUpdateAggregationSuspended(),
RawContactDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
RawContactDeltaListTests.buildUpdateAggregationDefault());
// Trim empty rows and try again, expecting delete of overall contact
RawContactModifier.trimEmpty(state, source);
RawContactDeltaListTests.assertDiffPattern(state,
RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
RawContactDeltaListTests.buildDelete(RawContacts.CONTENT_URI));
}
public void testTrimLeaveValid() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Test row that has type values with valid number
final RawContactDelta state = RawContactDeltaListTests.buildBeforeEntity(mContext, TEST_ID,
VER_FIRST);
final ValuesDelta values = RawContactModifier.insertChild(state, kindPhone, typeHome);
values.put(Phone.NUMBER, TEST_PHONE);
// Build diff, expecting insert for data row and update enforcement
RawContactDeltaListTests.assertDiffPattern(state,
RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
RawContactDeltaListTests.buildUpdateAggregationSuspended(),
RawContactDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
RawContactDeltaListTests.buildUpdateAggregationDefault());
// Trim empty rows and try again, expecting no differences
RawContactModifier.trimEmpty(state, source);
RawContactDeltaListTests.assertDiffPattern(state,
RawContactDeltaListTests.buildAssertVersion(VER_FIRST),
RawContactDeltaListTests.buildUpdateAggregationSuspended(),
RawContactDeltaListTests.buildOper(Data.CONTENT_URI, TYPE_INSERT,
RawContactDeltaListTests.buildDataInsert(values, TEST_ID)),
RawContactDeltaListTests.buildUpdateAggregationDefault());
}
public void testTrimEmptyUntouched() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Build "before" that has empty row
final RawContactDelta state = getRawContact(TEST_ID);
final ContentValues before = new ContentValues();
before.put(Data._ID, TEST_ID);
before.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
state.addEntry(ValuesDelta.fromBefore(before));
// Build diff, expecting no changes
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
// Try trimming existing empty, which we shouldn't touch
RawContactModifier.trimEmpty(state, source);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
}
public void testTrimEmptyAfterUpdate() {
final AccountType source = getAccountType();
final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Build "before" that has row with some phone number
final ContentValues before = new ContentValues();
before.put(Data._ID, TEST_ID);
before.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
before.put(kindPhone.typeColumn, typeHome.rawValue);
before.put(Phone.NUMBER, TEST_PHONE);
final RawContactDelta state = getRawContact(TEST_ID, before);
// Build diff, expecting no changes
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
// Now update row by changing number to empty string, expecting single update
final ValuesDelta child = state.getEntry(TEST_ID);
child.put(Phone.NUMBER, "");
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 3, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(1);
assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(2);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
// Now run trim, which should turn that update into delete
RawContactModifier.trimEmpty(state, source);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 1, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
}
public void testTrimInsertEmpty() {
final AccountType accountType = getAccountType();
final AccountTypeManager accountTypes = getAccountTypes(accountType);
final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Try creating a contact without any child entries
final RawContactDelta state = getRawContact(null);
final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
// Build diff, expecting single insert
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
state.buildDiff(diff);
assertEquals("Unexpected operations", 2, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
// Trim empty rows and try again, expecting no insert
RawContactModifier.trimEmpty(set, accountTypes);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
}
public void testTrimInsertInsert() {
final AccountType accountType = getAccountType();
final AccountTypeManager accountTypes = getAccountTypes(accountType);
final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Try creating a contact with single empty entry
final RawContactDelta state = getRawContact(null);
RawContactModifier.insertChild(state, kindPhone, typeHome);
final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
// Build diff, expecting two insert operations
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
state.buildDiff(diff);
assertEquals("Unexpected operations", 3, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(1);
assertEquals("Incorrect type", TYPE_INSERT, oper.getType());
assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
}
// Trim empty rows and try again, expecting silence
RawContactModifier.trimEmpty(set, accountTypes);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
}
public void testTrimUpdateRemain() {
final AccountType accountType = getAccountType();
final AccountTypeManager accountTypes = getAccountTypes(accountType);
final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Build "before" with two phone numbers
final ContentValues first = new ContentValues();
first.put(Data._ID, TEST_ID);
first.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
first.put(kindPhone.typeColumn, typeHome.rawValue);
first.put(Phone.NUMBER, TEST_PHONE);
final ContentValues second = new ContentValues();
second.put(Data._ID, TEST_ID);
second.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
second.put(kindPhone.typeColumn, typeHome.rawValue);
second.put(Phone.NUMBER, TEST_PHONE);
final RawContactDelta state = getRawContact(TEST_ID, first, second);
final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
// Build diff, expecting no changes
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
// Now update row by changing number to empty string, expecting single update
final ValuesDelta child = state.getEntry(TEST_ID);
child.put(Phone.NUMBER, "");
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 3, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(1);
assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(2);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
// Now run trim, which should turn that update into delete
RawContactModifier.trimEmpty(set, accountTypes);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 3, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(1);
assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(2);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
}
public void testTrimUpdateUpdate() {
final AccountType accountType = getAccountType();
final AccountTypeManager accountTypes = getAccountTypes(accountType);
final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
// Build "before" with two phone numbers
final ContentValues first = new ContentValues();
first.put(Data._ID, TEST_ID);
first.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
first.put(kindPhone.typeColumn, typeHome.rawValue);
first.put(Phone.NUMBER, TEST_PHONE);
final RawContactDelta state = getRawContact(TEST_ID, first);
final RawContactDeltaList set = RawContactDeltaList.fromSingle(state);
// Build diff, expecting no changes
final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
state.buildDiff(diff);
assertEquals("Unexpected operations", 0, diff.size());
// Now update row by changing number to empty string, expecting single update
final ValuesDelta child = state.getEntry(TEST_ID);
child.put(Phone.NUMBER, "");
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 3, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(1);
assertEquals("Incorrect type", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", Data.CONTENT_URI, oper.getUri());
}
{
final ContentProviderOperation oper = diff.get(2);
assertEquals("Expected aggregation mode change", TYPE_UPDATE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
// Now run trim, which should turn into deleting the whole contact
RawContactModifier.trimEmpty(set, accountTypes);
diff.clear();
state.buildDiff(diff);
assertEquals("Unexpected operations", 1, diff.size());
{
final ContentProviderOperation oper = diff.get(0);
assertEquals("Incorrect type", TYPE_DELETE, oper.getType());
assertEquals("Incorrect target", RawContacts.CONTENT_URI, oper.getUri());
}
}
public void testParseExtrasExistingName() {
final AccountType accountType = getAccountType();
// Build "before" name
final ContentValues first = new ContentValues();
first.put(Data._ID, TEST_ID);
first.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
first.put(StructuredName.GIVEN_NAME, TEST_NAME);
// Parse extras, making sure we keep single name
final RawContactDelta state = getRawContact(TEST_ID, first);
final Bundle extras = new Bundle();
extras.putString(Insert.NAME, TEST_NAME2);
RawContactModifier.parseExtras(mContext, accountType, state, extras);
final int nameCount = state.getMimeEntriesCount(StructuredName.CONTENT_ITEM_TYPE, true);
assertEquals("Unexpected names", 1, nameCount);
}
public void testParseExtrasIgnoreLimit() {
final AccountType accountType = getAccountType();
// Build "before" IM
final ContentValues first = new ContentValues();
first.put(Data._ID, TEST_ID);
first.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
first.put(Im.DATA, TEST_IM);
final RawContactDelta state = getRawContact(TEST_ID, first);
final int beforeCount = state.getMimeEntries(Im.CONTENT_ITEM_TYPE).size();
// We should ignore data that doesn't fit account type rules, since account type
// only allows single Im
final Bundle extras = new Bundle();
extras.putInt(Insert.IM_PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
extras.putString(Insert.IM_HANDLE, TEST_IM);
RawContactModifier.parseExtras(mContext, accountType, state, extras);
final int afterCount = state.getMimeEntries(Im.CONTENT_ITEM_TYPE).size();
assertEquals("Broke account type rules", beforeCount, afterCount);
}
public void testParseExtrasIgnoreUnhandled() {
final AccountType accountType = getAccountType();
final RawContactDelta state = getRawContact(TEST_ID);
// We should silently ignore types unsupported by account type
final Bundle extras = new Bundle();
extras.putString(Insert.POSTAL, TEST_POSTAL);
RawContactModifier.parseExtras(mContext, accountType, state, extras);
assertNull("Broke accoun type rules",
state.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE));
}
public void testParseExtrasJobTitle() {
final AccountType accountType = getAccountType();
final RawContactDelta state = getRawContact(TEST_ID);
// Make sure that we create partial Organizations
final Bundle extras = new Bundle();
extras.putString(Insert.JOB_TITLE, TEST_NAME);
RawContactModifier.parseExtras(mContext, accountType, state, extras);
final int count = state.getMimeEntries(Organization.CONTENT_ITEM_TYPE).size();
assertEquals("Expected to create organization", 1, count);
}
public void testMigrateWithDisplayNameFromGoogleToExchange1() {
AccountType oldAccountType = new GoogleAccountType(getContext(), "");
AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
ContactsMockContext context = new ContactsMockContext(getContext());
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
mockNameValues.put(StructuredName.PREFIX, "prefix");
mockNameValues.put(StructuredName.GIVEN_NAME, "given");
mockNameValues.put(StructuredName.MIDDLE_NAME, "middle");
mockNameValues.put(StructuredName.FAMILY_NAME, "family");
mockNameValues.put(StructuredName.SUFFIX, "suffix");
mockNameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "PHONETIC_FAMILY");
mockNameValues.put(StructuredName.PHONETIC_MIDDLE_NAME, "PHONETIC_MIDDLE");
mockNameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "PHONETIC_GIVEN");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
assertEquals(1, list.size());
ContentValues output = list.get(0).getAfter();
assertEquals("prefix", output.getAsString(StructuredName.PREFIX));
assertEquals("given", output.getAsString(StructuredName.GIVEN_NAME));
assertEquals("middle", output.getAsString(StructuredName.MIDDLE_NAME));
assertEquals("family", output.getAsString(StructuredName.FAMILY_NAME));
assertEquals("suffix", output.getAsString(StructuredName.SUFFIX));
// Phonetic middle name isn't supported by Exchange.
assertEquals("PHONETIC_FAMILY", output.getAsString(StructuredName.PHONETIC_FAMILY_NAME));
assertEquals("PHONETIC_GIVEN", output.getAsString(StructuredName.PHONETIC_GIVEN_NAME));
}
public void testMigrateWithDisplayNameFromGoogleToExchange2() {
AccountType oldAccountType = new GoogleAccountType(getContext(), "");
AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
ContactsMockContext context = new ContactsMockContext(getContext());
MockContentProvider provider = context.getContactsProvider();
String inputDisplayName = "prefix given middle family suffix";
// The method will ask the provider to split/join StructuredName.
Uri uriForBuildDisplayName =
ContactsContract.AUTHORITY_URI
.buildUpon()
.appendPath("complete_name")
.appendQueryParameter(StructuredName.DISPLAY_NAME, inputDisplayName)
.build();
provider.expectQuery(uriForBuildDisplayName)
.returnRow("prefix", "given", "middle", "family", "suffix")
.withProjection(StructuredName.PREFIX, StructuredName.GIVEN_NAME,
StructuredName.MIDDLE_NAME, StructuredName.FAMILY_NAME,
StructuredName.SUFFIX);
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
mockNameValues.put(StructuredName.DISPLAY_NAME, inputDisplayName);
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
assertEquals(1, list.size());
ContentValues outputValues = list.get(0).getAfter();
assertEquals("prefix", outputValues.getAsString(StructuredName.PREFIX));
assertEquals("given", outputValues.getAsString(StructuredName.GIVEN_NAME));
assertEquals("middle", outputValues.getAsString(StructuredName.MIDDLE_NAME));
assertEquals("family", outputValues.getAsString(StructuredName.FAMILY_NAME));
assertEquals("suffix", outputValues.getAsString(StructuredName.SUFFIX));
}
public void testMigrateWithStructuredNameFromExchangeToGoogle() {
AccountType oldAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
AccountType newAccountType = new GoogleAccountType(getContext(), "");
DataKind kind = newAccountType.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE);
ContactsMockContext context = new ContactsMockContext(getContext());
MockContentProvider provider = context.getContactsProvider();
// The method will ask the provider to split/join StructuredName.
Uri uriForBuildDisplayName =
ContactsContract.AUTHORITY_URI
.buildUpon()
.appendPath("complete_name")
.appendQueryParameter(StructuredName.PREFIX, "prefix")
.appendQueryParameter(StructuredName.GIVEN_NAME, "given")
.appendQueryParameter(StructuredName.MIDDLE_NAME, "middle")
.appendQueryParameter(StructuredName.FAMILY_NAME, "family")
.appendQueryParameter(StructuredName.SUFFIX, "suffix")
.build();
provider.expectQuery(uriForBuildDisplayName)
.returnRow("prefix given middle family suffix")
.withProjection(StructuredName.DISPLAY_NAME);
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
mockNameValues.put(StructuredName.PREFIX, "prefix");
mockNameValues.put(StructuredName.GIVEN_NAME, "given");
mockNameValues.put(StructuredName.MIDDLE_NAME, "middle");
mockNameValues.put(StructuredName.FAMILY_NAME, "family");
mockNameValues.put(StructuredName.SUFFIX, "suffix");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migrateStructuredName(context, oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
assertNotNull(list);
assertEquals(1, list.size());
ContentValues outputValues = list.get(0).getAfter();
assertEquals("prefix given middle family suffix",
outputValues.getAsString(StructuredName.DISPLAY_NAME));
}
public void testMigratePostalFromGoogleToExchange() {
AccountType oldAccountType = new GoogleAccountType(getContext(), "");
AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
mockNameValues.put(StructuredPostal.FORMATTED_ADDRESS, "formatted_address");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migratePostal(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
assertNotNull(list);
assertEquals(1, list.size());
ContentValues outputValues = list.get(0).getAfter();
// FORMATTED_ADDRESS isn't supported by Exchange.
assertNull(outputValues.getAsString(StructuredPostal.FORMATTED_ADDRESS));
assertEquals("formatted_address", outputValues.getAsString(StructuredPostal.STREET));
}
public void testMigratePostalFromExchangeToGoogle() {
AccountType oldAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
AccountType newAccountType = new GoogleAccountType(getContext(), "");
DataKind kind = newAccountType.getKindForMimetype(StructuredPostal.CONTENT_ITEM_TYPE);
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE);
mockNameValues.put(StructuredPostal.COUNTRY, "country");
mockNameValues.put(StructuredPostal.POSTCODE, "postcode");
mockNameValues.put(StructuredPostal.REGION, "region");
mockNameValues.put(StructuredPostal.CITY, "city");
mockNameValues.put(StructuredPostal.STREET, "street");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migratePostal(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(StructuredPostal.CONTENT_ITEM_TYPE);
assertNotNull(list);
assertEquals(1, list.size());
ContentValues outputValues = list.get(0).getAfter();
// Check FORMATTED_ADDRESS contains all info.
String formattedAddress = outputValues.getAsString(StructuredPostal.FORMATTED_ADDRESS);
assertNotNull(formattedAddress);
assertTrue(formattedAddress.contains("country"));
assertTrue(formattedAddress.contains("postcode"));
assertTrue(formattedAddress.contains("region"));
assertTrue(formattedAddress.contains("postcode"));
assertTrue(formattedAddress.contains("city"));
assertTrue(formattedAddress.contains("street"));
}
public void testMigrateEventFromGoogleToExchange1() {
testMigrateEventCommon(new GoogleAccountType(getContext(), ""),
new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE));
}
public void testMigrateEventFromExchangeToGoogle() {
testMigrateEventCommon(new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE),
new GoogleAccountType(getContext(), ""));
}
private void testMigrateEventCommon(AccountType oldAccountType, AccountType newAccountType) {
DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
mockNameValues.put(Event.START_DATE, "1972-02-08");
mockNameValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
assertNotNull(list);
assertEquals(1, list.size()); // Anniversary should be dropped.
ContentValues outputValues = list.get(0).getAfter();
assertEquals("1972-02-08", outputValues.getAsString(Event.START_DATE));
assertEquals(Event.TYPE_BIRTHDAY, outputValues.getAsInteger(Event.TYPE).intValue());
}
public void testMigrateEventFromGoogleToExchange2() {
AccountType oldAccountType = new GoogleAccountType(getContext(), "");
AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
DataKind kind = newAccountType.getKindForMimetype(Event.CONTENT_ITEM_TYPE);
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
// No year format is not supported by Exchange.
mockNameValues.put(Event.START_DATE, "--06-01");
mockNameValues.put(Event.TYPE, Event.TYPE_BIRTHDAY);
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Event.CONTENT_ITEM_TYPE);
mockNameValues.put(Event.START_DATE, "1980-08-02");
// Anniversary is not supported by Exchange
mockNameValues.put(Event.TYPE, Event.TYPE_ANNIVERSARY);
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migrateEvent(oldState, newState, kind, 1990);
List<ValuesDelta> list = newState.getMimeEntries(Event.CONTENT_ITEM_TYPE);
assertNotNull(list);
assertEquals(1, list.size()); // Anniversary should be dropped.
ContentValues outputValues = list.get(0).getAfter();
// Default year should be used.
assertEquals("1990-06-01", outputValues.getAsString(Event.START_DATE));
assertEquals(Event.TYPE_BIRTHDAY, outputValues.getAsInteger(Event.TYPE).intValue());
}
public void testMigrateEmailFromGoogleToExchange() {
AccountType oldAccountType = new GoogleAccountType(getContext(), "");
AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
DataKind kind = newAccountType.getKindForMimetype(Email.CONTENT_ITEM_TYPE);
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
mockNameValues.put(Email.TYPE, Email.TYPE_CUSTOM);
mockNameValues.put(Email.LABEL, "custom_type");
mockNameValues.put(Email.ADDRESS, "address1");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
mockNameValues.put(Email.TYPE, Email.TYPE_HOME);
mockNameValues.put(Email.ADDRESS, "address2");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
mockNameValues.put(Email.TYPE, Email.TYPE_WORK);
mockNameValues.put(Email.ADDRESS, "address3");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
// Exchange can have up to 3 email entries. This 4th entry should be dropped.
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
mockNameValues.put(Email.TYPE, Email.TYPE_OTHER);
mockNameValues.put(Email.ADDRESS, "address4");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(Email.CONTENT_ITEM_TYPE);
assertNotNull(list);
assertEquals(3, list.size());
ContentValues outputValues = list.get(0).getAfter();
assertEquals(Email.TYPE_CUSTOM, outputValues.getAsInteger(Email.TYPE).intValue());
assertEquals("custom_type", outputValues.getAsString(Email.LABEL));
assertEquals("address1", outputValues.getAsString(Email.ADDRESS));
outputValues = list.get(1).getAfter();
assertEquals(Email.TYPE_HOME, outputValues.getAsInteger(Email.TYPE).intValue());
assertEquals("address2", outputValues.getAsString(Email.ADDRESS));
outputValues = list.get(2).getAfter();
assertEquals(Email.TYPE_WORK, outputValues.getAsInteger(Email.TYPE).intValue());
assertEquals("address3", outputValues.getAsString(Email.ADDRESS));
}
public void testMigrateImFromGoogleToExchange() {
AccountType oldAccountType = new GoogleAccountType(getContext(), "");
AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
DataKind kind = newAccountType.getKindForMimetype(Im.CONTENT_ITEM_TYPE);
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
// Exchange doesn't support TYPE_HOME
mockNameValues.put(Im.TYPE, Im.TYPE_HOME);
mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_JABBER);
mockNameValues.put(Im.DATA, "im1");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
// Exchange doesn't support TYPE_WORK
mockNameValues.put(Im.TYPE, Im.TYPE_WORK);
mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_YAHOO);
mockNameValues.put(Im.DATA, "im2");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
mockNameValues.put(Im.TYPE, Im.TYPE_OTHER);
mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_CUSTOM);
mockNameValues.put(Im.CUSTOM_PROTOCOL, "custom_protocol");
mockNameValues.put(Im.DATA, "im3");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
// Exchange can have up to 3 IM entries. This 4th entry should be dropped.
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Im.CONTENT_ITEM_TYPE);
mockNameValues.put(Im.TYPE, Im.TYPE_OTHER);
mockNameValues.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
mockNameValues.put(Im.DATA, "im4");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(Im.CONTENT_ITEM_TYPE);
assertNotNull(list);
assertEquals(3, list.size());
assertNotNull(kind.defaultValues.getAsInteger(Im.TYPE));
int defaultType = kind.defaultValues.getAsInteger(Im.TYPE);
ContentValues outputValues = list.get(0).getAfter();
// HOME should become default type.
assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
assertEquals(Im.PROTOCOL_JABBER, outputValues.getAsInteger(Im.PROTOCOL).intValue());
assertEquals("im1", outputValues.getAsString(Im.DATA));
outputValues = list.get(1).getAfter();
assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
assertEquals(Im.PROTOCOL_YAHOO, outputValues.getAsInteger(Im.PROTOCOL).intValue());
assertEquals("im2", outputValues.getAsString(Im.DATA));
outputValues = list.get(2).getAfter();
assertEquals(defaultType, outputValues.getAsInteger(Im.TYPE).intValue());
assertEquals(Im.PROTOCOL_CUSTOM, outputValues.getAsInteger(Im.PROTOCOL).intValue());
assertEquals("custom_protocol", outputValues.getAsString(Im.CUSTOM_PROTOCOL));
assertEquals("im3", outputValues.getAsString(Im.DATA));
}
public void testMigratePhoneFromGoogleToExchange() {
AccountType oldAccountType = new GoogleAccountType(getContext(), "");
AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
DataKind kind = newAccountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
// Create 5 numbers.
// - "1" -- HOME
// - "2" -- WORK
// - "3" -- CUSTOM
// - "4" -- WORK
// - "5" -- WORK_MOBILE
// Then we convert it to Exchange account type.
// - "1" -- HOME
// - "2" -- WORK
// - "3" -- Because CUSTOM is not supported, it'll be changed to the default, MOBILE
// - "4" -- WORK
// - "5" -- WORK_MOBILE not suppoted again, so will be MOBILE.
// But then, Exchange doesn't support multiple MOBILE numbers, so "5" will be removed.
// i.e. the result will be:
// - "1" -- HOME
// - "2" -- WORK
// - "3" -- MOBILE
// - "4" -- WORK
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
mockNameValues.put(Phone.TYPE, Phone.TYPE_HOME);
mockNameValues.put(Phone.NUMBER, "1");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK);
mockNameValues.put(Phone.NUMBER, "2");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
// Exchange doesn't support this type. Default to MOBILE
mockNameValues.put(Phone.TYPE, Phone.TYPE_CUSTOM);
mockNameValues.put(Phone.LABEL, "custom_type");
mockNameValues.put(Phone.NUMBER, "3");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK);
mockNameValues.put(Phone.NUMBER, "4");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
mockNameValues.put(Phone.TYPE, Phone.TYPE_WORK_MOBILE);
mockNameValues.put(Phone.NUMBER, "5");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migrateGenericWithTypeColumn(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
assertNotNull(list);
assertEquals(4, list.size());
int defaultType = Phone.TYPE_MOBILE;
ContentValues outputValues = list.get(0).getAfter();
assertEquals(Phone.TYPE_HOME, outputValues.getAsInteger(Phone.TYPE).intValue());
assertEquals("1", outputValues.getAsString(Phone.NUMBER));
outputValues = list.get(1).getAfter();
assertEquals(Phone.TYPE_WORK, outputValues.getAsInteger(Phone.TYPE).intValue());
assertEquals("2", outputValues.getAsString(Phone.NUMBER));
outputValues = list.get(2).getAfter();
assertEquals(defaultType, outputValues.getAsInteger(Phone.TYPE).intValue());
assertNull(outputValues.getAsInteger(Phone.LABEL));
assertEquals("3", outputValues.getAsString(Phone.NUMBER));
outputValues = list.get(3).getAfter();
assertEquals(Phone.TYPE_WORK, outputValues.getAsInteger(Phone.TYPE).intValue());
assertEquals("4", outputValues.getAsString(Phone.NUMBER));
}
public void testMigrateOrganizationFromGoogleToExchange() {
AccountType oldAccountType = new GoogleAccountType(getContext(), "");
AccountType newAccountType = new ExchangeAccountType(getContext(), "", EXCHANGE_ACCT_TYPE);
DataKind kind = newAccountType.getKindForMimetype(Organization.CONTENT_ITEM_TYPE);
RawContactDelta oldState = new RawContactDelta();
ContentValues mockNameValues = new ContentValues();
mockNameValues.put(Data.MIMETYPE, Organization.CONTENT_ITEM_TYPE);
mockNameValues.put(Organization.COMPANY, "company1");
mockNameValues.put(Organization.DEPARTMENT, "department1");
oldState.addEntry(ValuesDelta.fromAfter(mockNameValues));
RawContactDelta newState = new RawContactDelta();
RawContactModifier.migrateGenericWithoutTypeColumn(oldState, newState, kind);
List<ValuesDelta> list = newState.getMimeEntries(Organization.CONTENT_ITEM_TYPE);
assertNotNull(list);
assertEquals(1, list.size());
ContentValues outputValues = list.get(0).getAfter();
assertEquals("company1", outputValues.getAsString(Organization.COMPANY));
assertEquals("department1", outputValues.getAsString(Organization.DEPARTMENT));
}
}