summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/danoeh/antennapod
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod')
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java192
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java136
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/ShownotesWebView.java167
3 files changed, 206 insertions, 289 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index 85978b761..256615199 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -1,40 +1,18 @@
package de.danoeh.antennapod.fragment;
-import android.annotation.SuppressLint;
import android.app.Activity;
-import android.content.ClipData;
-import android.content.Context;
-import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
-import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.Toast;
-
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.MediaplayerInfoActivity;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
-import de.danoeh.antennapod.core.util.Converter;
-import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.NetworkUtils;
-import de.danoeh.antennapod.core.util.ShareUtils;
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.core.util.playback.Timeline;
+import de.danoeh.antennapod.view.ShownotesWebView;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -44,72 +22,29 @@ import io.reactivex.schedulers.Schedulers;
* Displays the description of a Playable object in a Webview.
*/
public class ItemDescriptionFragment extends Fragment {
-
private static final String TAG = "ItemDescriptionFragment";
private static final String PREF = "ItemDescriptionFragmentPrefs";
private static final String PREF_SCROLL_Y = "prefScrollY";
private static final String PREF_PLAYABLE_ID = "prefPlayableId";
- private WebView webvDescription;
+ private ShownotesWebView webvDescription;
private Disposable webViewLoader;
private PlaybackController controller;
- /**
- * URL that was selected via long-press.
- */
- private String selectedURL;
-
-
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "Creating view");
- webvDescription = new WebView(getActivity().getApplicationContext());
- webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-
- TypedArray ta = getActivity().getTheme().obtainStyledAttributes(new int[]
- {android.R.attr.colorBackground});
- boolean black = UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark
- || UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack;
- int backgroundColor = ta.getColor(0, black ? Color.BLACK : Color.WHITE);
-
- ta.recycle();
- webvDescription.setBackgroundColor(backgroundColor);
- if (!NetworkUtils.networkAvailable()) {
- webvDescription.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
- // Use cached resources, even if they have expired
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- webvDescription.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
- }
-
- webvDescription.getSettings().setUseWideViewPort(false);
- webvDescription.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
- webvDescription.getSettings().setLoadWithOverviewMode(true);
- webvDescription.setOnLongClickListener(webViewLongClickListener);
- webvDescription.setWebViewClient(new WebViewClient() {
-
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- if (Timeline.isTimecodeLink(url)) {
- onTimecodeLinkSelected(url);
- } else {
- IntentUtils.openInBrowser(getContext(), url);
- }
- return true;
+ webvDescription = new ShownotesWebView(getActivity().getApplicationContext());
+ webvDescription.setTimecodeSelectedListener(time -> {
+ if (controller != null) {
+ controller.seekTo(time);
}
-
- @Override
- public void onPageFinished(WebView view, String url) {
- super.onPageFinished(view, url);
- Log.d(TAG, "Page finished");
- // Restoring the scroll position might not always work
- view.postDelayed(ItemDescriptionFragment.this::restoreFromPreference, 50);
- }
-
});
-
+ webvDescription.setPageFinishedListener(() -> {
+ // Restoring the scroll position might not always work
+ webvDescription.postDelayed(ItemDescriptionFragment.this::restoreFromPreference, 50);
+ });
registerForContextMenu(webvDescription);
return webvDescription;
}
@@ -127,91 +62,14 @@ public class ItemDescriptionFragment extends Fragment {
}
}
- private final View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View v) {
- WebView.HitTestResult r = webvDescription.getHitTestResult();
- if (r != null
- && r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
- Log.d(TAG, "Link of webview was long-pressed. Extra: " + r.getExtra());
- selectedURL = r.getExtra();
- webvDescription.showContextMenu();
- return true;
- }
- selectedURL = null;
- return false;
- }
- };
-
- @SuppressLint("NewApi")
@Override
public boolean onContextItemSelected(MenuItem item) {
- boolean handled = selectedURL != null;
- if (selectedURL != null) {
- switch (item.getItemId()) {
- case R.id.open_in_browser_item:
- IntentUtils.openInBrowser(getContext(), selectedURL);
- break;
- case R.id.share_url_item:
- ShareUtils.shareLink(getActivity(), selectedURL);
- break;
- case R.id.copy_url_item:
- ClipData clipData = ClipData.newPlainText(selectedURL,
- selectedURL);
- android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setPrimaryClip(clipData);
- Toast t = Toast.makeText(getActivity(),
- R.string.copied_url_msg, Toast.LENGTH_SHORT);
- t.show();
- break;
- case R.id.go_to_position_item:
- if (Timeline.isTimecodeLink(selectedURL)) {
- onTimecodeLinkSelected(selectedURL);
- } else {
- Log.e(TAG, "Selected go_to_position_item, but URL was no timecode link: " + selectedURL);
- }
- break;
- default:
- handled = false;
- break;
-
- }
- selectedURL = null;
- }
- return handled;
-
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
- if (selectedURL != null) {
- super.onCreateContextMenu(menu, v, menuInfo);
- if (Timeline.isTimecodeLink(selectedURL)) {
- menu.add(Menu.NONE, R.id.go_to_position_item, Menu.NONE,
- R.string.go_to_position_label);
- menu.setHeaderTitle(Converter.getDurationStringLong(Timeline.getTimecodeLinkTime(selectedURL)));
- } else {
- Uri uri = Uri.parse(selectedURL);
- final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(getActivity(), intent)) {
- menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE,
- R.string.open_in_browser_label);
- }
- menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE,
- R.string.copy_url_label);
- menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE,
- R.string.share_url_label);
- menu.setHeaderTitle(selectedURL);
- }
- }
+ return webvDescription.onContextItemSelected(item);
}
private void load() {
Log.d(TAG, "load()");
- if(webViewLoader != null) {
+ if (webViewLoader != null) {
webViewLoader.dispose();
}
webViewLoader = Observable.fromCallable(this::loadData)
@@ -227,7 +85,7 @@ public class ItemDescriptionFragment extends Fragment {
@NonNull
private String loadData() {
Timeline timeline = new Timeline(getActivity(), controller.getMedia());
- return timeline.processShownotes(true);
+ return timeline.processShownotes();
}
@Override
@@ -238,8 +96,7 @@ public class ItemDescriptionFragment extends Fragment {
private void savePreference() {
Log.d(TAG, "Saving preferences");
- SharedPreferences prefs = getActivity().getSharedPreferences(PREF,
- Activity.MODE_PRIVATE);
+ SharedPreferences prefs = getActivity().getSharedPreferences(PREF, Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
if (controller != null && controller.getMedia() != null && webvDescription != null) {
Log.d(TAG, "Saving scroll position: " + webvDescription.getScrollY());
@@ -251,15 +108,14 @@ public class ItemDescriptionFragment extends Fragment {
editor.putInt(PREF_SCROLL_Y, -1);
editor.putString(PREF_PLAYABLE_ID, "");
}
- editor.commit();
+ editor.apply();
}
private boolean restoreFromPreference() {
Log.d(TAG, "Restoring from preferences");
Activity activity = getActivity();
if (activity != null) {
- SharedPreferences prefs = activity.getSharedPreferences(
- PREF, Activity.MODE_PRIVATE);
+ SharedPreferences prefs = activity.getSharedPreferences(PREF, Activity.MODE_PRIVATE);
String id = prefs.getString(PREF_PLAYABLE_ID, "");
int scrollY = prefs.getInt(PREF_SCROLL_Y, -1);
if (controller != null && scrollY != -1 && controller.getMedia() != null
@@ -274,16 +130,6 @@ public class ItemDescriptionFragment extends Fragment {
return false;
}
- private void onTimecodeLinkSelected(String link) {
- int time = Timeline.getTimecodeLinkTime(link);
- if (getActivity() != null && getActivity() instanceof MediaplayerInfoActivity) {
- PlaybackController pc = ((MediaplayerInfoActivity) getActivity()).getPlaybackController();
- if (pc != null) {
- pc.seekTo(time);
- }
- }
- }
-
@Override
public void onStart() {
super.onStart();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index 7a3d034f1..e1202704a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -1,9 +1,7 @@
package de.danoeh.antennapod.fragment;
-import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
-import android.content.res.TypedArray;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -11,31 +9,22 @@ import android.text.Layout;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
-import android.view.ContextMenu;
import android.view.LayoutInflater;
-import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
-import android.widget.Toast;
import androidx.annotation.AttrRes;
-import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
-import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
-import com.joanzapata.iconify.Iconify;
-import com.joanzapata.iconify.widget.IconButton;
+import com.google.android.material.snackbar.Snackbar;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.actionbutton.ItemActionButton;
@@ -47,7 +36,6 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.util.ImageResourceUtils;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.Downloader;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
@@ -55,10 +43,9 @@ import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.DownloadRequester;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.DateUtils;
-import de.danoeh.antennapod.core.util.IntentUtils;
-import de.danoeh.antennapod.core.util.NetworkUtils;
-import de.danoeh.antennapod.core.util.ShareUtils;
+import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.core.util.playback.Timeline;
+import de.danoeh.antennapod.view.ShownotesWebView;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
@@ -99,7 +86,7 @@ public class ItemFragment extends Fragment {
private List<Downloader> downloaderList;
private ViewGroup root;
- private WebView webvDescription;
+ private ShownotesWebView webvDescription;
private TextView txtvPodcast;
private TextView txtvTitle;
private TextView txtvDuration;
@@ -111,11 +98,7 @@ public class ItemFragment extends Fragment {
private Button butAction2;
private Disposable disposable;
-
- /**
- * URL that was selected via long-press.
- */
- private String selectedURL;
+ private PlaybackController controller;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -134,7 +117,7 @@ public class ItemFragment extends Fragment {
txtvPodcast = layout.findViewById(R.id.txtvPodcast);
txtvPodcast.setOnClickListener(v -> openPodcast());
txtvTitle = layout.findViewById(R.id.txtvTitle);
- if(Build.VERSION.SDK_INT >= 23) {
+ if (Build.VERSION.SDK_INT >= 23) {
txtvTitle.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
}
txtvDuration = layout.findViewById(R.id.txtvDuration);
@@ -143,31 +126,11 @@ public class ItemFragment extends Fragment {
txtvTitle.setEllipsize(TextUtils.TruncateAt.END);
}
webvDescription = layout.findViewById(R.id.webvDescription);
- if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark ||
- UserPreferences.getTheme() == R.style.Theme_AntennaPod_TrueBlack) {
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
- webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- }
- webvDescription.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.black));
- }
- if (!NetworkUtils.networkAvailable()) {
- webvDescription.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
- // Use cached resources, even if they have expired
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- webvDescription.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
- }
- webvDescription.getSettings().setUseWideViewPort(false);
- webvDescription.getSettings().setLayoutAlgorithm(
- WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
- webvDescription.getSettings().setLoadWithOverviewMode(true);
- webvDescription.setOnLongClickListener(webViewLongClickListener);
-
- webvDescription.setWebViewClient(new WebViewClient() {
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- IntentUtils.openInBrowser(getContext(), url);
- return true;
+ webvDescription.setTimecodeSelectedListener(time -> {
+ if (controller != null && item.getMedia().getIdentifier().equals(controller.getMedia().getIdentifier())) {
+ controller.seekTo(time);
+ } else {
+ Snackbar.make(getView(), R.string.play_this_to_seek_position, Snackbar.LENGTH_LONG).show();
}
});
registerForContextMenu(webvDescription);
@@ -230,6 +193,8 @@ public class ItemFragment extends Fragment {
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
+ controller = new PlaybackController(getActivity(), false);
+ controller.init();
}
@Override
@@ -245,12 +210,13 @@ public class ItemFragment extends Fragment {
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
+ controller.release();
}
@Override
public void onDestroyView() {
super.onDestroyView();
- if(disposable != null) {
+ if (disposable != null) {
disposable.dispose();
}
if (webvDescription != null && root != null) {
@@ -364,76 +330,14 @@ public class ItemFragment extends Fragment {
}
}
- private final View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
-
- @Override
- public boolean onLongClick(View v) {
- WebView.HitTestResult r = webvDescription.getHitTestResult();
- if (r != null
- && r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
- Log.d(TAG, "Link of webview was long-pressed. Extra: " + r.getExtra());
- selectedURL = r.getExtra();
- webvDescription.showContextMenu();
- return true;
- }
- selectedURL = null;
- return false;
- }
- };
-
@Override
public boolean onContextItemSelected(MenuItem item) {
- boolean handled = selectedURL != null;
- if (selectedURL != null) {
- switch (item.getItemId()) {
- case R.id.open_in_browser_item:
- IntentUtils.openInBrowser(getContext(), selectedURL);
- break;
- case R.id.share_url_item:
- ShareUtils.shareLink(getActivity(), selectedURL);
- break;
- case R.id.copy_url_item:
- ClipData clipData = ClipData.newPlainText(selectedURL,
- selectedURL);
- android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
- .getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setPrimaryClip(clipData);
- Toast t = Toast.makeText(getActivity(),
- R.string.copied_url_msg, Toast.LENGTH_SHORT);
- t.show();
- break;
- default:
- handled = false;
- break;
-
- }
- selectedURL = null;
- }
- return handled;
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenu.ContextMenuInfo menuInfo) {
- if (selectedURL != null) {
- super.onCreateContextMenu(menu, v, menuInfo);
- Uri uri = Uri.parse(selectedURL);
- final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- if(IntentUtils.isCallable(getActivity(), intent)) {
- menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE,
- R.string.open_in_browser_label);
- }
- menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE,
- R.string.copy_url_label);
- menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE,
- R.string.share_url_label);
- menu.setHeaderTitle(selectedURL);
- }
+ return webvDescription.onContextItemSelected(item);
}
private void openPodcast() {
Fragment fragment = FeedItemlistFragment.newInstance(item.getFeedId());
- ((MainActivity)getActivity()).loadChildFragment(fragment);
+ ((MainActivity) getActivity()).loadChildFragment(fragment);
}
@Subscribe(threadMode = ThreadMode.MAIN)
@@ -452,11 +356,11 @@ public class ItemFragment extends Fragment {
Log.d(TAG, "onEventMainThread() called with: " + "event = [" + event + "]");
DownloaderUpdate update = event.update;
downloaderList = update.downloaders;
- if(item == null || item.getMedia() == null) {
+ if (item == null || item.getMedia() == null) {
return;
}
long mediaId = item.getMedia().getId();
- if(ArrayUtils.contains(update.mediaIds, mediaId)) {
+ if (ArrayUtils.contains(update.mediaIds, mediaId)) {
if (itemsLoaded && getActivity() != null) {
updateAppearance();
}
@@ -490,7 +394,7 @@ public class ItemFragment extends Fragment {
Context context = getContext();
if (feedItem != null && context != null) {
Timeline t = new Timeline(context, feedItem);
- webviewData = t.processShownotes(false);
+ webviewData = t.processShownotes();
}
return feedItem;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/view/ShownotesWebView.java b/app/src/main/java/de/danoeh/antennapod/view/ShownotesWebView.java
new file mode 100644
index 000000000..3ea57eb5e
--- /dev/null
+++ b/app/src/main/java/de/danoeh/antennapod/view/ShownotesWebView.java
@@ -0,0 +1,167 @@
+package de.danoeh.antennapod.view;
+
+import android.content.ClipData;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import androidx.core.content.ContextCompat;
+import com.google.android.material.snackbar.Snackbar;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.util.Consumer;
+import de.danoeh.antennapod.core.util.Converter;
+import de.danoeh.antennapod.core.util.IntentUtils;
+import de.danoeh.antennapod.core.util.NetworkUtils;
+import de.danoeh.antennapod.core.util.ShareUtils;
+import de.danoeh.antennapod.core.util.playback.Timeline;
+
+public class ShownotesWebView extends WebView implements View.OnLongClickListener {
+ private static final String TAG = "ShownotesWebView";
+
+ /**
+ * URL that was selected via long-press.
+ */
+ private String selectedUrl;
+ private Consumer<Integer> timecodeSelectedListener;
+ private Runnable pageFinishedListener;
+
+ public ShownotesWebView(Context context) {
+ super(context);
+ setup();
+ }
+
+ public ShownotesWebView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setup();
+ }
+
+ public ShownotesWebView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setup();
+ }
+
+ private void setup() {
+ setBackgroundColor(Color.TRANSPARENT);
+ if (!NetworkUtils.networkAvailable()) {
+ getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
+ // Use cached resources, even if they have expired
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
+ }
+ getSettings().setUseWideViewPort(false);
+ getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
+ getSettings().setLoadWithOverviewMode(true);
+ setOnLongClickListener(this);
+
+ setWebViewClient(new WebViewClient() {
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ if (Timeline.isTimecodeLink(url) && timecodeSelectedListener != null) {
+ timecodeSelectedListener.accept(Timeline.getTimecodeLinkTime(selectedUrl));
+ } else {
+ IntentUtils.openInBrowser(getContext(), url);
+ }
+ return true;
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ Log.d(TAG, "Page finished");
+ if (pageFinishedListener != null) {
+ pageFinishedListener.run();
+ }
+ }
+ });
+ }
+
+ @Override
+ public boolean onLongClick(View v) {
+ WebView.HitTestResult r = getHitTestResult();
+ if (r != null && r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
+ Log.d(TAG, "Link of webview was long-pressed. Extra: " + r.getExtra());
+ selectedUrl = r.getExtra();
+ showContextMenu();
+ return true;
+ }
+ selectedUrl = null;
+ return false;
+ }
+
+ public boolean onContextItemSelected(MenuItem item) {
+ if (selectedUrl == null) {
+ return false;
+ }
+
+ switch (item.getItemId()) {
+ case R.id.open_in_browser_item:
+ IntentUtils.openInBrowser(getContext(), selectedUrl);
+ break;
+ case R.id.share_url_item:
+ ShareUtils.shareLink(getContext(), selectedUrl);
+ break;
+ case R.id.copy_url_item:
+ ClipData clipData = ClipData.newPlainText(selectedUrl, selectedUrl);
+ android.content.ClipboardManager cm = (android.content.ClipboardManager) getContext()
+ .getSystemService(Context.CLIPBOARD_SERVICE);
+ cm.setPrimaryClip(clipData);
+ Snackbar.make(this, R.string.copied_url_msg, Snackbar.LENGTH_LONG).show();
+ break;
+ case R.id.go_to_position_item:
+ if (Timeline.isTimecodeLink(selectedUrl) && timecodeSelectedListener != null) {
+ timecodeSelectedListener.accept(Timeline.getTimecodeLinkTime(selectedUrl));
+ } else {
+ Log.e(TAG, "Selected go_to_position_item, but URL was no timecode link: " + selectedUrl);
+ }
+ break;
+ default:
+ selectedUrl = null;
+ return false;
+
+ }
+ selectedUrl = null;
+ return true;
+ }
+
+ @Override
+ protected void onCreateContextMenu(ContextMenu menu) {
+ super.onCreateContextMenu(menu);
+ if (selectedUrl == null) {
+ return;
+ }
+
+ if (Timeline.isTimecodeLink(selectedUrl)) {
+ menu.add(Menu.NONE, R.id.go_to_position_item, Menu.NONE, R.string.go_to_position_label);
+ menu.setHeaderTitle(Converter.getDurationStringLong(Timeline.getTimecodeLinkTime(selectedUrl)));
+ } else {
+ Uri uri = Uri.parse(selectedUrl);
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ if (IntentUtils.isCallable(getContext(), intent)) {
+ menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE, R.string.open_in_browser_label);
+ }
+ menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE, R.string.copy_url_label);
+ menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE, R.string.share_url_label);
+ menu.setHeaderTitle(selectedUrl);
+ }
+ }
+
+ public void setTimecodeSelectedListener(Consumer<Integer> timecodeSelectedListener) {
+ this.timecodeSelectedListener = timecodeSelectedListener;
+ }
+
+ public void setPageFinishedListener(Runnable pageFinishedListener) {
+ this.pageFinishedListener = pageFinishedListener;
+ }
+}