From 06a36b4a76767a4c2495343969ff1308de3bfe02 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Tue, 24 Oct 2017 16:43:44 +0300 Subject: [PATCH 01/35] First stab at a login AutoForeground Service The fragment attaches, detaches and spawns the email+password login Service, updating its UI to reflect the process's stage. --- WordPress/src/main/AndroidManifest.xml | 6 +- .../java/org/wordpress/android/WordPress.java | 20 + .../android/modules/AppComponent.java | 2 + .../android/ui/ActivityLauncher.java | 1 - .../login/LoginEmailPasswordFragment.java | 247 +++++++---- .../ui/accounts/login/LoginWpcomService.java | 400 ++++++++++++++++++ .../src/main/res/layout/new_blog_activity.xml | 2 +- .../main/res/layout/site_creating_screen.xml | 31 ++ WordPress/src/main/res/values/strings.xml | 7 + libs/utils/WordPressUtils/build.gradle | 1 + .../android/util/AutoForeground.java | 138 ++++++ 11 files changed, 763 insertions(+), 92 deletions(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java create mode 100644 WordPress/src/main/res/layout/site_creating_screen.xml create mode 100644 libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml index 4b5f8090eede..533fb575fff8 100644 --- a/WordPress/src/main/AndroidManifest.xml +++ b/WordPress/src/main/AndroidManifest.xml @@ -135,7 +135,7 @@ + { + + private static final String ARG_EMAIL = "ARG_EMAIL"; + private static final String ARG_PASSWORD = "ARG_PASSWORD"; + private static final String ARG_SOCIAL_ID_TOKEN = "ARG_SOCIAL_ID_TOKEN"; + private static final String ARG_SOCIAL_LOGIN = "ARG_SOCIAL_LOGIN"; + private static final String ARG_SOCIAL_SERVICE = "ARG_SOCIAL_SERVICE"; + + public enum LoginPhase { + IDLE, + AUTHENTICATING, + FETCHING_ACCOUNT, + FETCHING_SETTINGS, + FETCHING_SITES, + SUCCESS, + FAILURE + } + + public static class OnLoginStateUpdated { + public final LoginPhase state; + + public OnLoginStateUpdated(LoginPhase state) { + this.state = state; + } + } + + public static class OnCredentialsOK { + public OnCredentialsOK() {} + } + + @Inject Dispatcher mDispatcher; + @Inject AccountStore mAccountStore; + @Inject SiteStore mSiteStore; + + private LoginPhase mLoginPhase = LoginPhase.IDLE; + + private String mIdToken; + private String mService; + private boolean isSocialLogin; + + private ArrayList mOldSitesIDs; + + public static void loginWithEmailAndPassword( + Context context, + String email, + String password, + String idToken, String service, + boolean isSocialLogin) { + Intent intent = new Intent(context, LoginWpcomService.class); + intent.putExtra(ARG_EMAIL, email); + intent.putExtra(ARG_PASSWORD, password); + intent.putExtra(ARG_SOCIAL_ID_TOKEN, idToken); + intent.putExtra(ARG_SOCIAL_SERVICE, service); + intent.putExtra(ARG_SOCIAL_LOGIN, isSocialLogin); + context.startService(intent); + } + + public LoginWpcomService() { + super(OnLoginStateUpdated.class); + } + + @Override + protected OnLoginStateUpdated getCurrentStateEvent() { + return new OnLoginStateUpdated(mLoginPhase); + } + + @Override + public boolean isInProgress() { + return mLoginPhase != LoginPhase.IDLE + && mLoginPhase != LoginPhase.SUCCESS + && mLoginPhase != LoginPhase.FAILURE; + } + + @Override + public boolean isError() { + return mLoginPhase == LoginPhase.FAILURE; + } + + @Override + public Notification getNotification() { + switch (mLoginPhase) { + case AUTHENTICATING: + return getProgressNotification(25, "Login in: " + mLoginPhase.name()); + case FETCHING_ACCOUNT: + return getProgressNotification(50, "Login in: " + mLoginPhase.name()); + case FETCHING_SETTINGS: + return getProgressNotification(75, "Login in: " + mLoginPhase.name()); + case FETCHING_SITES: + return getProgressNotification(100, "Login in: " + mLoginPhase.name()); + case SUCCESS: + return getSuccessNotification("Logged in!"); + case FAILURE: + return getFailureNotification("Login failed :("); + } + + return null; + } + + private void setState(LoginPhase loginPhase) { + mLoginPhase = loginPhase; + notifyState(); + + if (loginPhase == LoginPhase.FAILURE || loginPhase == LoginPhase.SUCCESS) { + stopSelf(); + } + } + + @Override + public void onCreate() { + super.onCreate(); + ((WordPress) getApplication()).component().inject(this); + + AppLog.i(T.MAIN, "LoginWpcomService > Created"); + mDispatcher.register(this); + + // TODO: Recover any login attempts that were interrupted by the service being stopped? + } + + @Override + public void onDestroy() { + mDispatcher.unregister(this); + AppLog.i(T.MAIN, "LoginWpcomService > Destroyed"); + super.onDestroy(); + } + + private Intent getPendingIntent() { + return new Intent(this, WPMainActivity.class); + } + + private Notification getProgressNotification(int progress, String content) { + return new NotificationCompat.Builder(this) + .setContentTitle(content) + .setSmallIcon(R.drawable.ic_my_sites_24dp) + .setColor(getResources().getColor(R.color.blue_wordpress)) + .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), + R.mipmap.app_icon)) + .setAutoCancel(true) + .setContentIntent(PendingIntent.getActivity(LoginWpcomService.this, + AutoForeground.NOTIFICATION_ID_PROGRESS, + getPendingIntent(), + PendingIntent.FLAG_ONE_SHOT)) + .setProgress(100, progress, false) + .build(); + } + + private Notification getSuccessNotification(String content) { + return new NotificationCompat.Builder(this) + .setContentTitle(content) + .setSmallIcon(R.drawable.ic_my_sites_24dp) + .setColor(getResources().getColor(R.color.blue_wordpress)) + .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), + R.mipmap.app_icon)) + .setAutoCancel(true) + .setContentIntent(PendingIntent.getActivity(LoginWpcomService.this, + AutoForeground.NOTIFICATION_ID_SUCCESS, + getPendingIntent(), + PendingIntent.FLAG_ONE_SHOT)) + .build(); + } + + private Notification getFailureNotification(String content) { + return new NotificationCompat.Builder(this) + .setContentTitle(content) + .setSmallIcon(R.drawable.ic_my_sites_24dp) + .setColor(getResources().getColor(R.color.blue_wordpress)) + .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), + R.mipmap.app_icon)) + .setAutoCancel(true) + .setContentIntent(PendingIntent.getActivity(LoginWpcomService.this, + AutoForeground.NOTIFICATION_ID_FAILURE, + getPendingIntent(), + PendingIntent.FLAG_ONE_SHOT)) + .build(); + } + + @Override + public int onStartCommand(@Nullable Intent intent, int flags, int startId) { + if (intent == null) { + return START_NOT_STICKY; + } + + setState(LoginPhase.AUTHENTICATING); + + final String email = intent.getStringExtra(ARG_EMAIL); + final String password = intent.getStringExtra(ARG_PASSWORD); + + mIdToken = intent.getStringExtra(ARG_SOCIAL_ID_TOKEN); + mService = intent.getStringExtra(ARG_SOCIAL_SERVICE); + isSocialLogin = intent.getBooleanExtra(ARG_SOCIAL_LOGIN, false); + + mOldSitesIDs = SiteUtils.getCurrentSiteIds(mSiteStore, false); + + AccountStore.AuthenticatePayload payload = new AccountStore.AuthenticatePayload(email, password); + mDispatcher.dispatch(AuthenticationActionBuilder.newAuthenticateAction(payload)); + AppLog.i(T.NUX, "User tries to log in wpcom. Email: " + email); + + return START_REDELIVER_INTENT; + } + +// private void handleAuthError(AccountStore.AuthenticationErrorType error, String errorMessage) { +// if (error != AccountStore.AuthenticationErrorType.NEEDS_2FA) { +// AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_FAILED, error.getClass().getSimpleName(), +// error.toString(), errorMessage); +// +// if (isSocialLogin) { +// AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_FAILURE, error.getClass().getSimpleName(), +// error.toString(), errorMessage); +// } +// } +// +// switch (error) { +// case INCORRECT_USERNAME_OR_PASSWORD: +// case NOT_AUTHENTICATED: // NOT_AUTHENTICATED is the generic error from XMLRPC response on first call. +// showPasswordError(); +// break; +// case NEEDS_2FA: +// // login credentials were correct anyway so, offer to save to SmartLock +// saveCredentialsInSmartLock(mLoginListener.getSmartLockHelper(), mEmailAddress, mPassword); +// +// if (isSocialLogin) { +// mLoginListener.needs2faSocialConnect(mEmailAddress, mRequestedPassword, mIdToken, mService); +// } else { +// mLoginListener.needs2fa(mEmailAddress, mRequestedPassword); +// } +// +// break; +// case INVALID_REQUEST: +// // TODO: FluxC: could be specific? +// default: +// AppLog.e(T.NUX, "Server response: " + errorMessage); +// +// ToastUtils.showToast(getActivity(), +// errorMessage == null ? getString(R.string.error_generic) : errorMessage); +// break; +// } +// } + + protected void startPostLoginServices() { + // Get reader tags so they're available as soon as the Reader is accessed - done for + // both wp.com and self-hosted (self-hosted = "logged out" reader) - note that this + // uses the application context since the activity is finished immediately below + ReaderUpdateService.startService(getApplicationContext(), EnumSet.of(ReaderUpdateService + .UpdateTask.TAGS)); + + // Start Notification service + NotificationsUpdateService.startService(getApplicationContext()); + } + + private void doFinishLogin() { + startPostLoginServices(); + setState(LoginPhase.FETCHING_ACCOUNT); + mDispatcher.dispatch(AccountActionBuilder.newFetchAccountAction()); + } + + private EventBus getEventBus() { + return EventBus.getDefault(); + } + + private void signalCredentialsOK() { + getEventBus().post(new OnCredentialsOK()); + } + + // OnChanged events + + @SuppressWarnings("unused") + @Subscribe(threadMode = ThreadMode.MAIN) + public void onAuthenticationChanged(OnAuthenticationChanged event) { + if (event.isError()) { + AppLog.e(T.API, "onAuthenticationChanged has error: " + event.error.type + " - " + event.error.message); + setState(LoginPhase.FAILURE); +// handleAuthError(event.error.type, event.error.message); + return; + } + + AppLog.i(T.NUX, "onAuthenticationChanged: " + event.toString()); + + if (isSocialLogin) { + AccountStore.PushSocialLoginPayload payload = new AccountStore.PushSocialLoginPayload(mIdToken, mService); + mDispatcher.dispatch(AccountActionBuilder.newPushSocialConnectAction(payload)); + } else { + signalCredentialsOK(); + doFinishLogin(); + } + } + + @SuppressWarnings("unused") + @Subscribe(threadMode = ThreadMode.MAIN) + public void onSocialChanged(AccountStore.OnSocialChanged event) { + if (event.isError()) { + AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_CONNECT_FAILURE); + switch (event.error.type) { + case UNABLE_CONNECT: + AppLog.e(T.API, "Unable to connect WordPress.com account to social account."); + break; + case USER_ALREADY_ASSOCIATED: + AppLog.e(T.API, "This social account is already associated with a WordPress.com account."); + break; + // Ignore other error cases. The above are the only two we have chosen to log. + } + + doFinishLogin(); + } else if (!event.requiresTwoStepAuth) { + AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_CONNECT_SUCCESS); + doFinishLogin(); + } + } + + @SuppressWarnings("unused") + @Subscribe(threadMode = ThreadMode.MAIN) + public void onAccountChanged(AccountStore.OnAccountChanged event) { + if (event.isError()) { + AppLog.e(AppLog.T.API, "onAccountChanged has error: " + event.error.type + " - " + event.error.message); +// ToastUtils.showToast(getContext(), R.string.error_fetch_my_profile); +// onLoginFinished(false); + setState(LoginPhase.FAILURE); + return; + } + + if (event.causeOfChange == AccountAction.FETCH_ACCOUNT) { + setState(LoginPhase.FETCHING_SETTINGS); + // The user's account info has been fetched and stored - next, fetch the user's settings + mDispatcher.dispatch(AccountActionBuilder.newFetchSettingsAction()); + } else if (event.causeOfChange == AccountAction.FETCH_SETTINGS) { + setState(LoginPhase.FETCHING_SITES); + // The user's account settings have also been fetched and stored - now we can fetch the user's sites + mDispatcher.dispatch(SiteActionBuilder.newFetchSitesAction()); + } + } + + @SuppressWarnings("unused") + @Subscribe(threadMode = ThreadMode.MAIN) + public void onSiteChanged(SiteStore.OnSiteChanged event) { + if (event.isError()) { + AppLog.e(AppLog.T.API, "onSiteChanged has error: " + event.error.type + " - " + event.error.toString()); + if (event.error.type != SiteStore.SiteErrorType.DUPLICATE_SITE) { +// onLoginFinished(false); + setState(LoginPhase.FAILURE); + return; + } + + if (event.rowsAffected == 0) { + // If there is a duplicate site and not any site has been added, show an error and + // stop the sign in process +// ToastUtils.showToast(getContext(), R.string.cannot_add_duplicate_site); +// onLoginFinished(false); + setState(LoginPhase.FAILURE); + return; + } else { + // If there is a duplicate site, notify the user something could be wrong, + // but continue the sign in process +// ToastUtils.showToast(getContext(), R.string.duplicate_site_detected); + } + } + + startPostLoginServices(); + + AnalyticsUtils.trackAnalyticsSignIn(mAccountStore, mSiteStore, true); + + setState(LoginPhase.SUCCESS); + } +} diff --git a/WordPress/src/main/res/layout/new_blog_activity.xml b/WordPress/src/main/res/layout/new_blog_activity.xml index 8bdf62edb83e..c5b184d1804a 100644 --- a/WordPress/src/main/res/layout/new_blog_activity.xml +++ b/WordPress/src/main/res/layout/new_blog_activity.xml @@ -11,4 +11,4 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - \ No newline at end of file + diff --git a/WordPress/src/main/res/layout/site_creating_screen.xml b/WordPress/src/main/res/layout/site_creating_screen.xml new file mode 100644 index 000000000000..84185c5161af --- /dev/null +++ b/WordPress/src/main/res/layout/site_creating_screen.xml @@ -0,0 +1,31 @@ + + + + + + + + + diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index b3d923ba107d..16996a72fc27 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -18,6 +18,13 @@ Logging out from your account will remove all of @%s’s WordPress.com data from this device, including local drafts and local changes. This account has two step authentication enabled. Visit your security settings on WordPress.com and generate an application-specific password. + Preparing your site… + Fetching site info… + Setting the tagline… + Setting the theme… + Sorry, failed to properly create your site :( + Success! + Select categories Separate tags with commas diff --git a/libs/utils/WordPressUtils/build.gradle b/libs/utils/WordPressUtils/build.gradle index 2906a1f36df8..ca6ac552c1ea 100644 --- a/libs/utils/WordPressUtils/build.gradle +++ b/libs/utils/WordPressUtils/build.gradle @@ -21,6 +21,7 @@ dependencies { compile 'com.android.support:support-v13:25.3.1' compile 'com.android.support:design:25.3.1' compile 'com.android.support:recyclerview-v7:25.3.1' + compile 'org.greenrobot:eventbus:3.0.0' } android { diff --git a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java new file mode 100644 index 000000000000..da3172c84db2 --- /dev/null +++ b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java @@ -0,0 +1,138 @@ +package org.wordpress.android.util; + +import android.app.Notification; +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.IBinder; +import android.support.annotation.CallSuper; +import android.support.annotation.Nullable; +import android.support.v4.app.NotificationManagerCompat; + +import org.greenrobot.eventbus.EventBus; + +public abstract class AutoForeground extends Service { + + public static final int NOTIFICATION_ID_PROGRESS = 1; + public static final int NOTIFICATION_ID_SUCCESS = 2; + public static final int NOTIFICATION_ID_FAILURE = 3; + + public static class ServiceEventConnection { + private final ServiceConnection mServiceConnection; + + public ServiceEventConnection(Context context, Class clazz, Object client) { + EventBus.getDefault().register(client); + + mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + // nothing here + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + // nothing here + } + }; + + context.bindService(new Intent(context, clazz), mServiceConnection, Context.BIND_AUTO_CREATE); + } + + public void disconnect(Context context, Object client) { + context.unbindService(mServiceConnection); + EventBus.getDefault().unregister(client); + } + } + + private class LocalBinder extends Binder {} + + private final IBinder mBinder = new LocalBinder(); + + private final Class mEventClass; + + protected abstract EventClass getCurrentStateEvent(); + protected abstract Notification getNotification(); + protected abstract boolean isInProgress(); + protected abstract boolean isError(); + + protected AutoForeground(Class eventClass) { + mEventClass = eventClass; + } + + @Nullable + @CallSuper + @Override + public IBinder onBind(Intent intent) { + notifyState(); + + return mBinder; + } + + @CallSuper + @Override + public void onRebind(Intent intent) { + super.onRebind(intent); + + background(); + notifyState(); + } + + @CallSuper + @Override + public boolean onUnbind(Intent intent) { + if (!hasConnectedClients()) { + promoteForeground(); + } + + return true; // call onRebind() if new clients connect + } + + private EventBus getEventBus() { + return EventBus.getDefault(); + } + + private boolean hasConnectedClients() { + return getEventBus().hasSubscriberForEvent(mEventClass); + } + + private void promoteForeground() { + if (isInProgress()) { + startForeground(NOTIFICATION_ID_PROGRESS, getNotification()); + } + } + + private void background() { + stopForeground(true); + } + + @CallSuper + protected void notifyState() { + if (hasConnectedClients()) { + // just send a message to the connected clients + getEventBus().post(getCurrentStateEvent()); + return; + } + + // ok, no connected clients so, update will be redirected to a notification + + if (isInProgress()) { + // operation still is progress so, update the notification + NotificationManagerCompat.from(this).notify(NOTIFICATION_ID_PROGRESS, getNotification()); + return; + } + + // operation has ended so, demote the Service to a background one + background(); + + // dismiss the sticky notification + NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID_PROGRESS); + + // put out a simple success/failure notification + NotificationManagerCompat.from(this).notify( + isError() ? NOTIFICATION_ID_FAILURE : NOTIFICATION_ID_SUCCESS, + getNotification()); + } +} From 390ea2d697129e46167f5f805bd63ff44f8b9dcb Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Wed, 15 Nov 2017 16:10:44 +0200 Subject: [PATCH 02/35] Introduce a Service state for social login --- .../accounts/login/LoginEmailPasswordFragment.java | 13 +------------ .../ui/accounts/login/LoginWpcomService.java | 2 ++ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index 34e63c8d2c0c..426df1a9f033 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -347,20 +347,9 @@ public void onLoginStateUpdated(OnLoginStateUpdated event) { // nothing special to do, we'll start the service on next() break; case AUTHENTICATING: - if (!isInProgress()) { - startProgress(); - } - break; + case SOCIAL_LOGIN: case FETCHING_ACCOUNT: - if (!isInProgress()) { - startProgress(); - } - break; case FETCHING_SETTINGS: - if (!isInProgress()) { - startProgress(); - } - break; case FETCHING_SITES: if (!isInProgress()) { startProgress(); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 8ae1c8495810..c9ac5334bbee 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -48,6 +48,7 @@ public class LoginWpcomService extends AutoForeground { public enum LoginPhase { IDLE, AUTHENTICATING, + SOCIAL_LOGIN, FETCHING_ACCOUNT, FETCHING_SETTINGS, FETCHING_SITES, @@ -314,6 +315,7 @@ public void onAuthenticationChanged(OnAuthenticationChanged event) { AppLog.i(T.NUX, "onAuthenticationChanged: " + event.toString()); if (isSocialLogin) { + setState(LoginPhase.SOCIAL_LOGIN); AccountStore.PushSocialLoginPayload payload = new AccountStore.PushSocialLoginPayload(mIdToken, mService); mDispatcher.dispatch(AccountActionBuilder.newPushSocialConnectAction(payload)); } else { From d43430892b299834fd51de24db78ef677ff49e6f Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 11:46:28 +0200 Subject: [PATCH 03/35] Notify and resume for 2FA --- .../login/LoginEmailPasswordFragment.java | 13 ++- .../ui/accounts/login/LoginWpcomService.java | 106 ++++++++++-------- 2 files changed, 72 insertions(+), 47 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index 426df1a9f033..bcc86c429195 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -21,7 +21,6 @@ import org.wordpress.android.analytics.AnalyticsTracker; import org.wordpress.android.ui.accounts.login.LoginWpcomService.OnCredentialsOK; import org.wordpress.android.ui.accounts.login.LoginWpcomService.OnLoginStateUpdated; -import org.wordpress.android.util.AnalyticsUtils; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.AutoForeground; @@ -355,6 +354,18 @@ public void onLoginStateUpdated(OnLoginStateUpdated event) { startProgress(); } break; + case FAILURE_EMAIL_WRONG_PASSWORD: + endProgress(); + showPasswordError(); + break; + case FAILURE_2FA: + endProgress(); + mLoginListener.needs2fa(mEmailAddress, mRequestedPassword); + break; + case FAILURE_SOCIAL_2FA: + endProgress(); + mLoginListener.needs2faSocialConnect(mEmailAddress, mRequestedPassword, mIdToken, mService); + break; case FAILURE: endProgress(); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index c9ac5334bbee..7ef4d5a77eb0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -31,6 +31,7 @@ import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.AutoForeground; import org.wordpress.android.util.SiteUtils; +import org.wordpress.android.util.ToastUtils; import java.util.ArrayList; import java.util.EnumSet; @@ -53,6 +54,9 @@ public enum LoginPhase { FETCHING_SETTINGS, FETCHING_SITES, SUCCESS, + FAILURE_EMAIL_WRONG_PASSWORD, + FAILURE_2FA, + FAILURE_SOCIAL_2FA, FAILURE } @@ -74,6 +78,8 @@ public OnCredentialsOK() {} private LoginPhase mLoginPhase = LoginPhase.IDLE; + private String mEmail; + private String mPassword; private String mIdToken; private String mService; private boolean isSocialLogin; @@ -108,12 +114,15 @@ protected OnLoginStateUpdated getCurrentStateEvent() { public boolean isInProgress() { return mLoginPhase != LoginPhase.IDLE && mLoginPhase != LoginPhase.SUCCESS - && mLoginPhase != LoginPhase.FAILURE; + && !isError(); } @Override public boolean isError() { - return mLoginPhase == LoginPhase.FAILURE; + return mLoginPhase == LoginPhase.FAILURE + || mLoginPhase == LoginPhase.FAILURE_EMAIL_WRONG_PASSWORD + || mLoginPhase == LoginPhase.FAILURE_2FA + || mLoginPhase == LoginPhase.FAILURE_SOCIAL_2FA; } @Override @@ -129,6 +138,12 @@ public Notification getNotification() { return getProgressNotification(100, "Login in: " + mLoginPhase.name()); case SUCCESS: return getSuccessNotification("Logged in!"); + case FAILURE_EMAIL_WRONG_PASSWORD: + return getFailureNotification("Wrong password :("); + case FAILURE_2FA: + return getFailureNotification("Need to input a 2FA code to continue."); + case FAILURE_SOCIAL_2FA: + return getFailureNotification("Need to input a 2FA code to continue."); case FAILURE: return getFailureNotification("Login failed :("); } @@ -140,7 +155,7 @@ private void setState(LoginPhase loginPhase) { mLoginPhase = loginPhase; notifyState(); - if (loginPhase == LoginPhase.FAILURE || loginPhase == LoginPhase.SUCCESS) { + if (isError() || loginPhase == LoginPhase.SUCCESS) { stopSelf(); } } @@ -221,8 +236,8 @@ public int onStartCommand(@Nullable Intent intent, int flags, int startId) { setState(LoginPhase.AUTHENTICATING); - final String email = intent.getStringExtra(ARG_EMAIL); - final String password = intent.getStringExtra(ARG_PASSWORD); + mEmail = intent.getStringExtra(ARG_EMAIL); + mPassword = intent.getStringExtra(ARG_PASSWORD); mIdToken = intent.getStringExtra(ARG_SOCIAL_ID_TOKEN); mService = intent.getStringExtra(ARG_SOCIAL_SERVICE); @@ -230,50 +245,50 @@ public int onStartCommand(@Nullable Intent intent, int flags, int startId) { mOldSitesIDs = SiteUtils.getCurrentSiteIds(mSiteStore, false); - AccountStore.AuthenticatePayload payload = new AccountStore.AuthenticatePayload(email, password); + AccountStore.AuthenticatePayload payload = new AccountStore.AuthenticatePayload(mEmail, mPassword); mDispatcher.dispatch(AuthenticationActionBuilder.newAuthenticateAction(payload)); - AppLog.i(T.NUX, "User tries to log in wpcom. Email: " + email); + AppLog.i(T.NUX, "User tries to log in wpcom. Email: " + mEmail); return START_REDELIVER_INTENT; } -// private void handleAuthError(AccountStore.AuthenticationErrorType error, String errorMessage) { -// if (error != AccountStore.AuthenticationErrorType.NEEDS_2FA) { -// AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_FAILED, error.getClass().getSimpleName(), -// error.toString(), errorMessage); -// -// if (isSocialLogin) { -// AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_FAILURE, error.getClass().getSimpleName(), -// error.toString(), errorMessage); -// } -// } -// -// switch (error) { -// case INCORRECT_USERNAME_OR_PASSWORD: -// case NOT_AUTHENTICATED: // NOT_AUTHENTICATED is the generic error from XMLRPC response on first call. -// showPasswordError(); -// break; -// case NEEDS_2FA: -// // login credentials were correct anyway so, offer to save to SmartLock -// saveCredentialsInSmartLock(mLoginListener.getSmartLockHelper(), mEmailAddress, mPassword); -// -// if (isSocialLogin) { -// mLoginListener.needs2faSocialConnect(mEmailAddress, mRequestedPassword, mIdToken, mService); -// } else { -// mLoginListener.needs2fa(mEmailAddress, mRequestedPassword); -// } -// -// break; -// case INVALID_REQUEST: -// // TODO: FluxC: could be specific? -// default: -// AppLog.e(T.NUX, "Server response: " + errorMessage); -// -// ToastUtils.showToast(getActivity(), -// errorMessage == null ? getString(R.string.error_generic) : errorMessage); -// break; -// } -// } + private void handleAuthError(AccountStore.AuthenticationErrorType error, String errorMessage) { + if (error != AccountStore.AuthenticationErrorType.NEEDS_2FA) { + AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_FAILED, error.getClass().getSimpleName(), + error.toString(), errorMessage); + + if (isSocialLogin) { + AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_FAILURE, error.getClass().getSimpleName(), + error.toString(), errorMessage); + } + } + + switch (error) { + case INCORRECT_USERNAME_OR_PASSWORD: + case NOT_AUTHENTICATED: // NOT_AUTHENTICATED is the generic error from XMLRPC response on first call. + setState(LoginPhase.FAILURE); + break; + case NEEDS_2FA: + // login credentials were correct anyway so, offer to save to SmartLock + signalCredentialsOK(); + + if (isSocialLogin) { + setState(LoginPhase.FAILURE_SOCIAL_2FA); + } else { + setState(LoginPhase.FAILURE_2FA); + } + + break; + case INVALID_REQUEST: + // TODO: FluxC: could be specific? + default: + setState(LoginPhase.FAILURE); + AppLog.e(T.NUX, "Server response: " + errorMessage); + + ToastUtils.showToast(this, errorMessage == null ? getString(R.string.error_generic) : errorMessage); + break; + } + } protected void startPostLoginServices() { // Get reader tags so they're available as soon as the Reader is accessed - done for @@ -307,8 +322,7 @@ private void signalCredentialsOK() { public void onAuthenticationChanged(OnAuthenticationChanged event) { if (event.isError()) { AppLog.e(T.API, "onAuthenticationChanged has error: " + event.error.type + " - " + event.error.message); - setState(LoginPhase.FAILURE); -// handleAuthError(event.error.type, event.error.message); + handleAuthError(event.error.type, event.error.message); return; } From d0e8a353ff52200adbd1a5106dd7ab30238a85c5 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 12:00:21 +0200 Subject: [PATCH 04/35] Small code optimization --- .../ui/accounts/login/LoginWpcomService.java | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 7ef4d5a77eb0..0ead05ef2cce 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -182,14 +182,18 @@ private Intent getPendingIntent() { return new Intent(this, WPMainActivity.class); } - private Notification getProgressNotification(int progress, String content) { + private NotificationCompat.Builder getNotificationBuilder(String content) { return new NotificationCompat.Builder(this) .setContentTitle(content) .setSmallIcon(R.drawable.ic_my_sites_24dp) .setColor(getResources().getColor(R.color.blue_wordpress)) .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), R.mipmap.app_icon)) - .setAutoCancel(true) + .setAutoCancel(true); + } + + private Notification getProgressNotification(int progress, String content) { + return getNotificationBuilder(content) .setContentIntent(PendingIntent.getActivity(LoginWpcomService.this, AutoForeground.NOTIFICATION_ID_PROGRESS, getPendingIntent(), @@ -199,13 +203,7 @@ private Notification getProgressNotification(int progress, String content) { } private Notification getSuccessNotification(String content) { - return new NotificationCompat.Builder(this) - .setContentTitle(content) - .setSmallIcon(R.drawable.ic_my_sites_24dp) - .setColor(getResources().getColor(R.color.blue_wordpress)) - .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), - R.mipmap.app_icon)) - .setAutoCancel(true) + return getNotificationBuilder(content) .setContentIntent(PendingIntent.getActivity(LoginWpcomService.this, AutoForeground.NOTIFICATION_ID_SUCCESS, getPendingIntent(), @@ -214,13 +212,7 @@ private Notification getSuccessNotification(String content) { } private Notification getFailureNotification(String content) { - return new NotificationCompat.Builder(this) - .setContentTitle(content) - .setSmallIcon(R.drawable.ic_my_sites_24dp) - .setColor(getResources().getColor(R.color.blue_wordpress)) - .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), - R.mipmap.app_icon)) - .setAutoCancel(true) + return getNotificationBuilder(content) .setContentIntent(PendingIntent.getActivity(LoginWpcomService.this, AutoForeground.NOTIFICATION_ID_FAILURE, getPendingIntent(), @@ -266,7 +258,7 @@ private void handleAuthError(AccountStore.AuthenticationErrorType error, String switch (error) { case INCORRECT_USERNAME_OR_PASSWORD: case NOT_AUTHENTICATED: // NOT_AUTHENTICATED is the generic error from XMLRPC response on first call. - setState(LoginPhase.FAILURE); + setState(LoginPhase.FAILURE_EMAIL_WRONG_PASSWORD); break; case NEEDS_2FA: // login credentials were correct anyway so, offer to save to SmartLock From 0d78db4e97b0f0b2504a386b3bcc9865852ef750 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Thu, 16 Nov 2017 02:49:33 +0200 Subject: [PATCH 05/35] Non cancellable email+password login --- .../android/ui/accounts/login/LoginBaseFormFragment.java | 6 +++++- .../ui/accounts/login/LoginEmailPasswordFragment.java | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginBaseFormFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginBaseFormFragment.java index d3e7b3992a2a..4d52018e2c88 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginBaseFormFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginBaseFormFragment.java @@ -210,11 +210,15 @@ public boolean onOptionsItemSelected(MenuItem item) { } protected void startProgress() { + startProgress(true); + } + + protected void startProgress(boolean cancellable) { mPrimaryButton.setEnabled(false); mSecondaryButton.setEnabled(false); mProgressDialog = - ProgressDialog.show(getActivity(), "", getActivity().getString(getProgressBarText()), true, true, + ProgressDialog.show(getActivity(), "", getActivity().getString(getProgressBarText()), true, cancellable, new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialogInterface) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index bcc86c429195..f490338e6d09 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -195,7 +195,7 @@ protected void next() { return; } - startProgress(); + startProgress(false); mRequestedPassword = mPasswordInput.getEditText().getText().toString(); From 458bce7caacf30481216e82b7380915d5b624144 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 12:10:47 +0200 Subject: [PATCH 06/35] Separate class for the login notification builder --- .../ui/accounts/login/LoginNotification.java | 58 +++++++++++++++++ .../ui/accounts/login/LoginWpcomService.java | 64 +++---------------- 2 files changed, 67 insertions(+), 55 deletions(-) create mode 100644 WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java new file mode 100644 index 000000000000..eb9d3900c385 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java @@ -0,0 +1,58 @@ +package org.wordpress.android.ui.accounts.login; + +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.support.v4.app.NotificationCompat; + +import org.wordpress.android.R; +import org.wordpress.android.ui.main.WPMainActivity; +import org.wordpress.android.util.AutoForeground; + +class LoginNotification { + private static Intent getPendingIntent(Context context) { + return new Intent(context, WPMainActivity.class); + } + + private static NotificationCompat.Builder getNotificationBuilder(Context context, String content) { + return new NotificationCompat.Builder(context) + .setContentTitle(content) + .setSmallIcon(R.drawable.ic_my_sites_24dp) + .setColor(context.getResources().getColor(R.color.blue_wordpress)) + .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.app_icon)) + .setAutoCancel(true); + } + + static Notification progress(Context context, int progress, String content) { + return getNotificationBuilder(context, content) + .setContentIntent(PendingIntent.getActivity( + context, + AutoForeground.NOTIFICATION_ID_PROGRESS, + getPendingIntent(context), + PendingIntent.FLAG_ONE_SHOT)) + .setProgress(100, progress, false) + .build(); + } + + static Notification success(Context context, String content) { + return getNotificationBuilder(context, content) + .setContentIntent(PendingIntent.getActivity( + context, + AutoForeground.NOTIFICATION_ID_SUCCESS, + getPendingIntent(context), + PendingIntent.FLAG_ONE_SHOT)) + .build(); + } + + static Notification failure(Context context, String content) { + return getNotificationBuilder(context, content) + .setContentIntent(PendingIntent.getActivity( + context, + AutoForeground.NOTIFICATION_ID_FAILURE, + getPendingIntent(context), + PendingIntent.FLAG_ONE_SHOT)) + .build(); + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 0ead05ef2cce..f157b3567126 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -1,12 +1,9 @@ package org.wordpress.android.ui.accounts.login; import android.app.Notification; -import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.graphics.BitmapFactory; import android.support.annotation.Nullable; -import android.support.v4.app.NotificationCompat; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -23,7 +20,6 @@ import org.wordpress.android.fluxc.store.AccountStore.OnAuthenticationChanged; import org.wordpress.android.fluxc.store.SiteStore; import org.wordpress.android.ui.accounts.login.LoginWpcomService.OnLoginStateUpdated; -import org.wordpress.android.ui.main.WPMainActivity; import org.wordpress.android.ui.notifications.services.NotificationsUpdateService; import org.wordpress.android.ui.reader.services.ReaderUpdateService; import org.wordpress.android.util.AnalyticsUtils; @@ -129,23 +125,23 @@ public boolean isError() { public Notification getNotification() { switch (mLoginPhase) { case AUTHENTICATING: - return getProgressNotification(25, "Login in: " + mLoginPhase.name()); + return LoginNotification.progress(this, 25, "Login in: " + mLoginPhase.name()); case FETCHING_ACCOUNT: - return getProgressNotification(50, "Login in: " + mLoginPhase.name()); + return LoginNotification.progress(this, 50, "Login in: " + mLoginPhase.name()); case FETCHING_SETTINGS: - return getProgressNotification(75, "Login in: " + mLoginPhase.name()); + return LoginNotification.progress(this, 75, "Login in: " + mLoginPhase.name()); case FETCHING_SITES: - return getProgressNotification(100, "Login in: " + mLoginPhase.name()); + return LoginNotification.progress(this, 100, "Login in: " + mLoginPhase.name()); case SUCCESS: - return getSuccessNotification("Logged in!"); + return LoginNotification.success(this, "Logged in!"); case FAILURE_EMAIL_WRONG_PASSWORD: - return getFailureNotification("Wrong password :("); + return LoginNotification.failure(this, "Wrong password :("); case FAILURE_2FA: - return getFailureNotification("Need to input a 2FA code to continue."); + return LoginNotification.failure(this, "Need to input a 2FA code to continue."); case FAILURE_SOCIAL_2FA: - return getFailureNotification("Need to input a 2FA code to continue."); + return LoginNotification.failure(this, "Need to input a 2FA code to continue."); case FAILURE: - return getFailureNotification("Login failed :("); + return LoginNotification.failure(this, "Login failed :("); } return null; @@ -178,48 +174,6 @@ public void onDestroy() { super.onDestroy(); } - private Intent getPendingIntent() { - return new Intent(this, WPMainActivity.class); - } - - private NotificationCompat.Builder getNotificationBuilder(String content) { - return new NotificationCompat.Builder(this) - .setContentTitle(content) - .setSmallIcon(R.drawable.ic_my_sites_24dp) - .setColor(getResources().getColor(R.color.blue_wordpress)) - .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(), - R.mipmap.app_icon)) - .setAutoCancel(true); - } - - private Notification getProgressNotification(int progress, String content) { - return getNotificationBuilder(content) - .setContentIntent(PendingIntent.getActivity(LoginWpcomService.this, - AutoForeground.NOTIFICATION_ID_PROGRESS, - getPendingIntent(), - PendingIntent.FLAG_ONE_SHOT)) - .setProgress(100, progress, false) - .build(); - } - - private Notification getSuccessNotification(String content) { - return getNotificationBuilder(content) - .setContentIntent(PendingIntent.getActivity(LoginWpcomService.this, - AutoForeground.NOTIFICATION_ID_SUCCESS, - getPendingIntent(), - PendingIntent.FLAG_ONE_SHOT)) - .build(); - } - - private Notification getFailureNotification(String content) { - return getNotificationBuilder(content) - .setContentIntent(PendingIntent.getActivity(LoginWpcomService.this, - AutoForeground.NOTIFICATION_ID_FAILURE, - getPendingIntent(), - PendingIntent.FLAG_ONE_SHOT)) - .build(); - } - @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { if (intent == null) { From 7d1e7fa7cbbad3bc450b3b93690e3760282797fd Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Thu, 16 Nov 2017 12:01:41 +0200 Subject: [PATCH 07/35] Simplify the login progress notification message --- .../ui/accounts/login/LoginWpcomService.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index f157b3567126..022baccf2266 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -43,17 +43,23 @@ public class LoginWpcomService extends AutoForeground { private static final String ARG_SOCIAL_SERVICE = "ARG_SOCIAL_SERVICE"; public enum LoginPhase { - IDLE, - AUTHENTICATING, - SOCIAL_LOGIN, - FETCHING_ACCOUNT, - FETCHING_SETTINGS, - FETCHING_SITES, - SUCCESS, - FAILURE_EMAIL_WRONG_PASSWORD, - FAILURE_2FA, - FAILURE_SOCIAL_2FA, - FAILURE + IDLE(0), + AUTHENTICATING(25), + SOCIAL_LOGIN(25), + FETCHING_ACCOUNT(50), + FETCHING_SETTINGS(75), + FETCHING_SITES(100), + SUCCESS(100), + FAILURE_EMAIL_WRONG_PASSWORD(100), + FAILURE_2FA(100), + FAILURE_SOCIAL_2FA(100), + FAILURE(100); + + public final int progressPercent; + + LoginPhase(int progressPercent) { + this.progressPercent = progressPercent; + } } public static class OnLoginStateUpdated { @@ -125,13 +131,10 @@ public boolean isError() { public Notification getNotification() { switch (mLoginPhase) { case AUTHENTICATING: - return LoginNotification.progress(this, 25, "Login in: " + mLoginPhase.name()); case FETCHING_ACCOUNT: - return LoginNotification.progress(this, 50, "Login in: " + mLoginPhase.name()); case FETCHING_SETTINGS: - return LoginNotification.progress(this, 75, "Login in: " + mLoginPhase.name()); case FETCHING_SITES: - return LoginNotification.progress(this, 100, "Login in: " + mLoginPhase.name()); + return LoginNotification.progress(this, mLoginPhase.progressPercent, "Logging in..."); case SUCCESS: return LoginNotification.success(this, "Logged in!"); case FAILURE_EMAIL_WRONG_PASSWORD: From cccace6b0c31c70b1a227017c4602efab41f4712 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 12:12:27 +0200 Subject: [PATCH 08/35] Sticky EventBus message to hold login Service state --- .../android/ui/accounts/LoginActivity.java | 1 + .../login/LoginEmailPasswordFragment.java | 17 ++++++++- .../ui/accounts/login/LoginNotification.java | 9 ++++- .../ui/accounts/login/LoginWpcomService.java | 37 ++++++++++++------- .../android/util/AutoForeground.java | 20 ++++++---- 5 files changed, 58 insertions(+), 26 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java index dbc026c343fe..ea5beaf1373c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java @@ -305,6 +305,7 @@ public void usePasswordInstead(String email) { LoginEmailPasswordFragment loginEmailPasswordFragment = LoginEmailPasswordFragment.newInstance(email, null, null, null, false); slideInFragment(loginEmailPasswordFragment, true, LoginEmailPasswordFragment.TAG); + LoginEmailPasswordFragment.clearLoginServiceState(); } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index f490338e6d09..da8a3f4cb537 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -14,6 +14,7 @@ import android.widget.EditText; import android.widget.TextView; +import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import org.wordpress.android.R; @@ -95,6 +96,9 @@ public void onResume() { // connect to the Service. We'll receive updates via EventBus. mServiceEventConnection = new AutoForeground.ServiceEventConnection(getContext(), LoginWpcomService.class, this); + + // install the change listener as late as possible so the UI can be setup before triggering the + mPasswordInput.addTextChangedListener(this); } @Override @@ -131,7 +135,6 @@ protected void setupContent(ViewGroup rootView) { ((TextView) rootView.findViewById(R.id.login_email)).setText(mEmailAddress); mPasswordInput = (WPLoginInputRow) rootView.findViewById(R.id.login_password_row); - mPasswordInput.addTextChangedListener(this); mPasswordInput.setOnEditorCommitListener(this); } @@ -224,6 +227,8 @@ public void beforeTextChanged(CharSequence s, int start, int count, int after) { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { mPasswordInput.setError(null); + + clearLoginServiceState(); } private void showPasswordError() { @@ -234,6 +239,13 @@ private void showError(String error) { mPasswordInput.setError(error); } + public static void clearLoginServiceState() { + OnLoginStateUpdated onLoginStateUpdated = EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); + if (onLoginStateUpdated != null && onLoginStateUpdated.state.isTerminal()) { + EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); + } + } + // private void handleAuthError(AccountStore.AuthenticationErrorType error, String errorMessage) { // // if (error != AccountStore.AuthenticationErrorType.NEEDS_2FA) { @@ -337,7 +349,7 @@ public void onCredentialsOK(OnCredentialsOK event) { } @SuppressWarnings("unused") - @Subscribe(threadMode = ThreadMode.MAIN) + @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void onLoginStateUpdated(OnLoginStateUpdated event) { AppLog.i(T.NUX, "Received state: " + event.state.name()); @@ -372,6 +384,7 @@ public void onLoginStateUpdated(OnLoginStateUpdated event) { showError(getString(R.string.error_generic)); break; case SUCCESS: + LoginWpcomService.clearAllNotifications(getContext()); onLoginFinished(); break; } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java index eb9d3900c385..b5fe45221836 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java @@ -8,12 +8,17 @@ import android.support.v4.app.NotificationCompat; import org.wordpress.android.R; -import org.wordpress.android.ui.main.WPMainActivity; import org.wordpress.android.util.AutoForeground; class LoginNotification { private static Intent getPendingIntent(Context context) { - return new Intent(context, WPMainActivity.class); + Intent resumeIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); + + // apparently, we need to null out the package name to make the intent resume the app + resumeIntent.setSelector(null); + resumeIntent.setPackage(null); + + return resumeIntent; } private static NotificationCompat.Builder getNotificationBuilder(Context context, String content) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 022baccf2266..036c88bbfc80 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -60,6 +60,21 @@ public enum LoginPhase { LoginPhase(int progressPercent) { this.progressPercent = progressPercent; } + + public boolean isInProgress() { + return this != LoginPhase.IDLE && !isTerminal(); + } + + public boolean isError() { + return this == LoginPhase.FAILURE + || this == LoginPhase.FAILURE_EMAIL_WRONG_PASSWORD + || this == LoginPhase.FAILURE_2FA + || this == LoginPhase.FAILURE_SOCIAL_2FA; + } + + public boolean isTerminal() { + return this == LoginPhase.SUCCESS || isError(); + } } public static class OnLoginStateUpdated { @@ -86,8 +101,6 @@ public OnCredentialsOK() {} private String mService; private boolean isSocialLogin; - private ArrayList mOldSitesIDs; - public static void loginWithEmailAndPassword( Context context, String email, @@ -114,17 +127,12 @@ protected OnLoginStateUpdated getCurrentStateEvent() { @Override public boolean isInProgress() { - return mLoginPhase != LoginPhase.IDLE - && mLoginPhase != LoginPhase.SUCCESS - && !isError(); + return mLoginPhase.isInProgress(); } @Override public boolean isError() { - return mLoginPhase == LoginPhase.FAILURE - || mLoginPhase == LoginPhase.FAILURE_EMAIL_WRONG_PASSWORD - || mLoginPhase == LoginPhase.FAILURE_2FA - || mLoginPhase == LoginPhase.FAILURE_SOCIAL_2FA; + return mLoginPhase.isError(); } @Override @@ -151,10 +159,15 @@ public Notification getNotification() { } private void setState(LoginPhase loginPhase) { + if (!mLoginPhase.isInProgress() && loginPhase.isInProgress()) { + mDispatcher.register(this); + } + mLoginPhase = loginPhase; notifyState(); - if (isError() || loginPhase == LoginPhase.SUCCESS) { + if (mLoginPhase.isTerminal()) { + mDispatcher.unregister(this); stopSelf(); } } @@ -165,14 +178,12 @@ public void onCreate() { ((WordPress) getApplication()).component().inject(this); AppLog.i(T.MAIN, "LoginWpcomService > Created"); - mDispatcher.register(this); // TODO: Recover any login attempts that were interrupted by the service being stopped? } @Override public void onDestroy() { - mDispatcher.unregister(this); AppLog.i(T.MAIN, "LoginWpcomService > Destroyed"); super.onDestroy(); } @@ -192,8 +203,6 @@ public int onStartCommand(@Nullable Intent intent, int flags, int startId) { mService = intent.getStringExtra(ARG_SOCIAL_SERVICE); isSocialLogin = intent.getBooleanExtra(ARG_SOCIAL_LOGIN, false); - mOldSitesIDs = SiteUtils.getCurrentSiteIds(mSiteStore, false); - AccountStore.AuthenticatePayload payload = new AccountStore.AuthenticatePayload(mEmail, mPassword); mDispatcher.dispatch(AuthenticationActionBuilder.newAuthenticateAction(payload)); AppLog.i(T.NUX, "User tries to log in wpcom. Email: " + mEmail); diff --git a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java index da3172c84db2..4d0efaf2edd4 100644 --- a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java +++ b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java @@ -66,8 +66,6 @@ protected AutoForeground(Class eventClass) { @CallSuper @Override public IBinder onBind(Intent intent) { - notifyState(); - return mBinder; } @@ -77,7 +75,6 @@ public void onRebind(Intent intent) { super.onRebind(intent); background(); - notifyState(); } @CallSuper @@ -90,6 +87,12 @@ public boolean onUnbind(Intent intent) { return true; // call onRebind() if new clients connect } + public static void clearAllNotifications(Context context) { + NotificationManagerCompat.from(context).cancel(NOTIFICATION_ID_PROGRESS); + NotificationManagerCompat.from(context).cancel(NOTIFICATION_ID_SUCCESS); + NotificationManagerCompat.from(context).cancel(NOTIFICATION_ID_FAILURE); + } + private EventBus getEventBus() { return EventBus.getDefault(); } @@ -110,13 +113,15 @@ private void background() { @CallSuper protected void notifyState() { + // sticky emit the state. The stickiness serves as a state keeping mechanism for clients to re-read upon connect + getEventBus().postSticky(getCurrentStateEvent()); + if (hasConnectedClients()) { - // just send a message to the connected clients - getEventBus().post(getCurrentStateEvent()); + // there are connected clients so, nothing more to do here return; } - // ok, no connected clients so, update will be redirected to a notification + // ok, no connected clients so, update might need to be delivered to a notification as well if (isInProgress()) { // operation still is progress so, update the notification @@ -131,8 +136,7 @@ protected void notifyState() { NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID_PROGRESS); // put out a simple success/failure notification - NotificationManagerCompat.from(this).notify( - isError() ? NOTIFICATION_ID_FAILURE : NOTIFICATION_ID_SUCCESS, + NotificationManagerCompat.from(this).notify(isError() ? NOTIFICATION_ID_FAILURE : NOTIFICATION_ID_SUCCESS, getNotification()); } } From 05cdbcb9fc0f336d71e9b87bf9ddb9375879661a Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 01:39:43 +0200 Subject: [PATCH 09/35] Clear sticky login state when leaving email/pass screen --- .../java/org/wordpress/android/ui/accounts/LoginActivity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java index ea5beaf1373c..4d0d1a0498ba 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java @@ -318,6 +318,7 @@ public void forgotPassword(String url) { public void needs2fa(String email, String password) { Login2FaFragment login2FaFragment = Login2FaFragment.newInstance(email, password); slideInFragment(login2FaFragment, true, Login2FaFragment.TAG); + LoginEmailPasswordFragment.clearLoginServiceState(); } @Override @@ -327,6 +328,7 @@ public void needs2faSocial(String email, String userId, String nonceAuthenticato Login2FaFragment login2FaFragment = Login2FaFragment.newInstanceSocial(email, userId, nonceAuthenticator, nonceBackup, nonceSms); slideInFragment(login2FaFragment, true, Login2FaFragment.TAG); + LoginEmailPasswordFragment.clearLoginServiceState(); } @Override @@ -334,6 +336,7 @@ public void needs2faSocialConnect(String email, String password, String idToken, AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_2FA_NEEDED); Login2FaFragment login2FaFragment = Login2FaFragment.newInstanceSocialConnect(email, password, idToken, service); slideInFragment(login2FaFragment, true, Login2FaFragment.TAG); + LoginEmailPasswordFragment.clearLoginServiceState(); } @Override From 50113dcb9707f1832f6ff351da3d1eba1c7fc535 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 01:48:07 +0200 Subject: [PATCH 10/35] Remove notifications when client gets bound --- .../ui/accounts/login/LoginEmailPasswordFragment.java | 1 - .../org/wordpress/android/util/AutoForeground.java | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index da8a3f4cb537..7d6e0f1f7777 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -384,7 +384,6 @@ public void onLoginStateUpdated(OnLoginStateUpdated event) { showError(getString(R.string.error_generic)); break; case SUCCESS: - LoginWpcomService.clearAllNotifications(getContext()); onLoginFinished(); break; } diff --git a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java index 4d0efaf2edd4..4ebd3a04aefb 100644 --- a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java +++ b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java @@ -66,6 +66,7 @@ protected AutoForeground(Class eventClass) { @CallSuper @Override public IBinder onBind(Intent intent) { + clearAllNotifications(); return mBinder; } @@ -74,6 +75,7 @@ public IBinder onBind(Intent intent) { public void onRebind(Intent intent) { super.onRebind(intent); + clearAllNotifications(); background(); } @@ -87,10 +89,10 @@ public boolean onUnbind(Intent intent) { return true; // call onRebind() if new clients connect } - public static void clearAllNotifications(Context context) { - NotificationManagerCompat.from(context).cancel(NOTIFICATION_ID_PROGRESS); - NotificationManagerCompat.from(context).cancel(NOTIFICATION_ID_SUCCESS); - NotificationManagerCompat.from(context).cancel(NOTIFICATION_ID_FAILURE); + protected void clearAllNotifications() { + NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID_PROGRESS); + NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID_SUCCESS); + NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID_FAILURE); } private EventBus getEventBus() { From 4583596e37e646be4781a17d777de74225ad9a64 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 01:58:22 +0200 Subject: [PATCH 11/35] Use the provided onLoginFinished(boolean) --- .../ui/accounts/login/LoginBaseFormFragment.java | 2 +- .../ui/accounts/login/LoginEmailPasswordFragment.java | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginBaseFormFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginBaseFormFragment.java index 4d52018e2c88..9d909e1adf41 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginBaseFormFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginBaseFormFragment.java @@ -260,7 +260,7 @@ protected void doFinishLogin() { protected void onLoginFinished() { } - private void onLoginFinished(boolean success) { + protected void onLoginFinished(boolean success) { mLoginFinished = true; if (!success) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index 7d6e0f1f7777..41d098dfe7f4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -367,24 +367,23 @@ public void onLoginStateUpdated(OnLoginStateUpdated event) { } break; case FAILURE_EMAIL_WRONG_PASSWORD: - endProgress(); + onLoginFinished(false); showPasswordError(); break; case FAILURE_2FA: - endProgress(); + onLoginFinished(false); mLoginListener.needs2fa(mEmailAddress, mRequestedPassword); break; case FAILURE_SOCIAL_2FA: - endProgress(); + onLoginFinished(false); mLoginListener.needs2faSocialConnect(mEmailAddress, mRequestedPassword, mIdToken, mService); break; case FAILURE: - endProgress(); - + onLoginFinished(false); showError(getString(R.string.error_generic)); break; case SUCCESS: - onLoginFinished(); + onLoginFinished(true); break; } } From d375d729a51f72a8ea6a0727f7d98dddbb5d4f4d Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 02:09:55 +0200 Subject: [PATCH 12/35] Handle some more failure states in the UI --- .../accounts/login/LoginEmailPasswordFragment.java | 8 ++++++++ .../ui/accounts/login/LoginWpcomService.java | 13 +++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index 41d098dfe7f4..8bedeec37e3b 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -378,6 +378,14 @@ public void onLoginStateUpdated(OnLoginStateUpdated event) { onLoginFinished(false); mLoginListener.needs2faSocialConnect(mEmailAddress, mRequestedPassword, mIdToken, mService); break; + case FAILURE_FETCHING_ACCOUNT: + onLoginFinished(false); + showError(getString(R.string.error_fetch_my_profile)); + break; + case FAILURE_CANNOT_ADD_DUPLICATE_SITE: + onLoginFinished(false); + showError(getString(R.string.cannot_add_duplicate_site)); + break; case FAILURE: onLoginFinished(false); showError(getString(R.string.error_generic)); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 036c88bbfc80..913c0b269169 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -53,6 +53,8 @@ public enum LoginPhase { FAILURE_EMAIL_WRONG_PASSWORD(100), FAILURE_2FA(100), FAILURE_SOCIAL_2FA(100), + FAILURE_FETCHING_ACCOUNT(100), + FAILURE_CANNOT_ADD_DUPLICATE_SITE(100), FAILURE(100); public final int progressPercent; @@ -323,9 +325,7 @@ public void onSocialChanged(AccountStore.OnSocialChanged event) { public void onAccountChanged(AccountStore.OnAccountChanged event) { if (event.isError()) { AppLog.e(AppLog.T.API, "onAccountChanged has error: " + event.error.type + " - " + event.error.message); -// ToastUtils.showToast(getContext(), R.string.error_fetch_my_profile); -// onLoginFinished(false); - setState(LoginPhase.FAILURE); + setState(LoginPhase.FAILURE_FETCHING_ACCOUNT); return; } @@ -346,7 +346,6 @@ public void onSiteChanged(SiteStore.OnSiteChanged event) { if (event.isError()) { AppLog.e(AppLog.T.API, "onSiteChanged has error: " + event.error.type + " - " + event.error.toString()); if (event.error.type != SiteStore.SiteErrorType.DUPLICATE_SITE) { -// onLoginFinished(false); setState(LoginPhase.FAILURE); return; } @@ -354,14 +353,12 @@ public void onSiteChanged(SiteStore.OnSiteChanged event) { if (event.rowsAffected == 0) { // If there is a duplicate site and not any site has been added, show an error and // stop the sign in process -// ToastUtils.showToast(getContext(), R.string.cannot_add_duplicate_site); -// onLoginFinished(false); - setState(LoginPhase.FAILURE); + setState(LoginPhase.FAILURE_CANNOT_ADD_DUPLICATE_SITE); return; } else { // If there is a duplicate site, notify the user something could be wrong, // but continue the sign in process -// ToastUtils.showToast(getContext(), R.string.duplicate_site_detected); + ToastUtils.showToast(this, R.string.duplicate_site_detected); } } From 8b39c8b878a8fcc666a8388b6a6ef10283c7f2f0 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 02:12:33 +0200 Subject: [PATCH 13/35] Minor cleanup --- .../login/LoginEmailPasswordFragment.java | 90 ------------------- .../ui/accounts/login/LoginWpcomService.java | 20 +++-- 2 files changed, 11 insertions(+), 99 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index 8bedeec37e3b..90be6b2dc9da 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -205,9 +205,6 @@ protected void next() { LoginWpcomService.loginWithEmailAndPassword(getContext(), mEmailAddress, mRequestedPassword, mIdToken, mService, isSocialLogin); mOldSitesIDs = SiteUtils.getCurrentSiteIds(mSiteStore, false); - -// AuthenticatePayload payload = new AuthenticatePayload(mEmailAddress, mRequestedPassword); -// mDispatcher.dispatch(AuthenticationActionBuilder.newAuthenticateAction(payload)); } @Override @@ -246,93 +243,6 @@ public static void clearLoginServiceState() { } } -// private void handleAuthError(AccountStore.AuthenticationErrorType error, String errorMessage) { -// -// if (error != AccountStore.AuthenticationErrorType.NEEDS_2FA) { -// AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_FAILED, error.getClass().getSimpleName(), error.toString(), errorMessage); -// -// if (isSocialLogin) { -// AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_FAILURE, error.getClass().getSimpleName(), error.toString(), errorMessage); -// } -// } -// -// switch (error) { -// case INCORRECT_USERNAME_OR_PASSWORD: -// case NOT_AUTHENTICATED: // NOT_AUTHENTICATED is the generic error from XMLRPC response on first call. -// showPasswordError(); -// break; -// case NEEDS_2FA: -// // login credentials were correct anyway so, offer to save to SmartLock -// saveCredentialsInSmartLock(mLoginListener.getSmartLockHelper(), mEmailAddress, mPassword); -// -// if (isSocialLogin) { -// mLoginListener.needs2faSocialConnect(mEmailAddress, mRequestedPassword, mIdToken, mService); -// } else { -// mLoginListener.needs2fa(mEmailAddress, mRequestedPassword); -// } -// -// break; -// case INVALID_REQUEST: -// // TODO: FluxC: could be specific? -// default: -// AppLog.e(T.NUX, "Server response: " + errorMessage); -// -// ToastUtils.showToast(getActivity(), -// errorMessage == null ? getString(R.string.error_generic) : errorMessage); -// break; -// } -// } - - // OnChanged events - -// @SuppressWarnings("unused") -// @Subscribe(threadMode = ThreadMode.MAIN) -// public void onAuthenticationChanged(OnAuthenticationChanged event) { -// if (event.isError()) { -// endProgress(); -// -// AppLog.e(T.API, "onAuthenticationChanged has error: " + event.error.type + " - " + event.error.message); -// -// if (isAdded()) { -// handleAuthError(event.error.type, event.error.message); -// } -// -// return; -// } -// -// AppLog.i(T.NUX, "onAuthenticationChanged: " + event.toString()); -// -// if (isSocialLogin) { -// AccountStore.PushSocialLoginPayload payload = new AccountStore.PushSocialLoginPayload(mIdToken, mService); -// mDispatcher.dispatch(AccountActionBuilder.newPushSocialConnectAction(payload)); -// } else { -// saveCredentialsInSmartLock(mLoginListener.getSmartLockHelper(), mEmailAddress, mRequestedPassword); -// doFinishLogin(); -// } -// } -// -// @SuppressWarnings("unused") -// @Subscribe(threadMode = ThreadMode.MAIN) -// public void onSocialChanged(OnSocialChanged event) { -// if (event.isError()) { -// AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_CONNECT_FAILURE); -// switch (event.error.type) { -// case UNABLE_CONNECT: -// AppLog.e(T.API, "Unable to connect WordPress.com account to social account."); -// break; -// case USER_ALREADY_ASSOCIATED: -// AppLog.e(T.API, "This social account is already associated with a WordPress.com account."); -// break; -// // Ignore other error cases. The above are the only two we have chosen to log. -// } -// -// doFinishLogin(); -// } else if (!event.requiresTwoStepAuth) { -// AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_CONNECT_SUCCESS); -// doFinishLogin(); -// } -// } - @Override protected void onLoginFinished() { if (isSocialLogin) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 913c0b269169..4adc683c352a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -26,10 +26,8 @@ import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.AutoForeground; -import org.wordpress.android.util.SiteUtils; import org.wordpress.android.util.ToastUtils; -import java.util.ArrayList; import java.util.EnumSet; import javax.inject.Inject; @@ -43,22 +41,26 @@ public class LoginWpcomService extends AutoForeground { private static final String ARG_SOCIAL_SERVICE = "ARG_SOCIAL_SERVICE"; public enum LoginPhase { - IDLE(0), + IDLE, AUTHENTICATING(25), SOCIAL_LOGIN(25), FETCHING_ACCOUNT(50), FETCHING_SETTINGS(75), FETCHING_SITES(100), SUCCESS(100), - FAILURE_EMAIL_WRONG_PASSWORD(100), - FAILURE_2FA(100), - FAILURE_SOCIAL_2FA(100), - FAILURE_FETCHING_ACCOUNT(100), - FAILURE_CANNOT_ADD_DUPLICATE_SITE(100), - FAILURE(100); + FAILURE_EMAIL_WRONG_PASSWORD, + FAILURE_2FA, + FAILURE_SOCIAL_2FA, + FAILURE_FETCHING_ACCOUNT, + FAILURE_CANNOT_ADD_DUPLICATE_SITE, + FAILURE; public final int progressPercent; + LoginPhase() { + this.progressPercent = 0; + } + LoginPhase(int progressPercent) { this.progressPercent = progressPercent; } From b2281831bb11390027a0bda6f1717c8bba655d6e Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 02:13:51 +0200 Subject: [PATCH 14/35] Code cleanup to remove AS warnings --- .../ui/accounts/login/LoginWpcomService.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 4adc683c352a..2f17267a01e3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -84,13 +84,13 @@ public boolean isTerminal() { public static class OnLoginStateUpdated { public final LoginPhase state; - public OnLoginStateUpdated(LoginPhase state) { + OnLoginStateUpdated(LoginPhase state) { this.state = state; } } - public static class OnCredentialsOK { - public OnCredentialsOK() {} + static class OnCredentialsOK { + OnCredentialsOK() {} } @Inject Dispatcher mDispatcher; @@ -99,8 +99,6 @@ public OnCredentialsOK() {} private LoginPhase mLoginPhase = LoginPhase.IDLE; - private String mEmail; - private String mPassword; private String mIdToken; private String mService; private boolean isSocialLogin; @@ -200,16 +198,16 @@ public int onStartCommand(@Nullable Intent intent, int flags, int startId) { setState(LoginPhase.AUTHENTICATING); - mEmail = intent.getStringExtra(ARG_EMAIL); - mPassword = intent.getStringExtra(ARG_PASSWORD); + String email = intent.getStringExtra(ARG_EMAIL); + String password = intent.getStringExtra(ARG_PASSWORD); mIdToken = intent.getStringExtra(ARG_SOCIAL_ID_TOKEN); mService = intent.getStringExtra(ARG_SOCIAL_SERVICE); isSocialLogin = intent.getBooleanExtra(ARG_SOCIAL_LOGIN, false); - AccountStore.AuthenticatePayload payload = new AccountStore.AuthenticatePayload(mEmail, mPassword); + AccountStore.AuthenticatePayload payload = new AccountStore.AuthenticatePayload(email, password); mDispatcher.dispatch(AuthenticationActionBuilder.newAuthenticateAction(payload)); - AppLog.i(T.NUX, "User tries to log in wpcom. Email: " + mEmail); + AppLog.i(T.NUX, "User tries to log in wpcom. Email: " + email); return START_REDELIVER_INTENT; } From 9386143d34a266205e76f63dcd4b7c6e3d1451cb Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 02:32:30 +0200 Subject: [PATCH 15/35] Initialise the login state sticky event --- .../ui/accounts/login/LoginWpcomService.java | 5 +++++ .../org/wordpress/android/util/AutoForeground.java | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 2f17267a01e3..0b6ac1a378c5 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -127,6 +127,11 @@ protected OnLoginStateUpdated getCurrentStateEvent() { return new OnLoginStateUpdated(mLoginPhase); } + @Override + public boolean isIdle() { + return mLoginPhase == LoginPhase.IDLE; + } + @Override public boolean isInProgress() { return mLoginPhase.isInProgress(); diff --git a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java index 4ebd3a04aefb..c2c7af577bc5 100644 --- a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java +++ b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java @@ -55,6 +55,7 @@ private class LocalBinder extends Binder {} protected abstract EventClass getCurrentStateEvent(); protected abstract Notification getNotification(); + protected abstract boolean isIdle(); protected abstract boolean isInProgress(); protected abstract boolean isError(); @@ -62,6 +63,13 @@ protected AutoForeground(Class eventClass) { mEventClass = eventClass; } + @Override + public void onCreate() { + super.onCreate(); + + notifyState(); + } + @Nullable @CallSuper @Override @@ -125,6 +133,11 @@ protected void notifyState() { // ok, no connected clients so, update might need to be delivered to a notification as well + if (isIdle()) { + // no need to have a notification when idle + return; + } + if (isInProgress()) { // operation still is progress so, update the notification NotificationManagerCompat.from(this).notify(NOTIFICATION_ID_PROGRESS, getNotification()); From 8ed3321a6845c8044cf4b46e029c716b060885fd Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 12:49:43 +0200 Subject: [PATCH 16/35] SUCCESS doesn't need a progress percentage --- .../wordpress/android/ui/accounts/login/LoginWpcomService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 0b6ac1a378c5..b8536c654e0a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -47,7 +47,7 @@ public enum LoginPhase { FETCHING_ACCOUNT(50), FETCHING_SETTINGS(75), FETCHING_SITES(100), - SUCCESS(100), + SUCCESS, FAILURE_EMAIL_WRONG_PASSWORD, FAILURE_2FA, FAILURE_SOCIAL_2FA, From fe8369b184acc03e217a2b81e13baa1228a381f9 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 13:30:42 +0200 Subject: [PATCH 17/35] Missing cases from isError() --- .../android/ui/accounts/login/LoginWpcomService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index b8536c654e0a..342f1ee268fd 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -73,7 +73,9 @@ public boolean isError() { return this == LoginPhase.FAILURE || this == LoginPhase.FAILURE_EMAIL_WRONG_PASSWORD || this == LoginPhase.FAILURE_2FA - || this == LoginPhase.FAILURE_SOCIAL_2FA; + || this == LoginPhase.FAILURE_SOCIAL_2FA + || this == LoginPhase.FAILURE_FETCHING_ACCOUNT + || this == LoginPhase.FAILURE_CANNOT_ADD_DUPLICATE_SITE; } public boolean isTerminal() { From f386f9569da96a2ad3623727a44c02b3eb7e6d87 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 14:11:50 +0200 Subject: [PATCH 18/35] String resources, nicer login notifications --- .../ui/accounts/login/LoginNotification.java | 15 ++++++++++----- .../ui/accounts/login/LoginWpcomService.java | 12 ++++++------ WordPress/src/main/res/values/strings.xml | 6 ++++++ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java index b5fe45221836..a37f54ec726e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.BitmapFactory; +import android.support.annotation.StringRes; import android.support.v4.app.NotificationCompat; import org.wordpress.android.R; @@ -21,16 +22,15 @@ private static Intent getPendingIntent(Context context) { return resumeIntent; } - private static NotificationCompat.Builder getNotificationBuilder(Context context, String content) { + private static NotificationCompat.Builder getNotificationBuilder(Context context, @StringRes int content) { return new NotificationCompat.Builder(context) - .setContentTitle(content) .setSmallIcon(R.drawable.ic_my_sites_24dp) .setColor(context.getResources().getColor(R.color.blue_wordpress)) .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.app_icon)) .setAutoCancel(true); } - static Notification progress(Context context, int progress, String content) { + static Notification progress(Context context, int progress, @StringRes int content) { return getNotificationBuilder(context, content) .setContentIntent(PendingIntent.getActivity( context, @@ -41,7 +41,7 @@ static Notification progress(Context context, int progress, String content) { .build(); } - static Notification success(Context context, String content) { + static Notification success(Context context, @StringRes int content) { return getNotificationBuilder(context, content) .setContentIntent(PendingIntent.getActivity( context, @@ -51,8 +51,13 @@ static Notification success(Context context, String content) { .build(); } - static Notification failure(Context context, String content) { + static Notification failure(Context context, @StringRes int content) { + NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(); + bigTextStyle.setBigContentTitle(context.getString(R.string.notification_login_stopped)); + bigTextStyle.bigText(context.getString(content)); + return getNotificationBuilder(context, content) + .setStyle(bigTextStyle) .setContentIntent(PendingIntent.getActivity( context, AutoForeground.NOTIFICATION_ID_FAILURE, diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 342f1ee268fd..542b5803479a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -151,17 +151,17 @@ public Notification getNotification() { case FETCHING_ACCOUNT: case FETCHING_SETTINGS: case FETCHING_SITES: - return LoginNotification.progress(this, mLoginPhase.progressPercent, "Logging in..."); + return LoginNotification.progress(this, mLoginPhase.progressPercent, R.string.notification_logging_in); case SUCCESS: - return LoginNotification.success(this, "Logged in!"); + return LoginNotification.success(this, R.string.notification_logged_in); case FAILURE_EMAIL_WRONG_PASSWORD: - return LoginNotification.failure(this, "Wrong password :("); + return LoginNotification.failure(this, R.string.notification_error_wrong_password); case FAILURE_2FA: - return LoginNotification.failure(this, "Need to input a 2FA code to continue."); + return LoginNotification.failure(this, R.string.notification_2fa_needed); case FAILURE_SOCIAL_2FA: - return LoginNotification.failure(this, "Need to input a 2FA code to continue."); + return LoginNotification.failure(this, R.string.notification_2fa_needed); case FAILURE: - return LoginNotification.failure(this, "Login failed :("); + return LoginNotification.failure(this, R.string.notification_login_failed); } return null; diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 16996a72fc27..fc4d722c0c46 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2016,5 +2016,11 @@ The Google account \'%s\' doesn\'t match any existing account on WordPress.com. There was some trouble connecting with the Google account. \nMaybe try a different account? + Logging in… + Logged in successfully! + Login stopped + Please double check your password to continue. + Please provide an authentication code to continue. + An error has occurred. From a7c3773ffae2b55eb5e1ab4e5cdf5c583b751a56 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 14:16:53 +0200 Subject: [PATCH 19/35] LoginWpcomService is not involved in this flow --- .../java/org/wordpress/android/ui/accounts/LoginActivity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java index 4d0d1a0498ba..b9f0045247bc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java @@ -328,7 +328,6 @@ public void needs2faSocial(String email, String userId, String nonceAuthenticato Login2FaFragment login2FaFragment = Login2FaFragment.newInstanceSocial(email, userId, nonceAuthenticator, nonceBackup, nonceSms); slideInFragment(login2FaFragment, true, Login2FaFragment.TAG); - LoginEmailPasswordFragment.clearLoginServiceState(); } @Override From 0efd8280160b28964e63994f4cc3ba0c8650941b Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 14:20:27 +0200 Subject: [PATCH 20/35] clearLoginServiceState belongs in LoginWpcomService --- .../wordpress/android/ui/accounts/LoginActivity.java | 7 ++++--- .../ui/accounts/login/LoginEmailPasswordFragment.java | 10 +--------- .../android/ui/accounts/login/LoginWpcomService.java | 7 +++++++ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java index b9f0045247bc..e0edb012482e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java @@ -30,6 +30,7 @@ import org.wordpress.android.ui.accounts.login.LoginPrologueFragment; import org.wordpress.android.ui.accounts.login.LoginSiteAddressFragment; import org.wordpress.android.ui.accounts.login.LoginUsernamePasswordFragment; +import org.wordpress.android.ui.accounts.login.LoginWpcomService; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.HelpshiftHelper; import org.wordpress.android.util.HelpshiftHelper.Tag; @@ -305,7 +306,7 @@ public void usePasswordInstead(String email) { LoginEmailPasswordFragment loginEmailPasswordFragment = LoginEmailPasswordFragment.newInstance(email, null, null, null, false); slideInFragment(loginEmailPasswordFragment, true, LoginEmailPasswordFragment.TAG); - LoginEmailPasswordFragment.clearLoginServiceState(); + LoginWpcomService.clearLoginServiceState(); } @Override @@ -318,7 +319,7 @@ public void forgotPassword(String url) { public void needs2fa(String email, String password) { Login2FaFragment login2FaFragment = Login2FaFragment.newInstance(email, password); slideInFragment(login2FaFragment, true, Login2FaFragment.TAG); - LoginEmailPasswordFragment.clearLoginServiceState(); + LoginWpcomService.clearLoginServiceState(); } @Override @@ -335,7 +336,7 @@ public void needs2faSocialConnect(String email, String password, String idToken, AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_2FA_NEEDED); Login2FaFragment login2FaFragment = Login2FaFragment.newInstanceSocialConnect(email, password, idToken, service); slideInFragment(login2FaFragment, true, Login2FaFragment.TAG); - LoginEmailPasswordFragment.clearLoginServiceState(); + LoginWpcomService.clearLoginServiceState(); } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index 90be6b2dc9da..42aee860879c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -14,7 +14,6 @@ import android.widget.EditText; import android.widget.TextView; -import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; import org.wordpress.android.R; @@ -225,7 +224,7 @@ public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void onTextChanged(CharSequence s, int start, int before, int count) { mPasswordInput.setError(null); - clearLoginServiceState(); + LoginWpcomService.clearLoginServiceState(); } private void showPasswordError() { @@ -236,13 +235,6 @@ private void showError(String error) { mPasswordInput.setError(error); } - public static void clearLoginServiceState() { - OnLoginStateUpdated onLoginStateUpdated = EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); - if (onLoginStateUpdated != null && onLoginStateUpdated.state.isTerminal()) { - EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); - } - } - @Override protected void onLoginFinished() { if (isSocialLogin) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 542b5803479a..f1c53b827e1c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -120,6 +120,13 @@ public static void loginWithEmailAndPassword( context.startService(intent); } + public static void clearLoginServiceState() { + OnLoginStateUpdated onLoginStateUpdated = EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); + if (onLoginStateUpdated != null && onLoginStateUpdated.state.isTerminal()) { + EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); + } + } + public LoginWpcomService() { super(OnLoginStateUpdated.class); } From 8db8efdef3e9d6ca87bada1e802e601c500f99c6 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 14:26:40 +0200 Subject: [PATCH 21/35] More specific name for the method --- .../android/ui/accounts/login/LoginWpcomService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index f1c53b827e1c..375c22f6d09c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -275,7 +275,7 @@ protected void startPostLoginServices() { NotificationsUpdateService.startService(getApplicationContext()); } - private void doFinishLogin() { + private void fetchAccount() { startPostLoginServices(); setState(LoginPhase.FETCHING_ACCOUNT); mDispatcher.dispatch(AccountActionBuilder.newFetchAccountAction()); @@ -308,7 +308,7 @@ public void onAuthenticationChanged(OnAuthenticationChanged event) { mDispatcher.dispatch(AccountActionBuilder.newPushSocialConnectAction(payload)); } else { signalCredentialsOK(); - doFinishLogin(); + fetchAccount(); } } @@ -327,10 +327,10 @@ public void onSocialChanged(AccountStore.OnSocialChanged event) { // Ignore other error cases. The above are the only two we have chosen to log. } - doFinishLogin(); + fetchAccount(); } else if (!event.requiresTwoStepAuth) { AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_CONNECT_SUCCESS); - doFinishLogin(); + fetchAccount(); } } From bc0c97683812ed6c4e9f13ebd48e685010e1f205 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 14:30:13 +0200 Subject: [PATCH 22/35] No need to start the reader/notif services yet --- .../wordpress/android/ui/accounts/login/LoginWpcomService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 375c22f6d09c..d83b7ae71373 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -276,7 +276,6 @@ protected void startPostLoginServices() { } private void fetchAccount() { - startPostLoginServices(); setState(LoginPhase.FETCHING_ACCOUNT); mDispatcher.dispatch(AccountActionBuilder.newFetchAccountAction()); } From e102757c6b58ea823794f3faff7ab8a0057c1e14 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Fri, 17 Nov 2017 16:03:47 +0200 Subject: [PATCH 23/35] Contain clearLoginServiceState's usage --- .../wordpress/android/ui/accounts/LoginActivity.java | 4 ---- .../ui/accounts/login/LoginEmailPasswordFragment.java | 11 ++++++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java index e0edb012482e..dbc026c343fe 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/LoginActivity.java @@ -30,7 +30,6 @@ import org.wordpress.android.ui.accounts.login.LoginPrologueFragment; import org.wordpress.android.ui.accounts.login.LoginSiteAddressFragment; import org.wordpress.android.ui.accounts.login.LoginUsernamePasswordFragment; -import org.wordpress.android.ui.accounts.login.LoginWpcomService; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.HelpshiftHelper; import org.wordpress.android.util.HelpshiftHelper.Tag; @@ -306,7 +305,6 @@ public void usePasswordInstead(String email) { LoginEmailPasswordFragment loginEmailPasswordFragment = LoginEmailPasswordFragment.newInstance(email, null, null, null, false); slideInFragment(loginEmailPasswordFragment, true, LoginEmailPasswordFragment.TAG); - LoginWpcomService.clearLoginServiceState(); } @Override @@ -319,7 +317,6 @@ public void forgotPassword(String url) { public void needs2fa(String email, String password) { Login2FaFragment login2FaFragment = Login2FaFragment.newInstance(email, password); slideInFragment(login2FaFragment, true, Login2FaFragment.TAG); - LoginWpcomService.clearLoginServiceState(); } @Override @@ -336,7 +333,6 @@ public void needs2faSocialConnect(String email, String password, String idToken, AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_SOCIAL_2FA_NEEDED); Login2FaFragment login2FaFragment = Login2FaFragment.newInstanceSocialConnect(email, password, idToken, service); slideInFragment(login2FaFragment, true, Login2FaFragment.TAG); - LoginWpcomService.clearLoginServiceState(); } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index 42aee860879c..dddee8453b1a 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -84,7 +84,10 @@ public void onCreate(Bundle savedInstanceState) { mService = getArguments().getString(ARG_SOCIAL_SERVICE); isSocialLogin = getArguments().getBoolean(ARG_SOCIAL_LOGIN); - if (savedInstanceState != null) { + if (savedInstanceState == null) { + // cleanup the service state on first appearance + LoginWpcomService.clearLoginServiceState(); + } else { mRequestedPassword = savedInstanceState.getString(KEY_REQUESTED_PASSWORD); } } @@ -275,10 +278,16 @@ public void onLoginStateUpdated(OnLoginStateUpdated event) { case FAILURE_2FA: onLoginFinished(false); mLoginListener.needs2fa(mEmailAddress, mRequestedPassword); + + // consume the state so we don't relauch the 2FA dialog if user backs up + LoginWpcomService.clearLoginServiceState(); break; case FAILURE_SOCIAL_2FA: onLoginFinished(false); mLoginListener.needs2faSocialConnect(mEmailAddress, mRequestedPassword, mIdToken, mService); + + // consume the state so we don't relauch the 2FA dialog if user backs up + LoginWpcomService.clearLoginServiceState(); break; case FAILURE_FETCHING_ACCOUNT: onLoginFinished(false); From ec41e9e849ba73d9744209f519c45bb267ddba57 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Sat, 18 Nov 2017 01:23:05 +0200 Subject: [PATCH 24/35] Big title and big content for all login notifications --- .../ui/accounts/login/LoginNotification.java | 19 ++++++++++--------- WordPress/src/main/res/values/strings.xml | 11 ++++++++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java index a37f54ec726e..6c6949f2a0b3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java @@ -22,8 +22,14 @@ private static Intent getPendingIntent(Context context) { return resumeIntent; } - private static NotificationCompat.Builder getNotificationBuilder(Context context, @StringRes int content) { + private static NotificationCompat.Builder getNotificationBuilder(Context context, @StringRes int title, + @StringRes int content) { + NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(); + bigTextStyle.setBigContentTitle(context.getString(title)); + bigTextStyle.bigText(context.getString(content)); + return new NotificationCompat.Builder(context) + .setStyle(bigTextStyle) .setSmallIcon(R.drawable.ic_my_sites_24dp) .setColor(context.getResources().getColor(R.color.blue_wordpress)) .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.app_icon)) @@ -31,7 +37,7 @@ private static NotificationCompat.Builder getNotificationBuilder(Context context } static Notification progress(Context context, int progress, @StringRes int content) { - return getNotificationBuilder(context, content) + return getNotificationBuilder(context, R.string.notification_login_title_in_progress, content) .setContentIntent(PendingIntent.getActivity( context, AutoForeground.NOTIFICATION_ID_PROGRESS, @@ -42,7 +48,7 @@ static Notification progress(Context context, int progress, @StringRes int conte } static Notification success(Context context, @StringRes int content) { - return getNotificationBuilder(context, content) + return getNotificationBuilder(context, R.string.notification_login_title_success, content) .setContentIntent(PendingIntent.getActivity( context, AutoForeground.NOTIFICATION_ID_SUCCESS, @@ -52,12 +58,7 @@ static Notification success(Context context, @StringRes int content) { } static Notification failure(Context context, @StringRes int content) { - NotificationCompat.BigTextStyle bigTextStyle = new NotificationCompat.BigTextStyle(); - bigTextStyle.setBigContentTitle(context.getString(R.string.notification_login_stopped)); - bigTextStyle.bigText(context.getString(content)); - - return getNotificationBuilder(context, content) - .setStyle(bigTextStyle) + return getNotificationBuilder(context, R.string.notification_login_title_stopped, content) .setContentIntent(PendingIntent.getActivity( context, AutoForeground.NOTIFICATION_ID_FAILURE, diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index fc4d722c0c46..34350cf1b4e5 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2016,9 +2016,14 @@ The Google account \'%s\' doesn\'t match any existing account on WordPress.com. There was some trouble connecting with the Google account. \nMaybe try a different account? - Logging in… - Logged in successfully! - Login stopped + + Logged in! + Tap to continue. + + Login in progress… + Please wait while logging in. + + Login stopped Please double check your password to continue. Please provide an authentication code to continue. An error has occurred. From c8287d381d2cffe0bfe8439e38afa54a09e2839d Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Sat, 18 Nov 2017 01:39:09 +0200 Subject: [PATCH 25/35] Finish the sentence --- .../android/ui/accounts/login/LoginEmailPasswordFragment.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java index dddee8453b1a..a727f433da3e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginEmailPasswordFragment.java @@ -99,7 +99,8 @@ public void onResume() { // connect to the Service. We'll receive updates via EventBus. mServiceEventConnection = new AutoForeground.ServiceEventConnection(getContext(), LoginWpcomService.class, this); - // install the change listener as late as possible so the UI can be setup before triggering the + // install the change listener as late as possible so the UI can be setup (updated from the Service state) + // before triggering the state cleanup happening in the change listener. mPasswordInput.addTextChangedListener(this); } From 327750254d299aecff745a117f1e8f4a536c8813 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Sat, 18 Nov 2017 01:45:33 +0200 Subject: [PATCH 26/35] Just clear the sticky event. Leftovers from bad merge. --- .../android/ui/accounts/login/LoginWpcomService.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index d83b7ae71373..91e5ce6d825e 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -121,10 +121,7 @@ public static void loginWithEmailAndPassword( } public static void clearLoginServiceState() { - OnLoginStateUpdated onLoginStateUpdated = EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); - if (onLoginStateUpdated != null && onLoginStateUpdated.state.isTerminal()) { - EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); - } + EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); } public LoginWpcomService() { From d4f65a6cdd10c163ead18f7719670216ed0fefdb Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Sat, 18 Nov 2017 01:49:10 +0200 Subject: [PATCH 27/35] Minor code optimization --- .../android/ui/accounts/login/LoginWpcomService.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 91e5ce6d825e..925d063c23d6 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -277,12 +277,8 @@ private void fetchAccount() { mDispatcher.dispatch(AccountActionBuilder.newFetchAccountAction()); } - private EventBus getEventBus() { - return EventBus.getDefault(); - } - private void signalCredentialsOK() { - getEventBus().post(new OnCredentialsOK()); + EventBus.getDefault().post(new OnCredentialsOK()); } // OnChanged events From e4512f82c1fe67016d6d2f2ef5f816e80bf3a45e Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Sat, 18 Nov 2017 02:53:33 +0200 Subject: [PATCH 28/35] Don't set Large icon in login notifications That better matches other notifications in the app. --- .../wordpress/android/ui/accounts/login/LoginNotification.java | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java index 6c6949f2a0b3..3ea832bab673 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java @@ -32,7 +32,6 @@ private static NotificationCompat.Builder getNotificationBuilder(Context context .setStyle(bigTextStyle) .setSmallIcon(R.drawable.ic_my_sites_24dp) .setColor(context.getResources().getColor(R.color.blue_wordpress)) - .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.app_icon)) .setAutoCancel(true); } From 01b14490efdb77e95ed7ea068522c1f9a0ab3ceb Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Sat, 18 Nov 2017 02:57:34 +0200 Subject: [PATCH 29/35] Set title for standard notification style This way, a collapsed notification can still display useful information. --- .../wordpress/android/ui/accounts/login/LoginNotification.java | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java index 3ea832bab673..1e1e2371cd10 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java @@ -30,6 +30,7 @@ private static NotificationCompat.Builder getNotificationBuilder(Context context return new NotificationCompat.Builder(context) .setStyle(bigTextStyle) + .setContentTitle(context.getString(title)) .setSmallIcon(R.drawable.ic_my_sites_24dp) .setColor(context.getResources().getColor(R.color.blue_wordpress)) .setAutoCancel(true); From b8243bcf861860be35938271c9db116359ed155b Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Mon, 20 Nov 2017 15:11:12 +0200 Subject: [PATCH 30/35] Rename, better comments for getResumeIntent --- .../android/ui/accounts/login/LoginNotification.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java index 1e1e2371cd10..ce40738972a3 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java @@ -13,9 +13,11 @@ class LoginNotification { private static Intent getPendingIntent(Context context) { + // Let's get an Intent with the sole purpose of _resuming_ the app from the background Intent resumeIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); - // apparently, we need to null out the package name to make the intent resume the app + // getLaunchIntentForPackage() seems to set the Package Name but if we construct a launcher Intent manually + // the package name is not set so, let's null it out here to match the manual Intent. resumeIntent.setSelector(null); resumeIntent.setPackage(null); From ac72de2862512bf638e35950c7337182fb64da47 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Mon, 20 Nov 2017 15:29:15 +0200 Subject: [PATCH 31/35] Rename the method for better description --- .../android/ui/accounts/login/LoginNotification.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java index ce40738972a3..b40eb6d7ea65 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java @@ -4,7 +4,6 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.graphics.BitmapFactory; import android.support.annotation.StringRes; import android.support.v4.app.NotificationCompat; @@ -12,7 +11,7 @@ import org.wordpress.android.util.AutoForeground; class LoginNotification { - private static Intent getPendingIntent(Context context) { + private static Intent getResumeIntent(Context context) { // Let's get an Intent with the sole purpose of _resuming_ the app from the background Intent resumeIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()); @@ -43,7 +42,7 @@ static Notification progress(Context context, int progress, @StringRes int conte .setContentIntent(PendingIntent.getActivity( context, AutoForeground.NOTIFICATION_ID_PROGRESS, - getPendingIntent(context), + getResumeIntent(context), PendingIntent.FLAG_ONE_SHOT)) .setProgress(100, progress, false) .build(); @@ -54,7 +53,7 @@ static Notification success(Context context, @StringRes int content) { .setContentIntent(PendingIntent.getActivity( context, AutoForeground.NOTIFICATION_ID_SUCCESS, - getPendingIntent(context), + getResumeIntent(context), PendingIntent.FLAG_ONE_SHOT)) .build(); } @@ -64,7 +63,7 @@ static Notification failure(Context context, @StringRes int content) { .setContentIntent(PendingIntent.getActivity( context, AutoForeground.NOTIFICATION_ID_FAILURE, - getPendingIntent(context), + getResumeIntent(context), PendingIntent.FLAG_ONE_SHOT)) .build(); } From 398faac3ebe22615e64481853540c1512fd71883 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Mon, 20 Nov 2017 15:30:54 +0200 Subject: [PATCH 32/35] Set the standard content text along with the title --- .../wordpress/android/ui/accounts/login/LoginNotification.java | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java index b40eb6d7ea65..fc330292df53 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java @@ -32,6 +32,7 @@ private static NotificationCompat.Builder getNotificationBuilder(Context context return new NotificationCompat.Builder(context) .setStyle(bigTextStyle) .setContentTitle(context.getString(title)) + .setContentText(context.getString(content)) .setSmallIcon(R.drawable.ic_my_sites_24dp) .setColor(context.getResources().getColor(R.color.blue_wordpress)) .setAutoCancel(true); From d3124f8c8c977e0c6c7b03e9da9e7131acad2150 Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Mon, 27 Nov 2017 15:34:49 +0200 Subject: [PATCH 33/35] Add Tracks of the service phase updates --- .../android/ui/accounts/login/LoginWpcomService.java | 11 +++++++++++ .../wordpress/android/analytics/AnalyticsTracker.java | 1 + .../android/analytics/AnalyticsTrackerNosara.java | 2 ++ .../org/wordpress/android/util/AutoForeground.java | 8 ++++++++ 4 files changed, 22 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 925d063c23d6..e4a6e58bc8da 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -29,6 +29,8 @@ import org.wordpress.android.util.ToastUtils; import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; import javax.inject.Inject; @@ -183,6 +185,15 @@ private void setState(LoginPhase loginPhase) { mDispatcher.unregister(this); stopSelf(); } + + track(); + } + + private void track() { + Map props = new HashMap<>(); + props.put("login_phase", mLoginPhase.name()); + props.put("login_service_is_foreground", isForeground()); + AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_WPCOM_BACKGROUND_SERVICE_UPDATE, props); } @Override diff --git a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java index b70b283afc70..9574c536ac4b 100644 --- a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java +++ b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java @@ -239,6 +239,7 @@ public enum Stat { LOGIN_SOCIAL_2FA_NEEDED, LOGIN_SOCIAL_ACCOUNTS_NEED_CONNECTING, LOGIN_SOCIAL_ERROR_UNKNOWN_USER, + LOGIN_WPCOM_BACKGROUND_SERVICE_UPDATE, MEDIA_LIBRARY_ADDED_PHOTO, MEDIA_LIBRARY_ADDED_VIDEO, PERSON_REMOVED, diff --git a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java index 2b073d48ea02..d691d7da8ab0 100644 --- a/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java +++ b/libs/analytics/WordPressAnalytics/src/main/java/org/wordpress/android/analytics/AnalyticsTrackerNosara.java @@ -746,6 +746,8 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) { return "login_social_accounts_need_connecting"; case LOGIN_SOCIAL_ERROR_UNKNOWN_USER: return "login_social_error_unknown_user"; + case LOGIN_WPCOM_BACKGROUND_SERVICE_UPDATE: + return "login_wpcom_background_service_update"; case PERSON_REMOVED: return "people_management_person_removed"; case PERSON_UPDATED: diff --git a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java index c2c7af577bc5..669b0a7ff4c2 100644 --- a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java +++ b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/AutoForeground.java @@ -53,6 +53,8 @@ private class LocalBinder extends Binder {} private final Class mEventClass; + private boolean mIsForeground; + protected abstract EventClass getCurrentStateEvent(); protected abstract Notification getNotification(); protected abstract boolean isIdle(); @@ -63,6 +65,10 @@ protected AutoForeground(Class eventClass) { mEventClass = eventClass; } + public boolean isForeground() { + return mIsForeground; + } + @Override public void onCreate() { super.onCreate(); @@ -114,11 +120,13 @@ private boolean hasConnectedClients() { private void promoteForeground() { if (isInProgress()) { startForeground(NOTIFICATION_ID_PROGRESS, getNotification()); + mIsForeground = true; } } private void background() { stopForeground(true); + mIsForeground = false; } @CallSuper From 4e6526ca3305b40aac2b1ef9138a8aaa3e622a9c Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Mon, 27 Nov 2017 15:49:54 +0200 Subject: [PATCH 34/35] Track early, before foregroundness changes --- .../wordpress/android/ui/accounts/login/LoginWpcomService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index e4a6e58bc8da..77ca04e882db 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -179,14 +179,13 @@ private void setState(LoginPhase loginPhase) { } mLoginPhase = loginPhase; + track(); notifyState(); if (mLoginPhase.isTerminal()) { mDispatcher.unregister(this); stopSelf(); } - - track(); } private void track() { From f83dd70d1a8802c32ff3018f08776f0d78bd066c Mon Sep 17 00:00:00 2001 From: Stefanos Togkoulidis Date: Mon, 27 Nov 2017 16:56:25 +0200 Subject: [PATCH 35/35] Null check for mLoginPhase --- .../wordpress/android/ui/accounts/login/LoginWpcomService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java index 77ca04e882db..a47debd17f54 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginWpcomService.java @@ -190,7 +190,7 @@ private void setState(LoginPhase loginPhase) { private void track() { Map props = new HashMap<>(); - props.put("login_phase", mLoginPhase.name()); + props.put("login_phase", mLoginPhase == null ? "null" : mLoginPhase.name()); props.put("login_service_is_foreground", isForeground()); AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_WPCOM_BACKGROUND_SERVICE_UPDATE, props); }