Skip to content

Commit

Permalink
Google Drive auth and sync now working
Browse files Browse the repository at this point in the history
May still have bugs with handling modification times
  • Loading branch information
Nicholas Harrison committed Jul 2, 2022
1 parent 8971730 commit c54f227
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 62 deletions.
102 changes: 66 additions & 36 deletions app/src/main/java/com/orgzly/android/repos/GoogleDriveClient.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.orgzly.android.repos;

import android.app.Activity;
import android.content.Intent;
import android.content.Context;
import android.net.Uri;
import android.os.Build;

import androidx.annotation.RequiresApi;

import com.google.android.gms.auth.api.signin.GoogleSignIn;

import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.http.FileContent;
Expand All @@ -20,20 +22,16 @@

import java.io.BufferedOutputStream;
// import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import android.util.Log;

public class GoogleDriveClient {
private static final String TAG = GoogleDriveClient.class.getName();

Expand All @@ -48,10 +46,10 @@ public class GoogleDriveClient {

private final Context mContext;
private final long repoId;
private Drive mDriveService;
private static Drive mDriveService;

private Map<String, String> pathIds;
{
private static Map<String, String> pathIds;
static {
pathIds = new HashMap<>();
pathIds.put("My Drive", "root");
pathIds.put("", "root");
Expand All @@ -61,30 +59,61 @@ public GoogleDriveClient(Context context, long id) {
mContext = context;

repoId = id;
}

public void setService(Drive driveService) {
mDriveService = driveService;
if (isLinked()) setDriveService();
}

public boolean isLinked() {
// Check for existing Google Sign In account, if the user is already signed in
// the GoogleSignInAccount will be non-null.
return GoogleSignIn.getLastSignedInAccount(mContext) != null;
return getGoogleAccount() != null;
}

private GoogleSignInAccount getGoogleAccount() {
return GoogleSignIn.getLastSignedInAccount(mContext);
}

public Drive getDriveService(GoogleSignInAccount googleAccount) {
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(
mContext, Collections.singleton(DriveScopes.DRIVE));
credential.setSelectedAccount(googleAccount.getAccount());
return new Drive.Builder(
AndroidHttp.newCompatibleTransport(),
new GsonFactory(),
credential)
.setApplicationName("Orgzly")
.build();
}

public Drive getDriveService() {
if (mDriveService != null) return mDriveService;
return getDriveService(getGoogleAccount());
}

public void setDriveService() {
if (mDriveService == null) mDriveService = getDriveService();
}

public void setDriveService(GoogleSignInAccount googleAccount) {
mDriveService = getDriveService(googleAccount);
}

private void linkedOrThrow() throws IOException {
if (! isLinked()) {
throw new IOException(NOT_LINKED);
} else {
setDriveService();
}
}

@RequiresApi(api = Build.VERSION_CODES.N)
private String findId(String path) throws IOException {
if (pathIds.containsKey(path)) {
return pathIds.get(path);
}

String[] parts = path.split("/");
parts = Arrays.stream(parts).filter(s -> !s.isEmpty()).toArray(String[]::new);
String[] ids = new String[parts.length+1];

ids[0] = "root";
Expand All @@ -95,23 +124,21 @@ private String findId(String path) throws IOException {
.setSpaces("drive")
.setFields("files(id, name, mimeType)")
.execute();
List files = result.getFiles();
List<File> files = result.getFiles();
if (!files.isEmpty()) {
File file = (File) files.get(0);
ids[i+1] = file.getId();
}
}

for (int i = 0; i < ids.length; ++i) {
if (ids[i] == null) {
break;
}
pathIds.put(path, ids[i]);
if (ids[ids.length-1] != null) {
pathIds.put(path, ids[ids.length-1]);
}

return ids[ids.length-1]; // Returns null if no file is found
}

@RequiresApi(api = Build.VERSION_CODES.N)
public List<VersionedRook> getBooks(Uri repoUri) throws IOException {
linkedOrThrow();

Expand All @@ -129,24 +156,23 @@ public List<VersionedRook> getBooks(Uri repoUri) throws IOException {

try {

String folderId = findId(path);

String pathId = findId(path);

if (folderId != null) {
if (pathId != null) {

File folder = mDriveService.files().get(folderId)
.setFields("id, mimeType")
File folder = mDriveService.files().get(pathId)
.setFields("id, name, mimeType, version, modifiedTime")
.execute();

if (folder.getMimeType() == "application/vnd.google-apps.folder") {
if (folder.getMimeType().equals("application/vnd.google-apps.folder")) {

String pageToken = null;
do {
FileList result = mDriveService.files().list()
.setQ(String.format("mimeType != 'application/vnd.google-apps.folder' " +
"and '%s' in parents and trashed = false", folderId))
"and '%s' in parents and trashed = false", pathId))
.setSpaces("drive")
.setFields("nextPageToken, files(id, name, mimeType)")
.setFields("nextPageToken, files(id, name, mimeType, version, modifiedTime)")
.setPageToken(pageToken)
.execute();
for (File file : result.getFiles()) {
Expand All @@ -170,7 +196,7 @@ public List<VersionedRook> getBooks(Uri repoUri) throws IOException {
throw new IOException("Not a directory: " + repoUri);
}
} else {
throw new IOException("Not a directory: " + repoUri);
throw new IOException("Path not found: " + repoUri);
}

} catch (Exception e) {
Expand All @@ -187,6 +213,7 @@ public List<VersionedRook> getBooks(Uri repoUri) throws IOException {
/**
* Download file from Google Drive and store it to a local file.
*/
@RequiresApi(api = Build.VERSION_CODES.N)
public VersionedRook download(Uri repoUri, String fileName, java.io.File localFile) throws IOException {
linkedOrThrow();

Expand All @@ -200,10 +227,10 @@ public VersionedRook download(Uri repoUri, String fileName, java.io.File localFi

if (fileId != null) {
File file = mDriveService.files().get(fileId)
.setFields("id, mimeType, version, modifiedDate")
.setFields("id, mimeType, version, modifiedTime")
.execute();

if (file.getMimeType() != "application/vnd.google-apps.folder") {
if (!file.getMimeType().equals("application/vnd.google-apps.folder")) {

String rev = Long.toString(file.getVersion());
long mtime = file.getModifiedTime().getValue();
Expand Down Expand Up @@ -231,6 +258,7 @@ public VersionedRook download(Uri repoUri, String fileName, java.io.File localFi


/** Upload file to Google Drive. */
@RequiresApi(api = Build.VERSION_CODES.N)
public VersionedRook upload(java.io.File file, Uri repoUri, String fileName) throws IOException {
linkedOrThrow();

Expand Down Expand Up @@ -267,7 +295,7 @@ public VersionedRook upload(java.io.File file, Uri repoUri, String fileName) thr
pathIds.put(filePath, fileId);
} else {
fileMetadata = mDriveService.files().update(fileId, fileMetadata, mediaContent)
.setFields("id")
.setFields("id, version, modifiedTime")
.execute();
}

Expand All @@ -285,6 +313,7 @@ public VersionedRook upload(java.io.File file, Uri repoUri, String fileName) thr
return new VersionedRook(repoId, RepoType.GOOGLE_DRIVE, repoUri, bookUri, rev, mtime);
}

@RequiresApi(api = Build.VERSION_CODES.N)
public void delete(String path) throws IOException {
linkedOrThrow();

Expand All @@ -293,7 +322,7 @@ public void delete(String path) throws IOException {

if (fileId != null) {
File file = mDriveService.files().get(fileId).setFields("id, mimeType").execute();
if (file.getMimeType() != "application/vnd.google-apps.folder") {
if (!file.getMimeType().equals("application/vnd.google-apps.folder")) {
File fileMetadata = new File();
fileMetadata.setTrashed(true);
mDriveService.files().update(fileId, fileMetadata).execute();
Expand All @@ -313,6 +342,7 @@ public void delete(String path) throws IOException {
}
}

@RequiresApi(api = Build.VERSION_CODES.N)
public VersionedRook move(Uri repoUri, Uri from, Uri to) throws IOException {
linkedOrThrow();

Expand All @@ -324,10 +354,10 @@ public VersionedRook move(Uri repoUri, Uri from, Uri to) throws IOException {

if (fileId != null) {
fileMetadata = mDriveService.files().update(fileId, fileMetadata)
.setFields("id, mimeType, version, modifiedDate")
.setFields("id, mimeType, version, modifiedTime")
.execute();

if (fileMetadata.getMimeType() == "application/vnd.google-apps.folder") {
if (fileMetadata.getMimeType().equals("application/vnd.google-apps.folder")) {
throw new IOException("Relocated object not a file?");
}

Expand All @@ -336,7 +366,7 @@ public VersionedRook move(Uri repoUri, Uri from, Uri to) throws IOException {
String rev = Long.toString(fileMetadata.getVersion());
long mtime = fileMetadata.getModifiedTime().getValue();

return new VersionedRook(repoId, RepoType.DROPBOX, repoUri, to, rev, mtime);
return new VersionedRook(repoId, RepoType.GOOGLE_DRIVE, repoUri, to, rev, mtime);

} catch (Exception e) {
e.printStackTrace();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.orgzly.android.ui.repo.googledrive

import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.content.DialogInterface
Expand All @@ -10,7 +9,6 @@ import android.os.Bundle
import android.text.TextUtils
import android.view.Menu
import android.view.MenuItem
import android.widget.EditText
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
Expand Down Expand Up @@ -39,14 +37,9 @@ import com.google.android.gms.common.api.Scope;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.OnCompleteListener;

import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;

import androidx.annotation.NonNull;
import java.util.Collections;

import android.util.Log;

Expand Down Expand Up @@ -154,28 +147,17 @@ class GoogleDriveRepoActivity : CommonActivity() {
handleSignInResult(requestCode, resultData)
}

fun handleSignInResult(requestCode:Int, result:Intent?) {
private fun handleSignInResult(requestCode:Int, result:Intent?) {
if (requestCode == REQUEST_CODE_SIGN_IN)
{
GoogleSignIn.getSignedInAccountFromIntent(result)
.addOnSuccessListener({ googleAccount->
Log.d(TAG, "Signed in as " + googleAccount.getEmail())
// Use the authenticated account to sign in to the Drive service.
val credential = GoogleAccountCredential.usingOAuth2(
this, Collections.singleton(DriveScopes.DRIVE))
credential.setSelectedAccount(googleAccount.getAccount())
val googleDriveService = Drive.Builder(
AndroidHttp.newCompatibleTransport(),
GsonFactory(),
credential)
.setApplicationName("Orgzly")
.build()
// The DriveServiceHelper encapsulates all REST API and SAF functionality.
// Its instantiation is required before handling any onClick actions.
client.setService(googleDriveService);
showSnackbar(R.string.message_google_drive_linked)
})
.addOnFailureListener({ exception-> Log.d(TAG, "Unable to sign in." + exception) })
.addOnSuccessListener { googleAccount ->
Log.d(TAG, "Signed in as " + googleAccount.getEmail())
// Use the authenticated account to sign in to the Drive service.
client.setDriveService(googleAccount)
showSnackbar(R.string.message_google_drive_linked)
}
.addOnFailureListener { exception -> Log.d(TAG, "Unable to sign in.$exception") }
}
}

Expand Down

0 comments on commit c54f227

Please sign in to comment.