Add Google Smart Lock.

You now no longer have to type in your email and password, with Google
Smart Lock.

Simply tap "Basic Authentication", and if you've previously logged in,
let Google do it's magic and you don't even touch that log-in form.
This commit is contained in:
Jedi Burrell 2017-05-20 00:53:33 -04:00
parent f490acb1b1
commit 7dc4b2b4b7
6 changed files with 125 additions and 13 deletions

View File

@ -25,7 +25,7 @@ android {
}
}
compileSdkVersion 'android-O'
buildToolsVersion "26.0.0-rc1"
buildToolsVersion "26.0.0-rc2"
defaultConfig {
applicationId "com.fastaccess.github"
minSdkVersion 21
@ -162,6 +162,7 @@ dependencies {
compile "com.google.firebase:firebase-messaging:${firebase}"
releaseCompile "com.google.firebase:firebase-crash:${firebase}"
}
compile "com.google.android.gms:play-services-auth:10.2.6"
testCompile "junit:junit:${junitVersion}"
testCompile "org.mockito:mockito-core:${mockitoVersion}"
testCompile "org.assertj:assertj-core:${assertjVersion}"

View File

@ -8,6 +8,9 @@ import com.fastaccess.data.dao.model.Models;
import com.fastaccess.helper.TypeFaceHelper;
import com.fastaccess.provider.tasks.notification.NotificationSchedulerJobTask;
import com.fastaccess.provider.uil.UILProvider;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.common.api.GoogleApiClient;
import io.requery.Persistable;
import io.requery.android.sqlite.DatabaseSource;
@ -27,6 +30,7 @@ import shortbread.Shortbread;
public class App extends Application {
private static App instance;
private SingleEntityStore<Persistable> dataStore;
private static GoogleApiClient googleApiClient;
@Override public void onCreate() {
super.onCreate();
@ -46,6 +50,10 @@ public class App extends Application {
TypeFaceHelper.generateTypeface(this);
NotificationSchedulerJobTask.scheduleJob(this);
Shortbread.create(this);
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(Auth.CREDENTIALS_API)
.build();
googleApiClient.connect();
}
public SingleEntityStore<Persistable> getDataStore() {
@ -60,4 +68,8 @@ public class App extends Application {
}
return dataStore;
}
public GoogleApiClient getGoogleApiClient() {
return googleApiClient;
}
}

View File

@ -32,6 +32,7 @@ import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.helper.PrefGetter;
import com.fastaccess.helper.PrefHelper;
import com.fastaccess.helper.ViewHelper;
import com.fastaccess.ui.base.mvp.BaseMvp;
import com.fastaccess.ui.base.mvp.presenter.BasePresenter;
@ -50,6 +51,7 @@ import com.fastaccess.ui.modules.user.UserPagerActivity;
import com.fastaccess.ui.widgets.AvatarLayout;
import com.fastaccess.ui.widgets.dialog.MessageDialogView;
import com.fastaccess.ui.widgets.dialog.ProgressDialogFragment;
import com.google.android.gms.auth.api.Auth;
import com.nostra13.universalimageloader.core.ImageLoader;
import java.util.ArrayList;
@ -139,7 +141,11 @@ public abstract class BaseActivity<V extends BaseMvp.FAView, P extends BasePrese
@Override public void onMessageDialogActionClicked(boolean isOk, @Nullable Bundle bundle) {
if (isOk && bundle != null) {
boolean logout = bundle.getBoolean("logout");
if (logout) onRequireLogin();
if (logout){
onRequireLogin();
//if(App.getInstance().getGoogleApiClient().isConnected())
//Auth.CredentialsApi.disableAutoSignIn(App.getInstance().getGoogleApiClient());
}
}
}//pass
@ -193,7 +199,7 @@ public abstract class BaseActivity<V extends BaseMvp.FAView, P extends BasePrese
Toasty.warning(this, getString(R.string.unauthorized_user), Toast.LENGTH_LONG).show();
ImageLoader.getInstance().clearDiskCache();
ImageLoader.getInstance().clearMemoryCache();
PrefGetter.clear();
PrefHelper.clearKey("token");
App.getInstance().getDataStore()
.delete(Login.class)
.get()

View File

@ -3,6 +3,7 @@ package com.fastaccess.ui.modules.login;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -12,13 +13,16 @@ import android.support.annotation.StringRes;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TextInputEditText;
import android.support.design.widget.TextInputLayout;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import com.fastaccess.App;
import com.fastaccess.BuildConfig;
import com.fastaccess.R;
import com.fastaccess.data.dao.model.Login;
import com.fastaccess.helper.ActivityHelper;
import com.fastaccess.helper.AnimHelper;
import com.fastaccess.helper.BundleConstant;
@ -28,8 +32,10 @@ import com.fastaccess.helper.PrefHelper;
import com.fastaccess.ui.base.BaseActivity;
import com.fastaccess.ui.modules.main.MainActivity;
import com.fastaccess.ui.modules.settings.LanguageBottomSheetDialog;
import com.fastaccess.ui.modules.settings.SlackBottomSheetDialog;
import com.fastaccess.ui.widgets.FontEditText;
import com.google.android.gms.auth.api.Auth;
import com.google.android.gms.auth.api.credentials.Credential;
import com.google.android.gms.auth.api.credentials.CredentialRequest;
import com.google.android.gms.common.api.GoogleApiClient;
import java.util.Arrays;
import java.util.Locale;
@ -57,6 +63,10 @@ public class LoginActivity extends BaseActivity<LoginMvp.View, LoginPresenter> i
@Nullable @BindView(R.id.login) FloatingActionButton login;
@Nullable @BindView(R.id.progress) ProgressBar progress;
private String pass;
private static int RESOLUTION_CODE = 100;
private static int RESOLUTION_CHOOSER_CODE = 101;
@State boolean isBasicAuth;
public static void start(@NonNull Activity activity, boolean isBasicAuth) {
@ -65,6 +75,7 @@ public class LoginActivity extends BaseActivity<LoginMvp.View, LoginPresenter> i
.put(BundleConstant.YES_NO_EXTRA, isBasicAuth)
.end());
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("smartLock", true);
activity.startActivity(intent);
activity.finish();
}
@ -138,11 +149,43 @@ public class LoginActivity extends BaseActivity<LoginMvp.View, LoginPresenter> i
hideProgress();
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(SlackBottomSheetDialog.TAG, true);
startActivity(intent);
finishAffinity();
}
@Override public void onSuccessfullyLoggedIn(Login userModel) {
Credential credential = new Credential.Builder(userModel.getLogin())
.setPassword(pass)
.setProfilePictureUri(Uri.parse(userModel.getAvatarUrl()))
.build();
Auth.CredentialsApi.save(App.getInstance().getGoogleApiClient(), credential).setResultCallback(status -> {
if(status.isSuccess()) {
onSuccessfullyLoggedIn();
} else if(status.hasResolution()){
try {
status.startResolutionForResult(this, RESOLUTION_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
Log.e(getLoggingTag(), status+"");
onSuccessfullyLoggedIn();
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode==RESOLUTION_CODE) {
onSuccessfullyLoggedIn();
} else if (requestCode==RESOLUTION_CHOOSER_CODE) {
if (resultCode==RESULT_OK) {
Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
doLogin(credential.getId(), credential.getPassword());
}
}
}
@Override protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.LoginTheme);
super.onCreate(savedInstanceState);
@ -166,6 +209,43 @@ public class LoginActivity extends BaseActivity<LoginMvp.View, LoginPresenter> i
if(!Locale.getDefault().getLanguage().equals(language))
recreate();
}
if(isBasicAuth&&getIntent()!=null)
if(getIntent().hasExtra("smartLock"))
if(App.getInstance().getGoogleApiClient().isConnecting()&&
!App.getInstance().getGoogleApiClient().isConnected()) {
App.getInstance().getGoogleApiClient().registerConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(@Nullable Bundle bundle) {
doCredentialRequest();
}
@Override
public void onConnectionSuspended(int i) {
}
});
} else {
doCredentialRequest();
}
}
private void doCredentialRequest() {
CredentialRequest credentialRequest = new CredentialRequest.Builder()
.setPasswordLoginSupported(true)
.build();
Auth.CredentialsApi.request(App.getInstance().getGoogleApiClient(), credentialRequest).setResultCallback(credentialRequestResult -> {
if(credentialRequestResult.getStatus().isSuccess()) {
doLogin(credentialRequestResult.getCredential().getId(),
credentialRequestResult.getCredential().getPassword());
} else if(credentialRequestResult.getStatus().hasResolution())
try {
credentialRequestResult.getStatus().startResolutionForResult(this, RESOLUTION_CHOOSER_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
else {
Log.e(getLoggingTag(), credentialRequestResult.getStatus()+"");
}
});
}
private void showLanguage() {
@ -225,7 +305,15 @@ public class LoginActivity extends BaseActivity<LoginMvp.View, LoginPresenter> i
getPresenter().login(InputHelper.toString(username),
InputHelper.toString(password),
InputHelper.toString(twoFactor),
isBasicAuth);
isBasicAuth, false);
}
}
private void doLogin(String username, String password) {
if (progress == null || twoFactor == null || username == null || password == null) return;
if (progress.getVisibility() == View.GONE) {
pass = password;
getPresenter().login(username, password, "", isBasicAuth, true);
}
}
}

View File

@ -23,6 +23,8 @@ public interface LoginMvp {
void onEmptyPassword(boolean isEmpty);
void onSuccessfullyLoggedIn(Login userModel);
void onSuccessfullyLoggedIn();
}
@ -36,6 +38,6 @@ public interface LoginMvp {
void onUserResponse(@Nullable Login response);
void login(@NonNull String username, @NonNull String password, @Nullable String twoFactorCode, boolean isBasicAuth);
void login(@NonNull String username, @NonNull String password, @Nullable String twoFactorCode, boolean isBasicAuth, @Nullable boolean ignore);
}
}

View File

@ -101,20 +101,23 @@ public class LoginPresenter extends BasePresenter<LoginMvp.View> implements Logi
if (userModel != null) {
userModel.setToken(PrefGetter.getToken());
userModel.save(userModel);
sendToView(LoginMvp.View::onSuccessfullyLoggedIn);
if(getView()!=null)
getView().onSuccessfullyLoggedIn(userModel);
else
sendToView(LoginMvp.View::onSuccessfullyLoggedIn);
return;
}
sendToView(view -> view.showMessage(R.string.error, R.string.failed_login));
}
@Override public void login(@NonNull String username, @NonNull String password,
@Nullable String twoFactorCode, boolean isBasicAuth) {
@Nullable String twoFactorCode, boolean isBasicAuth, boolean ignore) {
boolean usernameIsEmpty = InputHelper.isEmpty(username);
boolean passwordIsEmpty = InputHelper.isEmpty(password);
if (getView() == null) return;
getView().onEmptyUserName(usernameIsEmpty);
getView().onEmptyPassword(passwordIsEmpty);
if (!usernameIsEmpty && !passwordIsEmpty) {
getView().onEmptyUserName(!ignore&&usernameIsEmpty);
getView().onEmptyPassword(!ignore&&passwordIsEmpty);
if ((!usernameIsEmpty && !passwordIsEmpty) || ignore) {
String authToken = Credentials.basic(username, password);
if (isBasicAuth) {
AuthModel authModel = new AuthModel();