Filter streams using Java 8 Stream's API instead of removing streams with list iterators and add a better toast when there is no audio stream for external players

This ensures to not remove streams from the StreamInfo lists themselves, and so to not have to create list copies.

The toast shown in RouterActivity, when there is no audio stream available for external players, is now shown, in the same case, when pressing the background button in VideoDetailFragment.
This commit is contained in:
AudricV 2022-06-16 11:14:02 +02:00
parent 73855cacb7
commit 036196a487
No known key found for this signature in database
GPG key ID: DA92EC7905614198
6 changed files with 123 additions and 132 deletions

View file

@ -69,7 +69,6 @@ import org.schabi.newpipe.util.ThemeHelper;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
@ -84,7 +83,7 @@ import us.shandian.giga.service.DownloadManagerService;
import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder; import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder;
import us.shandian.giga.service.MissionState; import us.shandian.giga.service.MissionState;
import static org.schabi.newpipe.util.ListHelper.keepStreamsWithDelivery; import static org.schabi.newpipe.util.ListHelper.getStreamsOfSpecifiedDelivery;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage; import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
public class DownloadDialog extends DialogFragment public class DownloadDialog extends DialogFragment
@ -149,25 +148,24 @@ public class DownloadDialog extends DialogFragment
public static DownloadDialog newInstance(final Context context, public static DownloadDialog newInstance(final Context context,
@NonNull final StreamInfo info) { @NonNull final StreamInfo info) {
// TODO: Adapt this code when the downloader support other types of stream deliveries // TODO: Adapt this code when the downloader support other types of stream deliveries
final List<VideoStream> videoStreams = new ArrayList<>(info.getVideoStreams());
final List<VideoStream> progressiveHttpVideoStreams = final List<VideoStream> progressiveHttpVideoStreams =
keepStreamsWithDelivery(videoStreams, DeliveryMethod.PROGRESSIVE_HTTP); getStreamsOfSpecifiedDelivery(info.getVideoStreams(),
DeliveryMethod.PROGRESSIVE_HTTP);
final List<VideoStream> videoOnlyStreams = new ArrayList<>(info.getVideoOnlyStreams());
final List<VideoStream> progressiveHttpVideoOnlyStreams = final List<VideoStream> progressiveHttpVideoOnlyStreams =
keepStreamsWithDelivery(videoOnlyStreams, DeliveryMethod.PROGRESSIVE_HTTP); getStreamsOfSpecifiedDelivery(info.getVideoOnlyStreams(),
DeliveryMethod.PROGRESSIVE_HTTP);
final List<AudioStream> audioStreams = new ArrayList<>(info.getAudioStreams());
final List<AudioStream> progressiveHttpAudioStreams = final List<AudioStream> progressiveHttpAudioStreams =
keepStreamsWithDelivery(audioStreams, DeliveryMethod.PROGRESSIVE_HTTP); getStreamsOfSpecifiedDelivery(info.getAudioStreams(),
DeliveryMethod.PROGRESSIVE_HTTP);
final List<SubtitlesStream> subtitlesStreams = new ArrayList<>(info.getSubtitles());
final List<SubtitlesStream> progressiveHttpSubtitlesStreams = final List<SubtitlesStream> progressiveHttpSubtitlesStreams =
keepStreamsWithDelivery(subtitlesStreams, DeliveryMethod.PROGRESSIVE_HTTP); getStreamsOfSpecifiedDelivery(info.getSubtitles(),
DeliveryMethod.PROGRESSIVE_HTTP);
final List<VideoStream> videoStreamsList = new ArrayList<>( final List<VideoStream> videoStreamsList = ListHelper.getSortedStreamVideosList(context,
ListHelper.getSortedStreamVideosList(context, progressiveHttpVideoStreams, progressiveHttpVideoStreams, progressiveHttpVideoOnlyStreams, false, false);
progressiveHttpVideoOnlyStreams, false, false));
final DownloadDialog instance = new DownloadDialog(); final DownloadDialog instance = new DownloadDialog();
instance.setInfo(info); instance.setInfo(info);

View file

@ -31,6 +31,7 @@ import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator; import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.Toast;
import androidx.annotation.AttrRes; import androidx.annotation.AttrRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -122,7 +123,7 @@ import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientat
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired; import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET; import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView; import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
import static org.schabi.newpipe.util.ListHelper.removeNonUrlAndTorrentStreams; import static org.schabi.newpipe.util.ListHelper.getNonUrlAndNonTorrentStreams;
public final class VideoDetailFragment public final class VideoDetailFragment
extends BaseStateFragment<StreamInfo> extends BaseStateFragment<StreamInfo>
@ -1092,9 +1093,6 @@ public final class VideoDetailFragment
} }
private void openBackgroundPlayer(final boolean append) { private void openBackgroundPlayer(final boolean append) {
final AudioStream audioStream = currentInfo.getAudioStreams()
.get(ListHelper.getDefaultAudioFormat(activity, currentInfo.getAudioStreams()));
final boolean useExternalAudioPlayer = PreferenceManager final boolean useExternalAudioPlayer = PreferenceManager
.getDefaultSharedPreferences(activity) .getDefaultSharedPreferences(activity)
.getBoolean(activity.getString(R.string.use_external_audio_player_key), false); .getBoolean(activity.getString(R.string.use_external_audio_player_key), false);
@ -1109,7 +1107,17 @@ public final class VideoDetailFragment
if (!useExternalAudioPlayer) { if (!useExternalAudioPlayer) {
openNormalBackgroundPlayer(append); openNormalBackgroundPlayer(append);
} else { } else {
startOnExternalPlayer(activity, currentInfo, audioStream); final List<AudioStream> audioStreams = getNonUrlAndNonTorrentStreams(
currentInfo.getAudioStreams());
final int index = ListHelper.getDefaultAudioFormat(activity, audioStreams);
if (index == -1) {
Toast.makeText(activity, R.string.no_audio_streams_available_for_external_players,
Toast.LENGTH_SHORT).show();
return;
}
startOnExternalPlayer(activity, currentInfo, audioStreams.get(index));
} }
} }
@ -2147,10 +2155,10 @@ public final class VideoDetailFragment
return; return;
} }
final List<VideoStream> videoStreams = removeNonUrlAndTorrentStreams( final List<VideoStream> videoStreams = getNonUrlAndNonTorrentStreams(
new ArrayList<>(currentInfo.getVideoStreams())); currentInfo.getVideoStreams());
final List<VideoStream> videoOnlyStreams = removeNonUrlAndTorrentStreams( final List<VideoStream> videoOnlyStreams = getNonUrlAndNonTorrentStreams(
new ArrayList<>(currentInfo.getVideoOnlyStreams())); currentInfo.getVideoOnlyStreams());
final AlertDialog.Builder builder = new AlertDialog.Builder(activity); final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.select_quality_external_players); builder.setTitle(R.string.select_quality_external_players);

View file

@ -1,6 +1,6 @@
package org.schabi.newpipe.player.resolver; package org.schabi.newpipe.player.resolver;
import static org.schabi.newpipe.util.ListHelper.removeTorrentStreams; import static org.schabi.newpipe.util.ListHelper.getNonTorrentStreams;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
@ -18,7 +18,6 @@ import org.schabi.newpipe.player.mediaitem.StreamInfoTag;
import org.schabi.newpipe.util.ListHelper; import org.schabi.newpipe.util.ListHelper;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class AudioPlaybackResolver implements PlaybackResolver { public class AudioPlaybackResolver implements PlaybackResolver {
@ -43,8 +42,7 @@ public class AudioPlaybackResolver implements PlaybackResolver {
return liveSource; return liveSource;
} }
final List<AudioStream> audioStreams = new ArrayList<>(info.getAudioStreams()); final List<AudioStream> audioStreams = getNonTorrentStreams(info.getAudioStreams());
removeTorrentStreams(audioStreams);
final int index = ListHelper.getDefaultAudioFormat(context, audioStreams); final int index = ListHelper.getDefaultAudioFormat(context, audioStreams);
if (index < 0 || index >= info.getAudioStreams().size()) { if (index < 0 || index >= info.getAudioStreams().size()) {

View file

@ -29,8 +29,8 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import static com.google.android.exoplayer2.C.TIME_UNSET; import static com.google.android.exoplayer2.C.TIME_UNSET;
import static org.schabi.newpipe.util.ListHelper.removeNonUrlAndTorrentStreams; import static org.schabi.newpipe.util.ListHelper.getNonUrlAndNonTorrentStreams;
import static org.schabi.newpipe.util.ListHelper.removeTorrentStreams; import static org.schabi.newpipe.util.ListHelper.getNonTorrentStreams;
public class VideoPlaybackResolver implements PlaybackResolver { public class VideoPlaybackResolver implements PlaybackResolver {
private static final String TAG = VideoPlaybackResolver.class.getSimpleName(); private static final String TAG = VideoPlaybackResolver.class.getSimpleName();
@ -70,24 +70,21 @@ public class VideoPlaybackResolver implements PlaybackResolver {
} }
final List<MediaSource> mediaSources = new ArrayList<>(); final List<MediaSource> mediaSources = new ArrayList<>();
final List<VideoStream> videoStreams = new ArrayList<>(info.getVideoStreams());
final List<VideoStream> videoOnlyStreams = new ArrayList<>(info.getVideoOnlyStreams());
removeTorrentStreams(videoStreams);
removeTorrentStreams(videoOnlyStreams);
// Create video stream source // Create video stream source
final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, final List<VideoStream> videoStreamsList = ListHelper.getSortedStreamVideosList(context,
videoStreams, videoOnlyStreams, false, true); getNonTorrentStreams(info.getVideoStreams()),
getNonTorrentStreams(info.getVideoOnlyStreams()), false, true);
final int index; final int index;
if (videos.isEmpty()) { if (videoStreamsList.isEmpty()) {
index = -1; index = -1;
} else if (playbackQuality == null) { } else if (playbackQuality == null) {
index = qualityResolver.getDefaultResolutionIndex(videos); index = qualityResolver.getDefaultResolutionIndex(videoStreamsList);
} else { } else {
index = qualityResolver.getOverrideResolutionIndex(videos, getPlaybackQuality()); index = qualityResolver.getOverrideResolutionIndex(videoStreamsList,
getPlaybackQuality());
} }
final MediaItemTag tag = StreamInfoTag.of(info, videos, index); final MediaItemTag tag = StreamInfoTag.of(info, videoStreamsList, index);
@Nullable final VideoStream video = tag.getMaybeQuality() @Nullable final VideoStream video = tag.getMaybeQuality()
.map(MediaItemTag.Quality::getSelectedVideoStream) .map(MediaItemTag.Quality::getSelectedVideoStream)
.orElse(null); .orElse(null);
@ -104,8 +101,7 @@ public class VideoPlaybackResolver implements PlaybackResolver {
} }
// Create optional audio stream source // Create optional audio stream source
final List<AudioStream> audioStreams = info.getAudioStreams(); final List<AudioStream> audioStreams = getNonTorrentStreams(info.getAudioStreams());
removeTorrentStreams(audioStreams);
final AudioStream audio = audioStreams.isEmpty() ? null : audioStreams.get( final AudioStream audio = audioStreams.isEmpty() ? null : audioStreams.get(
ListHelper.getDefaultAudioFormat(context, audioStreams)); ListHelper.getDefaultAudioFormat(context, audioStreams));
@ -129,13 +125,14 @@ public class VideoPlaybackResolver implements PlaybackResolver {
if (mediaSources.isEmpty()) { if (mediaSources.isEmpty()) {
return null; return null;
} }
// Below are auxiliary media sources // Below are auxiliary media sources
// Create subtitle sources // Create subtitle sources
final List<SubtitlesStream> subtitlesStreams = info.getSubtitles(); final List<SubtitlesStream> subtitlesStreams = info.getSubtitles();
if (subtitlesStreams != null) { if (subtitlesStreams != null) {
// Torrent and non URL subtitles are not supported by ExoPlayer // Torrent and non URL subtitles are not supported by ExoPlayer
final List<SubtitlesStream> nonTorrentAndUrlStreams = removeNonUrlAndTorrentStreams( final List<SubtitlesStream> nonTorrentAndUrlStreams = getNonUrlAndNonTorrentStreams(
subtitlesStreams); subtitlesStreams);
for (final SubtitlesStream subtitle : nonTorrentAndUrlStreams) { for (final SubtitlesStream subtitle : nonTorrentAndUrlStreams) {
final MediaFormat mediaFormat = subtitle.getFormat(); final MediaFormat mediaFormat = subtitle.getFormat();

View file

@ -23,10 +23,10 @@ import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public final class ListHelper { public final class ListHelper {
@ -116,27 +116,17 @@ public final class ListHelper {
* Return a {@link Stream} list which uses the given delivery method from a {@link Stream} * Return a {@link Stream} list which uses the given delivery method from a {@link Stream}
* list. * list.
* *
* @param streamList the original stream list * @param streamList the original {@link Stream stream} list
* @param deliveryMethod the delivery method * @param deliveryMethod the {@link DeliveryMethod delivery method}
* @param <S> the item type's class that extends {@link Stream} * @param <S> the item type's class that extends {@link Stream}
* @return a stream list which uses the given delivery method * @return a {@link Stream stream} list which uses the given delivery method
*/ */
@NonNull @NonNull
public static <S extends Stream> List<S> keepStreamsWithDelivery( public static <S extends Stream> List<S> getStreamsOfSpecifiedDelivery(
@NonNull final List<S> streamList, final List<S> streamList,
final DeliveryMethod deliveryMethod) { final DeliveryMethod deliveryMethod) {
if (streamList.isEmpty()) { return getFilteredStreamList(streamList,
return Collections.emptyList(); stream -> stream.getDeliveryMethod() == deliveryMethod);
}
final Iterator<S> streamListIterator = streamList.iterator();
while (streamListIterator.hasNext()) {
if (streamListIterator.next().getDeliveryMethod() != deliveryMethod) {
streamListIterator.remove();
}
}
return streamList;
} }
/** /**
@ -147,21 +137,10 @@ public final class ListHelper {
* @return a stream list which only contains URL streams and non-torrent streams * @return a stream list which only contains URL streams and non-torrent streams
*/ */
@NonNull @NonNull
public static <S extends Stream> List<S> removeNonUrlAndTorrentStreams( public static <S extends Stream> List<S> getNonUrlAndNonTorrentStreams(
@NonNull final List<S> streamList) { final List<S> streamList) {
if (streamList.isEmpty()) { return getFilteredStreamList(streamList,
return Collections.emptyList(); stream -> stream.isUrl() && stream.getDeliveryMethod() != DeliveryMethod.TORRENT);
}
final Iterator<S> streamListIterator = streamList.iterator();
while (streamListIterator.hasNext()) {
final S stream = streamListIterator.next();
if (!stream.isUrl() || stream.getDeliveryMethod() == DeliveryMethod.TORRENT) {
streamListIterator.remove();
}
}
return streamList;
} }
/** /**
@ -172,21 +151,10 @@ public final class ListHelper {
* @return a stream list which only contains non-torrent streams * @return a stream list which only contains non-torrent streams
*/ */
@NonNull @NonNull
public static <S extends Stream> List<S> removeTorrentStreams( public static <S extends Stream> List<S> getNonTorrentStreams(
@NonNull final List<S> streamList) { final List<S> streamList) {
if (streamList.isEmpty()) { return getFilteredStreamList(streamList,
return Collections.emptyList(); stream -> stream.getDeliveryMethod() != DeliveryMethod.TORRENT);
}
final Iterator<S> streamListIterator = streamList.iterator();
while (streamListIterator.hasNext()) {
final S stream = streamListIterator.next();
if (stream.getDeliveryMethod() == DeliveryMethod.TORRENT) {
streamListIterator.remove();
}
}
return streamList;
} }
/** /**
@ -224,6 +192,26 @@ public final class ListHelper {
// Utils // Utils
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
/**
* Get a filtered stream list, by using Java 8 Stream's API and the given predicate.
*
* @param streamList the stream list to filter
* @param streamListPredicate the predicate which will be used to filter streams
* @param <S> the item type's class that extends {@link Stream}
* @return a new stream list filtered using the given predicate
*/
private static <S extends Stream> List<S> getFilteredStreamList(
final List<S> streamList,
final Predicate<S> streamListPredicate) {
if (streamList == null) {
return Collections.emptyList();
}
return streamList.stream()
.filter(streamListPredicate)
.collect(Collectors.toList());
}
private static String computeDefaultResolution(final Context context, final int key, private static String computeDefaultResolution(final Context context, final int key,
final int value) { final int value) {
final SharedPreferences preferences final SharedPreferences preferences

View file

@ -63,7 +63,7 @@ import org.schabi.newpipe.util.external_communication.ShareUtils;
import java.util.List; import java.util.List;
import static org.schabi.newpipe.util.ListHelper.removeNonUrlAndTorrentStreams; import static org.schabi.newpipe.util.ListHelper.getNonUrlAndNonTorrentStreams;
public final class NavigationHelper { public final class NavigationHelper {
public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag"; public static final String MAIN_FRAGMENT_TAG = "main_fragment_tag";
@ -221,39 +221,42 @@ public final class NavigationHelper {
public static void playOnExternalAudioPlayer(@NonNull final Context context, public static void playOnExternalAudioPlayer(@NonNull final Context context,
@NonNull final StreamInfo info) { @NonNull final StreamInfo info) {
final List<AudioStream> audioStreams = info.getAudioStreams(); final List<AudioStream> audioStreams = info.getAudioStreams();
if (audioStreams.isEmpty()) { if (audioStreams == null || audioStreams.isEmpty()) {
Toast.makeText(context, R.string.audio_streams_empty, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.audio_streams_empty, Toast.LENGTH_SHORT).show();
return; return;
} }
final List<AudioStream> audioStreamsForExternalPlayers = removeNonUrlAndTorrentStreams(
audioStreams); final List<AudioStream> audioStreamsForExternalPlayers =
getNonUrlAndNonTorrentStreams(audioStreams);
if (audioStreamsForExternalPlayers.isEmpty()) { if (audioStreamsForExternalPlayers.isEmpty()) {
Toast.makeText(context, R.string.no_audio_streams_available_for_external_players, Toast.makeText(context, R.string.no_audio_streams_available_for_external_players,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
return; return;
} }
final int index = ListHelper.getDefaultAudioFormat(context,
audioStreamsForExternalPlayers);
final int index = ListHelper.getDefaultAudioFormat(context, audioStreamsForExternalPlayers);
final AudioStream audioStream = audioStreamsForExternalPlayers.get(index); final AudioStream audioStream = audioStreamsForExternalPlayers.get(index);
playOnExternalPlayer(context, info.getName(), info.getUploaderName(), audioStream); playOnExternalPlayer(context, info.getName(), info.getUploaderName(), audioStream);
} }
public static void playOnExternalVideoPlayer(final Context context, public static void playOnExternalVideoPlayer(final Context context,
@NonNull final StreamInfo info) { @NonNull final StreamInfo info) {
final List<VideoStream> videoStreams = info.getVideoStreams(); final List<VideoStream> videoStreams = info.getVideoStreams();
if (videoStreams.isEmpty()) { if (videoStreams == null || videoStreams.isEmpty()) {
Toast.makeText(context, R.string.video_streams_empty, Toast.LENGTH_SHORT).show(); Toast.makeText(context, R.string.video_streams_empty, Toast.LENGTH_SHORT).show();
return; return;
} }
final List<VideoStream> videoStreamsForExternalPlayers = final List<VideoStream> videoStreamsForExternalPlayers =
ListHelper.getSortedStreamVideosList(context, ListHelper.getSortedStreamVideosList(context,
removeNonUrlAndTorrentStreams(videoStreams), null, false, false); getNonUrlAndNonTorrentStreams(videoStreams), null, false, false);
if (videoStreamsForExternalPlayers.isEmpty()) { if (videoStreamsForExternalPlayers.isEmpty()) {
Toast.makeText(context, R.string.no_video_streams_available_for_external_players, Toast.makeText(context, R.string.no_video_streams_available_for_external_players,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
return; return;
} }
final int index = ListHelper.getDefaultResolutionIndex(context, final int index = ListHelper.getDefaultResolutionIndex(context,
videoStreamsForExternalPlayers); videoStreamsForExternalPlayers);
@ -267,27 +270,29 @@ public final class NavigationHelper {
@NonNull final Stream stream) { @NonNull final Stream stream) {
final DeliveryMethod deliveryMethod = stream.getDeliveryMethod(); final DeliveryMethod deliveryMethod = stream.getDeliveryMethod();
final String mimeType; final String mimeType;
if (deliveryMethod == DeliveryMethod.PROGRESSIVE_HTTP) {
if (stream.getFormat() != null) { if (!stream.isUrl() || deliveryMethod == DeliveryMethod.TORRENT) {
mimeType = stream.getFormat().getMimeType(); Toast.makeText(context, R.string.selected_stream_external_player_not_supported,
} else { Toast.LENGTH_SHORT).show();
return;
}
switch (deliveryMethod) {
case PROGRESSIVE_HTTP:
if (stream.getFormat() == null) {
if (stream instanceof AudioStream) { if (stream instanceof AudioStream) {
mimeType = "audio/*"; mimeType = "audio/*";
} else if (stream instanceof VideoStream) { } else if (stream instanceof VideoStream) {
mimeType = "video/*"; mimeType = "video/*";
} else { } else {
// This should never be reached, because subtitles are not opened in external // This should never be reached, because subtitles are not opened in
// players // external players
return; return;
} }
} else {
mimeType = stream.getFormat().getMimeType();
} }
} else { break;
if (!stream.isUrl() || deliveryMethod == DeliveryMethod.TORRENT) {
Toast.makeText(context, R.string.selected_stream_external_player_not_supported,
Toast.LENGTH_SHORT).show();
return;
} else {
switch (deliveryMethod) {
case HLS: case HLS:
mimeType = "application/x-mpegURL"; mimeType = "application/x-mpegURL";
break; break;
@ -298,12 +303,9 @@ public final class NavigationHelper {
mimeType = "application/vnd.ms-sstr+xml"; mimeType = "application/vnd.ms-sstr+xml";
break; break;
default: default:
// Progressive HTTP streams are handled above and torrents streams are not // Torrent streams are not exposed to external players
// exposed to external players
mimeType = ""; mimeType = "";
} }
}
}
final Intent intent = new Intent(); final Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW); intent.setAction(Intent.ACTION_VIEW);