jenkins-bot has submitted this change and it was merged.
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/page/PageActivity.java
M app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.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, 388 insertions(+), 4 deletions(-)
Approvals:
Sniedzielski: Looks good to me, approved
jenkins-bot: Verified
diff --git a/app/src/main/java/org/wikipedia/WikipediaApp.java
b/app/src/main/java/org/wikipedia/WikipediaApp.java
index 5d64cd7..63f481b 100644
--- a/app/src/main/java/org/wikipedia/WikipediaApp.java
+++ b/app/src/main/java/org/wikipedia/WikipediaApp.java
@@ -428,6 +428,21 @@
return enabled;
}
+ public int getLinkPreviewVersion() {
+ int version;
+ if (Prefs.hasLinkPreviewVersion()) {
+ version = Prefs.getLinkPreviewVersion();
+ } else {
+ version = new Random().nextInt(2);
+ Prefs.setLinkPreviewVersion(version);
+ }
+ return version;
+ }
+
+ public boolean isLinkPreviewExperimental() {
+ return getLinkPreviewVersion() != 0;
+ }
+
/**
* 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..4ffdd07 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().isLinkPreviewExperimental() ?
PROD_LINK_PREVIEW_VERSION_B : PROD_LINK_PREVIEW_VERSION);
return super.preprocessData(eventData);
}
diff --git a/app/src/main/java/org/wikipedia/page/PageActivity.java
b/app/src/main/java/org/wikipedia/page/PageActivity.java
index 27a1efb..ae4623e 100644
--- a/app/src/main/java/org/wikipedia/page/PageActivity.java
+++ b/app/src/main/java/org/wikipedia/page/PageActivity.java
@@ -16,6 +16,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;
@@ -50,6 +51,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;
@@ -663,7 +665,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.isLinkPreviewExperimental()
+ ? LinkPreviewDialogB.newInstance(title, entrySource)
+ : LinkPreviewDialog.newInstance(title, entrySource);
linkPreview.show(getSupportFragmentManager(),
LINK_PREVIEW_FRAGMENT_TAG);
}
}
@@ -672,7 +676,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/LinkPreviewContents.java
b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
index 8190bc6..979e92e 100755
--- a/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
+++ b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
@@ -3,6 +3,7 @@
import android.support.annotation.NonNull;
import android.text.TextUtils;
+import org.wikipedia.WikipediaApp;
import org.wikipedia.page.PageTitle;
import org.wikipedia.Site;
import org.json.JSONException;
@@ -41,7 +42,7 @@
public LinkPreviewContents(@NonNull RbPageLead pageLead, @NonNull Site
site) {
title = new PageTitle(pageLead.getDisplayTitle(), site);
extract = pageLead.getExtract();
- title.setThumbUrl(pageLead.getLeadImageUrl());
+ title.setThumbUrl(WikipediaApp.getInstance().getNetworkProtocol() +
":" + pageLead.getLeadImageUrl());
title.setDescription(pageLead.getDescription());
}
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..7dfd2dc
--- /dev/null
+++ b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialogB.java
@@ -0,0 +1,252 @@
+package org.wikipedia.page.linkpreview;
+
+import org.mediawiki.api.json.Api;
+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.ResourceUtil;
+
+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.L10nUtil.getStringForArticleLanguage;
+import static org.wikipedia.util.L10nUtil.setConditionalLayoutDirection;
+import static org.wikipedia.util.DimenUtil.calculateLeadImageWidth;
+
+public class LinkPreviewDialogB extends SwipeableBottomDialog implements
DialogInterface.OnDismissListener {
+ private static final String TAG = "LinkPreviewDialog";
+
+ private boolean navigateSuccess;
+
+ 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);
+ }
+
+ 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(),
+ 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 (!TextUtils.isEmpty(contents.getExtract())) {
+ extractText.setText(contents.getExtract());
+ }
+ int placeholderResId = ResourceUtil.getThemedAttributeId(getContext(),
R.attr.lead_image_drawable);
+ if (shouldDownloadLeadImage()) {
+ Picasso.with(getActivity())
+ .load(contents.getTitle().getThumbUrl())
+ .placeholder(placeholderResId)
+ .error(placeholderResId)
+ .into(leadImage);
+ } else {
+ Picasso.with(getActivity())
+ .load(placeholderResId)
+ .into(leadImage);
+ }
+ }
+
+ private boolean shouldDownloadLeadImage() {
+ return !TextUtils.isEmpty(contents.getTitle().getThumbUrl())
+ && WikipediaApp.getInstance().isImageDownloadEnabled();
+ }
+}
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: merged
Gerrit-Change-Id: Ic65ac96106b3949ce121ba7c86d4dda68bf2ea8f
Gerrit-PatchSet: 3
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Dbrant <[email protected]>
Gerrit-Reviewer: BearND <[email protected]>
Gerrit-Reviewer: Brion VIBBER <[email protected]>
Gerrit-Reviewer: Dbrant <[email protected]>
Gerrit-Reviewer: Mholloway <[email protected]>
Gerrit-Reviewer: Niedzielski <[email protected]>
Gerrit-Reviewer: Sniedzielski <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits