From a57fd69fb4787d08982c6cfb0d867f365588d6dc Mon Sep 17 00:00:00 2001 From: TiA4f8R <74829229+TiA4f8R@users.noreply.github.com> Date: Tue, 15 Dec 2020 20:11:55 +0100 Subject: [PATCH] External sharing improvements Improve NewPipe's share on some devices + fix crash when no browser is set on some devices Catching ActivityNotFoundException when trying to open the default browser Use an ACTION_CHOOSER intent and put as an extra intent the intent to open an URI / share an URI when no default app is set. Add a LinkHelper class which set a custom action when clicking web links in the description of a content. This class also helps to implement a confirmation dialog when trying to open web links in an external app. --- .../schabi/newpipe/about/AboutActivity.java | 12 +- .../fragments/detail/VideoDetailFragment.java | 28 +--- .../list/channel/ChannelFragment.java | 5 +- .../schabi/newpipe/report/ErrorActivity.java | 14 +- .../util/CommentTextOnTouchListener.java | 3 +- .../schabi/newpipe/util/ExtractorHelper.java | 4 +- .../org/schabi/newpipe/util/LinkHelper.java | 116 +++++++++++++++ .../schabi/newpipe/util/NavigationHelper.java | 27 +--- .../org/schabi/newpipe/util/ShareUtils.java | 138 ++++++++++++++---- .../giga/ui/adapter/MissionAdapter.java | 30 ++-- app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + checkstyle-suppressions.xml | 17 +-- 13 files changed, 285 insertions(+), 111 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/util/LinkHelper.java diff --git a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java index 2569f4a94..d11978c6b 100644 --- a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java +++ b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java @@ -146,16 +146,20 @@ public class AboutActivity extends AppCompatActivity { aboutBinding.appVersion.setText(BuildConfig.VERSION_NAME); aboutBinding.githubLink.setOnClickListener(nv -> - openUrlInBrowser(context, context.getString(R.string.github_url))); + openUrlInBrowser(context, context.getString(R.string.github_url), + false)); aboutBinding.donationLink.setOnClickListener(v -> - openUrlInBrowser(context, context.getString(R.string.donation_url))); + openUrlInBrowser(context, context.getString(R.string.donation_url), + false)); aboutBinding.websiteLink.setOnClickListener(nv -> - openUrlInBrowser(context, context.getString(R.string.website_url))); + openUrlInBrowser(context, context.getString(R.string.website_url), + false)); aboutBinding.privacyPolicyLink.setOnClickListener(v -> - openUrlInBrowser(context, context.getString(R.string.privacy_policy_url))); + openUrlInBrowser(context, context.getString(R.string.privacy_policy_url), + false)); return aboutBinding.getRoot(); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 8c9ed2bef..c9913a808 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -16,7 +16,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.provider.Settings; -import android.text.util.Linkify; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; @@ -96,6 +95,7 @@ import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.DeviceUtils; import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ImageDisplayConstants; +import org.schabi.newpipe.util.LinkHelper; import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; @@ -112,10 +112,7 @@ import java.util.Objects; import java.util.concurrent.TimeUnit; import icepick.State; -import io.noties.markwon.Markwon; -import io.noties.markwon.linkify.LinkifyPlugin; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; -import io.reactivex.rxjava3.core.Single; import io.reactivex.rxjava3.disposables.CompositeDisposable; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.schedulers.Schedulers; @@ -1233,26 +1230,17 @@ public final class VideoDetailFragment } if (description.getType() == Description.HTML) { - disposables.add(Single.just(description.getContent()) - .map(descriptionText -> - HtmlCompat.fromHtml(descriptionText, - HtmlCompat.FROM_HTML_MODE_LEGACY)) - .subscribeOn(Schedulers.computation()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(spanned -> { - videoDescriptionView.setText(spanned); - videoDescriptionView.setVisibility(View.VISIBLE); - })); + LinkHelper.createLinksFromHtmlBlock(requireContext(), description.getContent(), + videoDescriptionView, HtmlCompat.FROM_HTML_MODE_LEGACY); + videoDescriptionView.setVisibility(View.VISIBLE); } else if (description.getType() == Description.MARKDOWN) { - final Markwon markwon = Markwon.builder(requireContext()) - .usePlugin(LinkifyPlugin.create()) - .build(); - markwon.setMarkdown(videoDescriptionView, description.getContent()); + LinkHelper.createLinksFromMarkdownText(requireContext(), description.getContent(), + videoDescriptionView); videoDescriptionView.setVisibility(View.VISIBLE); } else { //== Description.PLAIN_TEXT - videoDescriptionView.setAutoLinkMask(Linkify.WEB_URLS); - videoDescriptionView.setText(description.getContent(), TextView.BufferType.SPANNABLE); + LinkHelper.createLinksFromPlainText(requireContext(), description.getContent(), + videoDescriptionView); videoDescriptionView.setVisibility(View.VISIBLE); } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 834d8052f..6bcaac630 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -1,8 +1,6 @@ package org.schabi.newpipe.fragments.list.channel; import android.content.Context; -import android.content.Intent; -import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; @@ -188,8 +186,7 @@ public class ChannelFragment extends BaseListInfoFragment private void openRssFeed() { final ChannelInfo info = currentInfo; if (info != null) { - final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(info.getFeedUrl())); - startActivity(intent); + ShareUtils.openUrlInBrowser(requireContext(), info.getFeedUrl(), false); } } diff --git a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java index a4b6af2ab..0321d197a 100644 --- a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java @@ -14,7 +14,6 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; @@ -207,8 +206,7 @@ public class ErrorActivity extends AppCompatActivity { openPrivacyPolicyDialog(this, "EMAIL")); activityErrorBinding.errorReportCopyButton.setOnClickListener(v -> { - ShareUtils.copyToClipboard(this, buildMarkdown()); - Toast.makeText(this, R.string.msg_copied, Toast.LENGTH_SHORT).show(); + ShareUtils.copyToClipboard(this, buildMarkdown()); }); activityErrorBinding.errorReportGitHubButton.setOnClickListener(v -> @@ -246,11 +244,7 @@ public class ErrorActivity extends AppCompatActivity { goToReturnActivity(); break; case R.id.menu_item_share_error: - final Intent intent = new Intent(); - intent.setAction(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_TEXT, buildJson()); - intent.setType("text/plain"); - startActivity(Intent.createChooser(intent, getString(R.string.share_dialog_title))); + ShareUtils.shareUrl(this, getString(R.string.error_report_title), buildJson()); break; } return false; @@ -273,10 +267,10 @@ public class ErrorActivity extends AppCompatActivity { .putExtra(Intent.EXTRA_SUBJECT, ERROR_EMAIL_SUBJECT) .putExtra(Intent.EXTRA_TEXT, buildJson()); if (i.resolveActivity(getPackageManager()) != null) { - startActivity(i); + ShareUtils.openContentInApp(context, i); } } else if (action.equals("GITHUB")) { // open the NewPipe issue page on GitHub - ShareUtils.openUrlInBrowser(this, ERROR_GITHUB_ISSUE_URL); + ShareUtils.openUrlInBrowser(this, ERROR_GITHUB_ISSUE_URL, false); } }) diff --git a/app/src/main/java/org/schabi/newpipe/util/CommentTextOnTouchListener.java b/app/src/main/java/org/schabi/newpipe/util/CommentTextOnTouchListener.java index 36f39a6e5..5c7eb4c3f 100644 --- a/app/src/main/java/org/schabi/newpipe/util/CommentTextOnTouchListener.java +++ b/app/src/main/java/org/schabi/newpipe/util/CommentTextOnTouchListener.java @@ -69,7 +69,8 @@ public class CommentTextOnTouchListener implements View.OnTouchListener { handled = handleUrl(v.getContext(), (URLSpan) link[0]); } if (!handled) { - link[0].onClick(widget); + ShareUtils.openUrlInBrowser(v.getContext(), + ((URLSpan) link[0]).getURL(), false); } } else if (action == MotionEvent.ACTION_DOWN) { Selection.setSelection(buffer, diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java index 103d9a72b..7046b8e49 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java @@ -365,8 +365,8 @@ public final class ExtractorHelper { } } - metaInfoTextView.setText(HtmlCompat.fromHtml(stringBuilder.toString(), - HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING)); + LinkHelper.createLinksFromHtmlBlock(context, stringBuilder.toString(), + metaInfoTextView, HtmlCompat.FROM_HTML_SEPARATOR_LINE_BREAK_HEADING); metaInfoTextView.setMovementMethod(LinkMovementMethod.getInstance()); metaInfoTextView.setVisibility(View.VISIBLE); metaInfoSeparator.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/org/schabi/newpipe/util/LinkHelper.java b/app/src/main/java/org/schabi/newpipe/util/LinkHelper.java new file mode 100644 index 000000000..fba30758f --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/util/LinkHelper.java @@ -0,0 +1,116 @@ +package org.schabi.newpipe.util; + +import android.content.Context; +import android.text.SpannableStringBuilder; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.text.style.URLSpan; +import android.text.util.Linkify; +import android.view.View; +import android.widget.TextView; + +import androidx.core.text.HtmlCompat; + +import io.noties.markwon.Markwon; +import io.noties.markwon.linkify.LinkifyPlugin; + +public final class LinkHelper { + private LinkHelper() { + } + + /** + * Create web links for contents with an HTML description. + *

+ * This will call + * {@link LinkHelper#changeIntentsOfDescriptionLinks(Context, CharSequence, TextView)} + * after linked the URLs with {@link HtmlCompat#fromHtml(String, int)}. + * + * @param context the context to use + * @param htmlBlock the htmlBlock to be linked + * @param textView the TextView to set the htmlBlock linked + * @param htmlCompatFlag the int flag to be set when {@link HtmlCompat#fromHtml(String, int)} + * will be called + */ + public static void createLinksFromHtmlBlock(final Context context, + final String htmlBlock, + final TextView textView, + final int htmlCompatFlag) { + changeIntentsOfDescriptionLinks(context, HtmlCompat.fromHtml(htmlBlock, htmlCompatFlag), + textView); + } + + /** + * Create web links for contents with a plain text description. + *

+ * This will call + * {@link LinkHelper#changeIntentsOfDescriptionLinks(Context, CharSequence, TextView)} + * after linked the URLs with {@link TextView#setAutoLinkMask(int)} and + * {@link TextView#setText(CharSequence, TextView.BufferType)}. + * + * @param context the context to use + * @param plainTextBlock the block of plain text to be linked + * @param textView the TextView to set the plain text block linked + */ + public static void createLinksFromPlainText(final Context context, + final String plainTextBlock, + final TextView textView) { + textView.setAutoLinkMask(Linkify.WEB_URLS); + textView.setText(plainTextBlock, TextView.BufferType.SPANNABLE); + changeIntentsOfDescriptionLinks(context, textView.getText(), textView); + } + + /** + * Create web links for contents with a markdown description. + *

+ * This will call + * {@link LinkHelper#changeIntentsOfDescriptionLinks(Context, CharSequence, TextView)} + * after creating an {@link Markwon} object and using + * {@link Markwon#setMarkdown(TextView, String)}. + * + * @param context the context to use + * @param markdownBlock the block of markdown text to be linked + * @param textView the TextView to set the plain text block linked + */ + public static void createLinksFromMarkdownText(final Context context, + final String markdownBlock, + final TextView textView) { + final Markwon markwon = Markwon.builder(context).usePlugin(LinkifyPlugin.create()).build(); + markwon.setMarkdown(textView, markdownBlock); + changeIntentsOfDescriptionLinks(context, textView.getText(), textView); + } + + /** + * Change links generated by libraries in the description of a content to a custom link action. + *

+ * Instead of using an ACTION_VIEW intent in the description of a content, this method will + * parse the CharSequence and replace all current web links with + * {@link ShareUtils#openUrlInBrowser(Context, String, Boolean)}. + *

+ * This method is required in order to intercept links and maybe, show a confirmation dialog + * before opening a web link. + * + * @param context the context to use + * @param chars the CharSequence to be parsed + * @param textView the TextView in which the converted CharSequence will be applied + */ + private static void changeIntentsOfDescriptionLinks(final Context context, + final CharSequence chars, + final TextView textView) { + final SpannableStringBuilder textBlockLinked = new SpannableStringBuilder(chars); + final URLSpan[] urls = textBlockLinked.getSpans(0, chars.length(), URLSpan.class); + + for (final URLSpan span : urls) { + final ClickableSpan clickableSpan = new ClickableSpan() { + public void onClick(final View view) { + ShareUtils.openUrlInBrowser(context, span.getURL(), false); + } + }; + textBlockLinked.setSpan(clickableSpan, textBlockLinked.getSpanStart(span), + textBlockLinked.getSpanEnd(span), textBlockLinked.getSpanFlags(span)); + textBlockLinked.removeSpan(span); + } + + textView.setText(textBlockLinked); + textView.setMovementMethod(LinkMovementMethod.getInstance()); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index c90bb3025..936b4595c 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -246,16 +246,14 @@ public final class NavigationHelper { public static void resolveActivityOrAskToInstall(final Context context, final Intent intent) { if (intent.resolveActivity(context.getPackageManager()) != null) { - context.startActivity(intent); + ShareUtils.openContentInApp(context, intent); } else { if (context instanceof Activity) { new AlertDialog.Builder(context) .setMessage(R.string.no_player_found) .setPositiveButton(R.string.install, (dialog, which) -> { - final Intent i = new Intent(); - i.setAction(Intent.ACTION_VIEW); - i.setData(Uri.parse(context.getString(R.string.fdroid_vlc_url))); - context.startActivity(i); + ShareUtils.openUrlInBrowser(context, + context.getString(R.string.fdroid_vlc_url), false); }) .setNegativeButton(R.string.cancel, (dialog, which) -> Log.i("NavigationHelper", "You unlocked a secret unicorn.")) @@ -568,27 +566,14 @@ public final class NavigationHelper { return getOpenIntent(context, url, service.getServiceId(), linkType); } - private static Uri openMarketUrl(final String packageName) { - return Uri.parse("market://details") - .buildUpon() - .appendQueryParameter("id", packageName) - .build(); - } - - private static Uri getGooglePlayUrl(final String packageName) { - return Uri.parse("https://play.google.com/store/apps/details") - .buildUpon() - .appendQueryParameter("id", packageName) - .build(); - } - private static void installApp(final Context context, final String packageName) { try { // Try market:// scheme - context.startActivity(new Intent(Intent.ACTION_VIEW, openMarketUrl(packageName))); + ShareUtils.openUrlInBrowser(context, "market://details?id=" + packageName, false); } catch (final ActivityNotFoundException e) { // Fall back to google play URL (don't worry F-Droid can handle it :) - context.startActivity(new Intent(Intent.ACTION_VIEW, getGooglePlayUrl(packageName))); + ShareUtils.openUrlInBrowser(context, + "https://play.google.com/store/apps/details?id=" + packageName, false); } } diff --git a/app/src/main/java/org/schabi/newpipe/util/ShareUtils.java b/app/src/main/java/org/schabi/newpipe/util/ShareUtils.java index b631f19da..142b2b20c 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ShareUtils.java +++ b/app/src/main/java/org/schabi/newpipe/util/ShareUtils.java @@ -1,5 +1,6 @@ package org.schabi.newpipe.util; +import android.content.ActivityNotFoundException; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -21,22 +22,80 @@ public final class ShareUtils { * Open the url with the system default browser. *

* If no browser is set as default, fallbacks to - * {@link ShareUtils#openInDefaultApp(Context, String)} + * {@link ShareUtils#openInDefaultApp(Context, Intent)} + * + * @param context the context to use + * @param url the url to browse + * @param httpDefaultBrowserTest the boolean to set if the + * test for the default browser will be for HTTP protocol + * or for the created intent + */ + public static void openUrlInBrowser(final Context context, final String url, + final Boolean httpDefaultBrowserTest) { + final String defaultPackageName; + final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (httpDefaultBrowserTest) { + defaultPackageName = getDefaultBrowserPackageName(context); + } else { + defaultPackageName = getDefaultAppPackageName(context, intent); + } + + if (defaultPackageName.equals("android")) { + // no browser set as default (doesn't work on some devices) + openInDefaultApp(context, intent); + } else { + try { + intent.setPackage(defaultPackageName); + context.startActivity(intent); + } catch (final ActivityNotFoundException e) { + // not a browser but an app chooser because of OEMs changes + intent.setPackage(null); + openInDefaultApp(context, intent); + } + } + } + + /** + * Open the url with the system default browser. + *

+ * If no browser is set as default, fallbacks to + * {@link ShareUtils#openInDefaultApp(Context, Intent)} + *

+ * This call {@link ShareUtils#openUrlInBrowser(Context, String, Boolean)} with true + * for the boolean parameter * * @param context the context to use * @param url the url to browse - */ + **/ public static void openUrlInBrowser(final Context context, final String url) { - final String defaultBrowserPackageName = getDefaultBrowserPackageName(context); + openUrlInBrowser(context, url, true); + } - if (defaultBrowserPackageName.equals("android")) { - // no browser set as default - openInDefaultApp(context, url); + /** + * Open a content with the system default browser. + *

+ * If no app is set as default, fallbacks to + * {@link ShareUtils#openInDefaultApp(Context, Intent)} + * + * @param context the context to use + * @param intent the intent of the file to open + */ + public static void openContentInApp(final Context context, final Intent intent) { + final String defaultAppPackageName = getDefaultAppPackageName(context, intent); + + if (defaultAppPackageName.equals("android")) { + // no app set as default (doesn't work on some devices) + openInDefaultApp(context, intent); } else { - final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)) - .setPackage(defaultBrowserPackageName) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + try { + intent.setPackage(defaultAppPackageName); + context.startActivity(intent); + } catch (final ActivityNotFoundException e) { + // not an app to open a file but an app chooser because of OEMs changes + intent.setPackage(null); + openInDefaultApp(context, intent); + } } } @@ -45,20 +104,38 @@ public final class ShareUtils { *

* If no app is set as default, it will open a chooser * - * @param context the context to use - * @param url the url to browse + * @param context the context to use + * @param viewIntent the intent to open */ - private static void openInDefaultApp(final Context context, final String url) { - final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - context.startActivity(Intent.createChooser( - intent, context.getString(R.string.share_dialog_title)) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + private static void openInDefaultApp(final Context context, final Intent viewIntent) { + final Intent intent = new Intent(Intent.ACTION_CHOOSER); + intent.putExtra(Intent.EXTRA_INTENT, viewIntent); + intent.putExtra(Intent.EXTRA_TITLE, context.getString(R.string.open_with)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } + + /** + * Get the default app package name. + *

+ * If no app is set as default, it will return "android". + *

+ * Note: it doesn't return "android" on some devices because some OEMs changed the app chooser. + * + * @param context the context to use + * @param intent the intent to get default app + * @return the package name of the default app, or the app chooser if there's no default + */ + private static String getDefaultAppPackageName(final Context context, final Intent intent) { + return context.getPackageManager().resolveActivity(intent, + PackageManager.MATCH_DEFAULT_ONLY).activityInfo.packageName; } /** * Get the default browser package name. *

* If no browser is set as default, it will return "android" + * Note: it doesn't return "android" on some devices because some OEMs changed the app chooser. * * @param context the context to use * @return the package name of the default browser, or "android" if there's no default @@ -66,8 +143,8 @@ public final class ShareUtils { private static String getDefaultBrowserPackageName(final Context context) { final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://")) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - final ResolveInfo resolveInfo = context.getPackageManager().resolveActivity( - intent, PackageManager.MATCH_DEFAULT_ONLY); + final ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, + PackageManager.MATCH_DEFAULT_ONLY); return resolveInfo.activityInfo.packageName; } @@ -79,13 +156,15 @@ public final class ShareUtils { * @param url the url to share */ public static void shareUrl(final Context context, final String subject, final String url) { - final Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("text/plain"); - intent.putExtra(Intent.EXTRA_SUBJECT, subject); - intent.putExtra(Intent.EXTRA_TEXT, url); - context.startActivity(Intent.createChooser( - intent, context.getString(R.string.share_dialog_title)) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + final Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject); + shareIntent.putExtra(Intent.EXTRA_TEXT, url); + final Intent intent = new Intent(Intent.ACTION_CHOOSER); + intent.putExtra(Intent.EXTRA_INTENT, shareIntent); + intent.putExtra(Intent.EXTRA_TITLE, context.getString(R.string.share_dialog_title)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); } /** @@ -100,14 +179,11 @@ public final class ShareUtils { ContextCompat.getSystemService(context, ClipboardManager.class); if (clipboardManager == null) { - Toast.makeText(context, - R.string.permission_denied, - Toast.LENGTH_LONG).show(); + Toast.makeText(context, R.string.permission_denied, Toast.LENGTH_LONG).show(); return; } clipboardManager.setPrimaryClip(ClipData.newPlainText(null, text)); - Toast.makeText(context, R.string.msg_copied, Toast.LENGTH_SHORT) - .show(); + Toast.makeText(context, R.string.msg_copied, Toast.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java index f102206c1..79b91cb57 100644 --- a/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java +++ b/app/src/main/java/us/shandian/giga/ui/adapter/MissionAdapter.java @@ -2,6 +2,7 @@ package us.shandian.giga.ui.adapter; import android.annotation.SuppressLint; import android.app.NotificationManager; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.graphics.Color; @@ -44,6 +45,7 @@ import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorInfo; import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.util.NavigationHelper; +import org.schabi.newpipe.util.ShareUtils; import java.io.File; import java.net.URI; @@ -346,10 +348,9 @@ public class MissionAdapter extends Adapter implements Handler.Callb if (BuildConfig.DEBUG) Log.v(TAG, "Mime: " + mimeType + " package: " + BuildConfig.APPLICATION_ID + ".provider"); - Uri uri = resolveShareableUri(mission); + final Uri uri = resolveShareableUri(mission); - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_VIEW); + Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(uri, mimeType); intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION); @@ -363,7 +364,7 @@ public class MissionAdapter extends Adapter implements Handler.Callb //mContext.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); if (intent.resolveActivity(mContext.getPackageManager()) != null) { - mContext.startActivity(intent); + ShareUtils.openContentInApp(mContext, intent); } else { Toast.makeText(mContext, R.string.toast_no_player, Toast.LENGTH_LONG).show(); } @@ -372,12 +373,23 @@ public class MissionAdapter extends Adapter implements Handler.Callb private void shareFile(Mission mission) { if (checkInvalidFile(mission)) return; - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType(resolveMimeType(mission)); - intent.putExtra(Intent.EXTRA_STREAM, resolveShareableUri(mission)); - intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION); + final Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType(resolveMimeType(mission)); + shareIntent.putExtra(Intent.EXTRA_STREAM, resolveShareableUri(mission)); + shareIntent.addFlags(FLAG_GRANT_READ_URI_PERMISSION); + final Intent intent = new Intent(Intent.ACTION_CHOOSER); + intent.putExtra(Intent.EXTRA_INTENT, shareIntent); + intent.putExtra(Intent.EXTRA_TITLE, mContext.getString(R.string.share_dialog_title)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - mContext.startActivity(Intent.createChooser(intent, null)); + try { + intent.setPackage("android"); + mContext.startActivity(intent); + } catch (final ActivityNotFoundException e) { + // falling back to OEM chooser if Android's system chooser was removed by the OEM + intent.setPackage(null); + mContext.startActivity(intent); + } } /** diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c128c4214..a6b64da71 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -651,4 +651,5 @@ Demander à Android de personnaliser la couleur de la notification en fonction de la couleur principale de la miniature (noter que cela n’est pas disponible sur tous les appareils) Afficher la miniature Utiliser la miniature pour l\'arrière-plan de l’écran de verrouillage et les notifications + Ouvrir avec \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8ac951b69..82a5bda6c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -11,6 +11,7 @@ https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc Open in browser Open in popup mode + Open with Share Download Download stream file diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml index 400a91a29..0aca3c4ab 100644 --- a/checkstyle-suppressions.xml +++ b/checkstyle-suppressions.xml @@ -12,21 +12,20 @@ lines="253,325"/> + files="ListHelper.java" + lines="281,313"/> + files="ContentSettingsFragment.java" + lines="227,245"/> - + files="WebMWriter.java" + lines="156,158"/> + files="Player.java"/> + files="VideoDetailFragment.java"/>