jenkins-bot has submitted this change and it was merged.

Change subject: Single "read next" item at the bottom of articles.
......................................................................


Single "read next" item at the bottom of articles.

- Includes A/B toggle based on app install ID. (Half of users will see the
  old "read more" section, and the other half will see the new one)
- Also feature-toggled only for non-production builds for now.
- The Read Next item is the result of a full-text search for the first
  item that has a lead image (and not the same as the original title).

Change-Id: Ifdc7080749c4a97c01b265c1586f287797fc0ab9
---
M wikipedia/res/layout/fragment_page.xml
A wikipedia/res/layout/group_bottom_content.xml
M wikipedia/res/values-qq/strings.xml
M wikipedia/res/values/strings.xml
M wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
M wikipedia/src/main/java/org/wikipedia/page/SuggestionsTask.java
M wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
M 
wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
A 
wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandlerOld.java
A 
wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentInterface.java
M wikipedia/src/main/java/org/wikipedia/search/FullSearchArticlesTask.java
11 files changed, 703 insertions(+), 171 deletions(-)

Approvals:
  BearND: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/wikipedia/res/layout/fragment_page.xml 
b/wikipedia/res/layout/fragment_page.xml
index f2b2dad..21902bc 100644
--- a/wikipedia/res/layout/fragment_page.xml
+++ b/wikipedia/res/layout/fragment_page.xml
@@ -94,11 +94,14 @@
                 android:layout_gravity="bottom"
                 android:orientation="vertical"
                 android:visibility="gone">
+
+                <!-- Old "read more" section, to be removed when the time is 
right. -->
                 <LinearLayout
                     android:id="@+id/read_more_container"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:orientation="vertical">
+                    android:orientation="vertical"
+                    android:visibility="gone">
                     <TextView
                         style="?android:textAppearanceLarge"
                         android:layout_width="wrap_content"
@@ -114,6 +117,9 @@
                         android:layout_width="match_parent"
                         android:layout_height="0dp"/>
                 </LinearLayout>
+                <!-- New "read next" section, to supersede the one above. -->
+                <include layout="@layout/group_bottom_content" />
+
                 <LinearLayout
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
diff --git a/wikipedia/res/layout/group_bottom_content.xml 
b/wikipedia/res/layout/group_bottom_content.xml
new file mode 100644
index 0000000..fdaa1ed
--- /dev/null
+++ b/wikipedia/res/layout/group_bottom_content.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
+    android:id="@+id/read_next_container"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:visibility="gone">
+    <TextView
+        style="?android:textAppearanceLarge"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="@dimen/activity_horizontal_margin"
+        android:paddingRight="@dimen/activity_horizontal_margin"
+        android:paddingBottom="16dp"
+        android:fontFamily="serif"
+        android:textSize="24sp"
+        android:text="@string/read_next_section"/>
+    <FrameLayout
+        android:id="@+id/read_next_images_container"
+        android:layout_width="match_parent"
+        android:layout_height="200dp">
+        <!-- dummy LinearLayout container for 2.3 support.
+        Remove when we drop support for 2.3. -->
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+            <org.wikipedia.page.leadimages.ImageViewWithFace
+                android:id="@+id/read_next_image_1"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:scaleType="centerCrop"
+                android:background="@android:color/white"/>
+        </LinearLayout>
+        <ImageView
+            android:id="@+id/read_next_image_placeholder"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scaleType="centerCrop"
+            android:src="?attr/lead_image_drawable"
+            android:contentDescription="@null"/>
+        <FrameLayout
+            android:id="@+id/read_next_title_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_gravity="bottom"
+            android:background="@drawable/lead_title_gradient">
+            <TextView
+                android:id="@+id/read_next_title_text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:fontFamily="serif"
+                android:textSize="@dimen/titleTextSize"
+                android:textColor="@color/lead_text_color"
+                android:shadowColor="@color/lead_text_shadow"
+                android:shadowRadius="2"
+                android:shadowDx="1"
+                android:shadowDy="1"
+                android:paddingTop="32dp"
+                android:paddingBottom="32dp"
+                android:paddingRight="@dimen/activity_horizontal_margin"
+                android:paddingLeft="@dimen/activity_horizontal_margin"/>
+            <TextView
+                android:id="@+id/read_next_description_text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="bottom"
+                android:fontFamily="serif"
+                android:textSize="@dimen/descriptionTextSize"
+                android:textColor="@color/lead_text_color"
+                android:shadowColor="@color/lead_text_shadow"
+                android:shadowRadius="2"
+                android:shadowDx="1"
+                android:shadowDy="1"
+                android:paddingBottom="16dp"
+                android:paddingRight="@dimen/activity_horizontal_margin"
+                android:paddingLeft="@dimen/activity_horizontal_margin"/>
+        </FrameLayout>
+    </FrameLayout>
+</LinearLayout>
diff --git a/wikipedia/res/values-qq/strings.xml 
b/wikipedia/res/values-qq/strings.xml
index f7035e5..eaccef2 100644
--- a/wikipedia/res/values-qq/strings.xml
+++ b/wikipedia/res/values-qq/strings.xml
@@ -337,6 +337,7 @@
   <string name="preference_summary_show_images">Description of the preference 
for whether images are loaded, mentioning that this setting should be disabled 
if the user\'s internet connection is slow, or if their data plan is limited or 
restricted.</string>
   <string name="read_more_section">Title of the Read More section at the 
bottom of each page.
 {{Identical|Read more}}</string>
+  <string name="read_next_section">Title of the Read Next section at the 
bottom of each page.</string>
   <string name="gallery_menu_more_info">Menu label for displaying additional 
information about the current image being shown in the gallery.
 {{Identical|More information}}</string>
   <string name="menu_gallery_visit_page">Menu label for navigating to the File 
page for the current image being shown in the gallery.</string>
diff --git a/wikipedia/res/values/strings.xml b/wikipedia/res/values/strings.xml
index 7598a3b..e6836d5 100644
--- a/wikipedia/res/values/strings.xml
+++ b/wikipedia/res/values/strings.xml
@@ -253,6 +253,7 @@
     <string name="preference_title_show_images">Show images</string>
     <string name="preference_summary_show_images">Enable or disable loading of 
images in pages. Uncheck this setting if your internet connection is slow, or 
if your data plan is limited.</string>
     <string name="read_more_section">Read more</string>
+    <string name="read_next_section">Read next</string>
     <string name="gallery_menu_more_info">More information</string>
     <string name="menu_gallery_visit_page">Go to file page</string>
     <string name="gallery_error_draw_failed">Could not draw the image.</string>
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
index 2448bda..ed2ef10 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
@@ -18,6 +18,8 @@
 import org.wikipedia.history.HistoryEntry;
 import org.wikipedia.interlanguage.LangLinksActivity;
 import org.wikipedia.page.bottomcontent.BottomContentHandler;
+import org.wikipedia.page.bottomcontent.BottomContentHandlerOld;
+import org.wikipedia.page.bottomcontent.BottomContentInterface;
 import org.wikipedia.page.gallery.GalleryActivity;
 import org.wikipedia.page.leadimages.LeadImagesHandler;
 import org.wikipedia.pageimages.PageImage;
@@ -109,7 +111,7 @@
     private PageTitle titleOriginal;
     private ViewGroup imagesContainer;
     private LeadImagesHandler leadImagesHandler;
-    private BottomContentHandler bottomContentHandler;
+    private BottomContentInterface bottomContentHandler;
     private SearchBarHideHandler searchBarHideHandler;
     private ObservableWebView webView;
     private SwipeRefreshLayoutWithScroll refreshView;
@@ -409,10 +411,17 @@
         searchBarHideHandler = getActivity().getSearchBarHideHandler();
         searchBarHideHandler.setScrollView(webView);
 
-        bottomContentHandler = new BottomContentHandler(this, bridge,
-                webView, linkHandler,
-                (ViewGroup) 
parentFragment.getView().findViewById(R.id.bottom_content_container),
-                title);
+        // TODO: remove this A/B toggle when we know which one we want to keep.
+        // (and when ready to release to production)
+        if (BottomContentHandler.useNewBottomContent(app)) {
+            bottomContentHandler = new BottomContentHandler(this, bridge, 
webView, linkHandler,
+                                   (ViewGroup) parentFragment.getView()
+                                   
.findViewById(R.id.bottom_content_container), title);
+        } else {
+            bottomContentHandler = new BottomContentHandlerOld(this, bridge, 
webView, linkHandler,
+                                   (ViewGroup) parentFragment.getView()
+                                   
.findViewById(R.id.bottom_content_container), title);
+        }
 
         //is this page in cache??
         if (app.getPageCache().has(titleOriginal)) {
diff --git a/wikipedia/src/main/java/org/wikipedia/page/SuggestionsTask.java 
b/wikipedia/src/main/java/org/wikipedia/page/SuggestionsTask.java
index f1e8891..b1e304b 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/SuggestionsTask.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/SuggestionsTask.java
@@ -12,17 +12,19 @@
 
 /**
  * Task for getting suggestions for further reading.
- * Take page title, run full text search with that query, get four results,
- * show top three that aren't the actual page title in question.
+ * Currently powered by full-text search based on the given page title.
  */
 public class SuggestionsTask extends FullSearchArticlesTask {
-    private static final int MAX_SIZE = 3;
-    private static final int MAX_REQUESTED = MAX_SIZE + 1;
     private final String title;
+    private final int numItems;
+    private final boolean requireThumbnail;
 
-    public SuggestionsTask(Api api, Site site, String title) {
-        super(api, site, title, MAX_REQUESTED, null);
+    public SuggestionsTask(Api api, Site site, String title, int thumbSize, 
int numItems,
+                           boolean requireThumbnail) {
+        super(api, site, title, numItems + 1, null, thumbSize);
         this.title = title;
+        this.numItems = numItems;
+        this.requireThumbnail = requireThumbnail;
     }
 
     @Override
@@ -31,17 +33,18 @@
     }
 
     /**
-     * Keep only top three entries that aren't the actual page title in 
question.
+     * Filter the list of suggestions to make sure the original page title 
isn't one of them,
+     * as well as whether the suggestion contains a thumbnail.
      *
      * @param searchResults original results from server
      * @return filtered results
      */
     public SearchResults filterResults(SearchResults searchResults) {
-        List<PageTitle> filteredResults = new ArrayList<PageTitle>();
+        List<PageTitle> filteredResults = new ArrayList<>();
         List<PageTitle> results = searchResults.getPageTitles();
-        for (int i = 0, count = 0; i < results.size() && count < MAX_SIZE; 
i++) {
+        for (int i = 0, count = 0; i < results.size() && count < numItems; 
i++) {
             final PageTitle res = results.get(i);
-            if (!title.equalsIgnoreCase(res.getPrefixedText())) {
+            if (!title.equalsIgnoreCase(res.getPrefixedText()) && 
(!requireThumbnail || res.getThumbUrl() != null)) {
                 filteredResults.add(res);
                 count++;
             }
diff --git a/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java 
b/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
index 5e50496..8526603 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
@@ -7,6 +7,7 @@
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.analytics.ToCInteractionFunnel;
 import org.wikipedia.bridge.CommunicationBridge;
+import org.wikipedia.page.bottomcontent.BottomContentHandler;
 import org.wikipedia.settings.PrefKeys;
 import org.wikipedia.views.DisableableDrawerLayout;
 import org.json.JSONException;
@@ -248,7 +249,7 @@
         private final ArrayList<Section> sections;
 
         private ToCAdapter(Page page) {
-            sections = new ArrayList<Section>();
+            sections = new ArrayList<>();
             for (Section s : page.getSections()) {
                 if (s.getLevel() < MAX_LEVELS && !s.isLead()) {
                     sections.add(s);
@@ -257,7 +258,7 @@
             if (page.couldHaveReadMoreSection()) {
                 // add a fake section at the end to represent the "read more" 
contents at the bottom:
                 sections.add(new Section(READ_MORE_SECTION_ID, 0,
-                        parentActivity.getString(R.string.read_more_section), 
"", ""));
+                        
parentActivity.getString(BottomContentHandler.useNewBottomContent(WikipediaApp.getInstance())
 ? R.string.read_next_section : R.string.read_more_section), "", ""));
             }
         }
 
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
 
b/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
index 25d4b76..d2c49f5 100644
--- 
a/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java
@@ -1,29 +1,28 @@
 package org.wikipedia.page.bottomcontent;
 
+import android.graphics.Bitmap;
+import android.graphics.PointF;
+import android.os.Build;
 import android.text.Html;
 import android.text.TextUtils;
 import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.webkit.WebView;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.ListAdapter;
-import android.widget.ListView;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.squareup.picasso.Picasso;
 
+import com.squareup.picasso.Target;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.wikipedia.PageTitle;
 import org.wikipedia.R;
 import org.wikipedia.Utils;
+import org.wikipedia.ViewAnimations;
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.analytics.SuggestedPagesFunnel;
 import org.wikipedia.bridge.CommunicationBridge;
@@ -34,13 +33,14 @@
 import org.wikipedia.page.PageActivity;
 import org.wikipedia.page.PageViewFragmentInternal;
 import org.wikipedia.page.SuggestionsTask;
+import org.wikipedia.page.leadimages.ImageViewWithFace;
 import org.wikipedia.search.SearchResults;
 import org.wikipedia.views.ObservableWebView;
 
-import java.util.List;
-
-public class BottomContentHandler implements 
ObservableWebView.OnScrollChangeListener,
-        ObservableWebView.OnContentHeightChangedListener {
+public class BottomContentHandler implements BottomContentInterface,
+                                             
ObservableWebView.OnScrollChangeListener,
+                                             
ObservableWebView.OnContentHeightChangedListener,
+                                             
ImageViewWithFace.OnImageLoadListener {
     private static final String TAG = "BottomContentHandler";
     private final PageViewFragmentInternal parentFragment;
     private final CommunicationBridge bridge;
@@ -56,15 +56,19 @@
     private TextView pageLastUpdatedText;
     private TextView pageLicenseText;
     private View readMoreContainer;
-    private ListView readMoreList;
+
+    private TextView readNextTitle;
+    private TextView readNextDescription;
+    private ImageView imagePlaceholder;
+    private ImageViewWithFace image1;
 
     private SuggestedPagesFunnel funnel;
     private SearchResults readMoreItems;
 
-    public BottomContentHandler(PageViewFragmentInternal parentFragment, 
CommunicationBridge bridge,
+    public BottomContentHandler(PageViewFragmentInternal parent, 
CommunicationBridge bridge,
                                 ObservableWebView webview, LinkHandler 
linkHandler,
-                                ViewGroup hidingView, PageTitle pageTitle) {
-        this.parentFragment = parentFragment;
+                                ViewGroup hidingView, final PageTitle 
pageTitle) {
+        this.parentFragment = parent;
         this.bridge = bridge;
         this.webView = webview;
         this.linkHandler = linkHandler;
@@ -77,69 +81,46 @@
         webview.addOnScrollChangeListener(this);
         webview.addOnContentHeightChangedListener(this);
 
-        pageLastUpdatedText = 
(TextView)bottomContentContainer.findViewById(R.id.page_last_updated_text);
-        pageLicenseText = 
(TextView)bottomContentContainer.findViewById(R.id.page_license_text);
-        readMoreContainer = 
bottomContentContainer.findViewById(R.id.read_more_container);
-        readMoreList = 
(ListView)bottomContentContainer.findViewById(R.id.read_more_list);
-
-        // set up pass-through scroll functionality for the ListView
-        readMoreList.setOnTouchListener(new View.OnTouchListener() {
-            private int touchSlop = 
ViewConfiguration.get(readMoreList.getContext())
-                                                     .getScaledTouchSlop();
-            private boolean slopReached;
-            private boolean doingSlopEvent;
-            private boolean isPressed = false;
-            private float startY;
-            private float amountScrolled;
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                int action = event.getActionMasked() & MotionEvent.ACTION_MASK;
-                switch (action) {
-                    case MotionEvent.ACTION_DOWN:
-                        isPressed = true;
-                        startY = event.getY();
-                        amountScrolled = 0;
-                        slopReached = false;
-                        break;
-                    case MotionEvent.ACTION_MOVE:
-                        if (isPressed && !doingSlopEvent) {
-                            int contentHeight = 
(int)(webView.getContentHeight() * displayDensity);
-                            int maxScroll = contentHeight - 
webView.getScrollY()
-                                            - webView.getHeight();
-                            int scrollAmount = Math.min((int) (startY - 
event.getY()), maxScroll);
-                            // manually scroll the WebView that's underneath 
us...
-                            webView.scrollBy(0, scrollAmount);
-                            amountScrolled += scrollAmount;
-                            if (Math.abs(amountScrolled) > touchSlop && 
!slopReached) {
-                                slopReached = true;
-                                // send an artificial Move event that scrolls 
it by an amount
-                                // that's greater than the touch slop, so that 
the currently
-                                // highlighted item is unselected.
-                                MotionEvent moveEvent = 
MotionEvent.obtain(event);
-                                moveEvent.setLocation(event.getX(), 
event.getY() + touchSlop * 2);
-                                doingSlopEvent = true;
-                                readMoreList.dispatchTouchEvent(moveEvent);
-                                doingSlopEvent = false;
-                            }
-                        }
-                        break;
-                    case MotionEvent.ACTION_UP:
-                    case MotionEvent.ACTION_CANCEL:
-                        isPressed = false;
-                        break;
-                    default:
-                        break;
-                }
-                return false;
-            }
-        });
+        pageLastUpdatedText = (TextView) 
bottomContentContainer.findViewById(R.id.page_last_updated_text);
+        pageLicenseText = (TextView) 
bottomContentContainer.findViewById(R.id.page_license_text);
+        readMoreContainer = 
bottomContentContainer.findViewById(R.id.read_next_container);
+        readNextTitle = (TextView) 
bottomContentContainer.findViewById(R.id.read_next_title_text);
+        readNextDescription = (TextView) 
bottomContentContainer.findViewById(R.id.read_next_description_text);
+        imagePlaceholder = (ImageView) 
bottomContentContainer.findViewById(R.id.read_next_image_placeholder);
+        image1 = (ImageViewWithFace) 
bottomContentContainer.findViewById(R.id.read_next_image_1);
+        image1.setOnImageLoadListener(this);
 
         funnel = new SuggestedPagesFunnel(app, pageTitle.getSite());
+
+        webview.addOnClickListener(new ObservableWebView.OnClickListener() {
+            @Override
+            public void onClick(float x, float y) {
+                // if the click event is within the area of the lead image, 
then the user
+                // must have wanted to click on the lead image!
+                int[] pos = new int[2];
+                imagePlaceholder.getLocationOnScreen(pos);
+                if (y > pos[1] && y < (pos[1] + imagePlaceholder.getHeight())) 
{
+                    PageTitle title = (PageTitle) image1.getTag();
+                    HistoryEntry historyEntry = new HistoryEntry(title, 
HistoryEntry.SOURCE_INTERNAL_LINK);
+                    activity.displayNewPage(title, historyEntry);
+                    funnel.logSuggestionClicked(pageTitle, 
readMoreItems.getPageTitles(), 0);
+                }
+            }
+        });
 
         // preload the display density, since it will be used in a lot of 
places
         displayDensity = activity.getResources().getDisplayMetrics().density;
         // hide ourselves by default
         hide();
+    }
+
+    public static boolean useNewBottomContent(WikipediaApp app) {
+        if (app.getReleaseType() == WikipediaApp.RELEASE_PROD) {
+            return false;
+        }
+        // decide what kind of bottom container this page will have, based on 
the app install ID.
+        final int hexBase = 16;
+        return 
Integer.parseInt(app.getAppInstallID().substring(app.getAppInstallID().length() 
- 1), hexBase) % 2 == 0;
     }
 
     @Override
@@ -168,6 +149,14 @@
             if (!firstTimeShown && readMoreItems != null) {
                 firstTimeShown = true;
                 funnel.logSuggestionsShown(pageTitle, 
readMoreItems.getPageTitles());
+                // and start fetching the lead image, if we have one
+                if (image1.getTag() != null && 
((PageTitle)image1.getTag()).getThumbUrl() != null
+                        && app.showImages()) {
+                    Picasso.with(parentFragment.getActivity())
+                           .load(((PageTitle)image1.getTag()).getThumbUrl())
+                           .noFade()
+                           .into((Target)image1);
+                }
             }
         }
     }
@@ -192,7 +181,7 @@
     public void beginLayout() {
         setupAttribution();
         if (parentFragment.getPage().couldHaveReadMoreSection()) {
-            preRequestReadMoreItems(activity.getLayoutInflater());
+            preRequestReadMoreItems();
         } else {
             
bottomContentContainer.findViewById(R.id.read_more_container).setVisibility(View.GONE);
             layoutContent();
@@ -216,17 +205,6 @@
             return;
         }
 
-        // calculate the height of the listview, based on the number of items 
inside it.
-        ListAdapter adapter = readMoreList.getAdapter();
-        if (adapter != null && adapter.getCount() > 0) {
-            ViewGroup.LayoutParams params = readMoreList.getLayoutParams();
-            final int itemHeight = 
(int)activity.getResources().getDimension(R.dimen.defaultListItemSize);
-            params.height = adapter.getCount() * itemHeight
-                            + (readMoreList.getDividerHeight() * 
(adapter.getCount() - 1));
-            readMoreList.setLayoutParams(params);
-        }
-
-        readMoreList.measure(View.MeasureSpec.UNSPECIFIED, 
View.MeasureSpec.UNSPECIFIED);
         bottomContentContainer.measure(View.MeasureSpec.UNSPECIFIED, 
View.MeasureSpec.UNSPECIFIED);
 
         // pad the bottom of the webview, to make room for ourselves
@@ -260,12 +238,12 @@
         }
     }
 
-    private void preRequestReadMoreItems(final LayoutInflater layoutInflater) {
+    private void preRequestReadMoreItems() {
         if (parentFragment.getPage().isMainPage()) {
             new MainPageReadMoreTopicTask(activity) {
                 @Override
                 public void onFinish(PageTitle myTitle) {
-                    requestReadMoreItems(layoutInflater, myTitle);
+                    requestReadMoreItems(myTitle);
                 }
 
                 @Override
@@ -277,25 +255,27 @@
                 }
             }.execute();
         } else {
-            requestReadMoreItems(layoutInflater, pageTitle);
+            requestReadMoreItems(pageTitle);
         }
     }
 
-    private void requestReadMoreItems(final LayoutInflater layoutInflater,
-                                      final PageTitle myTitle) {
+    private void requestReadMoreItems(final PageTitle myTitle) {
         if (myTitle == null || TextUtils.isEmpty(myTitle.getPrefixedText())) {
             hideReadMore();
             layoutContent();
             return;
         }
+
+        final int numSuggestions = 10;
         new SuggestionsTask(app.getAPIForSite(myTitle.getSite()), 
myTitle.getSite(),
-                myTitle.getPrefixedText()) {
+                myTitle.getPrefixedText(), 
(int)(parentFragment.getActivity().getResources().getDimension(R.dimen.leadImageWidth)
 / displayDensity),
+                numSuggestions, true) {
             @Override
             public void onFinish(SearchResults results) {
                 readMoreItems = results;
                 if (!readMoreItems.getPageTitles().isEmpty()) {
                     // If there are results, set up section and make sure it's 
visible
-                    setupReadMoreSection(layoutInflater, readMoreItems);
+                    setupReadNextSection(readMoreItems);
                     showReadMore();
                 } else {
                     // If there's no results, just hide the section
@@ -330,72 +310,98 @@
         pageTitle = newTitle;
     }
 
-    private void setupReadMoreSection(LayoutInflater layoutInflater, final 
SearchResults results) {
-        final ReadMoreAdapter adapter = new ReadMoreAdapter(layoutInflater, 
results.getPageTitles());
-        readMoreList.setAdapter(adapter);
-        readMoreList.setOnItemClickListener(new 
AdapterView.OnItemClickListener() {
+    private void setupReadNextSection(final SearchResults results) {
+        PageTitle title = results.getPageTitles().get(0);
+        readNextTitle.setText(title.getDisplayText());
+        readNextDescription.setVisibility(title.getDescription() == null ? 
View.GONE : View.VISIBLE);
+        final int bottomPaddingBase = 12;
+        int titleBottomPadding = bottomPaddingBase;
+        if (title.getDescription() != null) {
+            final int descriptionPadding = 18;
+            titleBottomPadding += descriptionPadding;
+            readNextDescription.setText(title.getDescription());
+        }
+        image1.setTag(title);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+            // for API >10, decrease line spacing and boost bottom padding to 
account for it.
+            // (in API 10, decreased line spacing cuts off the bottom of the 
text)
+            final float lineSpacing = 0.8f;
+            final int lineSpacePadding = 12;
+            readNextTitle.setLineSpacing(0, lineSpacing);
+            // however, if it's Lollipop or greater, then don't boost the 
bottom padding of the
+            // title text, since it now correctly does it automatically.
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+                titleBottomPadding += lineSpacePadding;
+            }
+        }
+        readNextTitle.setPadding(readNextTitle.getPaddingLeft(), 
readNextTitle.getPaddingTop(),
+                readNextTitle.getPaddingRight(), (int)(titleBottomPadding * 
displayDensity));
+    }
+
+    @Override
+    public void onImageLoaded(Bitmap bitmap, final PointF faceLocation) {
+        final int bmpHeight = bitmap.getHeight();
+        final float aspect = (float)bitmap.getHeight() / 
(float)bitmap.getWidth();
+        readMoreContainer.post(new Runnable() {
             @Override
-            public void onItemClick(AdapterView<?> parent, View view, int 
position, long id) {
-                PageTitle title = (PageTitle) adapter.getItem(position);
-                HistoryEntry historyEntry = new HistoryEntry(title, 
HistoryEntry.SOURCE_INTERNAL_LINK);
-                activity.displayNewPage(title, historyEntry);
-                funnel.logSuggestionClicked(pageTitle, 
results.getPageTitles(), position);
+            public void run() {
+                if (!parentFragment.isAdded()) {
+                    return;
+                }
+                int newWidth = image1.getWidth();
+                int newHeight = (int)(newWidth * aspect);
+
+                // give our image an offset based on the location of the face,
+                // relative to the image container
+                int imageBaseYOffset = 0;
+                float scale = (float)newHeight / (float)bmpHeight;
+                if (faceLocation.y > 0.0f) {
+                    int faceY = (int)(faceLocation.y * scale);
+                    // if we have a face, then offset to the face location
+                    imageBaseYOffset = -(faceY - (imagePlaceholder.getHeight() 
/ 2));
+                    // Adjust the face position by a slight amount.
+                    // The face recognizer gives the location of the *eyes*, 
whereas we actually
+                    // want to center on the *nose*...
+                    final int faceBoost = 24;
+                    imageBaseYOffset -= (faceBoost * displayDensity);
+                } else {
+                    // No face, so we'll just chop the top 25% off rather than 
centering
+                    final float oneQuarter = 0.25f;
+                    imageBaseYOffset = -(int)((newHeight - 
imagePlaceholder.getHeight()) * oneQuarter);
+                }
+                // is the offset too far to the top?
+                if (imageBaseYOffset > 0) {
+                    imageBaseYOffset = 0;
+                }
+                // is the offset too far to the bottom?
+                if (imageBaseYOffset < imagePlaceholder.getHeight() - 
newHeight) {
+                    imageBaseYOffset = imagePlaceholder.getHeight() - 
newHeight;
+                }
+
+                // resize our image to have the same proportions as the 
acquired bitmap,
+                // and offset it based on the face position
+                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) 
image1.getLayoutParams();
+                params.width = LinearLayout.LayoutParams.MATCH_PARENT;
+                if (newHeight < imagePlaceholder.getHeight()) {
+                    // if the height of the image is less than the container, 
then just
+                    // make it the same height as the placeholder.
+                    params.height = imagePlaceholder.getHeight();
+                    imageBaseYOffset = 0;
+                } else {
+                    params.height = newHeight;
+                }
+                params.topMargin = imageBaseYOffset;
+                image1.setLayoutParams(params);
+
+                // fade in the new image!
+                ViewAnimations.crossFade(imagePlaceholder, image1);
             }
         });
-        adapter.notifyDataSetChanged();
     }
 
-    private final class ReadMoreAdapter extends BaseAdapter {
-        private final LayoutInflater inflater;
-        private final List<PageTitle> results;
-
-        private ReadMoreAdapter(LayoutInflater inflater, List<PageTitle> 
results) {
-            this.inflater = inflater;
-            this.results = results;
-        }
-
-        @Override
-        public int getCount() {
-            return results == null ? 0 : results.size();
-        }
-
-        @Override
-        public Object getItem(int position) {
-            return results.get(position);
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position;
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            if (convertView == null) {
-                convertView = inflater.inflate(R.layout.item_search_result, 
parent, false);
-            }
-            TextView pageTitleText = (TextView) 
convertView.findViewById(R.id.result_title);
-            PageTitle result = (PageTitle) getItem(position);
-            pageTitleText.setText(result.getDisplayText());
-
-            TextView descriptionText = (TextView) 
convertView.findViewById(R.id.result_description);
-            descriptionText.setText(result.getDescription());
-
-            ImageView imageView = (ImageView) 
convertView.findViewById(R.id.result_image);
-            String thumbnail = result.getThumbUrl();
-            if (!app.showImages() || thumbnail == null) {
-                Picasso.with(parent.getContext())
-                        .load(R.drawable.ic_pageimage_placeholder)
-                        .into(imageView);
-            } else {
-                Picasso.with(parent.getContext())
-                        .load(thumbnail)
-                        .placeholder(R.drawable.ic_pageimage_placeholder)
-                        .error(R.drawable.ic_pageimage_placeholder)
-                        .into(imageView);
-            }
-
-            return convertView;
-        }
+    @Override
+    public void onImageFailed() {
+        // just keep showing the placeholder image...
     }
+
 }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandlerOld.java
 
b/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandlerOld.java
new file mode 100644
index 0000000..d014ad6
--- /dev/null
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandlerOld.java
@@ -0,0 +1,405 @@
+package org.wikipedia.page.bottomcontent;
+
+import android.text.Html;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.webkit.WebView;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.squareup.picasso.Picasso;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.wikipedia.PageTitle;
+import org.wikipedia.R;
+import org.wikipedia.Utils;
+import org.wikipedia.WikipediaApp;
+import org.wikipedia.analytics.SuggestedPagesFunnel;
+import org.wikipedia.bridge.CommunicationBridge;
+import org.wikipedia.history.HistoryEntry;
+import org.wikipedia.page.LinkHandler;
+import org.wikipedia.page.LinkMovementMethodExt;
+import org.wikipedia.page.Page;
+import org.wikipedia.page.PageActivity;
+import org.wikipedia.page.PageViewFragmentInternal;
+import org.wikipedia.page.SuggestionsTask;
+import org.wikipedia.search.SearchResults;
+import org.wikipedia.views.ObservableWebView;
+
+import java.util.List;
+
+public class BottomContentHandlerOld implements BottomContentInterface,
+                                                
ObservableWebView.OnScrollChangeListener,
+                                                
ObservableWebView.OnContentHeightChangedListener {
+    private static final String TAG = "BottomContentHandler";
+    private final PageViewFragmentInternal parentFragment;
+    private final CommunicationBridge bridge;
+    private final WebView webView;
+    private final LinkHandler linkHandler;
+    private PageTitle pageTitle;
+    private final PageActivity activity;
+    private final WikipediaApp app;
+    private float displayDensity;
+    private boolean firstTimeShown = false;
+
+    private View bottomContentContainer;
+    private TextView pageLastUpdatedText;
+    private TextView pageLicenseText;
+    private View readMoreContainer;
+    private ListView readMoreList;
+
+    private SuggestedPagesFunnel funnel;
+    private SearchResults readMoreItems;
+
+    public BottomContentHandlerOld(PageViewFragmentInternal parentFragment,
+                                   CommunicationBridge bridge, 
ObservableWebView webview,
+                                   LinkHandler linkHandler, ViewGroup 
hidingView,
+                                   PageTitle pageTitle) {
+        this.parentFragment = parentFragment;
+        this.bridge = bridge;
+        this.webView = webview;
+        this.linkHandler = linkHandler;
+        this.pageTitle = pageTitle;
+        activity = parentFragment.getActivity();
+        app = (WikipediaApp) activity.getApplicationContext();
+        displayDensity = activity.getResources().getDisplayMetrics().density;
+
+        bottomContentContainer = hidingView;
+        webview.addOnScrollChangeListener(this);
+        webview.addOnContentHeightChangedListener(this);
+
+        pageLastUpdatedText = 
(TextView)bottomContentContainer.findViewById(R.id.page_last_updated_text);
+        pageLicenseText = 
(TextView)bottomContentContainer.findViewById(R.id.page_license_text);
+        readMoreContainer = 
bottomContentContainer.findViewById(R.id.read_more_container);
+        readMoreList = 
(ListView)bottomContentContainer.findViewById(R.id.read_more_list);
+
+        // set up pass-through scroll functionality for the ListView
+        readMoreList.setOnTouchListener(new View.OnTouchListener() {
+            private int touchSlop = 
ViewConfiguration.get(readMoreList.getContext())
+                                                     .getScaledTouchSlop();
+            private boolean slopReached;
+            private boolean doingSlopEvent;
+            private boolean isPressed = false;
+            private float startY;
+            private float amountScrolled;
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                int action = event.getActionMasked() & MotionEvent.ACTION_MASK;
+                switch (action) {
+                    case MotionEvent.ACTION_DOWN:
+                        isPressed = true;
+                        startY = event.getY();
+                        amountScrolled = 0;
+                        slopReached = false;
+                        break;
+                    case MotionEvent.ACTION_MOVE:
+                        if (isPressed && !doingSlopEvent) {
+                            int contentHeight = 
(int)(webView.getContentHeight() * displayDensity);
+                            int maxScroll = contentHeight - 
webView.getScrollY()
+                                            - webView.getHeight();
+                            int scrollAmount = Math.min((int) (startY - 
event.getY()), maxScroll);
+                            // manually scroll the WebView that's underneath 
us...
+                            webView.scrollBy(0, scrollAmount);
+                            amountScrolled += scrollAmount;
+                            if (Math.abs(amountScrolled) > touchSlop && 
!slopReached) {
+                                slopReached = true;
+                                // send an artificial Move event that scrolls 
it by an amount
+                                // that's greater than the touch slop, so that 
the currently
+                                // highlighted item is unselected.
+                                MotionEvent moveEvent = 
MotionEvent.obtain(event);
+                                moveEvent.setLocation(event.getX(), 
event.getY() + touchSlop * 2);
+                                doingSlopEvent = true;
+                                readMoreList.dispatchTouchEvent(moveEvent);
+                                doingSlopEvent = false;
+                            }
+                        }
+                        break;
+                    case MotionEvent.ACTION_UP:
+                    case MotionEvent.ACTION_CANCEL:
+                        isPressed = false;
+                        break;
+                    default:
+                        break;
+                }
+                return false;
+            }
+        });
+
+        funnel = new SuggestedPagesFunnel(app, pageTitle.getSite());
+
+        // preload the display density, since it will be used in a lot of 
places
+        displayDensity = activity.getResources().getDisplayMetrics().density;
+        // hide ourselves by default
+        hide();
+    }
+
+    @Override
+    public void onScrollChanged(int oldScrollY, int scrollY) {
+        if (bottomContentContainer.getVisibility() == View.GONE) {
+            return;
+        }
+        int contentHeight = (int)(webView.getContentHeight() * displayDensity);
+        int bottomOffset = contentHeight - scrollY - webView.getHeight();
+        int bottomHeight = bottomContentContainer.getHeight();
+        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) 
bottomContentContainer.getLayoutParams();
+        if (bottomOffset > bottomHeight) {
+            if (params.bottomMargin != -bottomHeight) {
+                params.bottomMargin = -bottomHeight;
+                params.topMargin = 0;
+                bottomContentContainer.setLayoutParams(params);
+                bottomContentContainer.setVisibility(View.INVISIBLE);
+            }
+        } else {
+            params.bottomMargin = -bottomOffset;
+            params.topMargin = -bottomHeight;
+            bottomContentContainer.setLayoutParams(params);
+            if (bottomContentContainer.getVisibility() != View.VISIBLE) {
+                bottomContentContainer.setVisibility(View.VISIBLE);
+            }
+            if (!firstTimeShown && readMoreItems != null) {
+                firstTimeShown = true;
+                funnel.logSuggestionsShown(pageTitle, 
readMoreItems.getPageTitles());
+            }
+        }
+    }
+
+    @Override
+    public void onContentHeightChanged(int contentHeight) {
+        if (bottomContentContainer.getVisibility() != View.VISIBLE) {
+            return;
+        }
+        // trigger a manual scroll event to update our position
+        onScrollChanged(webView.getScrollY(), webView.getScrollY());
+    }
+
+    /**
+     * Hide the bottom content entirely.
+     * It can only be shown again by calling beginLayout()
+     */
+    public void hide() {
+        bottomContentContainer.setVisibility(View.GONE);
+    }
+
+    public void beginLayout() {
+        setupAttribution();
+        if (parentFragment.getPage().couldHaveReadMoreSection()) {
+            preRequestReadMoreItems(activity.getLayoutInflater());
+        } else {
+            
bottomContentContainer.findViewById(R.id.read_more_container).setVisibility(View.GONE);
+            layoutContent();
+        }
+    }
+
+    private void layoutContent() {
+        if (!parentFragment.isAdded()) {
+            return;
+        }
+        bottomContentContainer.setVisibility(View.INVISIBLE);
+        // keep trying until our layout has a height...
+        if (bottomContentContainer.getHeight() == 0) {
+            final int postDelay = 50;
+            bottomContentContainer.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    layoutContent();
+                }
+            }, postDelay);
+            return;
+        }
+
+        // calculate the height of the listview, based on the number of items 
inside it.
+        ListAdapter adapter = readMoreList.getAdapter();
+        if (adapter != null && adapter.getCount() > 0) {
+            ViewGroup.LayoutParams params = readMoreList.getLayoutParams();
+            final int itemHeight = 
(int)activity.getResources().getDimension(R.dimen.defaultListItemSize);
+            params.height = adapter.getCount() * itemHeight
+                            + (readMoreList.getDividerHeight() * 
(adapter.getCount() - 1));
+            readMoreList.setLayoutParams(params);
+        }
+
+        readMoreList.measure(View.MeasureSpec.UNSPECIFIED, 
View.MeasureSpec.UNSPECIFIED);
+        bottomContentContainer.measure(View.MeasureSpec.UNSPECIFIED, 
View.MeasureSpec.UNSPECIFIED);
+
+        // pad the bottom of the webview, to make room for ourselves
+        int totalHeight = bottomContentContainer.getMeasuredHeight();
+        JSONObject payload = new JSONObject();
+        try {
+            payload.put("paddingBottom", (int)(totalHeight / displayDensity));
+        } catch (JSONException e) {
+            throw new RuntimeException(e);
+        }
+        bridge.sendMessage("setPaddingBottom", payload);
+        // ^ sending the padding event will guarantee a ContentHeightChanged 
event to be triggered,
+        // which will update our margin based on the scroll offset, so we 
don't need to do it here.
+    }
+
+    private void setupAttribution() {
+        Page page = parentFragment.getPage();
+        
pageLicenseText.setText(Html.fromHtml(activity.getString(R.string.content_license_html)));
+        pageLicenseText.setMovementMethod(new 
LinkMovementMethodExt(linkHandler));
+
+        // Don't display last updated message for main page or file pages, 
because it's always wrong
+        if (page.isMainPage() || page.isFilePage()) {
+            pageLastUpdatedText.setVisibility(View.GONE);
+        } else {
+            String lastUpdatedHtml = "<a href=\"" + 
page.getTitle().getUriForAction("history")
+                    + "\">" + activity.getString(R.string.last_updated_text,
+                    
Utils.formatDateRelative(page.getPageProperties().getLastModified())
+                            + "</a>");
+            pageLastUpdatedText.setText(Html.fromHtml(lastUpdatedHtml));
+            pageLastUpdatedText.setMovementMethod(new 
LinkMovementMethodExt(linkHandler));
+        }
+    }
+
+    private void preRequestReadMoreItems(final LayoutInflater layoutInflater) {
+        if (parentFragment.getPage().isMainPage()) {
+            new MainPageReadMoreTopicTask(activity) {
+                @Override
+                public void onFinish(PageTitle myTitle) {
+                    requestReadMoreItems(layoutInflater, myTitle);
+                }
+
+                @Override
+                public void onCatch(Throwable caught) {
+                    // Read More titles are expendable.
+                    Log.w(TAG, "Error while getting Read More topic for main 
page.", caught);
+                    // but lay out the bottom content anyway:
+                    layoutContent();
+                }
+            }.execute();
+        } else {
+            requestReadMoreItems(layoutInflater, pageTitle);
+        }
+    }
+
+    private void requestReadMoreItems(final LayoutInflater layoutInflater,
+                                      final PageTitle myTitle) {
+        if (myTitle == null || TextUtils.isEmpty(myTitle.getPrefixedText())) {
+            hideReadMore();
+            layoutContent();
+            return;
+        }
+        final int numSuggestions = 3;
+        new SuggestionsTask(app.getAPIForSite(myTitle.getSite()), 
myTitle.getSite(),
+                myTitle.getPrefixedText(), 
(int)(parentFragment.getActivity().getResources().getDimension(R.dimen.leadImageWidth)
 / displayDensity),
+                numSuggestions, false) {
+            @Override
+            public void onFinish(SearchResults results) {
+                readMoreItems = results;
+                if (!readMoreItems.getPageTitles().isEmpty()) {
+                    // If there are results, set up section and make sure it's 
visible
+                    setupReadMoreSection(layoutInflater, readMoreItems);
+                    showReadMore();
+                } else {
+                    // If there's no results, just hide the section
+                    hideReadMore();
+                }
+                layoutContent();
+            }
+
+            @Override
+            public void onCatch(Throwable caught) {
+                // Read More titles are expendable.
+                Log.w(TAG, "Error while fetching Read More titles.", caught);
+                // but lay out the bottom content anyway:
+                layoutContent();
+            }
+        }.execute();
+    }
+
+    private void hideReadMore() {
+        readMoreContainer.setVisibility(View.GONE);
+    }
+
+    private void showReadMore() {
+        readMoreContainer.setVisibility(View.VISIBLE);
+    }
+
+    public PageTitle getTitle() {
+        return pageTitle;
+    }
+
+    public void setTitle(PageTitle newTitle) {
+        pageTitle = newTitle;
+    }
+
+    private void setupReadMoreSection(LayoutInflater layoutInflater, final 
SearchResults results) {
+        final ReadMoreAdapter adapter = new ReadMoreAdapter(layoutInflater, 
results.getPageTitles());
+        readMoreList.setAdapter(adapter);
+        readMoreList.setOnItemClickListener(new 
AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int 
position, long id) {
+                PageTitle title = (PageTitle) adapter.getItem(position);
+                HistoryEntry historyEntry = new HistoryEntry(title, 
HistoryEntry.SOURCE_INTERNAL_LINK);
+                activity.displayNewPage(title, historyEntry);
+                funnel.logSuggestionClicked(pageTitle, 
results.getPageTitles(), position);
+            }
+        });
+        adapter.notifyDataSetChanged();
+    }
+
+    private final class ReadMoreAdapter extends BaseAdapter {
+        private final LayoutInflater inflater;
+        private final List<PageTitle> results;
+
+        private ReadMoreAdapter(LayoutInflater inflater, List<PageTitle> 
results) {
+            this.inflater = inflater;
+            this.results = results;
+        }
+
+        @Override
+        public int getCount() {
+            return results == null ? 0 : results.size();
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return results.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = inflater.inflate(R.layout.item_search_result, 
parent, false);
+            }
+            TextView pageTitleText = (TextView) 
convertView.findViewById(R.id.result_title);
+            PageTitle result = (PageTitle) getItem(position);
+            pageTitleText.setText(result.getDisplayText());
+
+            TextView descriptionText = (TextView) 
convertView.findViewById(R.id.result_description);
+            descriptionText.setText(result.getDescription());
+
+            ImageView imageView = (ImageView) 
convertView.findViewById(R.id.result_image);
+            String thumbnail = result.getThumbUrl();
+            if (!app.showImages() || thumbnail == null) {
+                Picasso.with(parent.getContext())
+                        .load(R.drawable.ic_pageimage_placeholder)
+                        .into(imageView);
+            } else {
+                Picasso.with(parent.getContext())
+                        .load(thumbnail)
+                        .placeholder(R.drawable.ic_pageimage_placeholder)
+                        .error(R.drawable.ic_pageimage_placeholder)
+                        .into(imageView);
+            }
+
+            return convertView;
+        }
+    }
+}
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentInterface.java
 
b/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentInterface.java
new file mode 100644
index 0000000..a8d99bc
--- /dev/null
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentInterface.java
@@ -0,0 +1,12 @@
+package org.wikipedia.page.bottomcontent;
+
+import org.wikipedia.PageTitle;
+
+public interface BottomContentInterface {
+
+    void hide();
+    void beginLayout();
+    PageTitle getTitle();
+    void setTitle(PageTitle newTitle);
+
+}
diff --git 
a/wikipedia/src/main/java/org/wikipedia/search/FullSearchArticlesTask.java 
b/wikipedia/src/main/java/org/wikipedia/search/FullSearchArticlesTask.java
index 60454ec..1a39586 100644
--- a/wikipedia/src/main/java/org/wikipedia/search/FullSearchArticlesTask.java
+++ b/wikipedia/src/main/java/org/wikipedia/search/FullSearchArticlesTask.java
@@ -22,14 +22,21 @@
     private final String searchTerm;
     private final int maxResults;
     private final FTContinueOffset continueOffset;
+    private final int thumbSize;
 
     public FullSearchArticlesTask(Api api, Site site, String searchTerm, int 
maxResults,
                                   SearchResults.ContinueOffset continueOffset) 
{
+        this(api, site, searchTerm, maxResults, continueOffset, 
WikipediaApp.PREFERRED_THUMB_SIZE);
+    }
+
+    public FullSearchArticlesTask(Api api, Site site, String searchTerm, int 
maxResults,
+                                  SearchResults.ContinueOffset continueOffset, 
int thumbSize) {
         super(LOW_CONCURRENCY, api);
         this.site = site;
         this.searchTerm = searchTerm;
         this.maxResults = maxResults;
         this.continueOffset = (FTContinueOffset) continueOffset;
+        this.thumbSize = thumbSize;
     }
 
     @Override
@@ -46,7 +53,7 @@
                 .param("gsrprop", "redirecttitle")
                 .param("gsrlimit", maxResultsString)
                 .param("piprop", "thumbnail") // for thumbnail URLs
-                .param("pithumbsize", 
Integer.toString(WikipediaApp.PREFERRED_THUMB_SIZE))
+                .param("pithumbsize", Integer.toString(thumbSize))
                 .param("pilimit", maxResultsString);
         if (continueOffset != null) {
             req.param("continue", continueOffset.cont);

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

Gerrit-MessageType: merged
Gerrit-Change-Id: Ifdc7080749c4a97c01b265c1586f287797fc0ab9
Gerrit-PatchSet: 11
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: jenkins-bot <>

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

Reply via email to