From 335ff61011525597bbd9129d1c3fc2811c774d48 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Wed, 9 Jun 2021 10:23:41 -0300 Subject: [PATCH] Fix several Gif MP4 UX issues. --- .../securesms/MediaPreviewActivity.java | 37 +++++++++++-------- .../securesms/components/ThumbnailView.java | 3 +- .../conversation/ConversationItem.java | 1 + .../MediaOverviewPageFragment.java | 1 + .../mediapreview/MediaPreviewFragment.java | 6 ++- .../VideoMediaPreviewFragment.java | 18 ++++++++- .../MediaSendFragmentPagerAdapter.java | 5 ++- .../mediasend/MediaSendVideoFragment.java | 35 ++++++++++++------ .../securesms/mms/VideoSlide.java | 3 +- .../main/res/layout/thumbnail_player_stub.xml | 7 ---- app/src/main/res/layout/thumbnail_view.xml | 9 ----- 11 files changed, 75 insertions(+), 50 deletions(-) delete mode 100644 app/src/main/res/layout/thumbnail_player_stub.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java index 0c4e67e1bd..6e3fab17e4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java @@ -103,6 +103,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity public static final String HIDE_ALL_MEDIA_EXTRA = "came_from_all_media"; public static final String SHOW_THREAD_EXTRA = "show_thread"; public static final String SORTING_EXTRA = "sorting"; + public static final String IS_VIDEO_GIF = "is_video_gif"; private ViewPager mediaPager; private View detailsContainer; @@ -115,6 +116,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity private String initialMediaType; private long initialMediaSize; private String initialCaption; + private boolean initialMediaIsVideoGif; private boolean leftIsRecent; private MediaPreviewViewModel viewModel; private ViewPagerListener viewPagerListener; @@ -139,6 +141,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, attachment.getSize()); intent.putExtra(MediaPreviewActivity.CAPTION_EXTRA, attachment.getCaption()); intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, leftIsRecent); + intent.putExtra(MediaPreviewActivity.IS_VIDEO_GIF, attachment.isVideoGif()); intent.setDataAndType(attachment.getUri(), mediaRecord.getContentType()); return intent; } @@ -296,12 +299,13 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity showThread = intent.getBooleanExtra(SHOW_THREAD_EXTRA, false); sorting = MediaDatabase.Sorting.values()[intent.getIntExtra(SORTING_EXTRA, 0)]; - initialMediaUri = intent.getData(); - initialMediaType = intent.getType(); - initialMediaSize = intent.getLongExtra(SIZE_EXTRA, 0); - initialCaption = intent.getStringExtra(CAPTION_EXTRA); - leftIsRecent = intent.getBooleanExtra(LEFT_IS_RECENT_EXTRA, false); - restartItem = -1; + initialMediaUri = intent.getData(); + initialMediaType = intent.getType(); + initialMediaSize = intent.getLongExtra(SIZE_EXTRA, 0); + initialCaption = intent.getStringExtra(CAPTION_EXTRA); + leftIsRecent = intent.getBooleanExtra(LEFT_IS_RECENT_EXTRA, false); + initialMediaIsVideoGif = intent.getBooleanExtra(IS_VIDEO_GIF, false); + restartItem = -1; } private void initializeObservers() { @@ -354,7 +358,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity if (isMediaInDb()) { LoaderManager.getInstance(this).restartLoader(0, null, this); } else { - mediaPager.setAdapter(new SingleItemPagerAdapter(getSupportFragmentManager(), initialMediaUri, initialMediaType, initialMediaSize)); + mediaPager.setAdapter(new SingleItemPagerAdapter(getSupportFragmentManager(), initialMediaUri, initialMediaType, initialMediaSize, initialMediaIsVideoGif)); if (initialCaption != null) { detailsContainer.setVisibility(View.VISIBLE); @@ -632,21 +636,24 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity private static class SingleItemPagerAdapter extends FragmentStatePagerAdapter implements MediaItemAdapter { - private final Uri uri; - private final String mediaType; - private final long size; + private final Uri uri; + private final String mediaType; + private final long size; + private final boolean isVideoGif; private MediaPreviewFragment mediaPreviewFragment; SingleItemPagerAdapter(@NonNull FragmentManager fragmentManager, @NonNull Uri uri, @NonNull String mediaType, - long size) + long size, + boolean isVideoGif) { super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); - this.uri = uri; - this.mediaType = mediaType; - this.size = size; + this.uri = uri; + this.mediaType = mediaType; + this.size = size; + this.isVideoGif = isVideoGif; } @Override @@ -657,7 +664,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity @NonNull @Override public Fragment getItem(int position) { - mediaPreviewFragment = MediaPreviewFragment.newInstance(uri, mediaType, size, true); + mediaPreviewFragment = MediaPreviewFragment.newInstance(uri, mediaType, size, true, isVideoGif); return mediaPreviewFragment; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ThumbnailView.java b/app/src/main/java/org/thoughtcrime/securesms/components/ThumbnailView.java index 92a1fb5df1..8874598ba3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ThumbnailView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/ThumbnailView.java @@ -25,6 +25,7 @@ import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.blurhash.BlurHash; import org.thoughtcrime.securesms.database.AttachmentDatabase; +import org.thoughtcrime.securesms.giph.mp4.GiphyMp4PlaybackPolicy; import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri; import org.thoughtcrime.securesms.mms.GlideRequest; import org.thoughtcrime.securesms.mms.GlideRequests; @@ -61,7 +62,6 @@ public class ThumbnailView extends FrameLayout { private ImageView blurhash; private View playOverlay; private View captionIcon; - private Stub videoPlayer; private OnClickListener parentClickListener; private final int[] dimens = new int[2]; @@ -93,7 +93,6 @@ public class ThumbnailView extends FrameLayout { this.blurhash = findViewById(R.id.thumbnail_blurhash); this.playOverlay = findViewById(R.id.play_overlay); this.captionIcon = findViewById(R.id.thumbnail_caption_icon); - this.videoPlayer = new Stub<>(findViewById(R.id.thumbnail_player_stub)); super.setOnClickListener(new ThumbnailClickDispatcher()); if (attrs != null) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index 8e11b9269e..d907a16b5b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -1734,6 +1734,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo intent.putExtra(MediaPreviewActivity.DATE_EXTRA, messageRecord.getTimestamp()); intent.putExtra(MediaPreviewActivity.SIZE_EXTRA, slide.asAttachment().getSize()); intent.putExtra(MediaPreviewActivity.CAPTION_EXTRA, slide.getCaption().orNull()); + intent.putExtra(MediaPreviewActivity.IS_VIDEO_GIF, slide.isVideoGif()); intent.putExtra(MediaPreviewActivity.LEFT_IS_RECENT_EXTRA, false); context.startActivity(intent); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewPageFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewPageFragment.java index c59d556f0a..3431a792fc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewPageFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewPageFragment.java @@ -236,6 +236,7 @@ public final class MediaOverviewPageFragment extends Fragment intent.putExtra(MediaPreviewActivity.HIDE_ALL_MEDIA_EXTRA, true); intent.putExtra(MediaPreviewActivity.SHOW_THREAD_EXTRA, threadId == MediaDatabase.ALL_THREADS); intent.putExtra(MediaPreviewActivity.SORTING_EXTRA, sorting.ordinal()); + intent.putExtra(MediaPreviewActivity.IS_VIDEO_GIF, attachment.isVideoGif()); intent.setDataAndType(mediaRecord.getAttachment().getUri(), mediaRecord.getContentType()); context.startActivity(intent); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewFragment.java index 8962e73604..a5e36b02b0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewFragment.java @@ -24,21 +24,23 @@ public abstract class MediaPreviewFragment extends Fragment { static final String DATA_SIZE = "DATA_SIZE"; static final String DATA_CONTENT_TYPE = "DATA_CONTENT_TYPE"; static final String AUTO_PLAY = "AUTO_PLAY"; + static final String VIDEO_GIF = "VIDEO_GIF"; private AttachmentId attachmentId; protected Events events; public static MediaPreviewFragment newInstance(@NonNull Attachment attachment, boolean autoPlay) { - return newInstance(attachment.getUri(), attachment.getContentType(), attachment.getSize(), autoPlay); + return newInstance(attachment.getUri(), attachment.getContentType(), attachment.getSize(), autoPlay, attachment.isVideoGif()); } - public static MediaPreviewFragment newInstance(@NonNull Uri dataUri, @NonNull String contentType, long size, boolean autoPlay) { + public static MediaPreviewFragment newInstance(@NonNull Uri dataUri, @NonNull String contentType, long size, boolean autoPlay, boolean isVideoGif) { Bundle args = new Bundle(); args.putParcelable(MediaPreviewFragment.DATA_URI, dataUri); args.putString(MediaPreviewFragment.DATA_CONTENT_TYPE, contentType); args.putLong(MediaPreviewFragment.DATA_SIZE, size); args.putBoolean(MediaPreviewFragment.AUTO_PLAY, autoPlay); + args.putBoolean(MediaPreviewFragment.VIDEO_GIF, isVideoGif); MediaPreviewFragment fragment = createCorrectFragmentType(contentType); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/VideoMediaPreviewFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/VideoMediaPreviewFragment.java index ff4764db72..0db216f10c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/VideoMediaPreviewFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/VideoMediaPreviewFragment.java @@ -19,6 +19,7 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment { private static final String TAG = Log.tag(VideoMediaPreviewFragment.class); private VideoPlayer videoView; + private boolean isVideoGif; @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -35,6 +36,8 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment { long size = arguments.getLong(DATA_SIZE); boolean autoPlay = arguments.getBoolean(AUTO_PLAY); + isVideoGif = arguments.getBoolean(VIDEO_GIF); + if (!MediaUtil.isVideo(contentType)) { throw new AssertionError("This fragment can only display video"); } @@ -44,6 +47,11 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment { videoView.setWindow(requireActivity().getWindow()); videoView.setVideoSource(new VideoSlide(getContext(), uri, size, false), autoPlay); + if (isVideoGif) { + videoView.hideControls(); + videoView.loopForever(); + } + videoView.setOnClickListener(v -> events.singleTapOnMedia()); return itemView; @@ -56,6 +64,14 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment { } } + @Override + public void onResume() { + super.onResume(); + if (videoView != null && isVideoGif) { + videoView.play(); + } + } + @Override public void pause() { if (videoView != null) { @@ -65,6 +81,6 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment { @Override public View getPlaybackControls() { - return videoView != null ? videoView.getControlView() : null; + return videoView != null && !isVideoGif ? videoView.getControlView() : null; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragmentPagerAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragmentPagerAdapter.java index 612fac7f89..62b71936c5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragmentPagerAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendFragmentPagerAdapter.java @@ -30,7 +30,7 @@ class MediaSendFragmentPagerAdapter extends FragmentStatePagerAdapter { private final MediaConstraints mediaConstraints; MediaSendFragmentPagerAdapter(@NonNull FragmentManager fm, @NonNull MediaConstraints mediaConstraints) { - super(fm); + super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); this.mediaConstraints = mediaConstraints; this.media = new ArrayList<>(); this.fragments = new HashMap<>(); @@ -48,7 +48,8 @@ class MediaSendFragmentPagerAdapter extends FragmentStatePagerAdapter { } else if (MediaUtil.isVideoType(mediaItem.getMimeType())) { return MediaSendVideoFragment.newInstance(mediaItem.getUri(), mediaConstraints.getCompressedVideoMaxSize(ApplicationDependencies.getApplication()), - mediaConstraints.getVideoMaxSize(ApplicationDependencies.getApplication())); + mediaConstraints.getVideoMaxSize(ApplicationDependencies.getApplication()), + mediaItem.isVideoGif()); } else { throw new UnsupportedOperationException("Can only render images and videos. Found mimetype: '" + mediaItem.getMimeType() + "'"); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendVideoFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendVideoFragment.java index 94bd25486c..a101ee7127 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendVideoFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaSendVideoFragment.java @@ -30,9 +30,10 @@ public class MediaSendVideoFragment extends Fragment implements VideoEditorHud.E private static final String TAG = Log.tag(MediaSendVideoFragment.class); - private static final String KEY_URI = "uri"; - private static final String KEY_MAX_OUTPUT = "max_output_size"; - private static final String KEY_MAX_SEND = "max_send_size"; + private static final String KEY_URI = "uri"; + private static final String KEY_MAX_OUTPUT = "max_output_size"; + private static final String KEY_MAX_SEND = "max_send_size"; + private static final String KEY_IS_VIDEO_GIF = "is_video_gif"; private final Throttler videoScanThrottle = new Throttler(150); private final Handler handler = new Handler(Looper.getMainLooper()); @@ -40,15 +41,17 @@ public class MediaSendVideoFragment extends Fragment implements VideoEditorHud.E private Controller controller; private Data data = new Data(); private Uri uri; + private boolean isVideoGif; private VideoPlayer player; @Nullable private VideoEditorHud hud; private Runnable updatePosition; - public static MediaSendVideoFragment newInstance(@NonNull Uri uri, long maxCompressedVideoSize, long maxAttachmentSize) { + public static MediaSendVideoFragment newInstance(@NonNull Uri uri, long maxCompressedVideoSize, long maxAttachmentSize, boolean isVideoGif) { Bundle args = new Bundle(); args.putParcelable(KEY_URI, uri); args.putLong(KEY_MAX_OUTPUT, maxCompressedVideoSize); args.putLong(KEY_MAX_SEND, maxAttachmentSize); + args.putBoolean(KEY_IS_VIDEO_GIF, isVideoGif); MediaSendVideoFragment fragment = new MediaSendVideoFragment(); fragment.setArguments(args); @@ -76,15 +79,20 @@ public class MediaSendVideoFragment extends Fragment implements VideoEditorHud.E player = view.findViewById(R.id.video_player); - uri = requireArguments().getParcelable(KEY_URI); - long maxOutput = requireArguments().getLong(KEY_MAX_OUTPUT); - long maxSend = requireArguments().getLong(KEY_MAX_SEND); - VideoSlide slide = new VideoSlide(requireContext(), uri, 0, false); + uri = requireArguments().getParcelable(KEY_URI); + isVideoGif = requireArguments().getBoolean(KEY_IS_VIDEO_GIF); + + long maxOutput = requireArguments().getLong(KEY_MAX_OUTPUT); + long maxSend = requireArguments().getLong(KEY_MAX_SEND); + VideoSlide slide = new VideoSlide(requireContext(), uri, 0, isVideoGif); player.setWindow(requireActivity().getWindow()); player.setVideoSource(slide, true); - if (MediaConstraints.isVideoTranscodeAvailable()) { + if (slide.isVideoGif()) { + player.hideControls(); + player.loopForever(); + } else if (MediaConstraints.isVideoTranscodeAvailable()) { hud = view.findViewById(R.id.video_editor_hud); hud.setEventListener(this); updateHud(data); @@ -140,6 +148,10 @@ public class MediaSendVideoFragment extends Fragment implements VideoEditorHud.E public void onResume() { super.onResume(); startPositionUpdates(); + + if (player != null && isVideoGif) { + player.play(); + } } private void startPositionUpdates() { @@ -180,8 +192,9 @@ public class MediaSendVideoFragment extends Fragment implements VideoEditorHud.E @Override public @Nullable View getPlaybackControls() { if (hud != null && hud.getVisibility() == View.VISIBLE) return null; - - return player != null ? player.getControlView() : null; + else if (isVideoGif) return null; + else if (player != null) return player.getControlView(); + else return null; } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/VideoSlide.java b/app/src/main/java/org/thoughtcrime/securesms/mms/VideoSlide.java index ff92d00cc7..4f9074712f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/VideoSlide.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/VideoSlide.java @@ -27,6 +27,7 @@ import androidx.annotation.Nullable; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.attachments.Attachment; import org.thoughtcrime.securesms.database.AttachmentDatabase; +import org.thoughtcrime.securesms.giph.mp4.GiphyMp4PlaybackPolicy; import org.thoughtcrime.securesms.util.MediaUtil; public class VideoSlide extends Slide { @@ -54,7 +55,7 @@ public class VideoSlide extends Slide { @Override public boolean hasPlayOverlay() { - return true; + return !(isVideoGif() && GiphyMp4PlaybackPolicy.autoplay()); } @Override diff --git a/app/src/main/res/layout/thumbnail_player_stub.xml b/app/src/main/res/layout/thumbnail_player_stub.xml deleted file mode 100644 index 549be2c0b2..0000000000 --- a/app/src/main/res/layout/thumbnail_player_stub.xml +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/app/src/main/res/layout/thumbnail_view.xml b/app/src/main/res/layout/thumbnail_view.xml index 83f7facea4..9d3be4d75c 100644 --- a/app/src/main/res/layout/thumbnail_view.xml +++ b/app/src/main/res/layout/thumbnail_view.xml @@ -24,15 +24,6 @@ android:scaleType="fitCenter" android:contentDescription="@string/conversation_item__mms_image_description" /> - -