jenkins-bot has submitted this change and it was merged. Change subject: Fix possible NPE(s) when accessing parent fragment. ......................................................................
Fix possible NPE(s) when accessing parent fragment. In our LeadImagesHandler and BottomContentHandler, we use the getFragment() function which returns the "internal" fragment object that is currently hosted by the PageViewFragment. The problem is that, when a PageViewFragment is detached, it sets its instance of the internal object to null. So, if the Lead or Bottom components try to access the internal fragment using getFragment() from the result of an AsyncTask after the parent fragment is detached, they will get a null pointer. This patch refactors things so that the internal object itself is passed to the Lead and Bottom components, so that they will never receive a null reference to it. Change-Id: Ie78c76e12128a89218bcea8d65fbfeed01278a63 --- M wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java M wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java M wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java 3 files changed, 39 insertions(+), 58 deletions(-) Approvals: BearND: Looks good to me, approved jenkins-bot: Verified diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java index eb3efc8..9f7fd44 100644 --- a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java +++ b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java @@ -416,9 +416,9 @@ new SearchBarHideHandler(webView, getActivity().getToolbarView()); imagesContainer = (ViewGroup) parentFragment.getView().findViewById(R.id.page_images_container); - leadImagesHandler = new LeadImagesHandler(parentFragment, bridge, webView, imagesContainer); + leadImagesHandler = new LeadImagesHandler(getActivity(), this, bridge, webView, imagesContainer); - bottomContentHandler = new BottomContentHandler(parentFragment, bridge, + bottomContentHandler = new BottomContentHandler(this, bridge, webView, linkHandler, (ViewGroup) parentFragment.getView().findViewById(R.id.bottom_content_container), title); 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 97076b5..4d9f00f 100644 --- a/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java +++ b/wikipedia/src/main/java/org/wikipedia/page/bottomcontent/BottomContentHandler.java @@ -31,7 +31,7 @@ import org.wikipedia.page.LinkMovementMethodExt; import org.wikipedia.page.Page; import org.wikipedia.page.PageActivity; -import org.wikipedia.page.PageViewFragment; +import org.wikipedia.page.PageViewFragmentInternal; import org.wikipedia.page.SuggestionsTask; import org.wikipedia.search.FullSearchArticlesTask; import org.wikipedia.views.ObservableWebView; @@ -44,7 +44,7 @@ public class BottomContentHandler implements ObservableWebView.OnScrollChangeListener, ObservableWebView.OnContentHeightChangedListener { private static final String TAG = "BottomContentHandler"; - private final PageViewFragment parentFragment; + private final PageViewFragmentInternal parentFragment; private final CommunicationBridge bridge; private final WebView webView; private final LinkHandler linkHandler; @@ -63,7 +63,7 @@ private SuggestedPagesFunnel funnel; private FullSearchArticlesTask.FullSearchResults readMoreItems; - public BottomContentHandler(PageViewFragment parentFragment, CommunicationBridge bridge, + public BottomContentHandler(PageViewFragmentInternal parentFragment, CommunicationBridge bridge, ObservableWebView webview, LinkHandler linkHandler, ViewGroup hidingView, PageTitle pageTitle) { this.parentFragment = parentFragment; @@ -71,9 +71,9 @@ this.webView = webview; this.linkHandler = linkHandler; this.pageTitle = pageTitle; - activity = parentFragment.getFragment().getActivity(); + activity = parentFragment.getActivity(); app = (WikipediaApp) activity.getApplicationContext(); - displayDensity = parentFragment.getResources().getDisplayMetrics().density; + displayDensity = activity.getResources().getDisplayMetrics().density; bottomContentContainer = hidingView; webview.addOnScrollChangeListener(this); @@ -139,7 +139,7 @@ funnel = new SuggestedPagesFunnel(app, pageTitle.getSite()); // preload the display density, since it will be used in a lot of places - displayDensity = parentFragment.getResources().getDisplayMetrics().density; + displayDensity = activity.getResources().getDisplayMetrics().density; // hide ourselves by default hide(); } @@ -193,7 +193,7 @@ public void beginLayout() { setupAttribution(); - if (parentFragment.getFragment().getPage().couldHaveReadMoreSection()) { + if (parentFragment.getPage().couldHaveReadMoreSection()) { requestReadMoreItems(activity.getLayoutInflater()); } else { bottomContentContainer.findViewById(R.id.read_more_container).setVisibility(View.GONE); @@ -222,7 +222,7 @@ ListAdapter adapter = readMoreList.getAdapter(); if (adapter != null && adapter.getCount() > 0) { ViewGroup.LayoutParams params = readMoreList.getLayoutParams(); - final int itemHeight = (int)parentFragment.getResources().getDimension(R.dimen.defaultListItemSize); + final int itemHeight = (int)activity.getResources().getDimension(R.dimen.defaultListItemSize); params.height = adapter.getCount() * itemHeight + (readMoreList.getDividerHeight() * (adapter.getCount() - 1)); readMoreList.setLayoutParams(params); @@ -245,14 +245,14 @@ } private void setupAttribution() { - Page page = parentFragment.getFragment().getPage(); + Page page = parentFragment.getPage(); String lastUpdatedHtml = "<a href=\"" + page.getTitle().getUriForAction("history") - + "\">" + parentFragment.getString(R.string.last_updated_text, + + "\">" + activity.getString(R.string.last_updated_text, Utils.formatDateRelative(page.getPageProperties().getLastModified()) + "</a>"); pageLastUpdatedText.setText(Html.fromHtml(lastUpdatedHtml)); pageLastUpdatedText.setMovementMethod(new LinkMovementMethodExt(linkHandler)); - pageLicenseText.setText(Html.fromHtml(parentFragment.getString(R.string.content_license_html))); + pageLicenseText.setText(Html.fromHtml(activity.getString(R.string.content_license_html))); pageLicenseText.setMovementMethod(new LinkMovementMethodExt(linkHandler)); } diff --git a/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java b/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java index def891c..81fdd8c 100644 --- a/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java +++ b/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java @@ -1,5 +1,6 @@ package org.wikipedia.page.leadimages; +import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Point; @@ -29,9 +30,6 @@ import org.wikipedia.ViewAnimations; import org.wikipedia.WikipediaApp; import org.wikipedia.bridge.CommunicationBridge; -import org.wikipedia.page.Page; -import org.wikipedia.page.PageProperties; -import org.wikipedia.page.PageViewFragment; import org.wikipedia.page.PageViewFragmentInternal; import org.wikipedia.views.ObservableWebView; import org.wikipedia.wikidata.WikidataCache; @@ -39,7 +37,8 @@ import java.util.Map; public class LeadImagesHandler implements ObservableWebView.OnScrollChangeListener, ImageViewWithFace.OnImageLoadListener { - private final PageViewFragment parentFragment; + private final Context context; + private final PageViewFragmentInternal parentFragment; private final CommunicationBridge bridge; private final WebView webView; @@ -106,13 +105,15 @@ void onLayoutComplete(); } - public LeadImagesHandler(final PageViewFragment parentFragment, CommunicationBridge bridge, - ObservableWebView webview, ViewGroup hidingView) { + public LeadImagesHandler(final Context context, final PageViewFragmentInternal parentFragment, + CommunicationBridge bridge, ObservableWebView webview, + ViewGroup hidingView) { + this.context = context; this.parentFragment = parentFragment; this.imageContainer = hidingView; this.bridge = bridge; this.webView = webview; - displayDensity = parentFragment.getResources().getDisplayMetrics().density; + displayDensity = context.getResources().getDisplayMetrics().density; imagePlaceholder = (ImageView)imageContainer.findViewById(R.id.page_image_placeholder); image1 = (ImageViewWithFace)imageContainer.findViewById(R.id.page_image_1); @@ -122,7 +123,7 @@ webview.addOnScrollChangeListener(this); // preload the display density, since it will be used in a lot of places - displayDensity = parentFragment.getResources().getDisplayMetrics().density; + displayDensity = context.getResources().getDisplayMetrics().density; // get the screen height, using correct methods for different API versions if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { @@ -137,15 +138,13 @@ image1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - String imageName = parentFragment.getFragment().getPage().getPageProperties() - .getLeadImageName(); + String imageName = parentFragment.getPage().getPageProperties().getLeadImageName(); if (imageName == null) { return; } PageTitle imageTitle = new PageTitle("File:" + imageName, - parentFragment.getFragment().getTitle() - .getSite()); - parentFragment.getFragment().showImageGallery(imageTitle); + parentFragment.getTitle().getSite()); + parentFragment.showImageGallery(imageTitle); } }); @@ -276,7 +275,7 @@ * @param listener Listener that will receive an event when the layout is completed. */ public void beginLayout(OnLeadImageLayoutListener listener) { - String thumbUrl = getLeadImageUrl(); + String thumbUrl = parentFragment.getPage().getPageProperties().getLeadImageUrl(); if (!WikipediaApp.getInstance().showImages() || displayHeight < MIN_SCREEN_HEIGHT_DP || WikipediaApp.getInstance().getReleaseType() == WikipediaApp.RELEASE_PROD) { @@ -288,30 +287,13 @@ } // set the page title text, and honor any HTML formatting in the title - pageTitleText.setText(Html.fromHtml(parentFragment.getFragment().getPage().getDisplayTitle())); + pageTitleText.setText(Html.fromHtml(parentFragment.getPage().getDisplayTitle())); // hide the description text... pageDescriptionText.setVisibility(View.INVISIBLE); // kick off the (asynchronous) laying out of the page title text - layoutPageTitle((int)(parentFragment.getResources().getDimension(R.dimen.titleTextSize) + layoutPageTitle((int)(context.getResources().getDimension(R.dimen.titleTextSize) / displayDensity), listener); - } - - // NPE, you shall not pass: https://phabricator.wikimedia.org/T78501 - private String getLeadImageUrl() { - final PageViewFragmentInternal internalFragment = parentFragment.getFragment(); - if (internalFragment == null) { - return null; - } - final Page page = internalFragment.getPage(); - if (page == null) { - return null; - } - final PageProperties pageProperties = page.getPageProperties(); - if (pageProperties == null) { - return null; - } - return pageProperties.getLeadImageUrl(); } /** @@ -375,7 +357,7 @@ if (!parentFragment.isAdded()) { return; } - boolean isMainPage = parentFragment.getFragment().getPage().getPageProperties().isMainPage(); + boolean isMainPage = parentFragment.getPage().getPageProperties().isMainPage(); int titleContainerHeight; int titleBottomPadding = 0; @@ -398,17 +380,16 @@ image1.setVisibility(View.GONE); imagePlaceholder.setVisibility(View.GONE); // set the color of the title - pageTitleText.setTextColor(parentFragment - .getResources() - .getColor(Utils.getThemedAttributeId(parentFragment.getActivity(), R.attr.lead_disabled_text_color))); + pageTitleText.setTextColor(context.getResources() + .getColor(Utils.getThemedAttributeId(parentFragment.getActivity(), + R.attr.lead_disabled_text_color))); // remove bottom padding from the description pageDescriptionText.setPadding(pageDescriptionText.getPaddingLeft(), pageDescriptionText.getPaddingTop(), pageDescriptionText.getPaddingRight(), 0); // and give it no drop shadow pageTitleText.setShadowLayer(0, 0, 0, 0); // do the same for the description... - pageDescriptionText.setTextColor(parentFragment - .getResources() + pageDescriptionText.setTextColor(context.getResources() .getColor(Utils.getThemedAttributeId(parentFragment.getActivity(), R.attr.lead_disabled_text_color))); pageDescriptionText.setShadowLayer(0, 0, 0, 0); // remove any background from the title container @@ -427,14 +408,14 @@ imagePlaceholder.setVisibility(View.VISIBLE); // set the color of the title - pageTitleText.setTextColor(parentFragment.getResources().getColor(R.color.lead_text_color)); + pageTitleText.setTextColor(context.getResources().getColor(R.color.lead_text_color)); final int bottomPaddingNominal = 16; titleBottomPadding = (int)(bottomPaddingNominal * displayDensity); // and give it a nice drop shadow! - pageTitleText.setShadowLayer(2, 1, 1, parentFragment.getResources().getColor(R.color.lead_text_shadow)); + pageTitleText.setShadowLayer(2, 1, 1, context.getResources().getColor(R.color.lead_text_shadow)); // do the same for the description... - pageDescriptionText.setTextColor(parentFragment.getResources().getColor(R.color.lead_text_color)); - pageDescriptionText.setShadowLayer(2, 1, 1, parentFragment.getResources().getColor(R.color.lead_text_shadow)); + pageDescriptionText.setTextColor(context.getResources().getColor(R.color.lead_text_color)); + pageDescriptionText.setShadowLayer(2, 1, 1, context.getResources().getColor(R.color.lead_text_shadow)); // set the title container background to be a gradient pageTitleContainer.setBackgroundResource(R.drawable.lead_title_gradient); // set the correct padding on the container @@ -466,7 +447,7 @@ bridge.sendMessage("setPaddingTop", payload); // and start fetching the lead image, if we have one - String thumbUrl = getLeadImageUrl(); + String thumbUrl = parentFragment.getPage().getPageProperties().getLeadImageUrl(); if (!isMainPage && thumbUrl != null && leadImagesEnabled) { thumbUrl = WikipediaApp.getInstance().getNetworkProtocol() + ":" + thumbUrl; Picasso.with(parentFragment.getActivity()) @@ -493,7 +474,7 @@ * of loading the WebView contents. */ private void fetchWikiDataDescription() { - final PageTitle pageTitle = parentFragment.getFragment().getPage().getTitle(); + final PageTitle pageTitle = parentFragment.getPage().getTitle(); if (pageTitle != null) { final String language = pageTitle.getSite().getLanguage(); -- To view, visit https://gerrit.wikimedia.org/r/181068 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Ie78c76e12128a89218bcea8d65fbfeed01278a63 Gerrit-PatchSet: 2 Gerrit-Project: apps/android/wikipedia Gerrit-Branch: master Gerrit-Owner: Dbrant <dbr...@wikimedia.org> Gerrit-Reviewer: BearND <bsitzm...@wikimedia.org> Gerrit-Reviewer: Brion VIBBER <br...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits