/**
  * Receive notification from ContactSyncEngine that a Contact sync has completed. Start Activity
  * sync if we have not previously synced.
  */
 @Override
 public void onSyncComplete(ServiceStatus status) {
   LogUtils.logD(
       "ActivityEngine onSyncComplete, time:" + mLastStatusUpdated + ", state=" + mState);
   // fire off background grab of activities
   if (ServiceStatus.SUCCESS == status && (mLastStatusUpdated == 0) && (mState == State.IDLE)) {
     addStatusesSyncRequest();
     LogUtils.logD("ActivityEngine onSyncComplete FULL_SYNC_FIRST_TIME.");
   }
 }
 /** Handle an outstanding UI request. */
 @Override
 protected void processUiRequest(ServiceUiRequest requestId, Object data) {
   LogUtils.logD("ActivityEngine processUiRequest:" + requestId);
   switch (requestId) {
     case UPDATE_STATUSES:
       // this is full sync or push, or "refresh" button
       requestStatusesFromServer(true);
       break;
     case FETCH_STATUSES:
       // "more" button
       requestStatusesFromServer(false);
       break;
     case FETCH_TIMELINES:
       // "more" button - we only need time lines
       enqueueRequest(
           ServiceUiRequest.FETCH_TIMELINES.ordinal(), ActivitiesState.FETCHING_OLDER_TIMELINE);
       newState(State.FETCH_OLDER_CALLLOG_FROM_NATIVE_DB);
       startCallLogSync(false);
       break;
     case UPDATE_PHONE_CALLS:
       // something on the NAB has changed
       newState(State.UPDATE_CALLOG_FROM_NATIVE);
       startCallLogSync(true);
       break;
     case UPDATE_SMS:
       newState(State.FETCH_SMS_FROM_NATIVE_DB);
       startFetchingSMS();
       break;
     default:
       break;
   }
 }
  /**
   * Request Activities (Status/Timeline) events from Server.
   *
   * @param refresh boolean - is true when fetching latest statuses, false - when older
   */
  private void requestStatusesFromServer(boolean refresh) {
    if (!checkConnectivity()) {
      mRequestActivitiesRequired = true;
      return;
    }
    mRequestActivitiesRequired = false;
    if (!isContactSyncReady()
        || !EngineManager.getInstance().getContactSyncEngine().isFirstTimeSyncComplete()) {
      // this method will then call completeUiRequest(status, null);
      onSyncHelperComplete(ServiceStatus.ERROR_NOT_READY);
      return;
    }
    mLastStatusUpdated = StateTable.fetchLatestStatusUpdateTime(mDb.getReadableDatabase());
    mOldestStatusUpdated = StateTable.fetchOldestStatusUpdate(mDb.getReadableDatabase());

    LogUtils.logD("ActivityEngine getActivites last update = " + mLastStatusUpdated);

    int reqId = Activities.getActivities(this, null, applyActivitiesFilter(refresh));
    if (reqId > 0) {
      setReqId(reqId);
      enqueueRequest(
          reqId,
          refresh ? ActivitiesState.UPDATING_STATUSES : ActivitiesState.FETCHING_OLDER_STATUSES);

      if (mLastStatusUpdated == 0) {
        newState(State.FETCH_STATUSES_FIRST_TIME);
      } else {
        newState(State.UPDATE_STATUSES);
      }
    }
  }
 /** {@inheritDoc} */
 @Override
 public void onContactSyncStateChange(
     ContactSyncEngine.Mode mode,
     ContactSyncEngine.State oldState,
     ContactSyncEngine.State newState) {
   LogUtils.logD("ActivityEngine onContactSyncStateChange called.");
 }
 /**
  * TODO: investigate why duplicates here can appear. this method might be not necessary. Remove
  * Activities from list of Activities with Activity IDS matching ones we have already retrieved
  * (i.e .duplicates).
  */
 private void removeDuplicates(ArrayList<ActivityItem> activityList) {
   if (activityList.size() == 0) {
     return;
   }
   int dupCount = 0;
   List<Long> actIdList = new ArrayList<Long>();
   mDb.fetchActivitiesIds(actIdList, findFirstStatusUpdateTime(activityList));
   for (int i = 0; i < activityList.size(); ) {
     boolean inc = true;
     Long id = activityList.get(i).activityId;
     if (id != null) {
       for (Long l : actIdList) {
         if (l.compareTo(id) == 0) {
           activityList.remove(i);
           inc = false;
           dupCount++;
           break;
         }
       }
     }
     if (inc) {
       i++;
     }
   }
   LogUtils.logD("ActivityEngine removeDuplicates. Count dups = " + dupCount);
 }
 private void updateOldestStatusUpdateTime() {
   long tloStatus = StateTable.fetchLatestStatusUpdateTime(mDb.getReadableDatabase());
   // modify the timelines dates
   if (mOldestStatusUpdated < tloStatus) {
     StateTable.modifyOldestStatusTime(mOldestStatusUpdated, mDb.getWritableDatabase());
     LogUtils.logD("ActivityEngine: oldest status update set to = " + mOldestStatusUpdated);
   }
 }
 /**
  * Handle Status or Timeline Activity change Push message
  *
  * @param evt Push message type (Status change or Timeline change).
  */
 private void handlePushRequest(PushMessageTypes evt) {
   LogUtils.logD("ActivityEngine handlePushRequest");
   switch (evt) {
     case STATUS_ACTIVITY_CHANGE:
     case TIMELINE_ACTIVITY_CHANGE:
       addUiRequestToQueue(ServiceUiRequest.UPDATE_STATUSES, null);
       break;
     default:
       // do nothing
   }
 }
 /**
  * ActivitiesEngine run implementation Processes a response if one is available, Processes any
  * events in engine's UI queue. Issues get-activities request to server as part of sync.
  */
 @Override
 public void run() {
   LogUtils.logD("ActivityEngine run");
   processTimeout();
   if (mNextCleanup < System.currentTimeMillis()) {
     cleanDatabase();
     mNextCleanup = System.currentTimeMillis() + ACTIVITES_CLEANUP_SEC;
     LogUtils.logD("ActivityEngine.run() Clean database again at [" + mNextCleanup + "]");
     return;
   }
   if (isCommsResponseOutstanding() && processCommsInQueue()) {
     return;
   }
   if (isUiRequestOutstanding()) {
     processUiQueue();
   }
   if (mRequestActivitiesRequired) {
     requestStatusesFromServer(true);
   }
 }
  private Map<String, List<String>> applyActivitiesFilter(boolean refresh) {

    Map<String, List<String>> filter = new Hashtable<String, List<String>>();

    // filter out types we're not interested in
    List<String> statusFilter = new ArrayList<String>();
    statusFilter.add(FILTER_TRUE);
    filter.put(FILTER_STATUS, statusFilter);

    if (mLastStatusUpdated > 0) {
      if (refresh) {
        List<String> updateFilter = new ArrayList<String>();
        LogUtils.logD(
            "ActivityEngine TimeFilter newer= '"
                + FILTER_GT
                + (mLastStatusUpdated / MS_IN_SECOND)
                + "'");
        updateFilter.add(FILTER_GT + mLastStatusUpdated / MS_IN_SECOND);
        filter.put(FILTER_UPDATED, updateFilter);
      } else {
        List<String> updateFilter = new ArrayList<String>();
        LogUtils.logD(
            "ActivityEngine TimeFilter older= '"
                + FILTER_GT
                + (mOldestStatusUpdated / MS_IN_SECOND)
                + "'");
        updateFilter.add(FILTER_GT + mOldestStatusUpdated / MS_IN_SECOND);
        filter.put(FILTER_UPDATED, updateFilter);
      }
    } else { // 1st time
      List<String> fNum = new ArrayList<String>();
      fNum.add(FILTER_NUM);
      filter.put(FILTER_LIDS, fNum);
      List<String> sort = new ArrayList<String>();
      sort.add(FILTER_UPDATED_REV);
      filter.put(FILTER_SORT, sort);

      mOldestStatusUpdated = (System.currentTimeMillis() - WEEK_OLD_MILLIS) / MS_IN_SECOND;
    }
    return filter;
  }
 /**
  * Handle response received from transport layer (via EngineManager)
  *
  * @param resp Received Response item either a Status/Timeline related push message or a response
  *     to a get activities request.
  */
 @Override
 protected void processCommsResponse(DecodedResponse resp) {
   LogUtils.logD("ActivitiesEngine processCommsResponse");
   // handle push response
   if (resp.mReqId == 0 && resp.mDataTypes.size() > 0) {
     PushEvent evt = (PushEvent) resp.mDataTypes.get(0);
     handlePushRequest(evt.mMessageType);
   } else {
     dequeueRequest(resp.mReqId);
     handleGetActivitiesResponse(resp.mDataTypes);
   }
 }
  private ServiceStatus updateDatabase(ArrayList<ActivityItem> activityList) {
    ServiceStatus errorStatus = ServiceStatus.SUCCESS;

    // add retrieved items to Activities table in db
    removeDuplicates(activityList);

    // update the newest activity
    Long temp = findLastStatusUpdateTime(activityList);
    if (temp != Long.MIN_VALUE) {
      mLastStatusUpdated = temp;
    }
    if (activityList.size() > 0) {
      LogUtils.logD("ActivityEngine Added ActivityItems = " + activityList.size());
      // update database
      errorStatus = mDb.addActivities(activityList);
      if (errorStatus == ServiceStatus.SUCCESS) {
        updateLatestStatusUpdateTime();
        updateOldestStatusUpdateTime();
      }
    }
    return errorStatus;
  }
 /** This method adds a request to start sync of older statuses from Now+ server. */
 public void addGetOlderStatusesRequest() {
   LogUtils.logD("ActivityEngine addGetOlderStatusesRequest");
   addUiRequestToQueue(ServiceUiRequest.FETCH_STATUSES, null);
 }
 /** This method adds a request to start sync of the most recent statuses from Now+ server. */
 public void addStatusesSyncRequest() {
   LogUtils.logD("ActivityEngine addStatusesSyncRequest()");
   addUiRequestToQueue(ServiceUiRequest.UPDATE_STATUSES, null);
 }
 /** This method adds a request to get older timelines. */
 public void addOlderTimelinesRequest() {
   LogUtils.logD("ActivitiesEngine addOlderTimelinesRequest()");
   addUiRequestToQueue(ServiceUiRequest.FETCH_TIMELINES, null);
 }
 /** This method adds a request to get latest timelines. */
 protected void addGetNewSMSRequest() {
   LogUtils.logD("ActivitiesEngine addGetNewTimelinesRequest()");
   addUiRequestToQueue(ServiceUiRequest.UPDATE_SMS, null);
 }
 /** This method adds a request to get latest timelines. */
 protected void addGetNewPhonesCallsRequest() {
   LogUtils.logD("ActivitiesEngine addGetNewTimelinesRequest()");
   // TODO: I noticed there 2 NAB change events coming when the phone call
   // is made: try to filter one out
   addUiRequestToQueue(ServiceUiRequest.UPDATE_PHONE_CALLS, null);
 }
 /** {@inheritDoc} */
 @Override
 public void onProgressEvent(ContactSyncEngine.State currentState, int percent) {
   LogUtils.logD("ActivityEngine onProgressEvent");
 }