mirror of https://github.com/tasks/tasks
Add option to copy backup files to Google Drive
parent
f471b47b12
commit
31fb7e4397
@ -0,0 +1,104 @@
|
||||
package org.tasks.drive;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
|
||||
import com.google.api.client.http.InputStreamContent;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
import com.google.api.client.json.GenericJson;
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
import com.google.api.client.util.ExponentialBackOff;
|
||||
import com.google.api.services.drive.Drive;
|
||||
import com.google.api.services.drive.DriveRequest;
|
||||
import com.google.api.services.drive.DriveScopes;
|
||||
import com.google.api.services.drive.model.File;
|
||||
|
||||
import org.tasks.BuildConfig;
|
||||
import org.tasks.R;
|
||||
import org.tasks.injection.ForApplication;
|
||||
import org.tasks.preferences.Preferences;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class DriveInvoker {
|
||||
|
||||
private final Drive service;
|
||||
private final Context context;
|
||||
|
||||
@Inject
|
||||
public DriveInvoker(@ForApplication Context context, Preferences preferences) {
|
||||
this.context = context;
|
||||
if (preferences.getBoolean(R.string.p_google_drive_backup, false)) {
|
||||
GoogleAccountCredential credential =
|
||||
GoogleAccountCredential.usingOAuth2(
|
||||
context, Collections.singletonList(DriveScopes.DRIVE_FILE))
|
||||
.setBackOff(new ExponentialBackOff.Builder().build())
|
||||
.setSelectedAccountName(
|
||||
preferences.getStringValue(R.string.p_google_drive_backup_account));
|
||||
service =
|
||||
new Drive.Builder(new NetHttpTransport(), new JacksonFactory(), credential)
|
||||
.setApplicationName(String.format("Tasks/%s", BuildConfig.VERSION_NAME))
|
||||
.build();
|
||||
} else {
|
||||
service = null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<File> findFolder(String name) throws IOException {
|
||||
String query = String.format("name='%s'", name);
|
||||
return execute(service.files().list().setQ(query).setSpaces("drive")).getFiles();
|
||||
}
|
||||
|
||||
public File createFolder(String name) throws IOException {
|
||||
File folder = new File()
|
||||
.setName(name)
|
||||
.setMimeType("application/vnd.google-apps.folder");
|
||||
|
||||
return execute(service.files().create(folder).setFields("id"));
|
||||
}
|
||||
|
||||
public void createFile(String mime, String parent, String name, Uri uri) throws IOException {
|
||||
File metadata = new File()
|
||||
.setParents(Collections.singletonList(parent))
|
||||
.setMimeType(mime)
|
||||
.setName(name);
|
||||
InputStreamContent content =
|
||||
new InputStreamContent(mime, context.getContentResolver().openInputStream(uri));
|
||||
execute(service.files().create(metadata, content));
|
||||
}
|
||||
|
||||
private synchronized <T> T execute(DriveRequest<T> request) throws IOException {
|
||||
String caller = getCaller();
|
||||
Timber.d("%s request: %s", caller, request);
|
||||
T response = request.execute();
|
||||
Timber.d("%s response: %s", caller, prettyPrint(response));
|
||||
return response;
|
||||
}
|
||||
|
||||
private <T> Object prettyPrint(T object) throws IOException {
|
||||
if (BuildConfig.DEBUG) {
|
||||
if (object instanceof GenericJson) {
|
||||
return ((GenericJson) object).toPrettyString();
|
||||
}
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
private String getCaller() {
|
||||
if (BuildConfig.DEBUG) {
|
||||
try {
|
||||
return Thread.currentThread().getStackTrace()[4].getMethodName();
|
||||
} catch (Exception e) {
|
||||
Timber.e(e);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/**
|
||||
* Copyright (c) 2012 Todoroo Inc
|
||||
*
|
||||
* <p>See the file "LICENSE" for the full license governing this code.
|
||||
*/
|
||||
package org.tasks.drive;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
import com.todoroo.andlib.utility.DialogUtilities;
|
||||
import javax.inject.Inject;
|
||||
import org.tasks.R;
|
||||
import org.tasks.dialogs.DialogBuilder;
|
||||
import org.tasks.gtasks.GoogleAccountManager;
|
||||
import org.tasks.gtasks.PlayServices;
|
||||
import org.tasks.injection.ActivityComponent;
|
||||
import org.tasks.injection.InjectingAppCompatActivity;
|
||||
import org.tasks.play.AuthResultHandler;
|
||||
import org.tasks.preferences.Preferences;
|
||||
|
||||
/**
|
||||
* This activity allows users to sign in or log in to Google Tasks through the Android account
|
||||
* manager
|
||||
*
|
||||
* @author Sam Bosley
|
||||
*/
|
||||
public class DriveLoginActivity extends InjectingAppCompatActivity {
|
||||
|
||||
public static final int RC_REQUEST_OAUTH = 10987;
|
||||
private static final int RC_CHOOSE_ACCOUNT = 10988;
|
||||
@Inject DialogBuilder dialogBuilder;
|
||||
@Inject GoogleAccountManager accountManager;
|
||||
@Inject PlayServices playServices;
|
||||
@Inject Preferences preferences;
|
||||
private String accountName;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Intent chooseAccountIntent =
|
||||
android.accounts.AccountManager.newChooseAccountIntent(
|
||||
null, null, new String[] {"com.google"}, false, null, null, null, null);
|
||||
startActivityForResult(chooseAccountIntent, RC_CHOOSE_ACCOUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(ActivityComponent component) {
|
||||
component.inject(this);
|
||||
}
|
||||
|
||||
private void getAuthToken(String account) {
|
||||
final ProgressDialog pd = dialogBuilder.newProgressDialog(R.string.gtasks_GLA_authenticating);
|
||||
pd.show();
|
||||
accountName = account;
|
||||
getAuthToken(account, pd);
|
||||
}
|
||||
|
||||
private void getAuthToken(String a, final ProgressDialog pd) {
|
||||
playServices.getDriveAuthToken(
|
||||
this,
|
||||
a,
|
||||
new AuthResultHandler() {
|
||||
@Override
|
||||
public void authenticationSuccessful(String accountName) {
|
||||
preferences.setString(R.string.p_google_drive_backup_account, accountName);
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
DialogUtilities.dismissDialog(DriveLoginActivity.this, pd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void authenticationFailed(final String message) {
|
||||
runOnUiThread(
|
||||
() -> Toast.makeText(DriveLoginActivity.this, message, Toast.LENGTH_LONG).show());
|
||||
DialogUtilities.dismissDialog(DriveLoginActivity.this, pd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == RC_CHOOSE_ACCOUNT && resultCode == RESULT_OK) {
|
||||
String account = data.getStringExtra(android.accounts.AccountManager.KEY_ACCOUNT_NAME);
|
||||
getAuthToken(account);
|
||||
} else if (requestCode == RC_REQUEST_OAUTH && resultCode == RESULT_OK) {
|
||||
final ProgressDialog pd = dialogBuilder.newProgressDialog(R.string.gtasks_GLA_authenticating);
|
||||
pd.show();
|
||||
getAuthToken(accountName, pd);
|
||||
} else {
|
||||
// User didn't give permission--cancel
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
package org.tasks.gtasks;
|
||||
|
||||
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
|
||||
import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler;
|
||||
import com.google.api.client.http.HttpRequest;
|
||||
import com.google.api.client.http.HttpResponse;
|
||||
import com.google.api.client.http.HttpResponseException;
|
||||
import com.google.api.client.http.HttpStatusCodes;
|
||||
import com.google.api.client.http.HttpUnsuccessfulResponseHandler;
|
||||
import com.google.api.client.util.BackOff;
|
||||
import com.google.api.client.util.ExponentialBackOff;
|
||||
import com.todoroo.astrid.gtasks.api.HttpNotFoundException;
|
||||
import java.io.IOException;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class GoogleTasksUnsuccessfulResponseHandler implements HttpUnsuccessfulResponseHandler {
|
||||
|
||||
private static final BackOff BACKOFF = new ExponentialBackOff.Builder().build();
|
||||
|
||||
private final PlayServices playServices;
|
||||
private final GoogleAccountCredential googleAccountCredential;
|
||||
private final HttpBackOffUnsuccessfulResponseHandler backoffHandler =
|
||||
new HttpBackOffUnsuccessfulResponseHandler(BACKOFF);
|
||||
|
||||
public GoogleTasksUnsuccessfulResponseHandler(
|
||||
PlayServices playServices, GoogleAccountCredential googleAccountCredential) {
|
||||
this.playServices = playServices;
|
||||
this.googleAccountCredential = googleAccountCredential;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleResponse(HttpRequest request, HttpResponse response, boolean supportsRetry)
|
||||
throws IOException {
|
||||
HttpResponseException httpResponseException = new HttpResponseException(response);
|
||||
Timber.e(httpResponseException);
|
||||
if (!supportsRetry) {
|
||||
return false;
|
||||
}
|
||||
int statusCode = response.getStatusCode();
|
||||
if ((statusCode == HttpStatusCodes.STATUS_CODE_UNAUTHORIZED
|
||||
|| statusCode == HttpStatusCodes.STATUS_CODE_FORBIDDEN)) {
|
||||
boolean shouldRetry = playServices.clearToken(googleAccountCredential);
|
||||
if (!shouldRetry) {
|
||||
return false;
|
||||
}
|
||||
} else if (statusCode == 400) { // bad request
|
||||
throw httpResponseException;
|
||||
} else if (statusCode == HttpStatusCodes.STATUS_CODE_NOT_FOUND) {
|
||||
throw new HttpNotFoundException(httpResponseException);
|
||||
}
|
||||
|
||||
return backoffHandler.handleResponse(request, response, supportsRetry);
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package org.tasks.play;
|
||||
|
||||
public interface AuthResultHandler {
|
||||
void authenticationSuccessful(String accountName);
|
||||
|
||||
void authenticationFailed(String message);
|
||||
}
|
Loading…
Reference in New Issue