Bug 1247689 - Experiment: show prompt on third opening of reader view r?sebastian draft
authorAndrzej Hunt <ahunt@mozilla.com>
Fri, 29 Apr 2016 12:28:08 +0200
changeset 357787 c4af4f89f1a936ffd172139018e3243c25f30084
parent 357786 c9f3ba7a50d53e41e25159eb1620c99565af3a63
child 519705 52da04e9fcac683a262d04d502373622e5868933
push id16844
push userahunt@mozilla.com
push dateFri, 29 Apr 2016 10:33:33 +0000
reviewerssebastian
bugs1247689
milestone49.0a1
Bug 1247689 - Experiment: show prompt on third opening of reader view r?sebastian MozReview-Commit-ID: CMxdWuFIe5e
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/promotion/ReaderViewBookmarkPromotion.java
mobile/android/base/java/org/mozilla/gecko/promotion/SimpleHelperUI.java
mobile/android/base/java/org/mozilla/gecko/util/Experiments.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/moz.build
mobile/android/base/strings.xml.in
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -54,16 +54,17 @@ import org.mozilla.gecko.menu.GeckoMenuI
 import org.mozilla.gecko.mozglue.ContextUtils;
 import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent;
 import org.mozilla.gecko.overlays.ui.ShareDialog;
 import org.mozilla.gecko.permissions.Permissions;
 import org.mozilla.gecko.preferences.ClearOnShutdownPref;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.promotion.AddToHomeScreenPromotion;
 import org.mozilla.gecko.promotion.BookmarkStateChangeDelegate;
+import org.mozilla.gecko.promotion.ReaderViewBookmarkPromotion;
 import org.mozilla.gecko.prompts.Prompt;
 import org.mozilla.gecko.prompts.PromptListItem;
 import org.mozilla.gecko.reader.SavedReaderViewHelper;
 import org.mozilla.gecko.reader.ReaderModeUtils;
 import org.mozilla.gecko.reader.ReadingListHelper;
 import org.mozilla.gecko.restrictions.Restrictable;
 import org.mozilla.gecko.restrictions.RestrictedProfileConfiguration;
 import org.mozilla.gecko.restrictions.Restrictions;
@@ -210,16 +211,19 @@ public class BrowserApp extends GeckoApp
     private static final String BROWSER_SEARCH_TAG = "browser_search";
 
     // Request ID for startActivityForResult.
     private static final int ACTIVITY_REQUEST_PREFERENCES = 1001;
     private static final int ACTIVITY_REQUEST_TAB_QUEUE = 2001;
     public static final int ACTIVITY_REQUEST_FIRST_READERVIEW_BOOKMARK = 3001;
     public static final int ACTIVITY_RESULT_FIRST_READERVIEW_BOOKMARKS_GOTO_BOOKMARKS = 3002;
     public static final int ACTIVITY_RESULT_FIRST_READERVIEW_BOOKMARKS_IGNORE = 3003;
+    public static final int ACTIVITY_REQUEST_TRIPLE_READERVIEW = 4001;
+    public static final int ACTIVITY_RESULT_TRIPLE_READERVIEW_ADD_BOOKMARK = 4002;
+    public static final int ACTIVITY_RESULT_TRIPLE_READERVIEW_IGNORE = 4003;
 
     public static final String ACTION_VIEW_MULTIPLE = AppConstants.ANDROID_PACKAGE_NAME + ".action.VIEW_MULTIPLE";
 
     @RobocopTarget
     public static final String EXTRA_SKIP_STARTPANE = "skipstartpane";
     private static final String EOL_NOTIFIED = "eol_notified";
 
     private BrowserSearch mBrowserSearch;
@@ -301,17 +305,18 @@ public class BrowserApp extends GeckoApp
     // race by determining if the web content should be hidden at the animation's end.
     private boolean mHideWebContentOnAnimationEnd;
 
     private final DynamicToolbar mDynamicToolbar = new DynamicToolbar();
 
     private final List<BrowserAppDelegate> delegates = Collections.unmodifiableList(Arrays.asList(
             (BrowserAppDelegate) new AddToHomeScreenPromotion(),
             (BrowserAppDelegate) new ScreenshotDelegate(),
-            (BrowserAppDelegate) new BookmarkStateChangeDelegate()
+            (BrowserAppDelegate) new BookmarkStateChangeDelegate(),
+            (BrowserAppDelegate) new ReaderViewBookmarkPromotion()
     ));
 
     @NonNull
     private SearchEngineManager searchEngineManager; // Contains reference to Context - DO NOT LEAK!
 
     @Override
     public View onCreateView(final String name, final Context context, final AttributeSet attrs) {
         final View view;
@@ -347,16 +352,17 @@ public class BrowserApp extends GeckoApp
                 if (mZoomedView != null) {
                     mZoomedView.stopZoomDisplay(false);
                 }
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     updateHomePagerForTab(tab);
                 }
 
                 mDynamicToolbar.persistTemporaryVisibility();
+
                 break;
             case START:
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     invalidateOptionsMenu();
 
                     if (mDynamicToolbar.isEnabled()) {
                         mDynamicToolbar.setVisible(true, VisibilityTransition.ANIMATE);
                     }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/promotion/ReaderViewBookmarkPromotion.java
@@ -0,0 +1,119 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.promotion;
+
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+
+import com.keepsafe.switchboard.SwitchBoard;
+
+import org.mozilla.gecko.BrowserApp;
+import org.mozilla.gecko.BrowserAppDelegate;
+import org.mozilla.gecko.GeckoSharedPrefs;
+import org.mozilla.gecko.R;
+import org.mozilla.gecko.Tab;
+import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.reader.ReaderModeUtils;
+import org.mozilla.gecko.util.Experiments;
+
+import java.lang.ref.WeakReference;
+
+public class ReaderViewBookmarkPromotion extends BrowserAppDelegate implements Tabs.OnTabsChangedListener {
+    private WeakReference<BrowserApp> mBrowserApp;
+
+    private int mTimesEnteredReaderMode = 0;
+
+    @Override
+    public void onCreate(BrowserApp browserApp, Bundle savedInstanceState) {
+        mBrowserApp =  new WeakReference<>(browserApp);
+    }
+
+    @Override
+    public void onResume(BrowserApp browserApp) {
+        Tabs.registerOnTabsChangedListener(this);
+    }
+
+    @Override
+    public void onPause(BrowserApp browserApp) {
+        Tabs.unregisterOnTabsChangedListener(this);
+    }
+
+    @Override
+    public void onTabChanged(Tab tab, Tabs.TabEvents msg, String data) {
+        switch (msg) {
+            case LOCATION_CHANGE:
+                // old url: data
+                // new url: tab.getURL()
+                final boolean enteringReaderMode = ReaderModeUtils.isEnteringReaderMode(tab.getURL(), data);
+
+                if (mTimesEnteredReaderMode < 4 && enteringReaderMode) {
+                    mTimesEnteredReaderMode++;
+                }
+
+                if (mTimesEnteredReaderMode == 3) {
+                    promoteBookmarking();
+                }
+
+                break;
+        }
+    }
+
+    @Override
+    public void onActivityResult(BrowserApp browserApp, int requestCode, int resultCode,
+                                 Intent data) {
+        switch (requestCode) {
+            case BrowserApp.ACTIVITY_REQUEST_TRIPLE_READERVIEW:
+                if (resultCode == BrowserApp.ACTIVITY_RESULT_TRIPLE_READERVIEW_ADD_BOOKMARK) {
+                    final Tab tab = Tabs.getInstance().getSelectedTab();
+                    if (tab != null) {
+                        tab.addBookmark();
+                    }
+                } else if (resultCode == BrowserApp.ACTIVITY_RESULT_TRIPLE_READERVIEW_IGNORE) {
+                    // Nothing to do: we won't show this promotion again either way.
+                }
+                break;
+        }
+    }
+
+    private void promoteBookmarking() {
+        final BrowserApp browserApp = mBrowserApp.get();
+        if (browserApp == null) {
+            return;
+        }
+
+        final SharedPreferences prefs = GeckoSharedPrefs.forProfile(browserApp);
+
+        // We reuse the same preference as for the first offline reader view bookmark
+        // as we only want to show one of the two UIs (they both explain the same
+        // functionality).
+        if (prefs.getBoolean(SimpleHelperUI.PREF_FIRST_RVBP_SHOWN, false)) {
+            return;
+        }
+
+        boolean experimentEnabled = SwitchBoard.isInExperiment(browserApp, Experiments.TRIPLE_READERVIEW_BOOKMARK_PROMPT);
+
+        if (!experimentEnabled) {
+            return;
+        }
+
+        SimpleHelperUI.show(browserApp,
+                SimpleHelperUI.TRIPLE_READERVIEW_OPEN_TELEMETRYEXTRA,
+                BrowserApp.ACTIVITY_REQUEST_TRIPLE_READERVIEW,
+                R.string.helper_triple_readerview_open_title,
+                R.string.helper_triple_readerview_open_message,
+                R.drawable.helper_first_readerview_bookmark, // We share the icon with the usual helper UI
+                R.string.helper_triple_readerview_open_button,
+                BrowserApp.ACTIVITY_RESULT_TRIPLE_READERVIEW_ADD_BOOKMARK,
+                BrowserApp.ACTIVITY_RESULT_TRIPLE_READERVIEW_IGNORE);
+
+        GeckoSharedPrefs.forProfile(browserApp)
+                .edit()
+                .putBoolean(SimpleHelperUI.PREF_FIRST_RVBP_SHOWN, true)
+                .apply();
+    }
+
+}
--- a/mobile/android/base/java/org/mozilla/gecko/promotion/SimpleHelperUI.java
+++ b/mobile/android/base/java/org/mozilla/gecko/promotion/SimpleHelperUI.java
@@ -28,16 +28,17 @@ import org.mozilla.gecko.TelemetryContra
 /**
  * Generic HelperUI (prompt) that can be populated with an image, title, message and action button.
  * See show() for usage. This is run as an Activity, results must be handled in the parent Activities
  * onActivityResult().
  */
 public class SimpleHelperUI extends Locales.LocaleAwareActivity {
     public static final String PREF_FIRST_RVBP_SHOWN = "first_reader_view_bookmark_prompt_shown";
     public static final String FIRST_RVBP_SHOWN_TELEMETRYEXTRA = "first_readerview_bookmark_prompt";
+    public static final String TRIPLE_READERVIEW_OPEN_TELEMETRYEXTRA = "third_readerview_open_prompt";
 
     private View containerView;
 
     private boolean isAnimating;
 
     private String mTelemetryExtra;
 
     private static final String EXTRA_TELEMETRYEXTRA = "telemetryextra";
--- a/mobile/android/base/java/org/mozilla/gecko/util/Experiments.java
+++ b/mobile/android/base/java/org/mozilla/gecko/util/Experiments.java
@@ -42,16 +42,19 @@ public class Experiments {
     // Synchronizing the catalog of downloadable content from Kinto
     public static final String DOWNLOAD_CONTENT_CATALOG_SYNC = "download-content-catalog-sync";
 
     // Promotion for "Add to homescreen"
     public static final String PROMOTE_ADD_TO_HOMESCREEN = "promote-add-to-homescreen";
 
     public static final String PREF_ONBOARDING_VERSION = "onboarding_version";
 
+    // Promotion to bookmark reader-view items after entering reader view three times (Bug 1247689)
+    public static final String TRIPLE_READERVIEW_BOOKMARK_PROMPT = "triple-readerview-bookmark-prompt";
+
     private static volatile Boolean disabled = null;
 
     /**
      * Determines whether Switchboard is disabled by the MOZ_DISABLE_SWITCHBOARD
      * environment variable. We need to read this value from the intent string
      * extra because environment variables from our test harness aren't set
      * until Gecko is loaded, and we need to know this before then.
      *
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -773,8 +773,13 @@ just addresses the organization to follo
 <!ENTITY whatsnew_notification_title "&brandShortName; is up to date">
 <!ENTITY whatsnew_notification_summary "Find out what\'s new in this version">
 
 <!ENTITY promotion_add_to_homescreen "Add to home screen">
 
 <!ENTITY helper_first_offline_bookmark_title "Read offline">
 <!ENTITY helper_first_offline_bookmark_message "Find your Reader View items in Bookmarks, even offline.">
 <!ENTITY helper_first_offline_bookmark_button "Go to Bookmarks">
+
+<!ENTITY helper_triple_readerview_open_title "Available offline">
+<!ENTITY helper_triple_readerview_open_message "Bookmark Reader View items to read them offline.">
+<!ENTITY helper_triple_readerview_open_button "Add to Bookmarks">
+
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -505,16 +505,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'preferences/SetHomepagePreference.java',
     'preferences/SyncPreference.java',
     'PrefsHelper.java',
     'PrintHelper.java',
     'PrivateTab.java',
     'promotion/AddToHomeScreenPromotion.java',
     'promotion/BookmarkStateChangeDelegate.java',
     'promotion/HomeScreenPrompt.java',
+    'promotion/ReaderViewBookmarkPromotion.java',
     'promotion/SimpleHelperUI.java',
     'prompts/ColorPickerInput.java',
     'prompts/IconGridInput.java',
     'prompts/IntentChooserPrompt.java',
     'prompts/IntentHandler.java',
     'prompts/Prompt.java',
     'prompts/PromptInput.java',
     'prompts/PromptListAdapter.java',
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -606,9 +606,13 @@
   <string name="whatsnew_notification_url">https://support.mozilla.org/1/mobile/&formatS1;/&formatS2;/&formatS3;/new-android</string>
 
   <string name="promotion_add_to_homescreen">&promotion_add_to_homescreen;</string>
 
   <string name="helper_first_offline_bookmark_title">&helper_first_offline_bookmark_title;</string>
   <string name="helper_first_offline_bookmark_message">&helper_first_offline_bookmark_message;</string>
   <string name="helper_first_offline_bookmark_button">&helper_first_offline_bookmark_button;</string>
 
+  <string name="helper_triple_readerview_open_title">&helper_triple_readerview_open_title;</string>
+  <string name="helper_triple_readerview_open_message">&helper_triple_readerview_open_message;</string>
+  <string name="helper_triple_readerview_open_button">&helper_triple_readerview_open_button;</string>
+
 </resources>