@SafeVarargs
 @Override
 protected final void onProgressUpdate(
     TwitterWrapper.TwitterListResponse<org.mariotaku.twidere.api.twitter.model.Status>...
         values) {
   AsyncTaskUtils.executeTask(new CacheUsersStatusesTask(twitterWrapper.getContext()), values);
 }
 public GetStatusesTask(
     AsyncTwitterWrapper twitterWrapper,
     final long[] accountIds,
     final long[] maxIds,
     final long[] sinceIds,
     final String tag) {
   super(twitterWrapper.getContext(), tag);
   this.twitterWrapper = twitterWrapper;
   this.accountIds = accountIds;
   this.maxIds = maxIds;
   this.sinceIds = sinceIds;
 }
 @Override
 protected List<TwitterWrapper.StatusListResponse> doInBackground(final Object... params) {
   final List<TwitterWrapper.StatusListResponse> result = new ArrayList<>();
   if (accountIds == null) return result;
   int idx = 0;
   final SharedPreferencesWrapper preferences = twitterWrapper.getPreferences();
   final Context context = twitterWrapper.getContext();
   final ErrorInfoStore errorInfoStore = twitterWrapper.getErrorInfoStore();
   final int loadItemLimit = preferences.getInt(KEY_LOAD_ITEM_LIMIT, DEFAULT_LOAD_ITEM_LIMIT);
   for (final long accountId : accountIds) {
     final Twitter twitter = TwitterAPIFactory.getTwitterInstance(context, accountId, true);
     if (twitter == null) continue;
     try {
       final Paging paging = new Paging();
       paging.count(loadItemLimit);
       final long maxId, sinceId;
       if (maxIds != null && maxIds[idx] > 0) {
         maxId = maxIds[idx];
         paging.maxId(maxId);
       } else {
         maxId = -1;
       }
       if (sinceIds != null && sinceIds[idx] > 0) {
         sinceId = sinceIds[idx];
         paging.sinceId(sinceId - 1);
         if (maxIds == null || sinceIds[idx] <= 0) {
           paging.setLatestResults(true);
         }
       } else {
         sinceId = -1;
       }
       final List<org.mariotaku.twidere.api.twitter.model.Status> statuses =
           getStatuses(twitter, paging);
       TwitterContentUtils.getStatusesWithQuoteData(twitter, statuses);
       storeStatus(accountId, statuses, sinceId, maxId, true, loadItemLimit);
       publishProgress(new TwitterWrapper.StatusListResponse(accountId, statuses));
       errorInfoStore.remove(getErrorInfoKey(), accountId);
     } catch (final TwitterException e) {
       if (BuildConfig.DEBUG) {
         Log.w(LOGTAG, e);
       }
       if (e.isCausedByNetworkIssue()) {
         errorInfoStore.put(getErrorInfoKey(), accountId, ErrorInfoStore.CODE_NETWORK_ERROR);
       }
       result.add(new TwitterWrapper.StatusListResponse(accountId, e));
     }
     idx++;
   }
   return result;
 }
  private void storeStatus(
      long accountId,
      List<org.mariotaku.twidere.api.twitter.model.Status> statuses,
      long sinceId,
      long maxId,
      boolean notify,
      int loadItemLimit) {
    if (statuses == null || statuses.isEmpty() || accountId <= 0) {
      return;
    }
    final Uri uri = getDatabaseUri();
    final Context context = twitterWrapper.getContext();
    final ContentResolver resolver = context.getContentResolver();
    final boolean noItemsBefore = DataStoreUtils.getStatusCount(context, uri, accountId) <= 0;
    final ContentValues[] values = new ContentValues[statuses.size()];
    final long[] statusIds = new long[statuses.size()];
    long minId = -1;
    int minIdx = -1;
    boolean hasIntersection = false;
    for (int i = 0, j = statuses.size(); i < j; i++) {
      final org.mariotaku.twidere.api.twitter.model.Status status = statuses.get(i);
      values[i] = ContentValuesCreator.createStatus(status, accountId);
      values[i].put(Statuses.INSERTED_DATE, System.currentTimeMillis());
      final long id = status.getId();
      if (sinceId > 0 && id <= sinceId) {
        hasIntersection = true;
      }
      if (minId == -1 || id < minId) {
        minId = id;
        minIdx = i;
      }
      statusIds[i] = id;
    }
    // Delete all rows conflicting before new data inserted.
    final Expression accountWhere = Expression.equals(Statuses.ACCOUNT_ID, accountId);
    final Expression statusWhere =
        Expression.in(new Columns.Column(Statuses.STATUS_ID), new RawItemArray(statusIds));
    final String countWhere = Expression.and(accountWhere, statusWhere).getSQL();
    final String[] projection = {SQLFunctions.COUNT()};
    final int rowsDeleted;
    final Cursor countCur = resolver.query(uri, projection, countWhere, null, null);
    try {
      if (countCur != null && countCur.moveToFirst()) {
        rowsDeleted = countCur.getInt(0);
      } else {
        rowsDeleted = 0;
      }
    } finally {
      Utils.closeSilently(countCur);
    }

    // BEGIN HotMobi
    final RefreshEvent event = RefreshEvent.create(context, statusIds, getTimelineType());
    HotMobiLogger.getInstance(context).log(accountId, event);
    // END HotMobi

    // Insert a gap.
    final boolean deletedOldGap = rowsDeleted > 0 && ArrayUtils.contains(statusIds, maxId);
    final boolean noRowsDeleted = rowsDeleted == 0;
    final boolean insertGap =
        minId > 0 && (noRowsDeleted || deletedOldGap) && !noItemsBefore && !hasIntersection;
    if (insertGap && minIdx != -1) {
      values[minIdx].put(Statuses.IS_GAP, true);
    }
    // Insert previously fetched items.
    final Uri insertUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify);
    ContentResolverUtils.bulkInsert(resolver, insertUri, values);
  }