com.quarterfull.newsAndroid.NewsDetailFragment.java Source code

Java tutorial

Introduction

Here is the source code for com.quarterfull.newsAndroid.NewsDetailFragment.java

Source

/**
* Android ownCloud News
*
* @author David Luhmer
* @copyright 2013 David Luhmer david-dev@live.de
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*
*/

package com.quarterfull.newsAndroid;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.ConsoleMessage;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;

import com.nostra13.universalimageloader.cache.disc.DiskCache;
import com.nostra13.universalimageloader.core.ImageLoader;

import org.apache.commons.lang3.StringEscapeUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.File;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import butterknife.Bind;
import butterknife.ButterKnife;
import com.quarterfull.newsAndroid.database.model.Feed;
import com.quarterfull.newsAndroid.database.model.RssItem;
import com.quarterfull.newsAndroid.helper.AsyncTaskHelper;
import com.quarterfull.newsAndroid.helper.ColorHelper;
import com.quarterfull.newsAndroid.helper.ImageHandler;
import com.quarterfull.newsAndroid.helper.ThemeChooser;

public class NewsDetailFragment extends Fragment {
    public static final String ARG_SECTION_NUMBER = "ARG_SECTION_NUMBER";

    public final String TAG = getClass().getCanonicalName();

    public static int background_color = Integer.MIN_VALUE;

    @Bind(R.id.webview)
    WebView mWebView;
    @Bind(R.id.progressBarLoading)
    ProgressBar mProgressBarLoading;
    @Bind(R.id.progressbar_webview)
    ProgressBar mProgressbarWebView;

    private int section_number;
    public List<String> urls = new ArrayList<>();
    protected String html;

    public NewsDetailFragment() {
        //setRetainInstance(true);
    }

    public int getSectionNumber() {
        return section_number;
    }

    @Override
    public void onResume() {
        super.onResume();
        ResumeCurrentPage();
    }

    @Override
    public void onPause() {
        super.onPause();
        PauseCurrentPage();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mWebView != null) {
            mWebView.destroy();
        }
    }

    public void PauseCurrentPage() {
        if (mWebView != null) {
            mWebView.onPause();
            mWebView.pauseTimers();
        }
    }

    public void ResumeCurrentPage() {
        if (mWebView != null) {
            mWebView.onResume();
            mWebView.resumeTimers();
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_news_detail, container, false);

        section_number = (Integer) getArguments().get(ARG_SECTION_NUMBER);

        ButterKnife.bind(this, rootView);

        startLoadRssItemToWebViewTask();

        return rootView;
    }

    public void startLoadRssItemToWebViewTask() {
        AsyncTaskHelper.StartAsyncTask(new LoadRssItemToWebViewAsyncTask());
    }

    private class LoadRssItemToWebViewAsyncTask extends AsyncTask<Void, Void, String> {

        @Override
        protected void onPreExecute() {
            NewsDetailActivity ndActivity = ((NewsDetailActivity) getActivity());

            if (background_color != Integer.MIN_VALUE && ThemeChooser.isDarkTheme(ndActivity)) {
                mWebView.setBackgroundColor(background_color);
                ndActivity.mViewPager.setBackgroundColor(background_color);
            }

            init_webView();

            mWebView.setVisibility(View.GONE);
            mProgressBarLoading.setVisibility(View.VISIBLE);

            super.onPreExecute();
        }

        @Override
        protected String doInBackground(Void... voids) {
            NewsDetailActivity ndActivity = ((NewsDetailActivity) getActivity());

            RssItem rssItem = ndActivity.rssItems.get(section_number);

            return getHtmlPage(ndActivity, rssItem, true);
        }

        @Override
        protected void onPostExecute(String htmlPage) {
            mWebView.setVisibility(View.VISIBLE);
            mProgressBarLoading.setVisibility(View.GONE);

            SetSoftwareRenderModeForWebView(htmlPage, mWebView);

            html = htmlPage;
            mWebView.loadDataWithBaseURL("file:///android_asset/", htmlPage, "text/html", "UTF-8", "");
            super.onPostExecute(htmlPage);
        }
    }

    /**
     * This function has no effect on devices with api level < HONEYCOMB
     * @param htmlPage
     * @param webView
     */
    public static void SetSoftwareRenderModeForWebView(String htmlPage, WebView webView) {
        if (htmlPage.contains(".gif")) {
            webView.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
            Log.v("NewsDetailFragment", "Using LAYER_TYPE_SOFTWARE");
        } else {
            //webView.setLayerType(WebView.LAYER_TYPE_HARDWARE, null);
            //Log.v("NewsDetailFragment", "Using LAYER_TYPE_HARDWARE");

            if (webView.getLayerType() == WebView.LAYER_TYPE_HARDWARE) {
                Log.v("NewsDetailFragment", "Using LAYER_TYPE_HARDWARE");
            } else if (webView.getLayerType() == WebView.LAYER_TYPE_SOFTWARE) {
                Log.v("NewsDetailFragment", "Using LAYER_TYPE_SOFTWARE");
            } else {
                Log.v("NewsDetailFragment", "Using LAYER_TYPE_DEFAULT");
            }
        }
    }

    boolean changedUrl = false;

    @SuppressLint("SetJavaScriptEnabled")
    private void init_webView() {
        int backgroundColor = ColorHelper.getColorFromAttribute(getContext(), R.attr.news_detail_background_color);
        mWebView.setBackgroundColor(backgroundColor);

        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setAllowFileAccess(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(false);
        webSettings.setSupportMultipleWindows(false);
        webSettings.setSupportZoom(false);
        webSettings.setAppCacheEnabled(true);

        registerForContextMenu(mWebView);

        mWebView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onConsoleMessage(ConsoleMessage cm) {
                Log.v(TAG, cm.message() + " at " + cm.sourceId() + ":" + cm.lineNumber());
                return true;
            }

            @Override
            public void onProgressChanged(WebView view, int progress) {
                if (progress < 100 && mProgressbarWebView.getVisibility() == ProgressBar.GONE) {
                    mProgressbarWebView.setVisibility(ProgressBar.VISIBLE);
                }
                mProgressbarWebView.setProgress(progress);
                if (progress == 100) {
                    mProgressbarWebView.setVisibility(ProgressBar.GONE);

                    //The following three lines are a workaround for websites which don't use a background color
                    int bgColor = ContextCompat.getColor(getContext(),
                            R.color.slider_listview_text_color_dark_theme);
                    NewsDetailActivity ndActivity = ((NewsDetailActivity) getActivity());
                    mWebView.setBackgroundColor(bgColor);
                    ndActivity.mViewPager.setBackgroundColor(bgColor);

                    if (ThemeChooser.isDarkTheme(getActivity())) {
                        mWebView.setBackgroundColor(
                                ContextCompat.getColor(getContext(), android.R.color.transparent));
                    }
                }
            }
        });

        mWebView.setWebViewClient(new WebViewClient() {

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                if (changedUrl) {
                    changedUrl = false;

                    if (!url.equals("file:///android_asset/") && (urls.isEmpty() || !urls.get(0).equals(url))) {
                        urls.add(0, url);

                        Log.v(TAG, "Page finished (added): " + url);
                    }
                }

                super.onPageStarted(view, url, favicon);
            }
        });

        mWebView.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (v.getId() == R.id.webview && event.getAction() == MotionEvent.ACTION_DOWN) {
                    changedUrl = true;
                }

                return false;
            }
        });
    }

    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        if (v instanceof WebView) {
            WebView.HitTestResult result = ((WebView) v).getHitTestResult();
            if (result != null) {
                int type = result.getType();

                Document htmldoc = Jsoup.parse(html);

                FragmentTransaction ft = getFragmentManager().beginTransaction();

                if (type == WebView.HitTestResult.IMAGE_TYPE
                        || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
                    String imageUrl = result.getExtra();
                    if (imageUrl.startsWith("http") || imageUrl.startsWith("file")) {

                        URL mImageUrl;
                        String imgtitle;
                        String imgaltval;
                        String imgsrcval;

                        imgsrcval = imageUrl.substring(imageUrl.lastIndexOf('/') + 1, imageUrl.length());
                        Elements imgtag = htmldoc.getElementsByAttributeValueContaining("src", imageUrl);

                        try {
                            imgtitle = imgtag.first().attr("title");
                        } catch (NullPointerException e) {
                            imgtitle = "";
                        }
                        try {
                            imgaltval = imgtag.first().attr("alt");
                        } catch (NullPointerException e) {
                            imgaltval = "";
                        }
                        try {
                            mImageUrl = new URL(imageUrl);
                        } catch (MalformedURLException e) {
                            return;
                        }

                        String title = imgsrcval;
                        int titleIcon = android.R.drawable.ic_menu_gallery;
                        String text = (imgtitle.isEmpty()) ? imgaltval : imgtitle;

                        // Create and show the dialog.
                        DialogFragment newFragment = NewsDetailImageDialogFragment.newInstanceImage(title,
                                titleIcon, text, mImageUrl);
                        newFragment.show(ft, "menu_fragment_dialog");
                    }
                } else if (type == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
                    String url = result.getExtra();
                    URL mUrl;
                    String text;
                    try {
                        Elements urltag = htmldoc.getElementsByAttributeValueContaining("href", url);
                        text = urltag.text();
                        mUrl = new URL(url);
                    } catch (MalformedURLException e) {
                        return;
                    }

                    // Create and show the dialog.
                    DialogFragment newFragment = NewsDetailImageDialogFragment.newInstanceUrl(text,
                            mUrl.toString());
                    newFragment.show(ft, "menu_fragment_dialog");
                }
                //else if (type == WebView.HitTestResult.EMAIL_TYPE) { }
                //else if (type == WebView.HitTestResult.GEO_TYPE) { }
                //else if (type == WebView.HitTestResult.PHONE_TYPE) { }
                //else if (type == WebView.HitTestResult.EDIT_TEXT_TYPE) { }
            }
        }
    }

    @SuppressLint("SimpleDateFormat")
    public static String getHtmlPage(Context context, RssItem rssItem, boolean showHeader) {
        String feedTitle = "Undefined";
        String favIconUrl = null;

        Feed feed = rssItem.getFeed();
        int[] colors = ColorHelper.getColorsFromAttributes(context, R.attr.dividerLineColor,
                R.attr.rssItemListBackground);
        int feedColor = colors[0];
        if (feed != null) {
            feedTitle = StringEscapeUtils.escapeHtml4(feed.getFeedTitle());
            favIconUrl = feed.getFaviconUrl();
            if (feed.getAvgColour() != null)
                feedColor = Integer.parseInt(feed.getAvgColour());
        }

        if (favIconUrl != null) {
            DiskCache diskCache = ImageLoader.getInstance().getDiskCache();
            File file = diskCache.get(favIconUrl);
            if (file != null)
                favIconUrl = "file://" + file.getAbsolutePath();
        } else {
            favIconUrl = "file:///android_res/drawable/default_feed_icon_light.png";
        }

        String body_id;
        if (ThemeChooser.isDarkTheme(context)) {
            body_id = "darkTheme";
        } else
            body_id = "lightTheme";

        boolean isRightToLeft = context.getResources().getBoolean(R.bool.is_right_to_left);
        String rtlClass = isRightToLeft ? "rtl" : "";
        String borderSide = isRightToLeft ? "right" : "left";

        StringBuilder builder = new StringBuilder();

        builder.append(
                "<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=0\" />");
        builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"web.css\" />");
        builder.append("<style type=\"text/css\">");
        builder.append(String.format(
                "#top_section { border-%s: 4px solid %s; border-bottom: 1px solid %s; background: %s }", borderSide,
                ColorHelper.getCssColor(feedColor), ColorHelper.getCssColor(colors[0]),
                ColorHelper.getCssColor(colors[1])));
        builder.append("</style>");
        builder.append(String.format("</head><body id=\"%s\" class=\"%s\">", body_id, rtlClass));

        if (showHeader) {
            builder.append("<div id=\"top_section\">");
            builder.append("<div id=\"header\">");
            String title = StringEscapeUtils.escapeHtml4(rssItem.getTitle());
            String linkToFeed = StringEscapeUtils.escapeHtml4(rssItem.getLink());
            builder.append(String.format("<a href=\"%s\">%s</a>", linkToFeed, title));
            builder.append("</div>");

            String authorOfArticle = StringEscapeUtils.escapeHtml4(rssItem.getAuthor());
            if (authorOfArticle != null)
                if (!authorOfArticle.trim().equals(""))
                    feedTitle += " - " + authorOfArticle.trim();

            builder.append("<div id=\"header_small_text\">");

            builder.append("<div id=\"subscription\">");
            builder.append(String.format("<img id=\"imgFavicon\" src=\"%s\" />", favIconUrl));
            builder.append(feedTitle.trim());
            builder.append("</div>");

            Date date = rssItem.getPubDate();
            if (date != null) {
                String dateString = (String) DateUtils.getRelativeTimeSpanString(date.getTime());
                builder.append("<div id=\"datetime\">");
                builder.append(dateString);
                builder.append("</div>");
            }

            builder.append("</div>");

            builder.append("</div>");
        }

        String description = rssItem.getBody();
        builder.append("<div id=\"content\">");
        builder.append(getDescriptionWithCachedImages(description).trim());
        builder.append("</div>");

        builder.append("</body></html>");

        String htmlData = builder.toString().replaceAll("\"//", "\"https://");

        return htmlData;
    }

    private static String getDescriptionWithCachedImages(String text) {
        List<String> links = ImageHandler.getImageLinksFromText(text);
        DiskCache diskCache = ImageLoader.getInstance().getDiskCache();

        for (String link : links) {
            link = link.trim();
            try {
                File file = diskCache.get(link);
                if (file != null)
                    text = text.replace(link, "file://" + file.getAbsolutePath());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        return text;
    }

    static String getTextFromAssets(String fileName, Context context) {
        InputStream input;
        try {
            input = context.getAssets().open(fileName);
            int size = input.available();
            byte[] buffer = new byte[size];
            input.read(buffer);
            input.close();

            // byte buffer into a string
            return new String(buffer);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    private static String SearchString(String data, String startString, String endString) {
        int start = data.indexOf(startString) + startString.length();
        int end = data.indexOf(endString, start);
        if (start != (-1 + startString.length()) && end != -1)
            data = data.substring(start, end).trim();

        return data;
    }

    private static String convertHexColorFrom3To6Characters(String color) {
        for (int i = 1; i < 6; i += 2)
            color = color.substring(0, i) + color.charAt(i) + color.substring(i);

        return color;
    }
}