content: /*
   * 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.tests.engine.contactsync;
  
  import java.lang.reflect.Field;
  import java.util.ArrayList;
  import java.util.List;
  
  import android.app.Instrumentation;
  import android.os.Handler;
  import android.os.Looper;
  import android.os.Message;
  import android.os.MessageQueue;
  import android.test.InstrumentationTestCase;
  import android.test.suitebuilder.annotation.Suppress;
  import android.util.Log;
  
  import com.vodafone360.people.MainApplication;
  import com.vodafone360.people.database.DatabaseHelper;
  import com.vodafone360.people.datatypes.BaseDataType;
  import com.vodafone360.people.datatypes.ContactChanges;
  import com.vodafone360.people.engine.IEngineEventCallback;
  import com.vodafone360.people.engine.EngineManager.EngineId;
  import com.vodafone360.people.engine.contactsync.BaseSyncProcessor;
  import com.vodafone360.people.engine.contactsync.ContactSyncEngine;
  import com.vodafone360.people.engine.contactsync.IContactSyncCallback;
  import com.vodafone360.people.engine.contactsync.ProcessorFactory;
  import com.vodafone360.people.engine.contactsync.ContactSyncEngine.IContactSyncObserver;
  import com.vodafone360.people.engine.contactsync.ContactSyncEngine.Mode;
  import com.vodafone360.people.engine.contactsync.ContactSyncEngine.State;
  import com.vodafone360.people.service.ServiceStatus;
  import com.vodafone360.people.service.ServiceUiRequest;
  import com.vodafone360.people.service.agent.NetworkAgent;
  import com.vodafone360.people.service.agent.NetworkAgent.AgentState;
  import com.vodafone360.people.service.io.ResponseQueue;
  import com.vodafone360.people.service.io.ResponseQueue.DecodedResponse;
  import com.vodafone360.people.tests.engine.EngineTestFramework;
  import com.vodafone360.people.tests.engine.IEngineTestFrameworkObserver;
  
  public class ContactSyncEngineTest extends InstrumentationTestCase {
  
      private static final String LOG_TAG = "ContactSyncEngineTest";
  
      /**
       * The main application handle.
       */
      private MainApplication mApplication;
  
      /**
       * The engine test framework handle.
       */
      private EngineTestFramework mEngineTester;
  
      /**
       * The contact sync engine handle.
       */
      private ContactSyncEngine mContactSyncEngine;
  
      @Override
      protected void setUp() throws Exception {
  
          Log.i(LOG_TAG, "**** setUp() begin ****");
  
          super.setUp();
  
          // delete the database
          getInstrumentation().getTargetContext().deleteDatabase(getDatabaseName());
  
          // create an application instance
          mApplication = (MainApplication)Instrumentation.newApplication(MainApplication.class,
                  getInstrumentation().getTargetContext());
          mApplication.onCreate();
  
          Log.i(LOG_TAG, "**** setUp() end ****");
      }
  
      @Override
      protected void tearDown() throws Exception {
  
          Log.i(LOG_TAG, "**** tearDown() begin ****");
  
          mContactSyncEngine.onDestroy();
          if (mEngineTester != null)
              mEngineTester.stopEventThread();
  
          if (mApplication != null) {
              mApplication.onTerminate();
          }
  
          mApplication = null;
          mEngineTester = null;
          mContactSyncEngine = null;
  
          // always call at the end
          super.tearDown();
  
          Log.i(LOG_TAG, "**** tearDown() end ****");
      }
  
      /**
       * Sets up the test framework.
       * 
       * @param factory the factory used by the ContactSyncEngine
       * @param observer the test framework observer
       */
      private void setUpContactSyncEngineTestFramework(IEngineTestFrameworkObserver observer, 
      		ProcessorFactory factory) {
          mEngineTester = new EngineTestFramework(observer);
          mContactSyncEngine = new ContactSyncEngine(mApplication.getApplicationContext(),
          		mEngineTester, mApplication.getDatabase(), factory);
          mContactSyncEngine.onCreate();
  
          mEngineTester.setEngine(mContactSyncEngine);
      }
  
      /**
       * Sets up the ContactSyncEngine without the test framework.
       * 
       * @param eventCallback the engine event callback
       * @param factory the factory used by the ContactSyncEngine
       */
      private void minimalEngineSetup(IEngineEventCallback eventCallback, ProcessorFactory factory) {
  
          mContactSyncEngine = new ContactSyncEngine(mApplication.getApplicationContext(),
          		eventCallback, mApplication.getDatabase(), factory);
          mContactSyncEngine.onCreate();
      }
  
      /**
       * Checks that life cycle methods do not crash.
       */
      @Suppress
      public void testLifecycle() {
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase();
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          minimalEngineSetup(engineEventCallback, factory);
  
          mContactSyncEngine.onDestroy();
      }
  
      /**
       * Verifies that the first time sync can perform correctly with dummy
       * replies doing no modifications.
       */
      @Suppress
      // Breaks tests.
      public void testFirstTimeSync_dummyReplies() {
  
          Log.i(LOG_TAG, "**** testFirstTimeSync_dummyReplies ****");
  
          final FirstTimeSyncFrameworkHandler handler = new FirstTimeSyncFrameworkHandler();
          setUpContactSyncEngineTestFramework(handler, null);
          handler.setContactSyncEngine(mContactSyncEngine);
  
          NetworkAgent.setAgentState(AgentState.CONNECTED);
  
          mContactSyncEngine.addUiStartFullSync();
          ServiceStatus status = mEngineTester.waitForEvent();
          Log.d(LOG_TAG, "AFTER waitForEvent()");
          assertEquals(ServiceStatus.SUCCESS, status);
      }
  
      /**
       * Verifies that the first time sync triggers a call to the correct
       * processors and in the right order.
       */
      @Suppress
      // Breaks tests.
      public void testFirstTimeSync_dummyProcessors() {
  
          // list of the processors in calling order
          final ArrayList<Integer> processorTypeList = new ArrayList<Integer>();
          // list of expected processors in the right calling order
          final ArrayList<Integer> expectedTypeList = new ArrayList<Integer>();
  
          // set the expected processors
          expectedTypeList.add(new Integer(ProcessorFactory.DOWNLOAD_SERVER_CONTACTS));
          expectedTypeList.add(new Integer(ProcessorFactory.FETCH_NATIVE_CONTACTS));
          expectedTypeList.add(new Integer(ProcessorFactory.SYNC_ME_PROFILE));
          expectedTypeList.add(new Integer(ProcessorFactory.UPLOAD_SERVER_CONTACTS));
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
                  processorTypeList.add(new Integer(type));
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase();
          minimalEngineSetup(engineEventCallback, factory);
  
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          mContactSyncEngine.addUiStartFullSync();
  
          mContactSyncEngine.run();
  
          // check the processors order
          assertTrue(processorTypeList.equals(expectedTypeList));
      }
  
      /**
       * Verifies that events are fired after UI requests.
       */
      @Suppress
      // Breaks tests.
      public void testUiRequestCompleteEvent_fullSync() {
  
          Log.i(LOG_TAG, "**** testUiRequestCompleteEvent_fullSync() begin ****");
  
          final UiEventCall uiEventCall = new UiEventCall();
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase() {
  
              @Override
              public void onUiEvent(ServiceUiRequest event, int request, int status, Object data) {
  
                  Log
                          .i(LOG_TAG, "onUiEvent: " + event + ", " + request + ", " + status + ", "
                                  + data);
  
                  uiEventCall.event = event.ordinal();
                  uiEventCall.request = request;
                  uiEventCall.status = status;
                  uiEventCall.data = data;
              }
  
          };
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          minimalEngineSetup(engineEventCallback, factory);
  
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          long nextRuntime = mContactSyncEngine.getNextRunTime();
          // should be equal to -1 because first time sync has not been yet
          // started
          assertEquals(-1, nextRuntime);
  
          // set the connection to be fine
          NetworkAgent.setAgentState(AgentState.CONNECTED);
  
          // ask for a full sync
          mContactSyncEngine.addUiStartFullSync();
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertEquals(0, nextRuntime);
  
          mContactSyncEngine.run();
  
          // check that first time sync is completed
          assertEquals(ServiceUiRequest.UI_REQUEST_COMPLETE.ordinal(), uiEventCall.event);
          assertEquals(uiEventCall.status, ServiceStatus.SUCCESS.ordinal());
  
          Log.i(LOG_TAG, "**** testUiRequestCompleteEvent_fullSync() end ****");
      }
  
      /**
       * Verifies that server sync completes correctly.
       */
      @Suppress
      // Breaks tests.
      public void testUiRequestCompleteEvent_serverSync() {
  
          Log.i(LOG_TAG, "**** testUiRequestCompleteEvent_serverSync() begin ****");
  
          final UiEventCall uiEventCall = new UiEventCall();
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase() {
  
              @Override
              public void onUiEvent(ServiceUiRequest event, int request, int status, Object data) {
  
                  Log
                          .i(LOG_TAG, "onUiEvent: " + event + ", " + request + ", " + status + ", "
                                  + data);
  
                  uiEventCall.event = event.ordinal();
                  uiEventCall.request = request;
                  uiEventCall.status = status;
                  uiEventCall.data = data;
              }
  
          };
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          minimalEngineSetup(engineEventCallback, factory);
  
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          long nextRuntime = mContactSyncEngine.getNextRunTime();
          // should be equal to -1 because first time sync has not been yet
          // started
          assertEquals(-1, nextRuntime);
  
          // set the connection to be fine
          NetworkAgent.setAgentState(AgentState.CONNECTED);
  
          // ask for a full sync
          mContactSyncEngine.addUiStartFullSync();
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertEquals(0, nextRuntime);
  
          mContactSyncEngine.run();
  
          // check that first time sync is completed
          assertEquals(ServiceUiRequest.UI_REQUEST_COMPLETE.ordinal(), uiEventCall.event);
          assertEquals(uiEventCall.status, ServiceStatus.SUCCESS.ordinal());
  
          // check that first time sync is completed
          assertEquals(ServiceUiRequest.UI_REQUEST_COMPLETE.ordinal(), uiEventCall.event);
          assertEquals(uiEventCall.status, ServiceStatus.SUCCESS.ordinal());
  
          Log.i(LOG_TAG, "**** testUiRequestCompleteEvent_serverSync() end ****");
      }
  
      /**
       * Checks that the engine events are correctly sent to listeners.
       */
      @Suppress
      // Breaks tests.
      public void testEventCallback() {
  
          Log.i(LOG_TAG, "**** testEventCallback() begin ****");
  
          // Set up the expected events
          final ArrayList<ContactSyncObserver.ContactSyncStateChanged> expectedCssc = new ArrayList<ContactSyncObserver.ContactSyncStateChanged>();
          final ArrayList<ContactSyncObserver.ProgressEvent> expectedPe = new ArrayList<ContactSyncObserver.ProgressEvent>();
          final ArrayList<ContactSyncObserver.SyncComplete> expectedSc = new ArrayList<ContactSyncObserver.SyncComplete>();
  
          setupExpectedFirstTimeSyncObserverCalls(expectedCssc, expectedPe, expectedSc);
  
          final UiEventCall uiEventCall = new UiEventCall();
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase() {
  
              @Override
              public void onUiEvent(ServiceUiRequest event, int request, int status, Object data) {
  
                  Log
                          .i(LOG_TAG, "onUiEvent: " + event + ", " + request + ", " + status + ", "
                                  + data);
  
                  uiEventCall.event = event.ordinal();
                  uiEventCall.request = request;
                  uiEventCall.status = status;
                  uiEventCall.data = data;
              }
  
          };
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          final ContactSyncObserver observer = new ContactSyncObserver();
  
          minimalEngineSetup(engineEventCallback, factory);
  
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          // add a listener
          mContactSyncEngine.addEventCallback(observer);
  
          // ask for a full sync
          mContactSyncEngine.addUiStartFullSync();
  
          // perform the sync
          mContactSyncEngine.run();
  
          // compare the retrieved events with the expected ones
          assertTrue(expectedCssc.equals(observer.mCsscList));
          assertTrue(expectedPe.equals(observer.mPeList));
          assertTrue(expectedSc.equals(observer.mScList));
  
          Log.i(LOG_TAG, "**** testEventCallback() end ****");
      }
  
      /**
       * Checks the the method isFirstTimeSyncComplete() returns the correct
       * values.
       */
      @Suppress
      // Breaks tests.
      public void testIsFirstTimeSyncComplete() {
          Log.i(LOG_TAG, "**** testIsFirstTimeSyncComplete() begin ****");
  
          final UiEventCall uiEventCall = new UiEventCall();
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase() {
  
              @Override
              public void onUiEvent(ServiceUiRequest event, int request, int status, Object data) {
  
                  Log
                          .i(LOG_TAG, "onUiEvent: " + event + ", " + request + ", " + status + ", "
                                  + data);
  
                  uiEventCall.event = event.ordinal();
                  uiEventCall.request = request;
                  uiEventCall.status = status;
                  uiEventCall.data = data;
              }
  
          };
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          minimalEngineSetup(engineEventCallback, factory);
  
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          long nextRuntime = mContactSyncEngine.getNextRunTime();
          // should be equal to -1 because first time sync has not been yet
          // started
          assertEquals(-1, nextRuntime);
  
          // set the connection to be fine
          NetworkAgent.setAgentState(AgentState.CONNECTED);
  
          // first time sync has not been done yet
          assertEquals(false, mContactSyncEngine.isFirstTimeSyncComplete());
  
          // ask for a full sync
          mContactSyncEngine.addUiStartFullSync();
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertEquals(0, nextRuntime);
  
          // first time sync has still not been done yet
          assertEquals(false, mContactSyncEngine.isFirstTimeSyncComplete());
  
          mContactSyncEngine.run();
  
          // check that first time sync is completed
          assertEquals(ServiceUiRequest.UI_REQUEST_COMPLETE.ordinal(), uiEventCall.event);
          assertEquals(uiEventCall.status, ServiceStatus.SUCCESS.ordinal());
  
          // first time sync has been done
          assertEquals(true, mContactSyncEngine.isFirstTimeSyncComplete());
  
          Log.i(LOG_TAG, "**** testIsFirstTimeSyncComplete() end ****");
      }
  
      /**
       * Checks that nothing is scheduled before the first time sync has been
       * completed.
       */
      @Suppress
      public void testAutoSyncTimer() {
  
          Log.i(LOG_TAG, "**** testAutoSyncTimer() begin ****");
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase() {
  
              @Override
              public void onUiEvent(ServiceUiRequest event, int request, int status, Object data) {
  
                  Log
                          .i(LOG_TAG, "onUiEvent: " + event + ", " + request + ", " + status + ", "
                                  + data);
              }
  
          };
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          minimalEngineSetup(engineEventCallback, factory);
  
          // set the connection to be fine
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          // should be equal to -1 because first time sync has not been yet
          // started
          assertEquals(-1, mContactSyncEngine.getNextRunTime());
  
          mContactSyncEngine.run();
  
          assertEquals(-1, mContactSyncEngine.getNextRunTime());
  
          mContactSyncEngine.run();
  
          assertEquals(-1, mContactSyncEngine.getNextRunTime());
  
          Log.i(LOG_TAG, "**** testAutoSyncTimer() end ****");
      }
  
      /**
       * Checks that background sync is performed after the first time sync.
       */
      @Suppress
      // Breaks tests.
      public void testBackgroundSync() {
  
          Log.i(LOG_TAG, "**** testBackgroundSync() begin ****");
  
          final ArrayList<ProcessorLog> processorLogs = new ArrayList<ProcessorLog>();
          final UiEventCall uiEventCall = new UiEventCall();
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase() {
  
              @Override
              public void onUiEvent(ServiceUiRequest event, int request, int status, Object data) {
  
                  Log
                          .i(LOG_TAG, "onUiEvent: " + event + ", " + request + ", " + status + ", "
                                  + data);
  
                  uiEventCall.event = event.ordinal();
                  uiEventCall.request = request;
                  uiEventCall.status = status;
                  uiEventCall.data = data;
              }
  
          };
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
                  ProcessorLog log = new ProcessorLog();
                  log.type = type;
                  log.time = System.currentTimeMillis();
  
                  processorLogs.add(log);
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          minimalEngineSetup(engineEventCallback, factory);
  
          // set the connection to be fine
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          long nextRuntime = mContactSyncEngine.getNextRunTime();
          // should be equal to -1 because first time sync has not been yet
          // started
          assertEquals(-1, mContactSyncEngine.getNextRunTime());
  
          // force a first time sync
          mContactSyncEngine.addUiStartFullSync();
  
          nextRuntime = mContactSyncEngine.getNextRunTime();
          // next runtime should be now
          assertEquals(0, nextRuntime);
  
          // perform the first time sync
          mContactSyncEngine.run();
  
          // check that first time sync is completed
          assertEquals(ServiceUiRequest.UI_REQUEST_COMPLETE.ordinal(), uiEventCall.event);
          assertEquals(uiEventCall.status, ServiceStatus.SUCCESS.ordinal());
  
          // check that a thumbnail sync is scheduled for now
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertEquals(0, nextRuntime);
  
          // reset the processor logs
          processorLogs.clear();
  
          // get the thumbnail sync to be run
          mContactSyncEngine.run();
  
          // check processor calls
          ProcessorLog log;
          assertEquals(2, processorLogs.size());
          log = processorLogs.get(0);
          assertEquals(ProcessorFactory.DOWNLOAD_SERVER_THUMBNAILS, log.type);
          log = processorLogs.get(1);
          assertEquals(ProcessorFactory.UPLOAD_SERVER_THUMBNAILS, log.type);
  
          // check that native sync is scheduled for now
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertEquals(0, nextRuntime);
  
          // reset the processor logs
          processorLogs.clear();
  
          // get the native sync to be run
          mContactSyncEngine.run();
  
          // check processor calls
          assertEquals(1, processorLogs.size());
          log = processorLogs.get(0);
          assertEquals(ProcessorFactory.UPDATE_NATIVE_CONTACTS, log.type);
  
          // check that nothing else is scheduled
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertEquals(-1, nextRuntime);
  
          /*
           * long startingTime = System.currentTimeMillis(); long duration =
           * 60000; long currentTime, timeToWait; while( (currentTime =
           * System.currentTimeMillis()) < (startingTime + duration) ) {
           * nextRuntime = mContactSyncEngine.getNextRunTime(); timeToWait =
           * nextRuntime > currentTime ? (nextRuntime-currentTime) : 0;
           * Log.e(LOG_TAG,
           * "testBackgroundSyncAfterFirstTimeSync(), timeToWait ="+timeToWait);
           * if (timeToWait > 0) { try { synchronized (this) { wait(timeToWait); }
           * } catch(Exception e) { Log.e(LOG_TAG,
           * "testBackgroundSyncAfterFirstTimeSync(), error while waiting: "+e); }
           * } Log.e(LOG_TAG,
           * "testBackgroundSyncAfterFirstTimeSync(), calling run()");
           * mContactSyncEngine.run(); }
           */
  
          Log.i(LOG_TAG, "**** testBackgroundSync() end ****");
      }
  
      /**
       * Checks different sync request that come from: -first time sync -fake
       * database change event -full sync -server sync
       */
      @Suppress
      // Breaks tests.
      public void testAllSyncs() {
  
          Log.i(LOG_TAG, "**** testAllSyncs() begin ****");
  
          final ArrayList<ProcessorLog> processorLogs = new ArrayList<ProcessorLog>();
          final UiEventCall uiEventCall = new UiEventCall();
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase() {
  
              @Override
              public void onUiEvent(ServiceUiRequest event, int request, int status, Object data) {
  
                  Log
                          .i(LOG_TAG, "onUiEvent: " + event + ", " + request + ", " + status + ", "
                                  + data);
  
                  uiEventCall.event = event.ordinal();
                  uiEventCall.request = request;
                  uiEventCall.status = status;
                  uiEventCall.data = data;
              }
  
          };
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
                  ProcessorLog log = new ProcessorLog();
                  log.type = type;
                  log.time = System.currentTimeMillis();
  
                  processorLogs.add(log);
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          minimalEngineSetup(engineEventCallback, factory);
  
          // set the connection to be fine
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          long nextRuntime = mContactSyncEngine.getNextRunTime();
          // should be equal to -1 because first time sync has not been yet
          // started
          assertEquals(-1, mContactSyncEngine.getNextRunTime());
  
          // force a first time sync
          mContactSyncEngine.addUiStartFullSync();
  
          nextRuntime = mContactSyncEngine.getNextRunTime();
          // next runtime should be now
          assertEquals(0, nextRuntime);
  
          // perform the first time sync
          mContactSyncEngine.run();
  
          // check that first time sync is completed
          assertEquals(ServiceUiRequest.UI_REQUEST_COMPLETE.ordinal(), uiEventCall.event);
          assertEquals(uiEventCall.status, ServiceStatus.SUCCESS.ordinal());
  
          // check that a thumbnail sync is scheduled for now
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertEquals(0, nextRuntime);
  
          // reset the processor logs
          processorLogs.clear();
  
          // get the thumbnail sync to be run
          mContactSyncEngine.run();
  
          // check processor calls
          ProcessorLog log;
          assertEquals(2, processorLogs.size());
          log = processorLogs.get(0);
          assertEquals(ProcessorFactory.DOWNLOAD_SERVER_THUMBNAILS, log.type);
          log = processorLogs.get(1);
          assertEquals(ProcessorFactory.UPLOAD_SERVER_THUMBNAILS, log.type);
  
          // check that native sync is scheduled for now
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertEquals(0, nextRuntime);
  
          // reset the processor logs
          processorLogs.clear();
  
          // get the native sync to be run
          mContactSyncEngine.run();
  
          // check processor calls
          assertEquals(1, processorLogs.size());
          log = processorLogs.get(0);
          assertEquals(ProcessorFactory.UPDATE_NATIVE_CONTACTS, log.type);
  
          // reset the processor logs
          processorLogs.clear();
  
          // request a full sync
          mContactSyncEngine.addUiStartFullSync();
  
          nextRuntime = mContactSyncEngine.getNextRunTime();
          // next runtime should be now
          assertEquals(0, nextRuntime);
  
          // perform the full sync
          mContactSyncEngine.run();
  
          // check that first time sync is completed
          assertEquals(ServiceUiRequest.UI_REQUEST_COMPLETE.ordinal(), uiEventCall.event);
          assertEquals(uiEventCall.status, ServiceStatus.SUCCESS.ordinal());
  
          // get the thumbnail sync to be run
          mContactSyncEngine.run();
  
          // get the native sync to be run
          mContactSyncEngine.run();
  
          // get the thumbnail sync to be run
          mContactSyncEngine.run();
  
          // check nothing to be done
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertEquals(-1, nextRuntime);
  
          // fake a database change notification
          Handler handler = getContactSyncEngineHandler(mContactSyncEngine);
  
          Message msg = new Message();
          msg.what = ServiceUiRequest.DATABASE_CHANGED_EVENT.ordinal();
          msg.arg1 = DatabaseHelper.DatabaseChangeType.CONTACTS.ordinal();
          msg.arg2 = 0;
          handler.sendMessage(msg);
  
          final Looper looper = Looper.myLooper();
          final MessageQueue queue = Looper.myQueue();
          queue.addIdleHandler(new MessageQueue.IdleHandler() {
  
              @Override
              public boolean queueIdle() {
                  // message has been processed and the looper is now in idle
                  // state
                  // quit the loop() otherwise we would not be able to carry on
                  looper.quit();
  
                  return false;
              }
  
          });
  
          // get the message processed by the thread event loop
          Looper.loop();
  
          // check sync is scheduled within 30 seconds
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertTrue(isValueInsideErrorMargin(30000, nextRuntime - System.currentTimeMillis(), 5));
          final long timeBeforeWait = System.currentTimeMillis();
  
          // reset the processor logs
          processorLogs.clear();
  
          // call run() and check that nothing is performed
          mContactSyncEngine.run();
          assertEquals(0, processorLogs.size());
  
          // wait until we get the nextRuntime to now
          boolean isNextRuntimeNow = false;
          while (!isNextRuntimeNow) {
              try {
                  long timeToWait = mContactSyncEngine.getNextRunTime();
                  timeToWait = (timeToWait <= 0) ? 0 : timeToWait - System.currentTimeMillis();
                  if (timeToWait > 0) {
                      synchronized (this) {
                          Log.i(LOG_TAG, "timeToWait=" + timeToWait);
                          wait(timeToWait);
                      }
                  }
                  if (mContactSyncEngine.getNextRunTime() < System.currentTimeMillis()) {
                      isNextRuntimeNow = true;
                  }
              } catch (Exception e) {
                  Log.e(LOG_TAG, "testAllSyncs(): error while waiting for the runtime now");
              }
          }
  
          long timeAfterWait = System.currentTimeMillis();
  
          // check that we have waited about 30 seconds
          assertTrue(isValueInsideErrorMargin(timeAfterWait - timeBeforeWait, 30000, 5));
  
          // call run() until the sync is performed
          final long startTime = System.currentTimeMillis();
  
          while (processorLogs.size() < 7) {
  
              if (System.currentTimeMillis() - startTime > TEST_TIMEOUT) {
                  fail("It seems that the engine is stuck, the processor logs should contain 7 objects by now!");
              }
  
              mContactSyncEngine.run();
          }
  
          // check processor calls
          assertEquals(6, processorLogs.size());
          log = processorLogs.get(0);
          assertEquals(ProcessorFactory.DOWNLOAD_SERVER_CONTACTS, log.type);
          log = processorLogs.get(1);
          assertEquals(ProcessorFactory.UPLOAD_SERVER_CONTACTS, log.type);
          log = processorLogs.get(2);
          assertEquals(ProcessorFactory.DOWNLOAD_SERVER_THUMBNAILS, log.type);
          log = processorLogs.get(3);
          assertEquals(ProcessorFactory.UPLOAD_SERVER_THUMBNAILS, log.type);
          log = processorLogs.get(4);
          assertEquals(ProcessorFactory.SYNC_ME_PROFILE, log.type);
          log = processorLogs.get(5);
          assertEquals(ProcessorFactory.UPDATE_NATIVE_CONTACTS, log.type);
  
          Log.i(LOG_TAG, "**** testAllSyncs() end ****");
      }
  
      /**
       * Tests that the native sync is scheduled and performed after a first time
       * sync then a re-instantiation of the ContactSyncEngine.
       */
      @Suppress
      // Breaks tests.
      public void testNativeSync_newEngineInstantiation() {
  
          Log.i(LOG_TAG, "**** testNativeSync_newEngineInstantiation() begin ****");
  
          final ArrayList<ProcessorLog> processorLogs = new ArrayList<ProcessorLog>();
          final UiEventCall uiEventCall = new UiEventCall();
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase() {
  
              @Override
              public void onUiEvent(ServiceUiRequest event, int request, int status, Object data) {
  
                  Log
                          .i(LOG_TAG, "onUiEvent: " + event + ", " + request + ", " + status + ", "
                                  + data);
  
                  uiEventCall.event = event.ordinal();
                  uiEventCall.request = request;
                  uiEventCall.status = status;
                  uiEventCall.data = data;
              }
  
          };
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
                  ProcessorLog log = new ProcessorLog();
                  log.type = type;
                  log.time = System.currentTimeMillis();
  
                  processorLogs.add(log);
  
                  return new DummySyncProcessor(mContactSyncEngine, null);
              }
          };
  
          minimalEngineSetup(engineEventCallback, factory);
  
          // set the connection to be fine
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          long nextRuntime = mContactSyncEngine.getNextRunTime();
          // should be equal to -1 because first time sync has not been yet
          // started
          assertEquals(-1, mContactSyncEngine.getNextRunTime());
  
          // force a first time sync
          mContactSyncEngine.addUiStartFullSync();
  
          nextRuntime = mContactSyncEngine.getNextRunTime();
          // next runtime should be now
          assertEquals(0, nextRuntime);
  
          // perform the first time sync
          mContactSyncEngine.run();
  
          // check that first time sync is completed
          assertEquals(ServiceUiRequest.UI_REQUEST_COMPLETE.ordinal(), uiEventCall.event);
          assertEquals(uiEventCall.status, ServiceStatus.SUCCESS.ordinal());
  
          // destroy the engine
          mContactSyncEngine.onDestroy();
          mContactSyncEngine = null;
  
          // create a new ContactSyncEngine
          minimalEngineSetup(engineEventCallback, factory);
  
          processorLogs.clear();
  
          // check sync is scheduled within 30 seconds
          nextRuntime = mContactSyncEngine.getNextRunTime();
          assertTrue(isValueInsideErrorMargin(30000, nextRuntime - System.currentTimeMillis(), 5));
  
          final long timeBeforeWait = System.currentTimeMillis();
  
          // call run() and check that nothing is performed
          mContactSyncEngine.run();
          assertEquals(0, processorLogs.size());
  
          // wait until we get the nextRuntime to now
          boolean isNextRuntimeNow = false;
          while (!isNextRuntimeNow) {
              try {
                  long timeToWait = mContactSyncEngine.getNextRunTime();
                  timeToWait = (timeToWait <= 0) ? 0 : timeToWait - System.currentTimeMillis();
                  if (timeToWait > 0) {
                      synchronized (this) {
                          Log.i(LOG_TAG, "timeToWait=" + timeToWait);
                          wait(timeToWait);
                      }
                  }
                  if (mContactSyncEngine.getNextRunTime() < System.currentTimeMillis()) {
                      isNextRuntimeNow = true;
                  }
              } catch (Exception e) {
                  Log
                          .e(LOG_TAG,
                                  "testAllSyncsAfterFirstTimeSync(): error while waiting for the runtime now");
              }
          }
  
          long timeAfterWait = System.currentTimeMillis();
  
          // check that we have waited about 30 seconds
          assertTrue(isValueInsideErrorMargin(timeAfterWait - timeBeforeWait, 30000, 5));
  
          // call run() until the sync is performed
          final long startTime = System.currentTimeMillis();
  
          while (processorLogs.size() < 3) {
  
              if (System.currentTimeMillis() - startTime > TEST_TIMEOUT) {
                  fail("It seems that the engine is stuck, the processor logs should contain 3 objects by now!");
              }
  
              mContactSyncEngine.run();
          }
  
          // check processor calls
          ProcessorLog log;
          assertEquals(3, processorLogs.size());
          log = processorLogs.get(0);
          assertEquals(ProcessorFactory.FETCH_NATIVE_CONTACTS, log.type);
          log = processorLogs.get(1);
          assertEquals(ProcessorFactory.UPLOAD_SERVER_CONTACTS, log.type);
          log = processorLogs.get(2);
          assertEquals(ProcessorFactory.UPDATE_NATIVE_CONTACTS, log.type);
  
          Log.i(LOG_TAG, "**** testNativeSync_newEngineInstantiation() end ****");
      }
  
      /**
       * Tests the sync is cancelled in case we remove user data.
       */
      @Suppress
      // Breaks tests.
      public void testCancelSync() {
  
          Log.i(LOG_TAG, "**** testNativeSync_newEngineInstantiation() begin ****");
  
          final ArrayList<ProcessorLog> processorLogs = new ArrayList<ProcessorLog>();
          final UiEventCall uiEventCall = new UiEventCall();
          final ProcessorLog processorLog = new ProcessorLog();
  
          final IEngineEventCallback engineEventCallback = new HelperClasses.EngineCallbackBase() {
  
              @Override
              public void onUiEvent(ServiceUiRequest event, int request, int status, Object data) {
  
                  Log
                          .i(LOG_TAG, "onUiEvent: " + event + ", " + request + ", " + status + ", "
                                  + data);
  
                  uiEventCall.event = event.ordinal();
                  uiEventCall.request = request;
                  uiEventCall.status = status;
                  uiEventCall.data = data;
              }
  
          };
  
          final ProcessorFactory factory = new ProcessorFactory() {
  
              @Override
              public BaseSyncProcessor create(int type, IContactSyncCallback callback,
                      DatabaseHelper dbHelper) {
  
                  Log.i(LOG_TAG, "create(), type=" + type);
                  ProcessorLog log = new ProcessorLog();
                  log.type = type;
                  log.time = System.currentTimeMillis();
  
                  processorLogs.add(log);
  
                  return new BaseSyncProcessor(mContactSyncEngine, null) {
  
                      @Override
                      protected void doCancel() {
                          // cancel the job
                          processorLog.type = 1;
                      }
  
                      @Override
                      protected void doStart() {
                          // set a "timeout" to be called back immediately
                          setTimeout(0);
                          processorLog.type = 2;
                      }
  
                      @Override
                      public void onTimeoutEvent() {
                          // set the job as completed
                          Log.i(LOG_TAG, "onTimeoutEvent()");
                          complete(ServiceStatus.SUCCESS);
                          processorLog.type = 3;
                      }
  
                      @Override
                      public void processCommsResponse(DecodedResponse resp) {
                          // we don't need this case in this test
                          processorLog.type = 4;
                      }
                  };
              }
          };
  
          minimalEngineSetup(engineEventCallback, factory);
  
          // set the connection to be fine
          NetworkAgent.setAgentState(NetworkAgent.AgentState.CONNECTED);
  
          long nextRuntime = mContactSyncEngine.getNextRunTime();
          // should be equal to -1 because first time sync has not been yet
          // started
          assertEquals(-1, nextRuntime);
  
          // force a first time sync
          mContactSyncEngine.addUiStartFullSync();
  
          processorLog.type = 0;
  
          // start performing the sync
          mContactSyncEngine.run();
  
          // the first processor should have started
          assertTrue(processorLog.type == 2);
  
          // this will cancel any sync
          mContactSyncEngine.onReset();
  
          // get the engine to perform a cancel on the current processor
          mContactSyncEngine.run();
  
          assertTrue(processorLog.type == 1);
  
          // check that the engine cancelled the sync
          assertEquals(ServiceUiRequest.UI_REQUEST_COMPLETE.ordinal(), uiEventCall.event);
          assertEquals(uiEventCall.status, ServiceStatus.USER_CANCELLED.ordinal());
      }
  
      // //////////////////////////////
      // HELPER METHODS AND CLASSES //
      // //////////////////////////////
  
      /**
       * Timeout value used during loops that may freeze.
       */
      private final static long TEST_TIMEOUT = 10000;
  
      /**
       * Tells whether or not a value is contained within an acceptable error
       * margin.
       * 
       * @return true if below the error margin, false if not
       */
      private boolean isValueInsideErrorMargin(long expected, long measured, int errorMargin) {
  
          long margin = expected * errorMargin / 100;
          return (Math.abs(expected - measured) < margin);
      }
  
      /**
       * Gets the database name via reflection feature.
       * 
       * @return the database name
       */
      private String getDatabaseName() {
  
          try {
              Field dbName = DatabaseHelper.class.getDeclaredField("DATABASE_NAME");
              dbName.setAccessible(true);
              return (String)dbName.get(null);
          } catch (Exception e) {
              Log.e(LOG_TAG, "getDatabaseName(), error retrieving the database name... => " + e);
          }
  
          return null;
      }
  
      /**
       * Gets the Handler used by the ContactSyncEngine via reflection feature.
       * 
       * @param engine the ContactSyncEngine
       * @return the ContactSyncEngine Handler
       */
      private Handler getContactSyncEngineHandler(ContactSyncEngine engine) {
  
          try {
              Field handlerField = ContactSyncEngine.class.getDeclaredField("mDbChangeHandler");
              handlerField.setAccessible(true);
              Handler handler = (Handler)handlerField.get(engine);
              return handler;
          } catch (Exception e) {
              Log.e(LOG_TAG, "getDatabaseName(), error retrieving the database name... => " + e);
          }
          return null;
      }
  
      /**
       * Base class for tests using the test framework.
       */
      private static class ContactSyncFrameworkBase implements IEngineTestFrameworkObserver {
  
          protected ContactSyncEngine.State mState = ContactSyncEngine.State.IDLE;
  
          protected ContactSyncEngine mEngine;
  
          public void setContactSyncEngine(ContactSyncEngine engine) {
              mEngine = engine;
          }
  
          @Override
          public void onEngineException(Exception exp) {
  
          }
  
          @Override
          public void reportBackToEngine(int reqId, EngineId engine) {
  
          }
      }
  
      /**
       * Handles all the needed responses depending on the engine state.
       */
      private static class FirstTimeSyncFrameworkHandler extends ContactSyncFrameworkBase {
  
          public FirstTimeSyncFrameworkHandler() {
              mState = ContactSyncEngine.State.FETCHING_SERVER_CONTACTS;
          }
  
          @Override
          synchronized public void reportBackToEngine(int reqId, EngineId engine) {
              Log.d("TAG", "reportBackToEngine(), reqId=" + reqId + ", engine=" + engine);
              ResponseQueue respQueue = ResponseQueue.getInstance();
              List<BaseDataType> data = new ArrayList<BaseDataType>();
  
              switch (mState) {
                  case FETCHING_SERVER_CONTACTS:
                      Log.d(LOG_TAG, "reportBackToEngine(): state=FETCHING_SERVER_CONTACTS");
                      // Set the next expected state
                      mState = ContactSyncEngine.State.FETCHING_NATIVE_CONTACTS;
                      // Give it an empty server contacts list
                      ContactChanges contactChanges = new ContactChanges();
                      contactChanges.mNumberOfPages = 0;
                      contactChanges.mVersionAnchor = 0;
                      data.add(contactChanges);
                      respQueue.addToResponseQueue(new DecodedResponse(reqId, data, engine, DecodedResponse.ResponseType.GET_CONTACTCHANGES_RESPONSE.ordinal()));
                      mEngine.onCommsInMessage();
                      break;
                  case FETCHING_NATIVE_CONTACTS:
                      Log.d(LOG_TAG, "reportBackToEngine(): state=FETCHING_NATIVE_CONTACTS");
                      // Set the next expected state
                      mState = ContactSyncEngine.State.UPDATING_SERVER_CONTACTS;
                      break;
                  case UPDATING_SERVER_CONTACTS:
                      ContactChanges serverContactChanges = new ContactChanges();
                      serverContactChanges.mNumberOfPages = 0;
                      serverContactChanges.mVersionAnchor = 0;
                      data.add(serverContactChanges);
                      respQueue.addToResponseQueue(new DecodedResponse(reqId, data, engine, DecodedResponse.ResponseType.BULKUPDATE_CONTACTS_RESPONSE.ordinal()));
                      mEngine.onCommsInMessage();
                      Log.d(LOG_TAG, "reportBackToEngine(): state=UPDATING_SERVER_CONTACTS");
                      break;
                  case IDLE:
                      Log.d(LOG_TAG, "reportBackToEngine(): state=IDLE");
                      /*
                       * StatusMsg msg = new StatusMsg(); msg.mStatus = true;
                       * msg.mCode = "ok"; data.add(msg);
                       * respQueue.addToResponseQueue(reqId, data, engine);
                       * mEngine.onCommsInMessage();
                       */
                      break;
                  default:
                      Log.d(LOG_TAG, "reportBackToEngine(): state=default");
              }
          }
      }
  
      /**
       * Dummy implementation of a Processor used by the ContactSyncEngine.
       */
      private static class DummySyncProcessor extends BaseSyncProcessor {
  
          protected DummySyncProcessor(IContactSyncCallback callback, DatabaseHelper db) {
              super(callback, db);
  
          }
  
          @Override
          protected void doCancel() {
  
              Log.d(LOG_TAG, "doCancel");
          }
  
          @Override
          protected void doStart() {
  
              Log.d(LOG_TAG, "doStart");
              complete(ServiceStatus.SUCCESS);
          }
  
          @Override
          public void processCommsResponse(DecodedResponse resp) {
  
              Log.d(LOG_TAG, "processCommsResponse");
              complete(ServiceStatus.SUCCESS);
          }
      }
  
      /**
       * Class used to log the calls to the different methods of
       * IContactSyncObserver.
       */
      private static class ContactSyncObserver implements IContactSyncObserver {
  
          public static class ContactSyncStateChanged {
              Mode mode;
  
              State oldState;
  
              State newState;
  
              @Override
              public boolean equals(Object o) {
  
                  if (o == null || !(o instanceof ContactSyncStateChanged))
                      return false;
  
                  final ContactSyncStateChanged oContactSyncStateChanged = (ContactSyncStateChanged)o;
                  return (oContactSyncStateChanged.mode == mode)
                          && (oContactSyncStateChanged.oldState == oldState)
                          && (oContactSyncStateChanged.newState == newState);
              }
          }
  
          public static class ProgressEvent {
              State currentState;
  
              int percent;
  
              @Override
              public boolean equals(Object o) {
  
                  if (o == null || !(o instanceof ProgressEvent))
                      return false;
  
                  final ProgressEvent oProgressEvent = (ProgressEvent)o;
                  return (oProgressEvent.currentState == currentState)
                          && (oProgressEvent.percent == percent);
              }
          }
  
          public static class SyncComplete {
              ServiceStatus status;
  
              @Override
              public boolean equals(Object o) {
  
                  if (o == null || !(o instanceof SyncComplete))
                      return false;
  
                  final SyncComplete oSyncComplete = (SyncComplete)o;
                  return oSyncComplete.status == status;
              }
          }
  
          public ArrayList<ContactSyncStateChanged> mCsscList = new ArrayList<ContactSyncStateChanged>();
  
          public ArrayList<ProgressEvent> mPeList = new ArrayList<ProgressEvent>();
  
          public ArrayList<SyncComplete> mScList = new ArrayList<SyncComplete>();
  
          /**
           * Resets all the logs.
           */
          public void reset() {
              mCsscList.clear();
              mPeList.clear();
              mScList.clear();
          }
  
          @Override
          public void onContactSyncStateChange(Mode mode, State oldState, State newState) {
              Log.d(LOG_TAG, "onContactSyncStateChange(" + mode + ", " + oldState + ", " + newState
                      + ")");
  
              ContactSyncStateChanged cssc = new ContactSyncStateChanged();
              cssc.mode = mode;
              cssc.oldState = oldState;
              cssc.newState = newState;
  
              mCsscList.add(cssc);
          }
  
          @Override
          public void onProgressEvent(State currentState, int percent) {
              Log.d(LOG_TAG, "onProgressEvent(" + currentState + ", " + percent + ")");
  
              ProgressEvent pe = new ProgressEvent();
              pe.currentState = currentState;
              pe.percent = percent;
  
              mPeList.add(pe);
          }
  
          @Override
          public void onSyncComplete(ServiceStatus status) {
              Log.d(LOG_TAG, "onSyncComplete(" + status + ")");
  
              SyncComplete sc = new SyncComplete();
              sc.status = status;
  
              mScList.add(sc);
          }
      }
  
      /**
       * Sets the expected calls during a first time sync to the provided lists.
       * 
       * @param cssc the list of expected calls to onContactSyncStateChanged
       * @param pe the list of expected calls to onProgressEvent
       * @param sc the list of expected calls to onSyncComplete
       */
      private void setupExpectedFirstTimeSyncObserverCalls(
              ArrayList<ContactSyncObserver.ContactSyncStateChanged> csscList,
              ArrayList<ContactSyncObserver.ProgressEvent> peList,
              ArrayList<ContactSyncObserver.SyncComplete> scList) {
  
          // setting up expected ContactSyncStateChanged
          ContactSyncObserver.ContactSyncStateChanged cssc = new ContactSyncObserver.ContactSyncStateChanged();
          cssc.mode = Mode.FULL_SYNC_FIRST_TIME;
          cssc.oldState = State.IDLE;
          cssc.newState = State.FETCHING_SERVER_CONTACTS;
          csscList.add(cssc);
  
          cssc = new ContactSyncObserver.ContactSyncStateChanged();
          cssc.mode = Mode.FULL_SYNC_FIRST_TIME;
          cssc.oldState = State.FETCHING_SERVER_CONTACTS;
          cssc.newState = State.FETCHING_NATIVE_CONTACTS;
          csscList.add(cssc);
  
          cssc = new ContactSyncObserver.ContactSyncStateChanged();
          cssc.mode = Mode.FULL_SYNC_FIRST_TIME;
          cssc.oldState = State.FETCHING_NATIVE_CONTACTS;
          cssc.newState = State.UPDATING_SERVER_CONTACTS;
          csscList.add(cssc);
  
          cssc = new ContactSyncObserver.ContactSyncStateChanged();
          cssc.mode = Mode.FULL_SYNC_FIRST_TIME;
          cssc.oldState = State.UPDATING_SERVER_CONTACTS;
          cssc.newState = State.IDLE;
          csscList.add(cssc);
  
          // setting up expected ProgressEvent
          ContactSyncObserver.ProgressEvent pe = new ContactSyncObserver.ProgressEvent();
          pe = new ContactSyncObserver.ProgressEvent();
          pe.currentState = State.FETCHING_SERVER_CONTACTS;
          pe.percent = 0;
          peList.add(pe);
  
          pe = new ContactSyncObserver.ProgressEvent();
          pe.currentState = State.FETCHING_SERVER_CONTACTS;
          pe.percent = 100;
          peList.add(pe);
  
          pe = new ContactSyncObserver.ProgressEvent();
          pe.currentState = State.FETCHING_NATIVE_CONTACTS;
          pe.percent = 0;
          peList.add(pe);
  
          pe = new ContactSyncObserver.ProgressEvent();
          pe.currentState = State.FETCHING_NATIVE_CONTACTS;
          pe.percent = 100;
          peList.add(pe);
  
          pe = new ContactSyncObserver.ProgressEvent();
          pe.currentState = State.UPDATING_SERVER_CONTACTS;
          pe.percent = 0;
          peList.add(pe);
  
          pe = new ContactSyncObserver.ProgressEvent();
          pe.currentState = State.UPDATING_SERVER_CONTACTS;
          pe.percent = 100;
          peList.add(pe);
  
          // setting up expected SyncComplete
          ContactSyncObserver.SyncComplete sc = new ContactSyncObserver.SyncComplete();
          sc.status = ServiceStatus.SUCCESS;
          scList.add(sc);
      }
  
      /**
       * Class holding parameters from a UI event.
       */
      private static class UiEventCall {
          int event;
  
          int request;
  
          int status;
  
          Object data;
  
          /**
           * Resets the values from the last UI event.
           */
          public void reset() {
              event = -1;
              request = -1;
              status = -1;
              data = null;
          }
      }
  
      /**
       * Class holding a started processor log.
       */
      private static class ProcessorLog {
  
          /**
           * The processor type.
           */
          int type;
  
          /**
           * The time when the processor was started.
           */
          long time;
      }
  }
  