From f26a8799fa57518db0a51e54e2ddec1ca4291942 Mon Sep 17 00:00:00 2001 From: Jimmy Shih Date: Sat, 2 Feb 2013 13:16:04 -0800 Subject: [PATCH] Also sync "Shared with me" KML files. --- MyTracks/res/values/strings.xml | 10 +- .../mytracks/content/MyTracksProvider.java | 2 +- .../mytracks/io/drive/SendDriveAsyncTask.java | 9 +- .../apps/mytracks/io/sync/SyncAdapter.java | 106 +++++++++++------- .../apps/mytracks/io/sync/SyncUtils.java | 60 +++++++--- .../settings/GoogleSettingsActivity.java | 31 +++-- .../endtoendtest/sync/SyncTestUtils.java | 4 +- 7 files changed, 144 insertions(+), 78 deletions(-) diff --git a/MyTracks/res/values/strings.xml b/MyTracks/res/values/strings.xml index 1f41f0b1b..21934680e 100644 --- a/MyTracks/res/values/strings.xml +++ b/MyTracks/res/values/strings.xml @@ -1732,8 +1732,9 @@ limitations under the License. account. %1$s account name. E.g., 'foo@foo.com'."> - This will remove any mappings between tracks and %1$s Google Drive. After removal, when sending - to Google Drive or syncing with Google Drive, all tracks will be treated as new. + This will remove mappings between tracks and %1$s Google Drive. No tracks and no Google Drive + files will get removed. After switching account, when sending to Google Drive or syncing with + Google Drive, all tracks will be treated as new. - Check the files in %1$s Google Drive ‘%2$s’ folder. Files not mapped to existing - tracks will be synced as new tracks. If not desired, move those files to a different folder - beforehand. + All files in the %1$s Google Drive ‘%2$s’ folder will be treated as new. If not + desired, move the files to a different folder beforehand. idToFileMap = new HashMap(); - - do { - try { - FileList files = request.execute(); - - for (File file : files.getItems()) { - idToFileMap.put(file.getId(), file); - } - request.setPageToken(files.getNextPageToken()); - } catch (IOException e) { - Log.e(TAG, "IOException", e); - request.setPageToken(null); - } - } while (request.getPageToken() != null && request.getPageToken().length() > 0); - - // Handle new drive files + // Get all the KML files in the "My Drive:/My Tracks" folder + Files.List request = drive.files().list() + .setQ(String.format(Locale.US, SyncUtils.MY_TRACKS_FOLDER_FILES_QUERY, folderId)); + Map idToFileMap = getFiles(request); insertNewDriveFiles(idToFileMap.values()); + + // Get all the KML files in the "Shared with me:/" folder + request = drive.files().list().setQ(SyncUtils.SHARED_WITH_ME_FILES_QUERY); + idToFileMap = getFiles(request); + insertNewDriveFiles(idToFileMap.values()); + PreferencesUtils.setLong(context, R.string.drive_largest_change_id_key, largestChangeId); } @@ -172,8 +162,13 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { String deletedIds[] = TextUtils.split(driveDeletedList, ";"); for (String id : deletedIds) { File driveFile = drive.files().get(id).execute(); - if (SyncUtils.isDriveFileValid(driveFile, folderId)) { - drive.files().trash(id).execute(); + if (SyncUtils.isInFolder(driveFile, folderId)) { + if (!driveFile.getLabels().getTrashed()) { + drive.files().trash(id).execute(); + } + // if trashed, ignore + } else if (SyncUtils.isSharedWithMe(driveFile)) { + drive.files().delete(id).execute(); } } PreferencesUtils.setString( @@ -185,7 +180,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { Cursor cursor = null; try { // Get all the local tracks with drive file id - cursor = myTracksProviderUtils.getTrackCursor(SyncUtils.DRIVE_IDS_QUERY, null, null); + cursor = myTracksProviderUtils.getTrackCursor(SyncUtils.DRIVE_ID_TRACKS_QUERY, null, null); if (cursor != null && cursor.moveToFirst()) { do { Track track = myTracksProviderUtils.createTrack(cursor); @@ -203,19 +198,22 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { } changes.remove(driveId); } else { + if (!track.isSharedWithMe()) { - // Handle the case the track has changed - File driveFile = drive.files().get(driveId).execute(); - if (SyncUtils.isDriveFileValid(driveFile, folderId)) { - mergeFiles(track, driveFile); - } else { - /* - * Track has a drive id, but the drive id is no longer valid. - * E.g., the file is moved to another folder. Clear the drive id. - */ - track.setDriveId(""); - track.setModifiedTime(-1L); - myTracksProviderUtils.updateTrack(track); + // Handle the case the track has changed + File driveFile = drive.files().get(driveId).execute(); + if (SyncUtils.isValid(driveFile, folderId)) { + mergeFiles(track, driveFile); + } else { + /* + * Track has a drive id, but the drive id is no longer valid. + * E.g., the file is moved to another folder. Clear the drive + * id. + */ + track.setDriveId(""); + track.setModifiedTime(-1L); + myTracksProviderUtils.updateTrack(track); + } } } } while (cursor.moveToNext()); @@ -243,9 +241,9 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { private void insertNewTracks(String folderId) throws IOException { Cursor cursor = null; try { - cursor = myTracksProviderUtils.getTrackCursor(SyncUtils.NO_DRIVE_ID_QUERY, null, null); + cursor = myTracksProviderUtils.getTrackCursor(SyncUtils.NO_DRIVE_ID_TRACKS_QUERY, null, null); long recordingTrackId = PreferencesUtils.getLong(context, R.string.recording_track_id_key); - + if (cursor != null && cursor.moveToFirst()) { do { Track track = myTracksProviderUtils.createTrack(cursor); @@ -280,6 +278,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { Track track = myTracksProviderUtils.getTrack(tracksIds[0]); track.setDriveId(driveFile.getId()); track.setModifiedTime(driveFile.getModifiedDate().getValue()); + track.setSharedWithMe(driveFile.getSharedWithMeDate() != null); myTracksProviderUtils.updateTrack(track); Log.d(TAG, "Add from Google Drive " + track.getName()); } @@ -289,6 +288,30 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { } } + /** + * Gets all the files from a request. + * + * @param request the request + * @return a map of file id to file + */ + private Map getFiles(Files.List request) { + Map idToFileMap = new HashMap(); + do { + try { + FileList files = request.execute(); + + for (File file : files.getItems()) { + idToFileMap.put(file.getId(), file); + } + request.setPageToken(files.getNextPageToken()); + } catch (IOException e) { + Log.e(TAG, "IOException", e); + request.setPageToken(null); + } + } while (request.getPageToken() != null && request.getPageToken().length() > 0); + return idToFileMap; + } + /** * Gets the Drive changes in the My Tracks folder. Includes deleted files. * @@ -310,7 +333,13 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { } else { File file = change.getFile(); if (SyncUtils.isInFolder(file, folderId)) { - changes.put(change.getFileId(), file.getLabels().getTrashed() ? null : file); + if (file.getLabels().getTrashed()) { + changes.put(change.getFileId(), null); + } else { + changes.put(change.getFileId(), file); + } + } else if (SyncUtils.isSharedWithMe(file)) { + changes.put(change.getFileId(), file); } } } @@ -359,6 +388,7 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter { Track newTrack = myTracksProviderUtils.getTrack(tracksIds[0]); newTrack.setDriveId(driveFile.getId()); newTrack.setModifiedTime(driveModifiedTime); + newTrack.setSharedWithMe(driveFile.getSharedWithMeDate() != null); myTracksProviderUtils.updateTrack(newTrack); } else { diff --git a/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java b/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java index fb2d2b966..8bbc2198f 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java +++ b/MyTracks/src/com/google/android/apps/mytracks/io/sync/SyncUtils.java @@ -65,20 +65,38 @@ import java.util.Locale; */ public class SyncUtils { + // Request code to obtain Drive permission public static final int DRIVE_PERMISSION_REQUEST_CODE = 1; - public static final String DRIVE_IDS_QUERY = TracksColumns.DRIVEID + " IS NOT NULL AND " + // Get tracks with drive id + public static final String DRIVE_ID_TRACKS_QUERY = TracksColumns.DRIVEID + " IS NOT NULL AND " + TracksColumns.DRIVEID + "!=''"; - public static final String NO_DRIVE_ID_QUERY = TracksColumns.DRIVEID + " IS NULL OR " + + // Get tracks with drive id that are owned by me, not tracks ashared with me. + public static final String DRIVE_ID_TRACKS_BY_ME_QUERY = DRIVE_ID_TRACKS_QUERY + " AND " + + TracksColumns.SHAREDWITHME + "!=1"; + + // Get tracks without drive id + public static final String NO_DRIVE_ID_TRACKS_QUERY = TracksColumns.DRIVEID + " IS NULL OR " + TracksColumns.DRIVEID + "=''"; + // KML mime type public static final String KML_MIME_TYPE = "application/vnd.google-earth.kml+xml"; - public static final String GET_KML_FILES_QUERY = "'%s' in parents and mimeType = '" + + // Get My Tracks folder KML files + public static final String MY_TRACKS_FOLDER_FILES_QUERY = "'%s' in parents and mimeType = '" + KML_MIME_TYPE + "' and trashed = false"; - + + // Get shared with me KML files + public static final String SHARED_WITH_ME_FILES_QUERY = "sharedWithMe and mimeType = '" + + KML_MIME_TYPE + "'"; + + // Folder mime type private static final String FOLDER_MIME_TYPE = "application/vnd.google-apps.folder"; + + // Get My Tracks folder @VisibleForTesting - public static final String GET_MY_TRACKS_FOLDER_QUERY = + public static final String MY_TRACKS_FOLDER_QUERY = "'root' in parents and title = '%s' and mimeType = '" + FOLDER_MIME_TYPE + "' and trashed = false"; @@ -164,7 +182,7 @@ public class SyncUtils { } return null; } - + /** * Cancels any notification to request drive permission. * @@ -236,7 +254,7 @@ public class SyncUtils { try { String folderName = context.getString(R.string.my_tracks_app_name); List list = drive.files() - .list().setQ(String.format(Locale.US, GET_MY_TRACKS_FOLDER_QUERY, folderName)); + .list().setQ(String.format(Locale.US, MY_TRACKS_FOLDER_QUERY, folderName)); FileList result = list.execute(); for (File file : result.getItems()) { if (file.getTitle().equals(folderName)) { @@ -254,21 +272,33 @@ public class SyncUtils { } /** - * Returns true if the drive file is a kml file in the My Tracks folder and - * not trashed. + * Returns true if the drive file is a Shared with me KML file. + * + * @param driveFile the drive file + */ + public static boolean isSharedWithMe(File driveFile) { + if (driveFile == null) { + return false; + } + if (!SyncUtils.KML_MIME_TYPE.equals(driveFile.getMimeType())) { + return false; + } + return driveFile.getSharedWithMeDate() != null; + } + + /** + * Returns true if the drive file is a valid KML file in the My Tracks folder + * and not trashed. * * @param driveFile the drive file * @param folderId the My Tracks folder id */ - public static boolean isDriveFileValid(File driveFile, String folderId) { - if (isInFolder(driveFile, folderId)) { - return !driveFile.getLabels().getTrashed(); - } - return false; + public static boolean isValid(File driveFile, String folderId) { + return isInFolder(driveFile, folderId) && !driveFile.getLabels().getTrashed(); } /** - * Returns true if the drive file is a kml file in the My Tracks folder. + * Returns true if the drive file is a KML file in the My Tracks folder. * * @param driveFile the drive file * @param folderId the My Tracks folder id diff --git a/MyTracks/src/com/google/android/apps/mytracks/settings/GoogleSettingsActivity.java b/MyTracks/src/com/google/android/apps/mytracks/settings/GoogleSettingsActivity.java index 795556459..e19d9af05 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/settings/GoogleSettingsActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/settings/GoogleSettingsActivity.java @@ -121,6 +121,7 @@ public class GoogleSettingsActivity extends AbstractSettingsActivity { showDialog(DIALOG_CONFIRM_DRIVE_SYNC_ON); } else { handleSync(false); + clearSyncState(); } return false; } @@ -198,8 +199,8 @@ public class GoogleSettingsActivity extends AbstractSettingsActivity { @Override public void onClick(DialogInterface d, int button) { googleAccountPreference.setValue(newValue); - clearSyncState(); handleSync(false); + clearSyncState(); updateUiByAccountName(newValue); } }); @@ -215,25 +216,25 @@ public class GoogleSettingsActivity extends AbstractSettingsActivity { } /** - * Clears the sync state. + * Clears the sync state. Assumes sync is turned off. Do not want clearing the + * state to cause sync activities. */ private void clearSyncState() { - PreferencesUtils.setLong(this, R.string.drive_largest_change_id_key, - PreferencesUtils.DRIVE_LARGEST_CHANGE_ID_DEFAULT); - PreferencesUtils.setString( - this, R.string.drive_deleted_list_key, PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT); - MyTracksProviderUtils myTracksProviderUtils = MyTracksProviderUtils.Factory.get(this); Cursor cursor = null; try { - cursor = myTracksProviderUtils.getTrackCursor(SyncUtils.DRIVE_IDS_QUERY, null, null); + cursor = myTracksProviderUtils.getTrackCursor(SyncUtils.DRIVE_ID_TRACKS_QUERY, null, null); if (cursor != null && cursor.moveToFirst()) { do { Track track = myTracksProviderUtils.createTrack(cursor); - track.setDriveId(""); - track.setModifiedTime(-1L); - track.setSharedWithMe(false); - myTracksProviderUtils.updateTrack(track); + if (track.isSharedWithMe()) { + myTracksProviderUtils.deleteTrack(track.getId()); + } else { + track.setDriveId(""); + track.setModifiedTime(-1L); + track.setSharedWithMe(false); + myTracksProviderUtils.updateTrack(track); + } } while (cursor.moveToNext()); } } finally { @@ -241,6 +242,12 @@ public class GoogleSettingsActivity extends AbstractSettingsActivity { cursor.close(); } } + PreferencesUtils.setLong(this, R.string.drive_largest_change_id_key, + PreferencesUtils.DRIVE_LARGEST_CHANGE_ID_DEFAULT); + + // Clear the driveDeletedList last + PreferencesUtils.setString( + this, R.string.drive_deleted_list_key, PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT); } /** diff --git a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncTestUtils.java b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncTestUtils.java index 3420e6ba3..f756b6077 100644 --- a/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncTestUtils.java +++ b/MyTracksTest_E2E/src/com/google/android/apps/mytracks/endtoendtest/sync/SyncTestUtils.java @@ -138,7 +138,7 @@ public class SyncTestUtils { } String folderId = folder.getId(); return drive.files().list() - .setQ(String.format(Locale.US, SyncUtils.GET_KML_FILES_QUERY, folderId)).execute() + .setQ(String.format(Locale.US, SyncUtils.MY_TRACKS_FOLDER_FILES_QUERY, folderId)).execute() .getItems(); } @@ -330,7 +330,7 @@ public class SyncTestUtils { try { String folderName = context.getString(R.string.my_tracks_app_name); com.google.api.services.drive.Drive.Files.List list = drive.files().list() - .setQ(String.format(Locale.US, SyncUtils.GET_MY_TRACKS_FOLDER_QUERY, folderName)); + .setQ(String.format(Locale.US, SyncUtils.MY_TRACKS_FOLDER_QUERY, folderName)); FileList result = list.execute(); for (File file : result.getItems()) { if (file.getTitle().equals(folderName)) {