/** * Merge a local file with a Google Drive File. * * <p>The last modification is used to check which file to sync from. Then, the md5 checksum of * the file is used to check whether or not the file's content should be sync'ed. * * @param localFileUri Local file URI to save local changes against. * @param localFile Local file cursor to retrieve data from. * @param driveFile Google Drive file. */ private void mergeFiles(Uri localFileUri, Cursor localFile, File driveFile) { long localFileModificationDate = localFile.getLong(COLUMN_INDEX_MODIFICATION_DATE); Log.d( TAG, "Modification dates: " + localFileModificationDate + " - " + driveFile.getModifiedDate().getValue()); if (localFileModificationDate > driveFile.getModifiedDate().getValue()) { try { if (localFile.getShort(COLUMN_INDEX_DELETED) != 0) { Log.d(TAG, " > Deleting Drive file."); mService.files().delete(driveFile.getId()).execute(); mProvider.delete(localFileUri, null, null); } else { String localNote = localFile.getString(COLUMN_INDEX_NOTE); File updatedFile = null; // Update drive file. Log.d(TAG, " > Updating Drive file."); driveFile.setTitle(localFile.getString(COLUMN_INDEX_TITLE)); if (md5(localNote) != driveFile.getMd5Checksum()) { // Update both content and metadata. ByteArrayContent content = ByteArrayContent.fromString(TEXT_PLAIN, localNote); updatedFile = mService.files().update(driveFile.getId(), driveFile, content).execute(); } else { // Only update the metadata. updatedFile = mService.files().update(driveFile.getId(), driveFile).execute(); } ContentValues values = new ContentValues(); values.put( NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE, updatedFile.getModifiedDate().getValue()); mProvider.update(localFileUri, values, null, null); } } catch (IOException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } else if (localFileModificationDate < driveFile.getModifiedDate().getValue()) { // Update local file. Log.d(TAG, " > Updating local file."); ContentValues values = new ContentValues(); values.put(NotePad.Notes.COLUMN_NAME_TITLE, driveFile.getTitle()); values.put( NotePad.Notes.COLUMN_NAME_MODIFICATION_DATE, driveFile.getModifiedDate().getValue()); // Only download the content if it has changed. if (md5(localFile.getString(COLUMN_INDEX_NOTE)) != driveFile.getMd5Checksum()) { values.put(NotePad.Notes.COLUMN_NAME_NOTE, getFileContent(driveFile)); } try { mProvider.update(localFileUri, values, null, null); } catch (RemoteException e) { e.printStackTrace(); } } }
private void addToSnapshot(Snapshot root, ChangeRecord remoteChange) { switch (remoteChange.getOperation()) { case REMOTE_INSERT: String localName = stub.storage().remoteToLocal().get(remoteChange.getRemoteFileId()); if (StringUtils.isEmpty(localName)) { // Insert failed return; } File localFile = DriveUtils.absolutePath(localName); String parent = DriveUtils.relativePath(localFile.getParentFile()); if (root.getName().equals(parent)) { for (Snapshot sn : root.getChildren()) { if (sn.getName().equals(localName)) return; } Snapshot sn = stub.snapshot().make(localFile); root.addChild(sn); } else { for (Snapshot sn : root.getChildren()) { if (parent.startsWith(sn.getName())) { addToSnapshot(sn, remoteChange); return; } } // TODO the operations are not in sequence. // Didn't find? logger.warn( MessageFormat.format("Remote insert cannot find local parent {0}", remoteChange)); // throw new IllegalArgumentException(); } break; case REMOTE_CHANGE: { String fileName = remoteChange.getLocalFile(); if (fileName.equals(root.getName())) { com.google.api.services.drive.model.File remoteFile = remoteChange.getContext(0); root.setMd5Checksum(remoteFile.getMd5Checksum()); } else { for (Snapshot sn : root.getChildren()) { if (fileName.startsWith(sn.getName())) { addToSnapshot(sn, remoteChange); return; } } // Didn't find? logger.error( MessageFormat.format( "Local root doesn't contain this file {0}. Should be an error.", remoteChange)); // throw new IllegalArgumentException(); } break; } case REMOTE_RENAME: { String fileName = remoteChange.getLocalFile(); if (root.getName().startsWith(fileName)) { String newName = remoteChange.getContext(1); root.setName(root.getName().replaceFirst(fileName, newName)); for (Snapshot sn : root.getChildren()) { addToSnapshot(sn, remoteChange); } } else { for (Snapshot sn : root.getChildren()) { if (fileName.startsWith(sn.getName())) { addToSnapshot(sn, remoteChange); return; } } // Didn't find? logger.error( MessageFormat.format( "Remote rename cannot find local corresponding {0}, should be an error", remoteChange)); // throw new IllegalArgumentException(); } break; } case REMOTE_DELETE: String fileName = remoteChange.getLocalFile(); if (StringUtils.isEmpty(fileName)) { return; } for (int i = 0; i < root.getChildren().size(); i++) { Snapshot sn = root.getChildren().get(i); if (fileName.equals(sn.getName())) { root.getChildren().remove(sn); return; } if (fileName.startsWith(sn.getName())) { addToSnapshot(sn, remoteChange); return; } } // Didn't find? logger.warn( MessageFormat.format( "Remote change cannot find local corresponding {0}, possibly caused by deleting of parent folder", remoteChange)); // This means the remote change is out of date break; default: throw new IllegalArgumentException(); } }