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 a727f433da3e..550102a7d7cd 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 @@ -257,9 +257,9 @@ public void onCredentialsOK(OnCredentialsOK event) { @SuppressWarnings("unused") @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void onLoginStateUpdated(OnLoginStateUpdated event) { - AppLog.i(T.NUX, "Received state: " + event.state.name()); + AppLog.i(T.NUX, "Received state: " + event.getState().name()); - switch (event.state) { + switch (event.getState()) { case IDLE: // nothing special to do, we'll start the service on next() break; 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 a47debd17f54..39522fe0b450 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 @@ -20,21 +20,23 @@ 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.accounts.login.LoginWpcomService.LoginPhase; import org.wordpress.android.ui.notifications.services.NotificationsUpdateService; import org.wordpress.android.ui.reader.services.ReaderUpdateService; 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; +import org.wordpress.android.util.AutoForegroundNotification; import org.wordpress.android.util.ToastUtils; import java.util.EnumSet; -import java.util.HashMap; import java.util.Map; + import javax.inject.Inject; -public class LoginWpcomService extends AutoForeground { +public class LoginWpcomService extends AutoForeground { private static final String ARG_EMAIL = "ARG_EMAIL"; private static final String ARG_PASSWORD = "ARG_PASSWORD"; @@ -42,7 +44,7 @@ public class LoginWpcomService extends AutoForeground { private static final String ARG_SOCIAL_LOGIN = "ARG_SOCIAL_LOGIN"; private static final String ARG_SOCIAL_SERVICE = "ARG_SOCIAL_SERVICE"; - public enum LoginPhase { + public enum LoginPhase implements AutoForeground.ServicePhase { IDLE, AUTHENTICATING(25), SOCIAL_LOGIN(25), @@ -67,30 +69,43 @@ public enum LoginPhase { this.progressPercent = progressPercent; } + @Override + public boolean isIdle() { + return this == IDLE; + } + + @Override public boolean isInProgress() { - return this != LoginPhase.IDLE && !isTerminal(); + return this != IDLE && !isTerminal(); } + @Override 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_FETCHING_ACCOUNT - || this == LoginPhase.FAILURE_CANNOT_ADD_DUPLICATE_SITE; + return this == FAILURE + || this == FAILURE_EMAIL_WRONG_PASSWORD + || this == FAILURE_2FA + || this == FAILURE_SOCIAL_2FA + || this == FAILURE_FETCHING_ACCOUNT + || this == FAILURE_CANNOT_ADD_DUPLICATE_SITE; } + @Override public boolean isTerminal() { return this == LoginPhase.SUCCESS || isError(); } } - public static class OnLoginStateUpdated { - public final LoginPhase state; + public static class OnLoginStateUpdated implements AutoForeground.ServiceEvent { + private final LoginPhase state; OnLoginStateUpdated(LoginPhase state) { this.state = state; } + + @Override + public LoginPhase getState() { + return state; + } } static class OnCredentialsOK { @@ -101,8 +116,6 @@ static class OnCredentialsOK { @Inject AccountStore mAccountStore; @Inject SiteStore mSiteStore; - private LoginPhase mLoginPhase = LoginPhase.IDLE; - private String mIdToken; private String mService; private boolean isSocialLogin; @@ -123,75 +136,59 @@ public static void loginWithEmailAndPassword( } public static void clearLoginServiceState() { - EventBus.getDefault().removeStickyEvent(OnLoginStateUpdated.class); + clearServiceState(OnLoginStateUpdated.class); } public LoginWpcomService() { - super(OnLoginStateUpdated.class); - } - - @Override - protected OnLoginStateUpdated getCurrentStateEvent() { - return new OnLoginStateUpdated(mLoginPhase); + super(LoginPhase.IDLE, OnLoginStateUpdated.class); } @Override - public boolean isIdle() { - return mLoginPhase == LoginPhase.IDLE; + protected void onProgressStart() { + mDispatcher.register(this); } @Override - public boolean isInProgress() { - return mLoginPhase.isInProgress(); + protected void onProgressEnd() { + mDispatcher.unregister(this); } @Override - public boolean isError() { - return mLoginPhase.isError(); + protected OnLoginStateUpdated getStateEvent(LoginPhase phase) { + return new OnLoginStateUpdated(phase); } @Override - public Notification getNotification() { - switch (mLoginPhase) { + public Notification getNotification(LoginPhase phase) { + switch (phase) { case AUTHENTICATING: case FETCHING_ACCOUNT: case FETCHING_SETTINGS: case FETCHING_SITES: - return LoginNotification.progress(this, mLoginPhase.progressPercent, R.string.notification_logging_in); + return AutoForegroundNotification.progress(this, phase.progressPercent, + R.string.notification_login_title_in_progress, R.string.notification_logging_in); case SUCCESS: - return LoginNotification.success(this, R.string.notification_logged_in); + return AutoForegroundNotification.success(this, R.string.notification_login_title_success, + R.string.notification_logged_in); case FAILURE_EMAIL_WRONG_PASSWORD: - return LoginNotification.failure(this, R.string.notification_error_wrong_password); + return AutoForegroundNotification.failure(this, R.string.notification_login_title_stopped, + R.string.notification_error_wrong_password); case FAILURE_2FA: - return LoginNotification.failure(this, R.string.notification_2fa_needed); + return AutoForegroundNotification.failure(this, R.string.notification_login_title_stopped, + R.string.notification_2fa_needed); case FAILURE_SOCIAL_2FA: - return LoginNotification.failure(this, R.string.notification_2fa_needed); + return AutoForegroundNotification.failure(this, R.string.notification_login_title_stopped, + R.string.notification_2fa_needed); case FAILURE: - return LoginNotification.failure(this, R.string.notification_login_failed); + return AutoForegroundNotification.failure(this, R.string.notification_login_title_stopped, + R.string.notification_login_failed); } return null; } - private void setState(LoginPhase loginPhase) { - if (!mLoginPhase.isInProgress() && loginPhase.isInProgress()) { - mDispatcher.register(this); - } - - mLoginPhase = loginPhase; - track(); - notifyState(); - - if (mLoginPhase.isTerminal()) { - mDispatcher.unregister(this); - stopSelf(); - } - } - - private void track() { - Map props = new HashMap<>(); - props.put("login_phase", mLoginPhase == null ? "null" : mLoginPhase.name()); - props.put("login_service_is_foreground", isForeground()); + @Override + protected void trackPhaseUpdate(Map props) { AnalyticsTracker.track(AnalyticsTracker.Stat.LOGIN_WPCOM_BACKGROUND_SERVICE_UPDATE, props); } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/signup/SiteCreatingFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/signup/SiteCreatingFragment.java index 036ef9e8f5c3..12a42f051c12 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/signup/SiteCreatingFragment.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/signup/SiteCreatingFragment.java @@ -74,9 +74,9 @@ public void onPause() { @SuppressWarnings("unused") @Subscribe(threadMode = ThreadMode.MAIN) public void onSiteCreationPhaseUpdated(OnSiteCreationStateUpdated event) { - AppLog.i(T.NUX, "Received state: " + event.state.name()); + AppLog.i(T.NUX, "Received state: " + event.getState().name()); - switch (event.state) { + switch (event.getState()) { case IDLE: SiteCreationService.createSite(getActivity(), WordPress.getBuildConfigString(getActivity(), "DEBUG_DOTCOM_NEW_SITE_TITLE"), diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/signup/SiteCreationService.java b/WordPress/src/main/java/org/wordpress/android/ui/accounts/signup/SiteCreationService.java index 52daacabeca7..3d9697ecc1b4 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/signup/SiteCreationService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/accounts/signup/SiteCreationService.java @@ -1,12 +1,9 @@ package org.wordpress.android.ui.accounts.signup; 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 com.android.volley.VolleyError; import com.wordpress.rest.RestRequest; @@ -21,51 +18,85 @@ import org.wordpress.android.fluxc.generated.SiteActionBuilder; import org.wordpress.android.fluxc.model.SiteModel; import org.wordpress.android.fluxc.model.ThemeModel; -import org.wordpress.android.fluxc.store.AccountStore; import org.wordpress.android.fluxc.store.SiteStore; import org.wordpress.android.fluxc.store.ThemeStore; -import org.wordpress.android.ui.accounts.NewBlogActivity; import org.wordpress.android.ui.accounts.signup.SiteCreationService.OnSiteCreationStateUpdated; +import org.wordpress.android.ui.accounts.signup.SiteCreationService.SiteCreationPhase; import org.wordpress.android.ui.prefs.SiteSettingsInterface; import org.wordpress.android.util.AppLog; import org.wordpress.android.util.AppLog.T; import org.wordpress.android.util.AutoForeground; +import org.wordpress.android.util.AutoForegroundNotification; import org.wordpress.android.util.LanguageUtils; +import java.util.Map; + import javax.inject.Inject; -public class SiteCreationService extends AutoForeground { +public class SiteCreationService extends AutoForeground { private static final String ARG_SITE_TITLE = "ARG_SITE_TITLE"; private static final String ARG_SITE_TAGLINE = "ARG_SITE_TAGLINE"; private static final String ARG_SITE_SLUG = "ARG_SITE_SLUG"; private static final String ARG_SITE_THEME_ID = "ARG_SITE_THEME_ID"; - public enum SiteCreationPhase { + public enum SiteCreationPhase implements AutoForeground.ServicePhase { IDLE, - NEW_SITE, - FETCHING_NEW_SITE, - SET_TAGLINE, - SET_THEME, + NEW_SITE(25), + FETCHING_NEW_SITE(50), + SET_TAGLINE(75), + SET_THEME(100), SUCCESS, - FAILURE + FAILURE; + + public final int progressPercent; + + SiteCreationPhase() { + this.progressPercent = 0; + } + + SiteCreationPhase(int progressPercent) { + this.progressPercent = progressPercent; + } + + @Override + public boolean isIdle() { + return this == IDLE; + } + + @Override + public boolean isInProgress() { + return this != IDLE && !isTerminal(); + } + + @Override + public boolean isError() { + return this == FAILURE; + } + + @Override + public boolean isTerminal() { + return this == SUCCESS || isError(); + } } - public static class OnSiteCreationStateUpdated { - public final SiteCreationPhase state; + public static class OnSiteCreationStateUpdated implements AutoForeground.ServiceEvent { + private final SiteCreationPhase state; public OnSiteCreationStateUpdated(SiteCreationPhase state) { this.state = state; } + + @Override + public SiteCreationPhase getState() { + return state; + } } @Inject Dispatcher mDispatcher; - @Inject AccountStore mAccountStore; @Inject SiteStore mSiteStore; @Inject ThemeStore mThemeStore; - private SiteCreationPhase mSiteCreationPhase = SiteCreationPhase.IDLE; - private String mSiteTagline; private ThemeModel mSiteTheme; private long mNewSiteRemoteId; @@ -84,59 +115,55 @@ public static void createSite( context.startService(intent); } - public SiteCreationService() { - super(OnSiteCreationStateUpdated.class); + public static void clearSiteCreationServiceState() { + clearServiceState(SiteCreationService.OnSiteCreationStateUpdated.class); } - @Override - protected OnSiteCreationStateUpdated getCurrentStateEvent() { - return new OnSiteCreationStateUpdated(mSiteCreationPhase); + public SiteCreationService() { + super(SiteCreationPhase.IDLE, OnSiteCreationStateUpdated.class); } @Override - protected boolean isIdle() { - return mSiteCreationPhase == SiteCreationPhase.IDLE; + protected void onProgressStart() { + mDispatcher.register(this); } @Override - public boolean isInProgress() { - return mSiteCreationPhase != SiteCreationPhase.IDLE - && mSiteCreationPhase != SiteCreationPhase.SUCCESS - && mSiteCreationPhase != SiteCreationPhase.FAILURE; + protected void onProgressEnd() { + mDispatcher.unregister(this); } @Override - public boolean isError() { - return mSiteCreationPhase == SiteCreationPhase.FAILURE; + protected OnSiteCreationStateUpdated getStateEvent(SiteCreationPhase phase) { + return new OnSiteCreationStateUpdated(phase); } @Override - public Notification getNotification() { - switch (mSiteCreationPhase) { + public Notification getNotification(SiteCreationPhase phase) { + switch (phase) { case NEW_SITE: - return getProgressNotification(25, "Site creation in: " + mSiteCreationPhase.name()); case FETCHING_NEW_SITE: - return getProgressNotification(50, "Site creation in: " + mSiteCreationPhase.name()); case SET_TAGLINE: - return getProgressNotification(75, "Site creation in: " + mSiteCreationPhase.name()); case SET_THEME: - return getProgressNotification(100, "Site creation in: " + mSiteCreationPhase.name()); + return AutoForegroundNotification.progress(this, 25, + R.string.notification_site_creation_title_in_progress, + R.string.notification_site_creation_please_wait); case SUCCESS: - return getSuccessNotification("Site created!"); + return AutoForegroundNotification.success(this, + R.string.notification_site_creation_title_success, + R.string.notification_site_creation_created); case FAILURE: - return getFailureNotification("Site creation failed :("); + return AutoForegroundNotification.success(this, + R.string.notification_site_creation_title_stopped, + R.string.notification_site_creation_failed); } return null; } - private void setState(SiteCreationPhase siteCreationPhase) { - mSiteCreationPhase = siteCreationPhase; - notifyState(); - - if (siteCreationPhase == SiteCreationPhase.FAILURE || siteCreationPhase == SiteCreationPhase.SUCCESS) { - stopSelf(); - } + @Override + protected void trackPhaseUpdate(Map props) { + AnalyticsTracker.track(AnalyticsTracker.Stat.SITE_CREATION_BACKGROUND_SERVICE_UPDATE, props); } @Override @@ -145,68 +172,16 @@ public void onCreate() { ((WordPress) getApplication()).component().inject(this); AppLog.i(T.MAIN, "SiteCreationService > Created"); - mDispatcher.register(this); // TODO: Recover any site creations that were interrupted by the service being stopped? } @Override public void onDestroy() { - mDispatcher.unregister(this); AppLog.i(T.MAIN, "SiteCreationService > Destroyed"); super.onDestroy(); } - private Intent getPendingIntent() { - return new Intent(this, NewBlogActivity.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(SiteCreationService.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(SiteCreationService.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(SiteCreationService.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) { @@ -284,8 +259,9 @@ public void onSiteChanged(SiteStore.OnSiteChanged event) { } final SiteModel site = mSiteStore.getSiteBySiteId(mNewSiteRemoteId); + final SiteCreationPhase phase = getPhase(); - if (mSiteCreationPhase == SiteCreationPhase.FETCHING_NEW_SITE) { + if (phase == SiteCreationPhase.FETCHING_NEW_SITE) { Intent intent = new Intent(); if (site == null) { setState(SiteCreationPhase.FAILURE); @@ -334,7 +310,7 @@ public void onCredentialsValidated(Exception error) { siteSettings.init(false); siteSettings.setTagline(mSiteTagline); siteSettings.saveSettings(); - } else if (mSiteCreationPhase == SiteCreationPhase.SET_TAGLINE) { + } else if (phase == SiteCreationPhase.SET_TAGLINE) { setState(SiteCreationPhase.SET_THEME); activateTheme(site, mSiteTheme); } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java b/WordPress/src/main/java/org/wordpress/android/util/AutoForegroundNotification.java similarity index 79% rename from WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java rename to WordPress/src/main/java/org/wordpress/android/util/AutoForegroundNotification.java index fc330292df53..d4c8c6b39a95 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/accounts/login/LoginNotification.java +++ b/WordPress/src/main/java/org/wordpress/android/util/AutoForegroundNotification.java @@ -1,4 +1,4 @@ -package org.wordpress.android.ui.accounts.login; +package org.wordpress.android.util; import android.app.Notification; import android.app.PendingIntent; @@ -8,9 +8,8 @@ import android.support.v4.app.NotificationCompat; import org.wordpress.android.R; -import org.wordpress.android.util.AutoForeground; -class LoginNotification { +public class AutoForegroundNotification { 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()); @@ -38,8 +37,8 @@ private static NotificationCompat.Builder getNotificationBuilder(Context context .setAutoCancel(true); } - static Notification progress(Context context, int progress, @StringRes int content) { - return getNotificationBuilder(context, R.string.notification_login_title_in_progress, content) + public static Notification progress(Context context, int progress, @StringRes int title, @StringRes int content) { + return getNotificationBuilder(context, title, content) .setContentIntent(PendingIntent.getActivity( context, AutoForeground.NOTIFICATION_ID_PROGRESS, @@ -49,8 +48,8 @@ static Notification progress(Context context, int progress, @StringRes int conte .build(); } - static Notification success(Context context, @StringRes int content) { - return getNotificationBuilder(context, R.string.notification_login_title_success, content) + public static Notification success(Context context, @StringRes int title, @StringRes int content) { + return getNotificationBuilder(context, title, content) .setContentIntent(PendingIntent.getActivity( context, AutoForeground.NOTIFICATION_ID_SUCCESS, @@ -59,8 +58,8 @@ static Notification success(Context context, @StringRes int content) { .build(); } - static Notification failure(Context context, @StringRes int content) { - return getNotificationBuilder(context, R.string.notification_login_title_stopped, content) + public static Notification failure(Context context, @StringRes int title, @StringRes int content) { + return getNotificationBuilder(context, title, 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 076db5b1b3db..cac45da18a9a 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2010,12 +2010,19 @@ There was some trouble connecting with the Google account. \nMaybe try a different account? + + Site created! + Tap to continue. + Creating site… + Please wait while creating your site. + Site creation stopped + An error has occurred. + + 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. 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 9574c536ac4b..500c739c6889 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 @@ -262,6 +262,7 @@ public enum Stat { THEMES_SUPPORT_ACCESSED, THEMES_DETAILS_ACCESSED, ACCOUNT_SETTINGS_LANGUAGE_CHANGED, + SITE_CREATION_BACKGROUND_SERVICE_UPDATE, SITE_SETTINGS_ACCESSED, SITE_SETTINGS_ACCESSED_MORE_SETTINGS, SITE_SETTINGS_LEARN_MORE_CLICKED, 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 d691d7da8ab0..070527adb6b5 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 @@ -808,6 +808,8 @@ public static String getEventNameForStat(AnalyticsTracker.Stat stat) { return "themes_details_accessed"; case ACCOUNT_SETTINGS_LANGUAGE_CHANGED: return "account_settings_language_changed"; + case SITE_CREATION_BACKGROUND_SERVICE_UPDATE: + return "site_creation_background_service_update"; case SITE_SETTINGS_ACCESSED: return "site_settings_accessed"; case SITE_SETTINGS_ACCESSED_MORE_SETTINGS: diff --git a/libs/utils/WordPressUtils/src/main/AndroidManifest.xml b/libs/utils/WordPressUtils/src/main/AndroidManifest.xml index 44b1dcddc8bf..d52c0f661462 100644 --- a/libs/utils/WordPressUtils/src/main/AndroidManifest.xml +++ b/libs/utils/WordPressUtils/src/main/AndroidManifest.xml @@ -2,4 +2,5 @@ + 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 0245e2b19635..f434b4f5ee81 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 @@ -14,12 +14,31 @@ import org.greenrobot.eventbus.EventBus; -public abstract class AutoForeground extends Service { +import org.wordpress.android.util.AutoForeground.ServiceEvent; +import org.wordpress.android.util.AutoForeground.ServicePhase; + +import java.util.HashMap; +import java.util.Map; + +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 interface ServicePhase { + boolean isIdle(); + boolean isInProgress(); + boolean isError(); + boolean isTerminal(); + String name(); + } + + public interface ServiceEvent { + T getState(); + } + public static class ServiceEventConnection { private final ServiceConnection mServiceConnection; @@ -52,29 +71,35 @@ private class LocalBinder extends Binder {} private final IBinder mBinder = new LocalBinder(); private final Class mEventClass; - - protected abstract EventClass getCurrentStateEvent(); - protected abstract Notification getNotification(); + private final PhaseClass mInitialPhase; private boolean mIsForeground; - protected abstract boolean isIdle(); - protected abstract boolean isInProgress(); - protected abstract boolean isError(); + protected abstract void onProgressStart(); + protected abstract void onProgressEnd(); + + protected abstract EventClass getStateEvent(PhaseClass phase); + protected abstract Notification getNotification(PhaseClass phase); + protected abstract void trackPhaseUpdate(Map props); - protected AutoForeground(Class eventClass) { + protected AutoForeground(PhaseClass initialPhase, Class eventClass) { mEventClass = eventClass; + mInitialPhase = initialPhase; } public boolean isForeground() { return mIsForeground; } + protected PhaseClass getPhase() { + return EventBus.getDefault().getStickyEvent(mEventClass).getState(); + } + @Override public void onCreate() { super.onCreate(); - notifyState(); + notifyState(mInitialPhase); } @Nullable @@ -119,8 +144,9 @@ private boolean hasConnectedClients() { } private void promoteForeground() { - if (isInProgress()) { - startForeground(NOTIFICATION_ID_PROGRESS, getNotification()); + final PhaseClass phase = getPhase(); + if (phase.isInProgress()) { + startForeground(NOTIFICATION_ID_PROGRESS, getNotification(phase)); mIsForeground = true; } } @@ -131,9 +157,35 @@ private void background() { } @CallSuper - protected void notifyState() { + protected void setState(PhaseClass newPhase) { + if (!getPhase().isInProgress() && newPhase.isInProgress()) { + onProgressStart(); + } + + track(newPhase); + notifyState(newPhase); + + if (newPhase.isTerminal()) { + onProgressEnd(); + stopSelf(); + } + } + + private void track(ServicePhase phase) { + Map props = new HashMap<>(); + props.put("login_phase", phase == null ? "null" : phase.name()); + props.put("login_service_is_foreground", isForeground()); + trackPhaseUpdate(props); + } + + protected static void clearServiceState(T klass) { + EventBus.getDefault().removeStickyEvent(klass); + } + + @CallSuper + protected void notifyState(PhaseClass phase) { // sticky emit the state. The stickiness serves as a state keeping mechanism for clients to re-read upon connect - getEventBus().postSticky(getCurrentStateEvent()); + getEventBus().postSticky(getStateEvent(phase)); if (hasConnectedClients()) { // there are connected clients so, nothing more to do here @@ -142,14 +194,14 @@ protected void notifyState() { // ok, no connected clients so, update might need to be delivered to a notification as well - if (isIdle()) { + if (phase.isIdle()) { // no need to have a notification when idle return; } - if (isInProgress()) { + if (phase.isInProgress()) { // operation still is progress so, update the notification - NotificationManagerCompat.from(this).notify(NOTIFICATION_ID_PROGRESS, getNotification()); + NotificationManagerCompat.from(this).notify(NOTIFICATION_ID_PROGRESS, getNotification(phase)); return; } @@ -160,7 +212,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, - getNotification()); + NotificationManagerCompat.from(this).notify(phase.isError() ? NOTIFICATION_ID_FAILURE : NOTIFICATION_ID_SUCCESS, + getNotification(phase)); } }