/* * Copyright (c) 2015, Nils Braden * * This file is part of ttrss-reader-fork. This program is free software; you * can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation; * either version 3 of the License, or (at your option) any later * version. * * This program 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 * General Public License for more details. You should have received a * copy of the GNU General Public License along with this program; If * not, see http://www.gnu.org/licenses/. */ package org.ttrssreader.gui.view; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Environment; import android.util.Log; import android.webkit.URLUtil; import android.webkit.WebResourceRequest; import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; import org.ttrssreader.MyApplication; import org.ttrssreader.R; import org.ttrssreader.controllers.Controller; import org.ttrssreader.gui.MediaPlayerActivity; import org.ttrssreader.utils.AsyncTask; import org.ttrssreader.utils.FileUtils; import org.ttrssreader.utils.Utils; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.lang.ref.WeakReference; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.Locale; public class ArticleWebViewClient extends WebViewClient { private static final String TAG = ArticleWebViewClient.class.getSimpleName(); /* * Uses old deprecated method call and should be removed some day but until then I won't duplicate the code */ @Override public boolean shouldOverrideUrlLoading(WebView view, final WebResourceRequest request) { return shouldOverrideUrlLoading(view, request.getUrl().toString()); } @Override public boolean shouldOverrideUrlLoading(WebView view, final String url) { final Context context = view.getContext(); boolean audio = false; boolean video = false; for (String s : FileUtils.AUDIO_EXTENSIONS) { if (url.toLowerCase(Locale.getDefault()).contains("." + s)) { audio = true; break; } } for (String s : FileUtils.VIDEO_EXTENSIONS) { if (url.toLowerCase(Locale.getDefault()).contains("." + s)) { video = true; break; } } final String contentType = audio ? "audio/*" : "video/*"; if (audio || video) { // @formatter:off final CharSequence[] items = { context.getText(R.string.WebViewClientActivity_Display), context.getText(R.string.WebViewClientActivity_Download), context.getText(R.string.WebViewClientActivity_ChooseApp)}; // @formatter:on AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle("What shall we do?"); builder.setItems(items, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int item) { switch (item) { case 0: Log.i(TAG, "Displaying file in mediaplayer: " + url); Intent i = new Intent(context, MediaPlayerActivity.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.putExtra(MediaPlayerActivity.URL, url); context.startActivity(i); break; case 1: try { new AsyncMediaDownloader(context) .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new URL(url)); } catch (MalformedURLException e) { e.printStackTrace(); } break; case 2: Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse(url), contentType); context.startActivity(intent); break; default: Log.e(TAG, "Doing nothing, but why is that?? Item: " + item); break; } } }); AlertDialog alert = builder.create(); alert.show(); } else { Uri uri = Uri.parse(url); try { Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } catch (Exception e) { e.printStackTrace(); } } return true; } private class AsyncMediaDownloader extends AsyncTask<URL, Void, Void> { private final static int BUFFER = (int) Utils.KB; private WeakReference<Context> contextRef; AsyncMediaDownloader(Context context) { this.contextRef = new WeakReference<>(context); } protected Void doInBackground(URL... urls) { if (urls.length < 1) { String msg = "No URL given, skipping download..."; Log.w(TAG, msg); Utils.showFinishedNotification(msg, 0, true, contextRef.get()); return null; } else if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { String msg = "External Storage not available, skipping download..."; Log.w(TAG, msg); Utils.showFinishedNotification(msg, 0, true, contextRef.get()); return null; } long start = System.currentTimeMillis(); Utils.showRunningNotification(contextRef.get(), false); // Use configured output directory File folder = new File(Controller.getInstance().saveAttachmentPath()); if (!folder.exists() && !folder.mkdirs()) { // Folder could not be created, fallback to internal directory on sdcard folder = MyApplication.context().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS); if (folder != null && !folder.exists() && !folder.mkdirs()) { String msg = "Folder could not be created: " + folder.getAbsolutePath(); Log.w(TAG, msg); Utils.showFinishedNotification(msg, 0, true, contextRef.get()); } } BufferedInputStream in; FileOutputStream fos; BufferedOutputStream bout = null; int size = -1; File file; try { URL url = urls[0]; URLConnection c; c = Controller.getInstance().openConnection(url); file = new File(folder, URLUtil.guessFileName(url.toString(), null, ".mp3")); if (file.exists()) { size = (int) file.length(); c.setRequestProperty("Range", "bytes=" + size + "-"); // try to resume downloads } in = new BufferedInputStream(c.getInputStream()); fos = (size == 0) ? new FileOutputStream(file) : new FileOutputStream(file, true); bout = new BufferedOutputStream(fos, BUFFER); byte[] data = new byte[BUFFER]; int count; while ((count = in.read(data, 0, BUFFER)) >= 0) { bout.write(data, 0, count); size += count; } int time = (int) ((System.currentTimeMillis() - start) / Utils.SECOND); // Show Intent which opens the file Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), FileUtils.getMimeType(file.getName())); Log.i(TAG, "Finished. Path: " + file.getAbsolutePath() + " Time: " + time + "s Bytes: " + size); Utils.showFinishedNotification(file.getAbsolutePath(), time, false, contextRef.get(), intent); } catch (IOException e) { String msg = "Error while downloading: " + e; Log.e(TAG, msg, e); Utils.showFinishedNotification(msg, 0, true, contextRef.get()); } finally { // Remove "running"-notification Utils.showRunningNotification(contextRef.get(), true); if (bout != null) { try { bout.close(); } catch (IOException e) { // Empty! } } } return null; } } /* * Uses old deprecated method call and should be removed some day but until then I won't duplicate the code */ @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { return shouldInterceptRequest(view, request.getUrl().toString()); } /* * WebKit does not call onReceivedHttpAuthRequest (or onReceivedError for that matter) when * processing resources within a rendered document. As a result, it is not possible to * inject authentication information without intercepting the resource loading itself. */ @Override public WebResourceResponse shouldInterceptRequest(WebView view, String urlStr) { if (!Controller.getInstance().useHttpAuth()) return null; try { URL url = new URL(urlStr); if (!Controller.getInstance().urlNeedsAuthentication(url)) return null; URLConnection c = Controller.getInstance().openConnection(url); return new WebResourceResponse(c.getContentType(), c.getContentEncoding(), c.getInputStream()); } catch (IOException e) { Log.e(TAG, "Failed to fetch " + urlStr); } return null; } }