/**
   * Updates the has-draft status of a particular thread on a piecemeal basis, to be called when a
   * draft has appeared or disappeared.
   */
  public synchronized void setDraftState(long threadId, boolean hasDraft) {
    if (threadId <= 0) {
      return;
    }

    boolean changed;
    if (hasDraft) {
      changed = mDraftSet.add(threadId);
    } else {
      changed = mDraftSet.remove(threadId);
    }

    if (Log.isLoggable(LogTag.APP, Log.DEBUG)) {
      log("setDraftState: tid=" + threadId + ", value=" + hasDraft + ", changed=" + changed);
    }

    if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
      dump();
    }

    // Notify listeners if there was a change.
    if (changed) {
      for (OnDraftChangedListener l : mChangeListeners) {
        l.onDraftChanged(threadId, hasDraft);
      }
    }
  }
  /** Does the actual work of rebuilding the draft cache. */
  private synchronized void rebuildCache() {
    if (Log.isLoggable(LogTag.APP, Log.DEBUG)) {
      log("rebuildCache");
    }

    HashSet<Long> oldDraftSet = mDraftSet;
    HashSet<Long> newDraftSet = new HashSet<Long>(oldDraftSet.size());

    Cursor cursor =
        SqliteWrapper.query(
            mContext,
            mContext.getContentResolver(),
            MmsSms.CONTENT_DRAFT_URI,
            DRAFT_PROJECTION,
            null,
            null,
            null);

    if (cursor != null) {
      try {
        if (cursor.moveToFirst()) {
          for (; !cursor.isAfterLast(); cursor.moveToNext()) {
            long threadId = cursor.getLong(COLUMN_DRAFT_THREAD_ID);
            newDraftSet.add(threadId);
            if (Log.isLoggable(LogTag.APP, Log.DEBUG)) {
              log("rebuildCache: add tid=" + threadId);
            }
          }
        }
      } finally {
        cursor.close();
      }
    }
    mDraftSet = newDraftSet;

    if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
      dump();
    }

    // If nobody's interested in finding out about changes,
    // just bail out early.
    if (mChangeListeners.size() < 1) {
      return;
    }

    // Find out which drafts were removed and added and notify
    // listeners.
    Set<Long> added = new HashSet<Long>(newDraftSet);
    added.removeAll(oldDraftSet);
    Set<Long> removed = new HashSet<Long>(oldDraftSet);
    removed.removeAll(newDraftSet);

    for (OnDraftChangedListener l : mChangeListeners) {
      for (long threadId : added) {
        l.onDraftChanged(threadId, true);
      }
      for (long threadId : removed) {
        l.onDraftChanged(threadId, false);
      }
    }
  }