Fetch oauth tokens with coroutines

pull/1216/head
Alex Baker 5 years ago
parent b4df28ae3b
commit 0664e23076

@ -62,7 +62,7 @@ class HttpCredentialsAdapter @Inject constructor(private val googleAccountManage
}
}
fun checkToken(account: String?, scope: String) {
suspend fun checkToken(account: String?, scope: String) {
if (credentials == null) {
val token = googleAccountManager.getAccessToken(account, scope)
credentials = GoogleCredentials(AccessToken(token, null))

@ -25,7 +25,6 @@ import org.tasks.data.GoogleTaskListDao
import org.tasks.dialogs.DialogBuilder
import org.tasks.gtasks.GoogleAccountManager
import org.tasks.injection.InjectingAppCompatActivity
import org.tasks.play.AuthResultHandler
import org.tasks.preferences.ActivityPermissionRequestor
import org.tasks.preferences.PermissionRequestor
import javax.inject.Inject
@ -57,19 +56,20 @@ class GtasksLoginActivity : InjectingAppCompatActivity() {
startActivityForResult(chooseAccountIntent, RC_CHOOSE_ACCOUNT)
}
private fun getAuthToken(account: String) {
private suspend fun getAuthToken(account: String) {
val pd = dialogBuilder.newProgressDialog(R.string.gtasks_GLA_authenticating)
pd.show()
getAuthToken(account, pd)
}
private fun getAuthToken(a: String, pd: ProgressDialog) {
googleAccountManager.getTasksAuthToken(
this,
a,
object : AuthResultHandler {
override fun authenticationSuccessful(accountName: String) {
lifecycleScope.launch {
private suspend fun getAuthToken(accountName: String, pd: ProgressDialog) {
try {
googleAccountManager.getTasksAuthToken(this, accountName)
?.let { bundle ->
val intent = bundle[AccountManager.KEY_INTENT]
if (intent is Intent) {
startActivity(intent)
} else {
withContext(NonCancellable) {
var account = googleTaskListDao.getAccount(accountName)
if (account == null) {
@ -92,19 +92,20 @@ class GtasksLoginActivity : InjectingAppCompatActivity() {
}
}
override fun authenticationFailed(message: String?) {
setResult(Activity.RESULT_CANCELED, Intent().putExtra(EXTRA_ERROR, message))
DialogUtilities.dismissDialog(this@GtasksLoginActivity, pd)
finish()
}
})
} catch (e: Exception) {
setResult(Activity.RESULT_CANCELED, Intent().putExtra(EXTRA_ERROR, e.message))
DialogUtilities.dismissDialog(this@GtasksLoginActivity, pd)
finish()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == RC_CHOOSE_ACCOUNT) {
if (resultCode == Activity.RESULT_OK) {
val account = data!!.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)!!
getAuthToken(account)
lifecycleScope.launch {
getAuthToken(account)
}
} else {
finish()
}

@ -1,90 +0,0 @@
/*
* Copyright (c) 2012 Todoroo Inc
*
* 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 com.todoroo.andlib.utility.DialogUtilities;
import dagger.hilt.android.AndroidEntryPoint;
import javax.inject.Inject;
import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.gtasks.GoogleAccountManager;
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
*/
@AndroidEntryPoint
public class DriveLoginActivity extends InjectingAppCompatActivity {
public static final String EXTRA_ERROR = "extra_error";
private static final int RC_CHOOSE_ACCOUNT = 10988;
@Inject DialogBuilder dialogBuilder;
@Inject GoogleAccountManager googleAccountManager;
@Inject Preferences preferences;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent chooseAccountIntent =
android.accounts.AccountManager.newChooseAccountIntent(
null, null, new String[] {"com.google"}, null, null, null, null);
startActivityForResult(chooseAccountIntent, RC_CHOOSE_ACCOUNT);
}
private void getAuthToken(String account) {
final ProgressDialog pd = dialogBuilder.newProgressDialog(R.string.gtasks_GLA_authenticating);
pd.show();
getAuthToken(account, pd);
}
private void getAuthToken(String a, final ProgressDialog pd) {
googleAccountManager.getDriveAuthToken(
this,
a,
new AuthResultHandler() {
@Override
public void authenticationSuccessful(String accountName) {
preferences.setString(R.string.p_google_drive_backup_account, accountName);
preferences.setBoolean(R.string.p_google_drive_backup, true);
setResult(RESULT_OK);
DialogUtilities.dismissDialog(DriveLoginActivity.this, pd);
finish();
}
@Override
public void authenticationFailed(final String message) {
preferences.setBoolean(R.string.p_google_drive_backup, false);
setResult(RESULT_CANCELED, new Intent().putExtra(EXTRA_ERROR, message));
DialogUtilities.dismissDialog(DriveLoginActivity.this, pd);
finish();
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RC_CHOOSE_ACCOUNT) {
if (resultCode == RESULT_OK) {
String account = data.getStringExtra(android.accounts.AccountManager.KEY_ACCOUNT_NAME);
getAuthToken(account);
} else {
finish();
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}

@ -0,0 +1,90 @@
/*
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package org.tasks.drive
import android.accounts.AccountManager
import android.app.ProgressDialog
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import com.todoroo.andlib.utility.DialogUtilities
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import org.tasks.R
import org.tasks.dialogs.DialogBuilder
import org.tasks.gtasks.GoogleAccountManager
import org.tasks.injection.InjectingAppCompatActivity
import org.tasks.preferences.Preferences
import javax.inject.Inject
/**
* This activity allows users to sign in or log in to Google Tasks through the Android account
* manager
*
* @author Sam Bosley
*/
@AndroidEntryPoint
class DriveLoginActivity : InjectingAppCompatActivity() {
@Inject lateinit var dialogBuilder: DialogBuilder
@Inject lateinit var googleAccountManager: GoogleAccountManager
@Inject lateinit var preferences: Preferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val chooseAccountIntent = AccountManager.newChooseAccountIntent(
null, null, arrayOf("com.google"), null, null, null, null)
startActivityForResult(chooseAccountIntent, RC_CHOOSE_ACCOUNT)
}
private suspend fun getAuthToken(account: String?) {
val pd = dialogBuilder.newProgressDialog(R.string.gtasks_GLA_authenticating)
pd.show()
getAuthToken(account, pd)
}
private suspend fun getAuthToken(accountName: String?, pd: ProgressDialog) {
try {
googleAccountManager.getDriveAuthToken(this, accountName!!)
?.let { bundle ->
val intent = bundle[AccountManager.KEY_INTENT]
if (intent is Intent) {
startActivity(intent)
} else {
preferences.setString(R.string.p_google_drive_backup_account, accountName)
preferences.setBoolean(R.string.p_google_drive_backup, true)
setResult(RESULT_OK)
DialogUtilities.dismissDialog(this@DriveLoginActivity, pd)
finish()
}
}
} catch (e: Exception) {
preferences.setBoolean(R.string.p_google_drive_backup, false)
setResult(RESULT_CANCELED, Intent().putExtra(EXTRA_ERROR, e.message))
DialogUtilities.dismissDialog(this@DriveLoginActivity, pd)
finish()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == RC_CHOOSE_ACCOUNT) {
if (resultCode == RESULT_OK) {
val account = data!!.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)
lifecycleScope.launch {
getAuthToken(account)
}
} else {
finish()
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
companion object {
const val EXTRA_ERROR = "extra_error"
private const val RC_CHOOSE_ACCOUNT = 10988
}
}

@ -7,19 +7,15 @@ import android.accounts.OperationCanceledException
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.google.api.services.drive.DriveScopes
import com.google.api.services.tasks.TasksScopes
import com.google.common.collect.Lists
import com.todoroo.andlib.utility.AndroidUtilities
import dagger.hilt.android.qualifiers.ApplicationContext
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.tasks.R
import org.tasks.Strings.isNullOrEmpty
import org.tasks.play.AuthResultHandler
import org.tasks.preferences.PermissionChecker
import org.tasks.preferences.Preferences
import timber.log.Timber
@ -43,7 +39,7 @@ class GoogleAccountManager @Inject constructor(
emptyList()
}
fun getAccount(name: String): Account? = if (isNullOrEmpty(name)) {
fun getAccount(name: String?): Account? = if (isNullOrEmpty(name)) {
null
} else {
accountList.find { name.equals(it.name, ignoreCase = true) }
@ -53,16 +49,17 @@ class GoogleAccountManager @Inject constructor(
return getAccount(name) != null
}
fun getAccessToken(name: String, scope: String): String? {
AndroidUtilities.assertNotMainThread()
val account = getAccount(name)
suspend fun getAccessToken(name: String?, scope: String): String? {
val account = name?.let { getAccount(it) }
if (account == null) {
Timber.e("Cannot find account %s", name)
return null
}
val alreadyNotified = preferences.alreadyNotified(name, scope)
return try {
val token = accountManager.blockingGetAuthToken(account, "oauth2:$scope", !alreadyNotified)
val token = withContext(Dispatchers.IO) {
accountManager.blockingGetAuthToken(account, "oauth2:$scope", !alreadyNotified)
}
preferences.setAlreadyNotified(name, scope, isNullOrEmpty(token))
token
} catch (e: AuthenticatorException) {
@ -77,44 +74,26 @@ class GoogleAccountManager @Inject constructor(
}
}
fun getTasksAuthToken(activity: Activity, accountName: String, handler: AuthResultHandler) {
getToken(TasksScopes.TASKS, activity, accountName, handler)
suspend fun getTasksAuthToken(activity: Activity, accountName: String): Bundle? {
return getToken(TasksScopes.TASKS, activity, accountName)
}
fun getDriveAuthToken(activity: Activity, accountName: String, handler: AuthResultHandler) {
getToken(DriveScopes.DRIVE_FILE, activity, accountName, handler)
suspend fun getDriveAuthToken(activity: Activity, accountName: String): Bundle? {
return getToken(DriveScopes.DRIVE_FILE, activity, accountName)
}
@SuppressLint("CheckResult")
private fun getToken(
scope: String, activity: Activity, accountName: String, handler: AuthResultHandler) {
private suspend fun getToken(scope: String, activity: Activity, accountName: String): Bundle? {
val account = getAccount(accountName)
Single.fromCallable {
if (account == null) {
throw RuntimeException(
?: throw RuntimeException(
activity.getString(R.string.gtasks_error_accountNotFound, accountName))
}
AndroidUtilities.assertNotMainThread()
accountManager
return withContext(Dispatchers.IO) {
val bundle = accountManager
.getAuthToken(account, "oauth2:$scope", Bundle(), activity, null, null)
.result
preferences.setAlreadyNotified(accountName, scope, false)
bundle
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ bundle: Bundle ->
preferences.setAlreadyNotified(accountName, scope, false)
val intent = bundle[AccountManager.KEY_INTENT] as Intent?
if (intent != null) {
activity.startActivity(intent)
} else {
handler.authenticationSuccessful(accountName)
}
}
) { e: Throwable ->
Timber.e(e)
handler.authenticationFailed(e.message)
}
}
fun invalidateToken(token: String?) {

@ -1,7 +0,0 @@
package org.tasks.play
interface AuthResultHandler {
fun authenticationSuccessful(accountName: String)
fun authenticationFailed(message: String?)
}
Loading…
Cancel
Save