/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at
* src/com/vodafone360/people/VODAFONE.LICENSE.txt or
* http://github.com/360/360-Engine-for-Android
* See the License for the specific language governing permissions and
* limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each file and
* include the License file at src/com/vodafone360/people/VODAFONE.LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the fields
* enclosed by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2010 Vodafone Sales & Services Ltd. All rights reserved.
* Use is subject to license terms.
*/
package com.vodafone360.people.engine.contactsync;
import com.vodafone360.people.engine.contactsync.NativeContactsApi.Account;
import com.vodafone360.people.utils.LogUtils;
import com.vodafone360.people.utils.VersionUtils;
public class NativeExporter {
/**
* The undefined result when the NativeImporter has not been run yet.
* @see #getResult()
*/
public final static int RESULT_UNDEFINED = -1;
/**
* The ok result when the NativeImporter has finished successfully.
* @see #getResult()
*/
public final static int RESULT_OK = 0;
/**
* The undefined result when the NativeImporter has not been run yet.
* @see #getResult()
*/
public final static int RESULT_ERROR = 1;
/**
* Number of contacts to be processed "per tick".
* @see #tick()
*/
private final static int MAX_CONTACTS_OPERATION_COUNT = 2;
/**
* Handler to the People Contacts API.
*/
private PeopleContactsApi mPeopleContactsApi;
/**
* Handle to the Native Contacts API.
*/
private NativeContactsApi mNativeContactsApi;
/**
* Internal state representing the task to perform: gets the list of local contacts IDs to be synced to Native.
*/
private final static int STATE_GET_CONTACT_IDS = 0;
/**
* Internal state representing the task to perform: iterates through the list of syncable contacts IDs and sync to Native side.
*/
private final static int STATE_ITERATE_THROUGH_IDS = 1;
/**
* Internal state representing the task to perform: final state, nothing else to perform.
*/
private final static int STATE_DONE = 2;
/**
* The current state.
*/
private int mState = STATE_GET_CONTACT_IDS;
/**
* The list of local IDs from people contacts that need to be synced to Native.
*/
private long[] mSyncableContactsIds;
/**
* The index in the current people id.
* @see #mSyncableContactsIds
*/
private int mCurrentSyncableIdIndex = 0;
/**
* The result status.
*/
private int mResult = RESULT_UNDEFINED;
/**
* The total count of IDs to process (Native Database + People Database).
*/
private int mTotalIds = 0;
/**
* The current count of processed IDs.
*/
private int mProcessedIds = 0;
/**
* The Native Account where to write the Contacts.
*/
private Account mAccount = null;
/**
* Constructor.
*
* @param pca handler to the People Contacts API
* @param nca handler to the Native Contacts API
*/
public NativeExporter(PeopleContactsApi pca, NativeContactsApi nca) {
mPeopleContactsApi = pca;
mNativeContactsApi = nca;
if (VersionUtils.is2XPlatform()) {
final Account[] accounts = mNativeContactsApi.getAccountsByType(NativeContactsApi.PEOPLE_ACCOUNT_TYPE);
if (accounts != null) {
mAccount = accounts[0];
}
}
}
/**
* Gets the current position in the list of IDs.
*
* This can be used to track the current progress.
* @see #getCount()
*
* @return the last processed id position in the list of IDs
*/
public int getPosition() {
return mProcessedIds;
}
/**
* Gets the total number of IDs to process.
*
* @return the number of IDs to process
*/
public int getCount() {
return mTotalIds;
}
/**
* Sets the internal state to DONE with the provided result status.
*
* @param result the result status to set
*/
private void complete(int result) {
mState = STATE_DONE;
mResult = result;
}
/**
* Tick method to call each time there is time for processing the Native Contacts Import.
*
* Note: the method will block for some time to process a certain number of Contacts and then will
* return. It will have to be called until it returns true meaning that the Import is over.
*
* @return true when the Import Task is finished, false if not
*/
public boolean tick() {
switch(mState) {
case STATE_GET_CONTACT_IDS:
getContactIds();
break;
case STATE_ITERATE_THROUGH_IDS:
iterateThroughSyncableIds();
break;
}
return mState == STATE_DONE;
}
/**
* Gets the Import result.
*
* @see #RESULT_OK
* @see #RESULT_ERROR
* @see #RESULT_UNDEFINED
*
* @return the Import result
*/
public int getResult() {
return mResult;
}
/**
* Gets the list of local contacts IDs that need to be synced to Native.
*/
private void getContactIds() {
LogUtils.logD("NativeExporter.getIdList()");
mSyncableContactsIds = mPeopleContactsApi.getNativeSyncableContactIds();
// check if we have some work to do
if (mSyncableContactsIds != null) {
mState = STATE_ITERATE_THROUGH_IDS;
} else {
complete(RESULT_OK);
}
}
/**
* Iterates through the list of syncable contacts IDs and sync to Native side.
*/
private void iterateThroughSyncableIds() {
LogUtils.logD("NativeExporter.iterateThroughSyncableIds()");
final int limit = Math.min(mSyncableContactsIds.length, mCurrentSyncableIdIndex + MAX_CONTACTS_OPERATION_COUNT);
while (mCurrentSyncableIdIndex < limit) {
final ContactChange[] changes = mPeopleContactsApi.getNativeSyncableContactChanges(mSyncableContactsIds[mCurrentSyncableIdIndex]);
if (changes != null) {
exportContactChanges(changes);
}
mCurrentSyncableIdIndex++;
}
if (mCurrentSyncableIdIndex == mSyncableContactsIds.length) {
// Nothing else to do
complete(RESULT_OK);
}
}
/**
* Exports the contact changes to the native address book.
*
* @param changes the array of ContactChange that represent a full contact, a deleted contact or an updated contact
*/
private void exportContactChanges(ContactChange[] changes) {
// the ContactChange array that we'll get back from native
ContactChange[] nativeResponse = null;
switch(changes[0].getType()) {
case ContactChange.TYPE_ADD_CONTACT:
// add the contact on Native side
//the account can be null (theoretically)
if (mAccount != null) {
nativeResponse = mNativeContactsApi.addContact(mAccount, changes);
// sync back the native IDs on People side
if (!mPeopleContactsApi.syncBackNewNativeContact(changes, nativeResponse)) {
LogUtils.logE("NativeExporter.exportContactChanges() - Add Contact failed!");
}
}
break;
case ContactChange.TYPE_DELETE_CONTACT:
// delete the contact on Native side
mNativeContactsApi.removeContact(changes[0].getNabContactId());
// acknowledge the people side about deletion
if (!mPeopleContactsApi.syncBackDeletedNativeContact(changes[0])) {
LogUtils.logE("NativeExporter.exportContactChanges() - Syncing back Contact deletion to Client side failed!");
}
break;
case ContactChange.TYPE_UPDATE_CONTACT:
case ContactChange.TYPE_ADD_DETAIL:
case ContactChange.TYPE_DELETE_DETAIL:
case ContactChange.TYPE_UPDATE_DETAIL:
// update the contact on Native side
nativeResponse = mNativeContactsApi.updateContact(changes);
// acknowledge People side about deleted details and added details Native IDs
if (!mPeopleContactsApi.syncBackUpdatedNativeContact(changes, nativeResponse)) {
LogUtils.logE("NativeExporter.exportContactChanges() - Update Contact failed!");
}
break;
default:
LogUtils.logE("NativeExporter.exportContactChanges() - Aborted exporting because of unknown type("+changes[0].getType()+")!");
break;
}
}
}