/** 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; }