From af9988fb196ab47eafb5453a73f653e48bd7abdd Mon Sep 17 00:00:00 2001 From: Maxime Biais Date: Thu, 7 Nov 2019 10:00:15 +0100 Subject: [PATCH 1/4] Gutenberg progressive rollout to 5% of our _wpcom_ userbase --- .../java/org/wordpress/android/WordPress.java | 2 +- .../wordpress/android/ui/prefs/AppPrefs.java | 9 +++++ .../org/wordpress/android/util/SiteUtils.java | 40 ++++++++++++++++++- .../util/analytics/AnalyticsUtils.java | 3 +- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/WordPress.java b/WordPress/src/main/java/org/wordpress/android/WordPress.java index 992c8f9919b9..a258b9069110 100644 --- a/WordPress/src/main/java/org/wordpress/android/WordPress.java +++ b/WordPress/src/main/java/org/wordpress/android/WordPress.java @@ -895,7 +895,7 @@ public void onAppComesFromBackground() { } // Let's migrate the old editor preference if available in AppPrefs to the remote backend - SiteUtils.migrateAppWideMobileEditorPreferenceToRemote(mContext, mDispatcher); + SiteUtils.migrateAppWideMobileEditorPreferenceToRemote(mAccountStore, mSiteStore, mDispatcher); if (mFirstActivityResumed) { deferredInit(); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java index 98a13bf8c178..2962155ae8f0 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java @@ -115,6 +115,7 @@ public enum DeletablePrefKey implements PrefKey { NEWS_CARD_SHOWN_VERSION, AVATAR_VERSION, GUTENBERG_DEFAULT_FOR_NEW_POSTS, + USER_IN_GUTENBERG_ROLLOUT_GROUP, SHOULD_AUTO_ENABLE_GUTENBERG_FOR_THE_NEW_POSTS, GUTENBERG_OPT_IN_DIALOG_SHOWN, @@ -607,6 +608,14 @@ public static boolean isDefaultAppWideEditorPreferenceSet() { return !"".equals(getString(DeletablePrefKey.GUTENBERG_DEFAULT_FOR_NEW_POSTS)); } + public static boolean isUserInGutenbergRolloutGroup() { + return getBoolean(DeletablePrefKey.GUTENBERG_DEFAULT_FOR_NEW_POSTS, false); + } + + public static void setUserInGutenbergRolloutGroup() { + setBoolean(DeletablePrefKey.GUTENBERG_DEFAULT_FOR_NEW_POSTS, true); + } + public static void removeAppWideEditorPreference() { remove(DeletablePrefKey.GUTENBERG_DEFAULT_FOR_NEW_POSTS); } diff --git a/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java b/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java index a004ea48c4f1..7b2d6ed785a2 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java @@ -1,6 +1,5 @@ package org.wordpress.android.util; -import android.content.Context; import android.text.TextUtils; import androidx.annotation.NonNull; @@ -10,6 +9,7 @@ import org.wordpress.android.fluxc.Dispatcher; import org.wordpress.android.fluxc.generated.SiteActionBuilder; import org.wordpress.android.fluxc.model.SiteModel; +import org.wordpress.android.fluxc.store.AccountStore; import org.wordpress.android.fluxc.store.SiteStore; import org.wordpress.android.fluxc.store.SiteStore.DesignateMobileEditorForAllSitesPayload; import org.wordpress.android.fluxc.store.SiteStore.DesignateMobileEditorPayload; @@ -25,6 +25,7 @@ public class SiteUtils { public static final String GB_EDITOR_NAME = "gutenberg"; public static final String AZTEC_EDITOR_NAME = "aztec"; + private static final int GB_ROLLOUT_PERCENTAGE = 5; /** * Migrate the old app-wide editor preference value to per-site setting. wpcom sites will make a network call @@ -35,8 +36,43 @@ public class SiteUtils { * -- 12.9 OPTED OUT (were auto-opted in but turned it OFF) -> turn all sites OFF in 13.0 * */ - public static void migrateAppWideMobileEditorPreferenceToRemote(final Context context, + public static void migrateAppWideMobileEditorPreferenceToRemote(final AccountStore accountStore, + final SiteStore siteStore, final Dispatcher dispatcher) { + // In a later version we might override mobile_editor setting if it's set to `aztec` and show a specific notice + // for these users ("We made a lot of progress on the block editor and we think it's now better than + // the classic editor, we switched it on, but you can change the configuration in your Site Settings"). + // ^ This code should be here. + + // If the user is already in the rollout group, we can skip this the migration. + if (AppPrefs.isUserInGutenbergRolloutGroup()) { + return; + } + + // Check if the user has been "randomly" selected to enter the rollout group. + // + // For self hosted sites, there are often one or two users, and the user id is probably 0, 1 in these cases. + // If we exclude low ids, we won't get an not an homogeneous distribution over self hosted and WordPress.com users, + // but the purpose of this is to do a progressive rollout, not an necessarily an homogeneous rollout. + // + // To exclude ids 0 and 1, to rollout for 10% users, we'll use a test like `id % 100 >= 90` instead of `id % 100 < 10`. + if (accountStore.getAccount().getUserId() % 100 >= (100 - GB_ROLLOUT_PERCENTAGE)) { + // We want to make sure to enable Gutenberg only on the sites they didn't opt-out. + for (SiteModel site : siteStore.getSites()) { + if (TextUtils.isEmpty(site.getMobileEditor())) { + // Enable Gutenberg + enableBlockEditor(dispatcher, site); + AnalyticsUtils.trackWithSiteDetails(Stat.EDITOR_GUTENBERG_ENABLED, site, + BlockEditorEnabledSource.ON_PROGRESSIVE_ROLLOUT.asPropertyMap()); + // Show the info popup when the user creates a new post for the first time on this site + AppPrefs.setShowGutenbergInfoPopupForTheNewPosts(site.getUrl(), true); + } + } + + // After enabling Gutenberg on these sites, we consider the user entered the rollout group + AppPrefs.setUserInGutenbergRolloutGroup(); + } + if (!AppPrefs.isDefaultAppWideEditorPreferenceSet()) { return; } diff --git a/WordPress/src/main/java/org/wordpress/android/util/analytics/AnalyticsUtils.java b/WordPress/src/main/java/org/wordpress/android/util/analytics/AnalyticsUtils.java index fea7c9bf8ae3..5e3f53e9ebf9 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/analytics/AnalyticsUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/util/analytics/AnalyticsUtils.java @@ -73,7 +73,8 @@ public class AnalyticsUtils { public enum BlockEditorEnabledSource { VIA_SITE_SETTINGS, ON_SITE_CREATION, - ON_BLOCK_POST_OPENING; + ON_BLOCK_POST_OPENING, + ON_PROGRESSIVE_ROLLOUT; public Map asPropertyMap() { Map properties = new HashMap<>(); From a837ae6c53b275ab888f7f861f06e47f6df2a209 Mon Sep 17 00:00:00 2001 From: Maxime Biais Date: Thu, 7 Nov 2019 12:27:47 +0100 Subject: [PATCH 2/4] Fix checkstyle violations --- .../main/java/org/wordpress/android/util/SiteUtils.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java b/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java index 7b2d6ed785a2..24caf38f452e 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java @@ -52,10 +52,11 @@ public static void migrateAppWideMobileEditorPreferenceToRemote(final AccountSto // Check if the user has been "randomly" selected to enter the rollout group. // // For self hosted sites, there are often one or two users, and the user id is probably 0, 1 in these cases. - // If we exclude low ids, we won't get an not an homogeneous distribution over self hosted and WordPress.com users, - // but the purpose of this is to do a progressive rollout, not an necessarily an homogeneous rollout. + // If we exclude low ids, we won't get an not an homogeneous distribution over self hosted and WordPress.com + // users, but the purpose of this is to do a progressive rollout, not an necessarily an homogeneous rollout. // - // To exclude ids 0 and 1, to rollout for 10% users, we'll use a test like `id % 100 >= 90` instead of `id % 100 < 10`. + // To exclude ids 0 and 1, to rollout for 10% users, + // we'll use a test like `id % 100 >= 90` instead of `id % 100 < 10`. if (accountStore.getAccount().getUserId() % 100 >= (100 - GB_ROLLOUT_PERCENTAGE)) { // We want to make sure to enable Gutenberg only on the sites they didn't opt-out. for (SiteModel site : siteStore.getSites()) { From 2ff8e8d7d56fab7cceed59d839b3b9c9d83bb00c Mon Sep 17 00:00:00 2001 From: Maxime Biais Date: Wed, 13 Nov 2019 14:52:50 +0100 Subject: [PATCH 3/4] Exclude users from the cohort if they have at least one Aztec enabled site --- .../wordpress/android/ui/prefs/AppPrefs.java | 4 +-- .../org/wordpress/android/util/SiteUtils.java | 31 +++++++++++++++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java index 2962155ae8f0..44f86eefd33c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java @@ -609,11 +609,11 @@ public static boolean isDefaultAppWideEditorPreferenceSet() { } public static boolean isUserInGutenbergRolloutGroup() { - return getBoolean(DeletablePrefKey.GUTENBERG_DEFAULT_FOR_NEW_POSTS, false); + return getBoolean(DeletablePrefKey.USER_IN_GUTENBERG_ROLLOUT_GROUP, false); } public static void setUserInGutenbergRolloutGroup() { - setBoolean(DeletablePrefKey.GUTENBERG_DEFAULT_FOR_NEW_POSTS, true); + setBoolean(DeletablePrefKey.USER_IN_GUTENBERG_ROLLOUT_GROUP, true); } public static void removeAppWideEditorPreference() { diff --git a/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java b/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java index 24caf38f452e..f64e0f34f4f6 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java @@ -39,6 +39,11 @@ public class SiteUtils { public static void migrateAppWideMobileEditorPreferenceToRemote(final AccountStore accountStore, final SiteStore siteStore, final Dispatcher dispatcher) { + // Skip if the user is not signed in + if (!FluxCUtils.isSignedInWPComOrHasWPOrgSite(accountStore, siteStore)) { + return; + } + // In a later version we might override mobile_editor setting if it's set to `aztec` and show a specific notice // for these users ("We made a lot of progress on the block editor and we think it's now better than // the classic editor, we switched it on, but you can change the configuration in your Site Settings"). @@ -58,18 +63,22 @@ public static void migrateAppWideMobileEditorPreferenceToRemote(final AccountSto // To exclude ids 0 and 1, to rollout for 10% users, // we'll use a test like `id % 100 >= 90` instead of `id % 100 < 10`. if (accountStore.getAccount().getUserId() % 100 >= (100 - GB_ROLLOUT_PERCENTAGE)) { - // We want to make sure to enable Gutenberg only on the sites they didn't opt-out. + if (atLeastOneSiteHasAztecEnabled(siteStore)) { + // If the user has opt-ed out from at least one of their site, then exclude them from the cohort + return; + } + + // Force the dialog to be shown on updated sites for (SiteModel site : siteStore.getSites()) { if (TextUtils.isEmpty(site.getMobileEditor())) { - // Enable Gutenberg - enableBlockEditor(dispatcher, site); - AnalyticsUtils.trackWithSiteDetails(Stat.EDITOR_GUTENBERG_ENABLED, site, - BlockEditorEnabledSource.ON_PROGRESSIVE_ROLLOUT.asPropertyMap()); - // Show the info popup when the user creates a new post for the first time on this site AppPrefs.setShowGutenbergInfoPopupForTheNewPosts(site.getUrl(), true); } } + // Enable Gutenberg for all sites using a single network call + dispatcher.dispatch(SiteActionBuilder.newDesignateMobileEditorForAllSitesAction( + new DesignateMobileEditorForAllSitesPayload(SiteUtils.GB_EDITOR_NAME))); + // After enabling Gutenberg on these sites, we consider the user entered the rollout group AppPrefs.setUserInGutenbergRolloutGroup(); } @@ -88,6 +97,16 @@ public static void migrateAppWideMobileEditorPreferenceToRemote(final AccountSto } } + private static boolean atLeastOneSiteHasAztecEnabled(final SiteStore siteStore) { + // We want to make sure to enable Gutenberg only on the sites they didn't opt-out. + for (SiteModel site : siteStore.getSites()) { + if (TextUtils.equals(site.getMobileEditor(), AZTEC_EDITOR_NAME)) { + return true; + } + } + return false; + } + public static boolean enableBlockEditorOnSiteCreation(Dispatcher dispatcher, SiteStore siteStore, int siteLocalSiteID) { SiteModel newSiteModel = siteStore.getSiteByLocalId(siteLocalSiteID); From eec0ca77d3699ef4c02c60e80240875e8aec0226 Mon Sep 17 00:00:00 2001 From: Maxime Biais Date: Thu, 14 Nov 2019 12:30:22 +0100 Subject: [PATCH 4/4] Abort gutenberg opt-in if the network is not available --- .../src/main/java/org/wordpress/android/util/SiteUtils.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java b/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java index f64e0f34f4f6..0061fc548404 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/util/SiteUtils.java @@ -5,6 +5,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import org.wordpress.android.WordPress; import org.wordpress.android.analytics.AnalyticsTracker.Stat; import org.wordpress.android.fluxc.Dispatcher; import org.wordpress.android.fluxc.generated.SiteActionBuilder; @@ -68,6 +69,11 @@ public static void migrateAppWideMobileEditorPreferenceToRemote(final AccountSto return; } + if (!NetworkUtils.isNetworkAvailable(WordPress.getContext())) { + // If the network is not available, abort. We can't update the remote setting. + return; + } + // Force the dialog to be shown on updated sites for (SiteModel site : siteStore.getSites()) { if (TextUtils.isEmpty(site.getMobileEditor())) {