/** Implement method of BookmarksInsertionManager.BookmarkInserter. */
  @Override
  public boolean insertFolder(BookmarkRecord record) {
    // A folder that is *not* deleted needs its androidID updated, so that
    // updateBookkeeping can re-parent, etc.
    Record toStore = prepareRecord(record);
    try {
      Uri recordURI = dbHelper.insert(toStore);
      if (recordURI == null) {
        delegate.onRecordStoreFailed(
            new RuntimeException("Got null URI inserting folder with guid " + toStore.guid + "."),
            record.guid);
        return false;
      }
      toStore.androidID = ContentUris.parseId(recordURI);
      Logger.debug(
          LOG_TAG,
          "Inserted folder with guid " + toStore.guid + " as androidID " + toStore.androidID);

      updateBookkeeping(toStore);
    } catch (Exception e) {
      delegate.onRecordStoreFailed(e, record.guid);
      return false;
    }
    trackRecord(toStore);
    delegate.onRecordStoreSucceeded(record.guid);
    return true;
  }
  /**
   * Produce a record that is some combination of the remote and local records provided.
   *
   * <p>The returned record must be produced without mutating either remoteRecord or localRecord. It
   * is acceptable to return either remoteRecord or localRecord if no modifications are to be
   * propagated.
   *
   * <p>The returned record *should* have the local androidID and the remote GUID, and some optional
   * merge of data from the two records.
   *
   * <p>This method can be called with records that are identical, or differ in any regard.
   *
   * <p>This method will not be called if:
   *
   * <p>* either record is marked as deleted, or * there is no local mapping for a new remote
   * record.
   *
   * <p>Otherwise, it will be called precisely once.
   *
   * <p>Side-effects (e.g., for transactional storage) can be hooked in here.
   *
   * @param remoteRecord The record retrieved from upstream, already adjusted for clock skew.
   * @param localRecord The record retrieved from local storage.
   * @param lastRemoteRetrieval The timestamp of the last retrieved set of remote records, adjusted
   *     for clock skew.
   * @param lastLocalRetrieval The timestamp of the last retrieved set of local records.
   * @return A Record instance to apply, or null to apply nothing.
   */
  protected Record reconcileRecords(
      final Record remoteRecord,
      final Record localRecord,
      final long lastRemoteRetrieval,
      final long lastLocalRetrieval) {
    Logger.debug(
        LOG_TAG, "Reconciling remote " + remoteRecord.guid + " against local " + localRecord.guid);

    if (localRecord.equalPayloads(remoteRecord)) {
      if (remoteRecord.lastModified > localRecord.lastModified) {
        Logger.debug(LOG_TAG, "Records are equal. No record application needed.");
        return null;
      }

      // Local wins.
      return null;
    }

    // TODO: Decide what to do based on:
    // * Which of the two records is modified;
    // * Whether they are equal or congruent;
    // * The modified times of each record (interpreted through the lens of clock skew);
    // * ...
    boolean localIsMoreRecent = localRecord.lastModified > remoteRecord.lastModified;
    Logger.debug(LOG_TAG, "Local record is more recent? " + localIsMoreRecent);
    Record donor = localIsMoreRecent ? localRecord : remoteRecord;

    // Modify the local record to match the remote record's GUID and values.
    // Preserve the local Android ID, and merge data where possible.
    // It sure would be nice if copyWithIDs didn't give a shit about androidID, mm?
    Record out = donor.copyWithIDs(remoteRecord.guid, localRecord.androidID);

    // We don't want to upload the record if the remote record was
    // applied without changes.
    // This logic will become more complicated as reconciling becomes smarter.
    if (!localIsMoreRecent) {
      trackRecord(out);
    }
    return out;
  }