Signal-Android/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageActivity.java

183 wiersze
5.5 KiB
Java

package org.thoughtcrime.securesms.revealable;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.lifecycle.ViewModelProvider;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.mms.VideoSlide;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.thoughtcrime.securesms.video.VideoPlayer;
import java.util.concurrent.TimeUnit;
public class ViewOnceMessageActivity extends PassphraseRequiredActivity implements VideoPlayer.PlayerStateCallback {
private static final String TAG = Log.tag(ViewOnceMessageActivity.class);
private static final String KEY_MESSAGE_ID = "message_id";
private static final String KEY_URI = "uri";
private ImageView image;
private VideoPlayer video;
private View closeButton;
private TextView duration;
private ViewOnceMessageViewModel viewModel;
private Uri uri;
private final Handler handler = new Handler(Looper.getMainLooper());
private final Runnable durationUpdateRunnable = () -> {
long timeLeft = TimeUnit.MILLISECONDS.toSeconds(video.getDuration() - video.getPlaybackPosition());
long minutes = timeLeft / 60;
long seconds = timeLeft % 60;
duration.setText(getString(R.string.ViewOnceMessageActivity_video_duration, minutes, seconds));
scheduleDurationUpdate();
};
public static Intent getIntent(@NonNull Context context, long messageId, @NonNull Uri uri) {
Intent intent = new Intent(context, ViewOnceMessageActivity.class);
intent.putExtra(KEY_MESSAGE_ID, messageId);
intent.putExtra(KEY_URI, uri);
return intent;
}
@Override
protected void attachBaseContext(@NonNull Context newBase) {
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
super.attachBaseContext(newBase);
}
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
super.onCreate(savedInstanceState, ready);
setContentView(R.layout.view_once_message_activity);
this.image = findViewById(R.id.view_once_image);
this.video = findViewById(R.id.view_once_video);
this.duration = findViewById(R.id.view_once_duration);
this.closeButton = findViewById(R.id.view_once_close_button);
this.uri = getIntent().getParcelableExtra(KEY_URI);
closeButton.setOnClickListener(v -> finish());
initViewModel(getIntent().getLongExtra(KEY_MESSAGE_ID, -1), uri);
}
@Override
protected void onStop() {
super.onStop();
cancelDurationUpdate();
video.cleanup();
BlobProvider.getInstance().delete(this, uri);
finish();
}
@Override
public void onPlayerReady() {
handler.post(durationUpdateRunnable);
}
private void initViewModel(long messageId, @NonNull Uri uri) {
ViewOnceMessageRepository repository = new ViewOnceMessageRepository(this);
viewModel = new ViewModelProvider(this, new ViewOnceMessageViewModel.Factory(messageId, repository)).get(ViewOnceMessageViewModel.class);
viewModel.getMessage().observe(this, (message) -> {
if (message == null) return;
if (message.isPresent()) {
displayMedia(uri);
} else {
image.setImageDrawable(null);
finish();
}
});
}
private void displayMedia(@NonNull Uri uri) {
if (MediaUtil.isVideoType(PartAuthority.getAttachmentContentType(this, uri))) {
displayVideo(uri);
} else {
displayImage(uri);
}
}
private void displayVideo(@NonNull Uri uri) {
video.setVisibility(View.VISIBLE);
image.setVisibility(View.GONE);
duration.setVisibility(View.VISIBLE);
VideoSlide videoSlide = new VideoSlide(this, uri, 0, false);
video.setWindow(getWindow());
video.setPlayerStateCallbacks(this);
video.setVideoSource(videoSlide, true, TAG);
video.hideControls();
video.loopForever();
}
private void displayImage(@NonNull Uri uri) {
video.setVisibility(View.GONE);
image.setVisibility(View.VISIBLE);
duration.setVisibility(View.GONE);
GlideApp.with(this)
.load(new DecryptableUri(uri))
.into(image);
}
private void scheduleDurationUpdate() {
handler.postDelayed(durationUpdateRunnable, 100);
}
private void cancelDurationUpdate() {
handler.removeCallbacks(durationUpdateRunnable);
}
private class ViewOnceGestureListener extends GestureDetector.SimpleOnGestureListener {
private final View view;
private ViewOnceGestureListener(View view) {
this.view = view;
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
view.performClick();
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
finish();
return true;
}
}
}