Initial work to add the image of the content in the share sheet

Also do some fixes when sharing a file in downloads and some improvements in JavaDocs of ShareUtils class.
This commit is contained in:
TiA4f8R 2021-03-20 16:35:14 +01:00
parent 2fb86364ab
commit d85afd6435
No known key found for this signature in database
GPG key ID: E6D3E7F5949450DD
10 changed files with 93 additions and 31 deletions

View file

@ -234,7 +234,7 @@ public class RouterActivity extends AppCompatActivity {
.setPositiveButton(R.string.open_in_browser, .setPositiveButton(R.string.open_in_browser,
(dialog, which) -> ShareUtils.openUrlInBrowser(this, url)) (dialog, which) -> ShareUtils.openUrlInBrowser(this, url))
.setNegativeButton(R.string.share, .setNegativeButton(R.string.share,
(dialog, which) -> ShareUtils.shareText(this, "", url, false)) //no subject (dialog, which) -> ShareUtils.shareText(this, "", url, "")) //no subject
.setNeutralButton(R.string.cancel, null) .setNeutralButton(R.string.cancel, null)
.setOnDismissListener(dialog -> finish()) .setOnDismissListener(dialog -> finish())
.show(); .show();

View file

@ -454,8 +454,8 @@ public final class VideoDetailFragment
break; break;
case R.id.detail_controls_share: case R.id.detail_controls_share:
if (currentInfo != null) { if (currentInfo != null) {
ShareUtils.shareText(requireContext(), ShareUtils.shareText(requireContext(), currentInfo.getName(),
currentInfo.getName(), currentInfo.getUrl()); currentInfo.getUrl(), currentInfo.getThumbnailUrl());
} }
break; break;
case R.id.detail_controls_open_in_browser: case R.id.detail_controls_open_in_browser:

View file

@ -203,7 +203,8 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
break; break;
case R.id.menu_item_share: case R.id.menu_item_share:
if (currentInfo != null) { if (currentInfo != null) {
ShareUtils.shareText(requireContext(), name, currentInfo.getOriginalUrl()); ShareUtils.shareText(requireContext(), name, currentInfo.getOriginalUrl(),
currentInfo.getAvatarUrl());
} }
break; break;
default: default:

View file

@ -251,7 +251,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
ShareUtils.openUrlInBrowser(requireContext(), url); ShareUtils.openUrlInBrowser(requireContext(), url);
break; break;
case R.id.menu_item_share: case R.id.menu_item_share:
ShareUtils.shareText(requireContext(), name, url); ShareUtils.shareText(requireContext(), name, url, currentInfo.getThumbnailUrl());
break; break;
case R.id.menu_item_bookmark: case R.id.menu_item_bookmark:
onBookmarkClicked(); onBookmarkClicked();

View file

@ -293,7 +293,8 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
val actions = DialogInterface.OnClickListener { _, i -> val actions = DialogInterface.OnClickListener { _, i ->
when (i) { when (i) {
0 -> ShareUtils.shareText(requireContext(), selectedItem.name, selectedItem.url) 0 -> ShareUtils.shareText(requireContext(), selectedItem.name, selectedItem.url,
selectedItem.thumbnailUrl)
1 -> ShareUtils.openUrlInBrowser(requireContext(), selectedItem.url) 1 -> ShareUtils.openUrlInBrowser(requireContext(), selectedItem.url)
2 -> deleteChannel(selectedItem) 2 -> deleteChannel(selectedItem)
} }

View file

@ -313,7 +313,8 @@ public final class PlayQueueActivity extends AppCompatActivity
final MenuItem share = popupMenu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 3, final MenuItem share = popupMenu.getMenu().add(RECYCLER_ITEM_POPUP_MENU_GROUP_ID, 3,
Menu.NONE, R.string.share); Menu.NONE, R.string.share);
share.setOnMenuItemClickListener(menuItem -> { share.setOnMenuItemClickListener(menuItem -> {
shareText(getApplicationContext(), item.getTitle(), item.getUrl()); shareText(getApplicationContext(), item.getTitle(), item.getUrl(),
item.getThumbnailUrl());
return true; return true;
}); });

View file

@ -3593,7 +3593,8 @@ public final class Player implements
} else if (v.getId() == binding.moreOptionsButton.getId()) { } else if (v.getId() == binding.moreOptionsButton.getId()) {
onMoreOptionsClicked(); onMoreOptionsClicked();
} else if (v.getId() == binding.share.getId()) { } else if (v.getId() == binding.share.getId()) {
ShareUtils.shareText(context, getVideoTitle(), getVideoUrlAtCurrentTime()); ShareUtils.shareText(context, getVideoTitle(), getVideoUrlAtCurrentTime(),
currentItem.getThumbnailUrl());
} else if (v.getId() == binding.playWithKodi.getId()) { } else if (v.getId() == binding.playWithKodi.getId()) {
onPlayWithKodiClicked(); onPlayWithKodiClicked();
} else if (v.getId() == binding.openInBrowser.getId()) { } else if (v.getId() == binding.openInBrowser.getId()) {

View file

@ -8,6 +8,7 @@ import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.net.Uri; import android.net.Uri;
import android.os.Build;
import android.widget.Toast; import android.widget.Toast;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
@ -25,15 +26,15 @@ public final class ShareUtils {
* second param (a system chooser will be opened if there are multiple markets and no default) * second param (a system chooser will be opened if there are multiple markets and no default)
* and falls back to Google Play Store web URL if no app to handle the market scheme was found. * and falls back to Google Play Store web URL if no app to handle the market scheme was found.
* <p> * <p>
* It uses {@link ShareUtils#openIntentInApp(Context, Intent, boolean)} to open market scheme * It uses {@link #openIntentInApp(Context, Intent, boolean)} to open market scheme
* and {@link ShareUtils#openUrlInBrowser(Context, String, boolean)} to open Google Play Store * and {@link #openUrlInBrowser(Context, String, boolean)} to open Google Play Store
* web URL with false for the boolean param. * web URL with false for the boolean param.
* *
* @param context the context to use * @param context the context to use
* @param packageId the package id of the app to be installed * @param packageId the package id of the app to be installed
*/ */
public static void installApp(final Context context, final String packageId) { public static void installApp(final Context context, final String packageId) {
// Try market:// scheme // Try market scheme
final boolean marketSchemeResult = openIntentInApp(context, new Intent(Intent.ACTION_VIEW, final boolean marketSchemeResult = openIntentInApp(context, new Intent(Intent.ACTION_VIEW,
Uri.parse("market://details?id=" + packageId)) Uri.parse("market://details?id=" + packageId))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), false); .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), false);
@ -48,7 +49,7 @@ public final class ShareUtils {
* Open the url with the system default browser. * Open the url with the system default browser.
* <p> * <p>
* If no browser is set as default, fallbacks to * If no browser is set as default, fallbacks to
* {@link ShareUtils#openAppChooser(Context, Intent, boolean)} * {@link #openAppChooser(Context, Intent, boolean)}
* *
* @param context the context to use * @param context the context to use
* @param url the url to browse * @param url the url to browse
@ -56,7 +57,8 @@ public final class ShareUtils {
* for HTTP protocol or for the created intent * for HTTP protocol or for the created intent
* @return true if the URL can be opened or false if it cannot * @return true if the URL can be opened or false if it cannot
*/ */
public static boolean openUrlInBrowser(final Context context, final String url, public static boolean openUrlInBrowser(final Context context,
final String url,
final boolean httpDefaultBrowserTest) { final boolean httpDefaultBrowserTest) {
final String defaultPackageName; final String defaultPackageName;
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)) final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url))
@ -96,9 +98,9 @@ public final class ShareUtils {
* Open the url with the system default browser. * Open the url with the system default browser.
* <p> * <p>
* If no browser is set as default, fallbacks to * If no browser is set as default, fallbacks to
* {@link ShareUtils#openAppChooser(Context, Intent, boolean)} * {@link #openAppChooser(Context, Intent, boolean)}
* <p> * <p>
* This calls {@link ShareUtils#openUrlInBrowser(Context, String, boolean)} with true * This calls {@link #openUrlInBrowser(Context, String, boolean)} with true
* for the boolean parameter * for the boolean parameter
* *
* @param context the context to use * @param context the context to use
@ -113,19 +115,20 @@ public final class ShareUtils {
* Open an intent with the system default app. * Open an intent with the system default app.
* <p> * <p>
* The intent can be of every type, excepted a web intent for which * The intent can be of every type, excepted a web intent for which
* {@link ShareUtils#openUrlInBrowser(Context, String, boolean)} should be used. * {@link #openUrlInBrowser(Context, String, boolean)} should be used.
* <p> * <p>
* If no app is set as default, fallbacks to * If no app is set as default, fallbacks to
* {@link ShareUtils#openAppChooser(Context, Intent, boolean)}. * {@link #openAppChooser(Context, Intent, boolean)}.
* <p> * <p>
* *
* @param context the context to use * @param context the context to use
* @param intent the intent to open * @param intent the intent to open
* @param showToast the boolean to set if a toast is displayed to user when no app is installed * @param showToast a boolean to set if a toast is displayed to user when no app is installed
* to open the intent (true) or not (false) * to open the intent (true) or not (false)
* @return true if the intent can be opened or false if it cannot be * @return true if the intent can be opened or false if it cannot be
*/ */
public static boolean openIntentInApp(final Context context, final Intent intent, public static boolean openIntentInApp(final Context context,
final Intent intent,
final boolean showToast) { final boolean showToast) {
final String defaultPackageName = getDefaultAppPackageName(context, intent); final String defaultPackageName = getDefaultAppPackageName(context, intent);
@ -178,6 +181,36 @@ public final class ShareUtils {
if (setTitleChooser) { if (setTitleChooser) {
chooserIntent.putExtra(Intent.EXTRA_TITLE, context.getString(R.string.open_with)); chooserIntent.putExtra(Intent.EXTRA_TITLE, context.getString(R.string.open_with));
} }
// Migrate any clip data and flags from the original intent.
final int permFlags;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
permFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
} else {
permFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
}
if (permFlags != 0) {
ClipData targetClipData = intent.getClipData();
if (targetClipData == null && intent.getData() != null) {
final ClipData.Item item = new ClipData.Item(intent.getData());
final String[] mimeTypes;
if (intent.getType() != null) {
mimeTypes = new String[] {intent.getType()};
} else {
mimeTypes = new String[] {};
}
targetClipData = new ClipData(null, mimeTypes, item);
}
if (targetClipData != null) {
chooserIntent.setClipData(targetClipData);
chooserIntent.addFlags(permFlags);
}
}
context.startActivity(chooserIntent); context.startActivity(chooserIntent);
} }
@ -208,24 +241,45 @@ public final class ShareUtils {
/** /**
* Open the android share menu to share the current url. * Open the android share menu to share the current url.
* *
* @param context the context to use * @param context the context to use
* @param subject the url subject, typically the title * @param subject the url subject, typically the title
* @param url the url to share * @param url the url to share
* @param imagePreviewUrl the image of the subject
*/ */
public static void shareText(final Context context, final String subject, final String url) {
shareText(context, subject, url, true);
}
public static void shareText(final Context context, public static void shareText(final Context context,
final String subject, final String subject,
final String url, final String url,
final String imagePreviewUrl) {
shareText(context, subject, url, imagePreviewUrl, true);
}
/**
* Open the android share sheet to share the current url.
*
* For Android 10+ users, a content preview is shown, which includes the title of the shared
* content.
* Support sharing the image of the content needs to done, if possible.
*
* @param context the context to use
* @param subject the url subject, typically the title
* @param url the url to share
* @param imagePreviewUrl the image of the subject
* @param showPreviewText show the subject as an extra title of the Android share sheet if true
*/
public static void shareText(final Context context,
final String subject,
final String url,
final String imagePreviewUrl,
final boolean showPreviewText) { final boolean showPreviewText) {
final Intent shareIntent = new Intent(Intent.ACTION_SEND); final Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain"); shareIntent.setType("text/plain");
if (!subject.isEmpty() && showPreviewText) { if (!imagePreviewUrl.isEmpty() && !subject.isEmpty() && showPreviewText) {
shareIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
shareIntent.putExtra(Intent.EXTRA_TITLE, subject); shareIntent.putExtra(Intent.EXTRA_TITLE, subject);
/* TODO: add the image of the content to Android share sheet with setClipData after
generating a content URI of this image, then use ClipData.newUri(the content
resolver, null, the content URI) and set the ClipData to the share intent with
shareIntent.setClipData(generated ClipData).*/
//shareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} }
shareIntent.putExtra(Intent.EXTRA_TEXT, url); shareIntent.putExtra(Intent.EXTRA_TEXT, url);

View file

@ -88,7 +88,8 @@ public enum StreamDialogEntry {
}), }),
share(R.string.share, (fragment, item) -> share(R.string.share, (fragment, item) ->
ShareUtils.shareText(fragment.getContext(), item.getName(), item.getUrl())), ShareUtils.shareText(fragment.getContext(), item.getName(), item.getUrl(),
item.getThumbnailUrl())),
open_in_browser(R.string.open_in_browser, (fragment, item) -> open_in_browser(R.string.open_in_browser, (fragment, item) ->
ShareUtils.openUrlInBrowser(fragment.getContext(), item.getUrl())); ShareUtils.openUrlInBrowser(fragment.getContext(), item.getUrl()));

View file

@ -376,8 +376,11 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
final Intent intent = new Intent(Intent.ACTION_CHOOSER); final Intent intent = new Intent(Intent.ACTION_CHOOSER);
intent.putExtra(Intent.EXTRA_INTENT, shareIntent); intent.putExtra(Intent.EXTRA_INTENT, shareIntent);
intent.putExtra(Intent.EXTRA_TITLE, mContext.getString(R.string.share_dialog_title)); if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
intent.putExtra(Intent.EXTRA_TITLE, mContext.getString(R.string.share_dialog_title));
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(FLAG_GRANT_READ_URI_PERMISSION);
mContext.startActivity(intent); mContext.startActivity(intent);
} }