Dbrant has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/250724

Change subject: A/B test of two link preview designs.
......................................................................

A/B test of two link preview designs.

This implements an a/b test of two designs for the link preview dialog:
A) The current design.
B) The original "prototype 1" design, which includes an excerpt of text
with the lead image side by side, and no overflow menu (and no thumbnail
gallery).

The hope is to gauge user response to a trimmed-down, back-to-basics
design, and see how it affects engagement.

Bug: T117065
Change-Id: Ic65ac96106b3949ce121ba7c86d4dda68bf2ea8f
---
M app/src/main/java/org/wikipedia/WikipediaApp.java
M app/src/main/java/org/wikipedia/analytics/LinkPreviewFunnel.java
M app/src/main/java/org/wikipedia/crash/hockeyapp/HockeyAppExceptionHandler.java
M app/src/main/java/org/wikipedia/page/PageActivity.java
A app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialogB.java
M app/src/main/java/org/wikipedia/settings/Prefs.java
A app/src/main/res/layout/dialog_link_preview_b.xml
M app/src/main/res/values/preference_keys.xml
M app/src/main/res/xml/developer_preferences.xml
9 files changed, 384 insertions(+), 3 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/apps/android/wikipedia 
refs/changes/24/250724/1

diff --git a/app/src/main/java/org/wikipedia/WikipediaApp.java 
b/app/src/main/java/org/wikipedia/WikipediaApp.java
index e5f92ad..88375b9 100644
--- a/app/src/main/java/org/wikipedia/WikipediaApp.java
+++ b/app/src/main/java/org/wikipedia/WikipediaApp.java
@@ -440,6 +440,17 @@
         return enabled;
     }
 
+    public int getLinkPreviewVersion() {
+        int version;
+        if (Prefs.hasLinkPreviewVersion()) {
+            version = Prefs.getLinkPreviewVersion();
+        } else {
+            version = new Random().nextInt(2);
+            Prefs.setLinkPreviewVersion(version);
+        }
+        return version;
+    }
+
     /**
      * Gets the currently-selected theme for the app.
      * @return Theme that is currently selected, which is the actual theme ID 
that can
diff --git a/app/src/main/java/org/wikipedia/analytics/LinkPreviewFunnel.java 
b/app/src/main/java/org/wikipedia/analytics/LinkPreviewFunnel.java
index 9b69a19..0a16d62 100644
--- a/app/src/main/java/org/wikipedia/analytics/LinkPreviewFunnel.java
+++ b/app/src/main/java/org/wikipedia/analytics/LinkPreviewFunnel.java
@@ -10,6 +10,7 @@
     private static final String SCHEMA_NAME = "MobileWikiAppLinkPreview";
     private static final int REV_ID = 14095177;
     private static final int PROD_LINK_PREVIEW_VERSION = 3;
+    private static final int PROD_LINK_PREVIEW_VERSION_B = 4;
 
     public LinkPreviewFunnel(WikipediaApp app) {
         super(app, SCHEMA_NAME, REV_ID, app.isProdRelease() ? 
Funnel.SAMPLE_LOG_100 : Funnel.SAMPLE_LOG_ALL);
@@ -17,7 +18,7 @@
 
     @Override
     protected JSONObject preprocessData(@NonNull JSONObject eventData) {
-        preprocessData(eventData, "version", PROD_LINK_PREVIEW_VERSION);
+        preprocessData(eventData, "version", 
WikipediaApp.getInstance().getLinkPreviewVersion() == 0 ? 
PROD_LINK_PREVIEW_VERSION : PROD_LINK_PREVIEW_VERSION_B);
         return super.preprocessData(eventData);
     }
 
diff --git 
a/app/src/main/java/org/wikipedia/crash/hockeyapp/HockeyAppExceptionHandler.java
 
b/app/src/main/java/org/wikipedia/crash/hockeyapp/HockeyAppExceptionHandler.java
index 11bcfcb..e4d3179 100644
--- 
a/app/src/main/java/org/wikipedia/crash/hockeyapp/HockeyAppExceptionHandler.java
+++ 
b/app/src/main/java/org/wikipedia/crash/hockeyapp/HockeyAppExceptionHandler.java
@@ -34,6 +34,7 @@
     @Override
     public void uncaughtException(Thread thread, Throwable exception) {
         Log.e(getClass().getName(), "", exception);
+        exception.printStackTrace();
         if (Constants.FILES_PATH == null) {
             // If the files path is null, the exception can't be stored
             // Always call the default handler instead
diff --git a/app/src/main/java/org/wikipedia/page/PageActivity.java 
b/app/src/main/java/org/wikipedia/page/PageActivity.java
index ce9921a..1d995c3 100644
--- a/app/src/main/java/org/wikipedia/page/PageActivity.java
+++ b/app/src/main/java/org/wikipedia/page/PageActivity.java
@@ -17,6 +17,7 @@
 import org.wikipedia.login.LoginActivity;
 import org.wikipedia.page.gallery.GalleryActivity;
 import org.wikipedia.page.linkpreview.LinkPreviewDialog;
+import org.wikipedia.page.linkpreview.LinkPreviewDialogB;
 import org.wikipedia.random.RandomHandler;
 import org.wikipedia.recurring.RecurringTasksExecutor;
 import org.wikipedia.search.SearchArticlesFragment;
@@ -51,6 +52,7 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.design.widget.NavigationView;
+import android.support.v4.app.DialogFragment;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentTransaction;
 import android.support.v4.view.GravityCompat;
@@ -660,7 +662,9 @@
 
     public void showLinkPreview(PageTitle title, int entrySource) {
         if 
(getSupportFragmentManager().findFragmentByTag(LINK_PREVIEW_FRAGMENT_TAG) == 
null) {
-            LinkPreviewDialog linkPreview = 
LinkPreviewDialog.newInstance(title, entrySource);
+            DialogFragment linkPreview = app.getLinkPreviewVersion() == 0
+                    ? LinkPreviewDialog.newInstance(title, entrySource)
+                    : LinkPreviewDialogB.newInstance(title, entrySource);
             linkPreview.show(getSupportFragmentManager(), 
LINK_PREVIEW_FRAGMENT_TAG);
         }
     }
@@ -669,7 +673,7 @@
      * Dismiss the current link preview, if one is open.
      */
     private void hideLinkPreview() {
-        LinkPreviewDialog linkPreview = (LinkPreviewDialog) 
getSupportFragmentManager().findFragmentByTag(LINK_PREVIEW_FRAGMENT_TAG);
+        DialogFragment linkPreview = (DialogFragment) 
getSupportFragmentManager().findFragmentByTag(LINK_PREVIEW_FRAGMENT_TAG);
         if (linkPreview != null) {
             linkPreview.dismiss();
         }
diff --git 
a/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialogB.java 
b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialogB.java
new file mode 100644
index 0000000..712cf84
--- /dev/null
+++ b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialogB.java
@@ -0,0 +1,253 @@
+package org.wikipedia.page.linkpreview;
+
+import org.mediawiki.api.json.Api;
+import org.wikipedia.Utils;
+import org.wikipedia.history.HistoryEntry;
+import org.wikipedia.page.PageActivity;
+import org.wikipedia.page.PageTitle;
+import org.wikipedia.R;
+import org.wikipedia.WikipediaApp;
+import org.wikipedia.analytics.LinkPreviewFunnel;
+import org.wikipedia.server.PageLead;
+import org.wikipedia.server.PageServiceFactory;
+import org.wikipedia.server.restbase.RbPageLead;
+import org.wikipedia.settings.RbSwitch;
+import org.wikipedia.util.ApiUtil;
+import org.wikipedia.util.FeedbackUtil;
+import org.wikipedia.util.PageLoadUtil;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.squareup.picasso.Picasso;
+
+import java.util.Map;
+
+import retrofit.RetrofitError;
+import retrofit.client.Response;
+
+import static org.wikipedia.util.L10nUtils.getStringForArticleLanguage;
+import static org.wikipedia.util.L10nUtils.setConditionalLayoutDirection;
+
+public class LinkPreviewDialogB extends SwipeableBottomDialog implements 
DialogInterface.OnDismissListener {
+    private static final String TAG = "LinkPreviewDialog";
+
+    private boolean navigateSuccess = false;
+
+    private ProgressBar progressBar;
+    private TextView extractText;
+    private ImageView leadImage;
+
+    private PageTitle pageTitle;
+    private int entrySource;
+
+    private LinkPreviewFunnel funnel;
+    private LinkPreviewContents contents;
+    private OnNavigateListener onNavigateListener;
+
+    private View.OnClickListener goToPageListener = new View.OnClickListener() 
{
+        @Override
+        public void onClick(View v) {
+            goToLinkedPage();
+        }
+    };
+
+    public static LinkPreviewDialogB newInstance(PageTitle title, int 
entrySource) {
+        LinkPreviewDialogB dialog = new LinkPreviewDialogB();
+        Bundle args = new Bundle();
+        args.putParcelable("title", title);
+        args.putInt("entrySource", entrySource);
+        dialog.setArguments(args);
+        return dialog;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setStyle(STYLE_NO_TITLE, R.style.LinkPreviewDialog);
+        setContentPeekHeight((int) 
getResources().getDimension(R.dimen.linkPreviewPeekHeight));
+    }
+
+    @Override
+    protected View inflateDialogView(LayoutInflater inflater, ViewGroup 
container) {
+        WikipediaApp app = WikipediaApp.getInstance();
+        boolean shouldLoadImages = app.isImageDownloadEnabled();
+        pageTitle = getArguments().getParcelable("title");
+        entrySource = getArguments().getInt("entrySource");
+
+        View rootView = inflater.inflate(R.layout.dialog_link_preview_b, 
container);
+        progressBar = (ProgressBar) 
rootView.findViewById(R.id.link_preview_progress);
+        leadImage = (ImageView) 
rootView.findViewById(R.id.link_preview_lead_image);
+
+        View overlayRootView = addOverlay(inflater, 
R.layout.dialog_link_preview_overlay);
+        Button goButton = (Button) 
overlayRootView.findViewById(R.id.link_preview_go_button);
+        goButton.setOnClickListener(goToPageListener);
+        goButton.setText(getStringForArticleLanguage(pageTitle, 
R.string.button_continue_to_article));
+
+        TextView titleText = (TextView) 
rootView.findViewById(R.id.link_preview_title);
+        titleText.setOnClickListener(goToPageListener);
+        titleText.setText(pageTitle.getDisplayText());
+        setConditionalLayoutDirection(rootView, 
pageTitle.getSite().getLanguageCode());
+        if (!ApiUtil.hasKitKat()) {
+            // for oldish devices, reset line spacing to 1, since it truncates 
the descenders.
+            titleText.setLineSpacing(0, 1.0f);
+        } else if (!ApiUtil.hasLollipop()) {
+            // for <5.0, give the title a bit more bottom padding, since these 
versions
+            // incorrectly cut off the bottom of the text when line spacing is 
<1.
+            //final int bottomPadding = 8;
+            //ViewUtil.setBottomPaddingDp(titleText, bottomPadding);
+        }
+
+        onNavigateListener = new DefaultOnNavigateListener();
+        extractText = (TextView) 
rootView.findViewById(R.id.link_preview_extract);
+        extractText.setMovementMethod(new ScrollingMovementMethod());
+
+        // show the progress bar while we load content...
+        progressBar.setVisibility(View.VISIBLE);
+
+        // and kick off the task to load all the things...
+        // Use RESTBase if the user is in the sample group
+        if (pageTitle.getSite().getLanguageCode().equalsIgnoreCase("en")
+                && RbSwitch.INSTANCE.isRestBaseEnabled()) {
+            loadContentWithRestBase(shouldLoadImages);
+        } else {
+            loadContentWithMwapi();
+        }
+
+        funnel = new LinkPreviewFunnel(app);
+        funnel.logLinkClick();
+
+        return rootView;
+    }
+
+    public interface OnNavigateListener {
+        void onNavigate(PageTitle title);
+    }
+
+    public void goToLinkedPage() {
+        navigateSuccess = true;
+        funnel.logNavigate();
+        if (getDialog() != null) {
+            getDialog().dismiss();
+        }
+        if (onNavigateListener != null) {
+            onNavigateListener.onNavigate(pageTitle);
+        }
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialogInterface) {
+        super.onDismiss(dialogInterface);
+        if (!navigateSuccess) {
+            funnel.logCancel();
+        }
+    }
+
+    private void loadContentWithMwapi() {
+        Log.v(TAG, "Loading link preview with MWAPI");
+        new 
LinkPreviewMwapiFetchTask(WikipediaApp.getInstance().getAPIForSite(pageTitle.getSite()),
 pageTitle).execute();
+    }
+
+    private void loadContentWithRestBase(boolean shouldLoadImages) {
+        Log.v(TAG, "Loading link preview with RESTBase");
+        PageServiceFactory.create(pageTitle.getSite()).pageLead(
+                pageTitle.getPrefixedText(),
+                PageLoadUtil.calculateLeadImageWidth(),
+                !shouldLoadImages,
+                linkPreviewOnLoadCallback);
+    }
+
+    private PageLead.Callback linkPreviewOnLoadCallback = new 
PageLead.Callback() {
+        @Override
+        public void success(PageLead pageLead, Response response) {
+            Log.v(TAG, response.getUrl());
+            progressBar.setVisibility(View.GONE);
+            if (pageLead.getLeadSectionContent() != null) {
+                contents = new LinkPreviewContents((RbPageLead) pageLead, 
pageTitle.getSite());
+                layoutPreview();
+            } else {
+                FeedbackUtil.showMessage(getActivity(), 
R.string.error_network_error);
+                dismiss();
+            }
+        }
+
+        @Override
+        public void failure(RetrofitError error) {
+            Log.e(TAG, "Link preview fetch error: " + error);
+            // Fall back to MWAPI
+            loadContentWithMwapi();
+        }
+    };
+
+    private PageActivity getPageActivity() {
+        return (PageActivity) getActivity();
+    }
+
+    private class DefaultOnNavigateListener implements OnNavigateListener {
+        @Override
+        public void onNavigate(PageTitle title) {
+            HistoryEntry newEntry = new HistoryEntry(title, entrySource);
+            getPageActivity().displayNewPage(title, newEntry);
+        }
+    }
+
+    private class LinkPreviewMwapiFetchTask extends PreviewFetchTask {
+        LinkPreviewMwapiFetchTask(Api api, PageTitle title) {
+            super(api, title);
+        }
+
+        @Override
+        public void onFinish(Map<PageTitle, LinkPreviewContents> result) {
+            if (!isAdded()) {
+                return;
+            }
+            progressBar.setVisibility(View.GONE);
+            if (result.size() > 0) {
+                contents = (LinkPreviewContents) result.values().toArray()[0];
+                layoutPreview();
+            } else {
+                FeedbackUtil.showMessage(getActivity(), 
R.string.error_network_error);
+                dismiss();
+            }
+        }
+        @Override
+        public void onCatch(Throwable caught) {
+            Log.e(TAG, "caught " + caught.getMessage());
+            if (!isAdded()) {
+                return;
+            }
+            progressBar.setVisibility(View.GONE);
+            FeedbackUtil.showError(getActivity(), caught);
+            dismiss();
+        }
+    }
+
+    private void layoutPreview() {
+        if (contents.getExtract().length() > 0) {
+            extractText.setText(contents.getExtract());
+        }
+        int placeholderResId = Utils.getThemedAttributeId(getContext(), 
R.attr.lead_image_drawable);
+        if (!TextUtils.isEmpty(contents.getTitle().getThumbUrl())
+                && WikipediaApp.getInstance().isImageDownloadEnabled()) {
+            Picasso.with(getActivity())
+                    .load(contents.getTitle().getThumbUrl())
+                    .placeholder(placeholderResId)
+                    .error(placeholderResId)
+                    .into(leadImage);
+        } else {
+            Picasso.with(getActivity())
+                    .load(placeholderResId)
+                    .into(leadImage);
+        }
+    }
+}
diff --git a/app/src/main/java/org/wikipedia/settings/Prefs.java 
b/app/src/main/java/org/wikipedia/settings/Prefs.java
index 0b5dd29..2adf738 100644
--- a/app/src/main/java/org/wikipedia/settings/Prefs.java
+++ b/app/src/main/java/org/wikipedia/settings/Prefs.java
@@ -337,6 +337,18 @@
         return 
contains(R.string.preference_key_feature_select_text_and_share_tutorials_enabled);
     }
 
+    public static int getLinkPreviewVersion() {
+        return getInt(R.string.preference_key_link_preview_version, 0);
+    }
+
+    public static void setLinkPreviewVersion(int version) {
+        setInt(R.string.preference_key_link_preview_version, version);
+    }
+
+    public static boolean hasLinkPreviewVersion() {
+        return contains(R.string.preference_key_link_preview_version);
+    }
+
     public static boolean isTocTutorialEnabled() {
         return getBoolean(R.string.preference_key_toc_tutorial_enabled, true);
     }
diff --git a/app/src/main/res/layout/dialog_link_preview_b.xml 
b/app/src/main/res/layout/dialog_link_preview_b.xml
new file mode 100644
index 0000000..46678b7
--- /dev/null
+++ b/app/src/main/res/layout/dialog_link_preview_b.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android";
+    xmlns:tools="http://schemas.android.com/tools";
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="8dp"
+            android:background="@drawable/link_preview_top_shadow"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:minHeight="@dimen/linkPreviewPeekHeight"
+            android:orientation="vertical"
+            android:background="?attr/link_preview_background_color"
+            android:animateLayoutChanges="true">
+
+            <TextView
+                android:id="@+id/link_preview_title"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical"
+                style="@style/RtlAwareTextView"
+                android:background="?attr/selectableItemBackground"
+                android:textColor="?attr/link_color"
+                android:paddingTop="16dp"
+                android:paddingLeft="16dp"
+                android:paddingRight="16dp"
+                android:paddingBottom="16dp"
+                android:textSize="22sp"
+                android:fontFamily="serif"
+                android:lineSpacingMultiplier="0.9"
+                android:maxLines="2"
+                android:ellipsize="end"
+                tools:text="Lorem ipsum" />
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="0.5dp"
+                android:background="@color/gray_highlight"/>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+                <TextView
+                    android:id="@+id/link_preview_extract"
+                    android:layout_width="0dp"
+                    android:layout_height="180dp"
+                    android:layout_weight="1"
+                    style="@style/RtlAwareTextView"
+                    android:paddingTop="8dp"
+                    android:paddingLeft="16dp"
+                    android:paddingRight="16dp"
+                    android:textSize="16sp"
+                    android:lineSpacingMultiplier="1.3"
+                    android:textColor="?attr/link_preview_text_color"
+                    android:textIsSelectable="true"
+                    android:maxLines="7"
+                    android:ellipsize="end"
+                    tools:text="Lorem ipsum"/>
+                <ImageView
+                    android:id="@+id/link_preview_lead_image"
+                    android:layout_width="160dp"
+                    android:layout_height="match_parent"
+                    android:src="?attr/lead_image_drawable"
+                    android:contentDescription="@null"
+                    android:scaleType="centerCrop"/>
+            </LinearLayout>
+
+            <View
+                android:id="@+id/link_preview_bottom_padding"
+                android:layout_width="match_parent"
+                android:layout_height="70dp"/>
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <ProgressBar
+        android:id="@+id/link_preview_progress"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"/>
+
+</FrameLayout>
diff --git a/app/src/main/res/values/preference_keys.xml 
b/app/src/main/res/values/preference_keys.xml
index 0c74af6..2b65c24 100644
--- a/app/src/main/res/values/preference_keys.xml
+++ b/app/src/main/res/values/preference_keys.xml
@@ -33,6 +33,7 @@
     <string name="preference_key_last_run_time_format">%s-lastrun</string>
     <string name="preference_key_tabs">tabs</string>
     <string name="preference_key_show_link_previews">showLinkPreviews</string>
+    <string 
name="preference_key_link_preview_version">linkPreviewVersion</string>
     <string name="preference_key_session_data">session_data</string>
     <string name="preference_key_session_timeout">session_timeout</string>
     <string name="preference_key_remote_log">remoteLog</string>
diff --git a/app/src/main/res/xml/developer_preferences.xml 
b/app/src/main/res/xml/developer_preferences.xml
index 757cd08..efc9b34 100644
--- a/app/src/main/res/xml/developer_preferences.xml
+++ b/app/src/main/res/xml/developer_preferences.xml
@@ -7,6 +7,12 @@
             
android:key="@string/preference_key_feature_select_text_and_share_tutorials_enabled"
             
android:title="@string/preference_key_feature_select_text_and_share_tutorials_enabled"
 />
 
+        <!--suppress AndroidUnknownAttribute -->
+        <org.wikipedia.settings.IntPreference
+            style="@style/IntPreference"
+            android:key="@string/preference_key_link_preview_version"
+            android:title="@string/preference_key_link_preview_version" />
+
     </PreferenceCategory>
 
     <PreferenceCategory 
android:title="@string/preferences_developer_restbase_heading">

-- 
To view, visit https://gerrit.wikimedia.org/r/250724
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic65ac96106b3949ce121ba7c86d4dda68bf2ea8f
Gerrit-PatchSet: 1
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Dbrant <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to