Merge pull request #514 from JediBurrell/master

Fix #512, Add Google Smart Lock, Android O Autofill, Fix Bug.
This commit is contained in:
Jedi Burrell 2017-05-20 06:38:58 -04:00 committed by GitHub
commit ebcf4fa495
11 changed files with 328 additions and 54 deletions

View File

@ -24,12 +24,12 @@ android {
storePassword((buildProperties.secrets['android_store_password'] | buildProperties.notThere['android_store_password']).string)
}
}
compileSdkVersion 25
buildToolsVersion "26-rc1"
compileSdkVersion 'android-O'
buildToolsVersion "26.0.0-rc2"
defaultConfig {
applicationId "com.fastaccess.github"
minSdkVersion 21
targetSdkVersion 26
targetSdkVersion 'O'
versionCode 210
versionName "2.1.0"
signingConfig signingConfigs.signing
@ -107,12 +107,6 @@ android {
testOptions {
unitTests.returnDefaultValues = true
}
splits{
density{
enable true
}
}
}
repositories {
@ -143,11 +137,11 @@ dependencies {
compile "com.jakewharton:butterknife:${butterKnifeVersion}"
compile 'it.sephiroth.android.library.bottomnavigation:bottom-navigation:2.0.1-rc1'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.2.2'
compile 'io.reactivex:rxjava:1.2.3'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
compile 'com.annimon:stream:1.1.7'
compile 'com.github.GrenderG:Toasty:1.1.3'
compile 'uk.co.samuelwall:material-tap-target-prompt:1.9.2'
compile 'com.github.JediBurrell:MaterialTapTargetPrompt:-SNAPSHOT'
compile 'com.github.k0shk0sh:RetainedDateTimePickers:1.0.2'
compile 'com.github.daniel-stoneuk:material-about-library:1.8.1'
compile 'io.requery:requery:1.3.0'
@ -168,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

@ -1,11 +1,9 @@
package com.fastaccess.ui.base;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.TextView;
import com.fastaccess.R;
import com.fastaccess.helper.PrefGetter;
import net.grandcentrix.thirtyinch.TiActivity;
import net.grandcentrix.thirtyinch.TiPresenter;

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

@ -134,7 +134,7 @@ public class GithubActionService extends IntentService {
private void starGist(@Nullable String id) {
if (id != null) {
String msg = getString(R.string.staring, getString(R.string.gist));
String msg = getString(R.string.starring, getString(R.string.gist));
RestProvider.getGistService()
.starGist(id)
.doOnSubscribe(() -> showNotification(msg))
@ -146,7 +146,7 @@ public class GithubActionService extends IntentService {
private void starRepo(@Nullable String id, @Nullable String login) {
if (id != null && login != null) {
String msg = getString(R.string.staring, id);
String msg = getString(R.string.starring, id);
RestProvider.getRepoService()
.starRepo(login, id)
.doOnSubscribe(() -> showNotification(msg))
@ -158,7 +158,7 @@ public class GithubActionService extends IntentService {
private void unStarGist(@Nullable String id) {
if (id != null) {
String msg = getString(R.string.un_staring, getString(R.string.gist));
String msg = getString(R.string.un_starring, getString(R.string.gist));
RestProvider.getGistService()
.unStarGist(id)
.doOnSubscribe(() -> showNotification(msg))
@ -170,7 +170,7 @@ public class GithubActionService extends IntentService {
private void unStarRepo(@Nullable String id, @Nullable String login) {
if (id != null && login != null) {
String msg = getString(R.string.un_staring, id);
String msg = getString(R.string.un_starring, id);
RestProvider.getRepoService()
.unstarRepo(login, id)
.doOnSubscribe(() -> showNotification(msg))

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,7 +3,9 @@ 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;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -11,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;
@ -27,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;
@ -56,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) {
@ -64,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();
}
@ -137,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);
@ -150,7 +194,13 @@ public class LoginActivity extends BaseActivity<LoginMvp.View, LoginPresenter> i
isBasicAuth = getIntent().getExtras().getBoolean(BundleConstant.YES_NO_EXTRA);
}
}
if (password != null) password.setHint(isBasicAuth ? getString(R.string.password) : getString(R.string.access_token));
if (username != null)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
username.setAutofillHints(View.AUTOFILL_HINT_USERNAME);
if (password != null) {
password.setHint(isBasicAuth ? getString(R.string.password) : getString(R.string.access_token));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) password.setAutofillHints(View.AUTOFILL_HINT_PASSWORD);
}
if (Arrays.asList(getResources().getStringArray(R.array.languages_array_values)).contains(Locale.getDefault().getLanguage())){
String language = PrefHelper.getString("app_language");
PrefHelper.set("app_language", Locale.getDefault().getLanguage());
@ -159,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() {
@ -218,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();

View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/material_indigo_700"
android:fitsSystemWindows="true"
android:orientation="vertical"
app:statusBarBackground="@color/material_indigo_900"
tools:context=".ui.modules.login.LoginActivity"
tools:ignore="Overdraw">
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/spacing_s_large"
android:minHeight="350dp"
android:minWidth="250dp"
app:cardElevation="@dimen/spacing_normal">
<LinearLayout
android:id="@+id/loginForm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.fastaccess.ui.widgets.FontTextView
android:id="@+id/mainCard"
style="@style/TextAppearance.AppCompat.Title.Inverse"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?colorAccent"
android:gravity="center"
android:paddingBottom="@dimen/spacing_large"
android:paddingEnd="@dimen/spacing_xs_large"
android:paddingStart="@dimen/spacing_xs_large"
android:paddingTop="@dimen/spacing_large"
android:text="@string/sign_in_to_github"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="@dimen/spacing_normal"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/spacing_normal"
android:paddingEnd="@dimen/spacing_xs_large"
android:paddingStart="@dimen/spacing_xs_large"
android:paddingTop="@dimen/spacing_normal">
<android.support.design.widget.TextInputLayout
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/username">
<android.support.design.widget.TextInputEditText
android:id="@+id/usernameEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:maxLines="1"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_xs_large"
android:hint="@string/password"
app:passwordToggleEnabled="true"
app:passwordToggleTint="?colorAccent">
<android.support.design.widget.TextInputEditText
android:id="@+id/passwordEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionSend"
android:inputType="textPassword"
android:maxLines="1"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/twoFactor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_xs_large"
android:hint="@string/twoFactor"
android:visibility="gone"
tools:visibility="visible">
<android.support.design.widget.TextInputEditText
android:id="@+id/twoFactorEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionSend"
android:inputType="text"
android:maxLines="1"/>
</android.support.design.widget.TextInputLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<android.support.design.widget.FloatingActionButton
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_send"
android:tint="@color/white"
app:fabSize="normal"/>
<ProgressBar
android:id="@+id/progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/fab_margin"
android:visibility="gone"/>
</FrameLayout>
<com.fastaccess.ui.widgets.FontTextView
style="@style/TextAppearance.AppCompat.Small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bottom_border"
android:gravity="center"
android:paddingBottom="@dimen/spacing_normal"
android:text="@string/or_character"/>
<com.fastaccess.ui.widgets.FontTextView
style="@style/TextAppearance.AppCompat.Small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacing_normal"
android:gravity="center"
android:text="@string/login_using_your_default_browser"/>
<com.fastaccess.ui.widgets.FontButton
android:id="@+id/browserLogin"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/open_in_browser"/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

View File

@ -47,27 +47,22 @@
<group
android:id="@+id/group_three"
android:checkableBehavior="none">
<menu>
<item
android:id="@+id/supportDev"
android:icon="@drawable/ic_heart"
android:title="@string/support_development"/>
<item
android:id="@+id/settings"
android:icon="@drawable/ic_settings"
android:title="@string/settings"/>
<item
android:id="@+id/about"
android:icon="@drawable/ic_info"
android:title="@string/about"/>
<item
android:id="@+id/logout"
android:icon="@drawable/ic_logout"
android:title="@string/logout"/>
</menu>
<item
android:id="@+id/supportDev"
android:icon="@drawable/ic_heart"
android:title="@string/support_development"/>
<item
android:id="@+id/settings"
android:icon="@drawable/ic_settings"
android:title="@string/settings"/>
<item
android:id="@+id/about"
android:icon="@drawable/ic_info"
android:title="@string/about"/>
<item
android:id="@+id/logout"
android:icon="@drawable/ic_logout"
android:title="@string/logout"/>
</group>
</menu>

View File

@ -280,8 +280,8 @@
<string name="marking_as_read">Marking notification as read</string>
<string name="forking_gist">Forking gist</string>
<string name="forking" formatted="true" translatable="false">Forking %s</string>
<string name="staring" formatted="true" translatable="false">Staring %s</string>
<string name="un_staring" formatted="true" translatable="false">Unstaring %s</string>
<string name="starring" formatted="true" translatable="false">Starring %s</string>
<string name="un_starring" formatted="true" translatable="false">Unstarring %s</string>
<string name="un_watching" formatted="true" translatable="false">Unwatching %s</string>
<string name="watching" formatted="true" translatable="false">Watching %s</string>
<string name="login_using_your_default_browser">Login using your default browser (OAuth)</string>