mirror of https://github.com/NekoX-Dev/NekoX.git
1146 lines
48 KiB
Java
1146 lines
48 KiB
Java
package org.telegram.ui.Components;
|
|
|
|
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
|
|
|
import android.animation.Animator;
|
|
import android.animation.AnimatorListenerAdapter;
|
|
import android.animation.AnimatorSet;
|
|
import android.animation.ObjectAnimator;
|
|
import android.animation.ValueAnimator;
|
|
import android.annotation.SuppressLint;
|
|
import android.app.Activity;
|
|
import android.app.ActivityManager;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.SharedPreferences;
|
|
import android.content.res.Configuration;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.Outline;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Path;
|
|
import android.graphics.PixelFormat;
|
|
import android.graphics.PorterDuff;
|
|
import android.os.Build;
|
|
import android.view.Gravity;
|
|
import android.view.MotionEvent;
|
|
import android.view.ScaleGestureDetector;
|
|
import android.view.View;
|
|
import android.view.ViewConfiguration;
|
|
import android.view.ViewGroup;
|
|
import android.view.ViewOutlineProvider;
|
|
import android.view.WindowManager;
|
|
import android.webkit.WebView;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.ImageView;
|
|
|
|
import androidx.core.math.MathUtils;
|
|
import androidx.dynamicanimation.animation.DynamicAnimation;
|
|
import androidx.dynamicanimation.animation.FloatPropertyCompat;
|
|
import androidx.dynamicanimation.animation.SpringAnimation;
|
|
import androidx.dynamicanimation.animation.SpringForce;
|
|
|
|
import com.google.android.exoplayer2.C;
|
|
|
|
import org.telegram.messenger.AndroidUtilities;
|
|
import org.telegram.messenger.ApplicationLoader;
|
|
import org.telegram.messenger.R;
|
|
import org.telegram.ui.ActionBar.Theme;
|
|
import org.telegram.ui.LaunchActivity;
|
|
import org.telegram.ui.PhotoViewer;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
public class PipVideoOverlay {
|
|
public final static boolean IS_TRANSITION_ANIMATION_SUPPORTED = true;
|
|
public final static float ROUNDED_CORNERS_DP = 10;
|
|
|
|
private final static float SIDE_PADDING_DP = 16;
|
|
private final static FloatPropertyCompat<PipVideoOverlay> PIP_X_PROPERTY = new SimpleFloatPropertyCompat<>("pipX", obj -> obj.pipX, (obj, value) -> {
|
|
obj.windowLayoutParams.x = (int) (obj.pipX = value);
|
|
try {
|
|
obj.windowManager.updateViewLayout(obj.contentView, obj.windowLayoutParams);
|
|
} catch (IllegalArgumentException e) {
|
|
obj.pipXSpring.cancel();
|
|
}
|
|
}), PIP_Y_PROPERTY = new SimpleFloatPropertyCompat<>("pipY", obj -> obj.pipY, (obj, value) -> {
|
|
obj.windowLayoutParams.y = (int) (obj.pipY = value);
|
|
|
|
try {
|
|
obj.windowManager.updateViewLayout(obj.contentView, obj.windowLayoutParams);
|
|
} catch (IllegalArgumentException e) {
|
|
obj.pipYSpring.cancel();
|
|
}
|
|
});
|
|
|
|
@SuppressLint("StaticFieldLeak")
|
|
private static PipVideoOverlay instance = new PipVideoOverlay();
|
|
|
|
private float minScaleFactor = 0.75f, maxScaleFactor = 1.4f;
|
|
|
|
private WindowManager windowManager;
|
|
private WindowManager.LayoutParams windowLayoutParams;
|
|
private ViewGroup contentView;
|
|
private FrameLayout contentFrameLayout;
|
|
private View innerView;
|
|
private FrameLayout controlsView;
|
|
|
|
private ScaleGestureDetector scaleGestureDetector;
|
|
private GestureDetectorFixDoubleTap gestureDetector;
|
|
private boolean isScrolling;
|
|
private boolean isScrollDisallowed;
|
|
private View consumingChild;
|
|
private boolean isShowingControls;
|
|
private ValueAnimator controlsAnimator;
|
|
|
|
private PipConfig pipConfig;
|
|
private int pipWidth, pipHeight;
|
|
private float scaleFactor = 1f;
|
|
private float pipX, pipY;
|
|
private SpringAnimation pipXSpring, pipYSpring;
|
|
private Float aspectRatio;
|
|
|
|
private boolean isVisible;
|
|
|
|
private VideoForwardDrawable videoForwardDrawable = new VideoForwardDrawable(false);
|
|
private int mVideoWidth, mVideoHeight;
|
|
private EmbedBottomSheet parentSheet;
|
|
private PhotoViewer photoViewer;
|
|
private ImageView playPauseButton;
|
|
private boolean isVideoCompleted;
|
|
private float videoProgress, bufferProgress;
|
|
private VideoProgressView videoProgressView;
|
|
private boolean isDismissing;
|
|
private boolean onSideToDismiss;
|
|
private Runnable progressRunnable = () -> {
|
|
if (photoViewer == null) {
|
|
return;
|
|
}
|
|
VideoPlayer videoPlayer = photoViewer.getVideoPlayer();
|
|
if (videoPlayer == null) {
|
|
return;
|
|
}
|
|
videoProgress = videoPlayer.getCurrentPosition() / (float) videoPlayer.getDuration();
|
|
if (photoViewer == null) {
|
|
bufferProgress = videoPlayer.getBufferedPosition() / (float) videoPlayer.getDuration();
|
|
}
|
|
videoProgressView.invalidate();
|
|
|
|
AndroidUtilities.runOnUIThread(this.progressRunnable, 500);
|
|
};
|
|
private boolean canLongClick;
|
|
private float[] longClickStartPoint = new float[2];
|
|
private Runnable longClickCallback = this::onLongClick;
|
|
|
|
private boolean postedDismissControls;
|
|
private Runnable dismissControlsCallback = () -> {
|
|
if (photoViewer != null && photoViewer.getVideoPlayerRewinder().rewindCount > 0) {
|
|
AndroidUtilities.runOnUIThread(this.dismissControlsCallback, 1500);
|
|
return;
|
|
}
|
|
toggleControls(isShowingControls = false);
|
|
postedDismissControls = false;
|
|
};
|
|
|
|
public static void onRewindCanceled() {
|
|
instance.onRewindCanceledInternal();
|
|
}
|
|
|
|
private void onRewindCanceledInternal() {
|
|
videoForwardDrawable.setShowing(false);
|
|
}
|
|
|
|
public static void onUpdateRewindProgressUi(long timeDiff, float progress, boolean rewindByBackSeek) {
|
|
instance.onUpdateRewindProgressUiInternal(timeDiff, progress, rewindByBackSeek);
|
|
}
|
|
|
|
private void onUpdateRewindProgressUiInternal(long timeDiff, float progress, boolean rewindByBackSeek) {
|
|
videoForwardDrawable.setTime(0);
|
|
if (rewindByBackSeek) {
|
|
videoProgress = progress;
|
|
|
|
if (videoProgressView != null) {
|
|
videoProgressView.invalidate();
|
|
}
|
|
if (controlsView != null) {
|
|
controlsView.invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void onRewindStart(boolean rewindForward) {
|
|
instance.onRewindStartInternal(rewindForward);
|
|
}
|
|
|
|
private void onRewindStartInternal(boolean rewindForward) {
|
|
videoForwardDrawable.setOneShootAnimation(false);
|
|
videoForwardDrawable.setLeftSide(!rewindForward);
|
|
videoForwardDrawable.setShowing(true);
|
|
if (videoProgressView != null) {
|
|
videoProgressView.invalidate();
|
|
}
|
|
if (controlsView != null) {
|
|
controlsView.invalidate();
|
|
}
|
|
}
|
|
|
|
protected void onLongClick() {
|
|
if (photoViewer == null || photoViewer.getVideoPlayer() == null || isDismissing || isVideoCompleted || isScrolling || scaleGestureDetector.isInProgress() || !canLongClick) {
|
|
return;
|
|
}
|
|
|
|
VideoPlayer videoPlayer = photoViewer.getVideoPlayer();
|
|
boolean forward = longClickStartPoint[0] >= getSuggestedWidth() * scaleFactor * 0.5f;
|
|
|
|
long current = videoPlayer.getCurrentPosition();
|
|
long total = videoPlayer.getDuration();
|
|
if (current == C.TIME_UNSET || total < 15 * 1000) {
|
|
return;
|
|
}
|
|
|
|
photoViewer.getVideoPlayerRewinder().startRewind(videoPlayer, forward, photoViewer.getCurrentVideoSpeed());
|
|
|
|
if (!isShowingControls) {
|
|
toggleControls(isShowingControls = true);
|
|
if (!postedDismissControls) {
|
|
AndroidUtilities.runOnUIThread(dismissControlsCallback, 1500);
|
|
postedDismissControls = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private PipConfig getPipConfig() {
|
|
if (pipConfig == null) {
|
|
pipConfig = new PipConfig(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y);
|
|
}
|
|
return pipConfig;
|
|
}
|
|
|
|
public static boolean isVisible() {
|
|
return instance.isVisible;
|
|
}
|
|
|
|
private int getSuggestedWidth() {
|
|
return getSuggestedWidth(getRatio());
|
|
}
|
|
|
|
private static int getSuggestedWidth(float ratio) {
|
|
if (ratio >= 1) {
|
|
return (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.35f);
|
|
}
|
|
return (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.6f);
|
|
}
|
|
|
|
private int getSuggestedHeight() {
|
|
return getSuggestedHeight(getRatio());
|
|
}
|
|
|
|
private static int getSuggestedHeight(float ratio) {
|
|
return (int) (getSuggestedWidth(ratio) * ratio);
|
|
}
|
|
|
|
private float getRatio() {
|
|
if (aspectRatio == null) {
|
|
aspectRatio = mVideoHeight / (float) mVideoWidth;
|
|
|
|
maxScaleFactor = (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(SIDE_PADDING_DP * 2)) / (float) getSuggestedWidth();
|
|
videoForwardDrawable.setPlayScaleFactor(aspectRatio < 1 ? 0.6f : 0.45f);
|
|
}
|
|
return aspectRatio;
|
|
}
|
|
|
|
private void toggleControls(boolean show) {
|
|
controlsAnimator = ValueAnimator.ofFloat(show ? 0 : 1, show ? 1 : 0f).setDuration(200);
|
|
controlsAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
controlsAnimator.addUpdateListener(animation -> {
|
|
float value = (float) animation.getAnimatedValue();
|
|
controlsView.setAlpha(value);
|
|
});
|
|
controlsAnimator.addListener(new AnimatorListenerAdapter() {
|
|
@Override
|
|
public void onAnimationEnd(Animator animation) {
|
|
controlsAnimator = null;
|
|
}
|
|
});
|
|
controlsAnimator.start();
|
|
}
|
|
|
|
public static void dimissAndDestroy() {
|
|
if (instance.parentSheet != null) {
|
|
instance.parentSheet.destroy();
|
|
} else if (instance.photoViewer != null) {
|
|
instance.photoViewer.destroyPhotoViewer();
|
|
}
|
|
dismiss();
|
|
}
|
|
|
|
public static void dismiss() {
|
|
dismiss(false);
|
|
}
|
|
|
|
public static void dismiss(boolean animate) {
|
|
instance.dismissInternal(animate);
|
|
}
|
|
|
|
private void dismissInternal(boolean animate) {
|
|
if (isDismissing) {
|
|
return;
|
|
}
|
|
isDismissing = true;
|
|
|
|
if (controlsAnimator != null) {
|
|
controlsAnimator.cancel();
|
|
}
|
|
|
|
if (postedDismissControls) {
|
|
AndroidUtilities.cancelRunOnUIThread(dismissControlsCallback);
|
|
postedDismissControls = false;
|
|
}
|
|
|
|
if (pipXSpring != null) {
|
|
pipXSpring.cancel();
|
|
pipYSpring.cancel();
|
|
}
|
|
|
|
// Animate is a flag for PhotoViewer transition, not ours
|
|
if (animate) {
|
|
AndroidUtilities.runOnUIThread(this::onDismissedInternal, 100);
|
|
} else {
|
|
AnimatorSet set = new AnimatorSet();
|
|
set.setDuration(250);
|
|
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
set.playTogether(
|
|
ObjectAnimator.ofFloat(contentView, View.ALPHA, 0f),
|
|
ObjectAnimator.ofFloat(contentView, View.SCALE_X, 0.1f),
|
|
ObjectAnimator.ofFloat(contentView, View.SCALE_Y, 0.1f)
|
|
);
|
|
set.addListener(new AnimatorListenerAdapter() {
|
|
@Override
|
|
public void onAnimationEnd(Animator animation) {
|
|
onDismissedInternal();
|
|
}
|
|
});
|
|
set.start();
|
|
}
|
|
}
|
|
|
|
private void onDismissedInternal() {
|
|
try {
|
|
if (controlsView.getParent() != null) {
|
|
windowManager.removeViewImmediate(contentView);
|
|
}
|
|
} catch (IllegalArgumentException ignored) {}
|
|
|
|
videoProgressView = null;
|
|
innerView = null;
|
|
photoViewer = null;
|
|
parentSheet = null;
|
|
consumingChild = null;
|
|
isScrolling = false;
|
|
isVisible = false;
|
|
isDismissing = false;
|
|
canLongClick = false;
|
|
|
|
cancelRewind();
|
|
AndroidUtilities.cancelRunOnUIThread(longClickCallback);
|
|
}
|
|
|
|
private void cancelRewind() {
|
|
if (photoViewer == null) {
|
|
return;
|
|
}
|
|
|
|
if (photoViewer.getVideoPlayerRewinder().rewindCount > 0) {
|
|
photoViewer.getVideoPlayerRewinder().cancelRewind();
|
|
}
|
|
}
|
|
|
|
public static void updatePlayButton() {
|
|
instance.updatePlayButtonInternal();
|
|
}
|
|
|
|
private void updatePlayButtonInternal() {
|
|
if (photoViewer == null) {
|
|
return;
|
|
}
|
|
VideoPlayer videoPlayer = photoViewer.getVideoPlayer();
|
|
if (videoPlayer == null || playPauseButton == null) {
|
|
return;
|
|
}
|
|
AndroidUtilities.cancelRunOnUIThread(progressRunnable);
|
|
if (!videoPlayer.isPlaying()) {
|
|
if (isVideoCompleted) {
|
|
playPauseButton.setImageResource(R.drawable.pip_replay_large);
|
|
} else {
|
|
playPauseButton.setImageResource(R.drawable.pip_play_large);
|
|
}
|
|
} else {
|
|
playPauseButton.setImageResource(R.drawable.pip_pause_large);
|
|
AndroidUtilities.runOnUIThread(progressRunnable, 500);
|
|
}
|
|
}
|
|
|
|
public static void onVideoCompleted() {
|
|
instance.onVideoCompletedInternal();
|
|
}
|
|
|
|
private void onVideoCompletedInternal() {
|
|
if (!isVisible || videoProgressView == null) {
|
|
return;
|
|
}
|
|
isVideoCompleted = true;
|
|
videoProgress = 0f;
|
|
bufferProgress = 0f;
|
|
if (videoProgressView != null) {
|
|
videoProgressView.invalidate();
|
|
}
|
|
|
|
updatePlayButtonInternal();
|
|
AndroidUtilities.cancelRunOnUIThread(progressRunnable);
|
|
if (!isShowingControls) {
|
|
toggleControls(true);
|
|
AndroidUtilities.cancelRunOnUIThread(dismissControlsCallback);
|
|
}
|
|
}
|
|
|
|
public static void setBufferedProgress(float progress) {
|
|
instance.bufferProgress = progress;
|
|
if (instance.videoProgressView != null) {
|
|
instance.videoProgressView.invalidate();
|
|
}
|
|
}
|
|
|
|
public static void setParentSheet(EmbedBottomSheet parentSheet) {
|
|
instance.parentSheet = parentSheet;
|
|
}
|
|
|
|
public static void setPhotoViewer(PhotoViewer photoViewer) {
|
|
instance.photoViewer = photoViewer;
|
|
instance.updatePlayButtonInternal();
|
|
}
|
|
|
|
public static Rect getPipRect(boolean inAnimation, float aspectRatio) {
|
|
Rect rect = new Rect();
|
|
float ratio = 1f / aspectRatio;
|
|
if (!instance.isVisible || inAnimation) {
|
|
float savedPipX = instance.getPipConfig().getPipX(), savedPipY = instance.getPipConfig().getPipY();
|
|
float scaleFactor = instance.getPipConfig().getScaleFactor();
|
|
|
|
rect.width = getSuggestedWidth(ratio) * scaleFactor;
|
|
rect.height = getSuggestedHeight(ratio) * scaleFactor;
|
|
if (savedPipX != -1) {
|
|
rect.x = savedPipX + rect.width / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - rect.width - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP);
|
|
} else {
|
|
rect.x = AndroidUtilities.displaySize.x - rect.width - AndroidUtilities.dp(SIDE_PADDING_DP);
|
|
}
|
|
if (savedPipY != -1) {
|
|
rect.y = MathUtils.clamp(savedPipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - AndroidUtilities.dp(SIDE_PADDING_DP) - rect.height) + AndroidUtilities.statusBarHeight;
|
|
} else {
|
|
rect.y = AndroidUtilities.dp(SIDE_PADDING_DP) + AndroidUtilities.statusBarHeight;
|
|
}
|
|
return rect;
|
|
}
|
|
|
|
rect.x = instance.pipX;
|
|
rect.y = instance.pipY + AndroidUtilities.statusBarHeight;
|
|
rect.width = instance.pipWidth;
|
|
rect.height = instance.pipHeight;
|
|
return rect;
|
|
}
|
|
|
|
public static boolean show(boolean inAppOnly, Activity activity, View pipContentView, int videoWidth, int videoHeight) {
|
|
return show(inAppOnly, activity, pipContentView, videoWidth, videoHeight, false);
|
|
}
|
|
|
|
public static boolean show(boolean inAppOnly, Activity activity, View pipContentView, int videoWidth, int videoHeight, boolean animate) {
|
|
return instance.showInternal(inAppOnly, activity, pipContentView, videoWidth, videoHeight, animate);
|
|
}
|
|
|
|
private boolean showInternal(boolean inAppOnly, Activity activity, View pipContentView, int videoWidth, int videoHeight, boolean animate) {
|
|
if (isVisible) {
|
|
return false;
|
|
}
|
|
isVisible = true;
|
|
|
|
mVideoWidth = videoWidth;
|
|
mVideoHeight = videoHeight;
|
|
aspectRatio = null;
|
|
|
|
float savedPipX = getPipConfig().getPipX(), savedPipY = getPipConfig().getPipY();
|
|
scaleFactor = getPipConfig().getScaleFactor();
|
|
|
|
pipWidth = (int) (getSuggestedWidth() * scaleFactor);
|
|
pipHeight = (int) (getSuggestedHeight() * scaleFactor);
|
|
isShowingControls = false;
|
|
|
|
float stiffness = 650f;
|
|
pipXSpring = new SpringAnimation(this, PIP_X_PROPERTY)
|
|
.setSpring(new SpringForce()
|
|
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
|
|
.setStiffness(stiffness))
|
|
.addEndListener((animation, canceled, value, velocity) -> getPipConfig().setPipX(value));
|
|
pipYSpring = new SpringAnimation(this, PIP_Y_PROPERTY)
|
|
.setSpring(new SpringForce()
|
|
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
|
|
.setStiffness(stiffness))
|
|
.addEndListener((animation, canceled, value, velocity) -> getPipConfig().setPipY(value));
|
|
|
|
Context context = ApplicationLoader.applicationContext;
|
|
int touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
|
scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.OnScaleGestureListener() {
|
|
@Override
|
|
public boolean onScale(ScaleGestureDetector detector) {
|
|
scaleFactor = MathUtils.clamp(scaleFactor * detector.getScaleFactor(), minScaleFactor, maxScaleFactor);
|
|
pipWidth = (int) (getSuggestedWidth() * scaleFactor);
|
|
pipHeight = (int) (getSuggestedHeight() * scaleFactor);
|
|
AndroidUtilities.runOnUIThread(()->{
|
|
contentView.invalidate();
|
|
contentFrameLayout.requestLayout();
|
|
});
|
|
|
|
float finalX = detector.getFocusX() >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP);
|
|
if (!pipXSpring.isRunning()) {
|
|
pipXSpring.setStartValue(pipX)
|
|
.getSpring()
|
|
.setFinalPosition(finalX);
|
|
} else {
|
|
pipXSpring.getSpring().setFinalPosition(finalX);
|
|
}
|
|
pipXSpring.start();
|
|
|
|
float finalY = MathUtils.clamp(detector.getFocusY() - pipHeight / 2f, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - pipHeight - AndroidUtilities.dp(SIDE_PADDING_DP));
|
|
if (!pipYSpring.isRunning()) {
|
|
pipYSpring.setStartValue(pipY)
|
|
.getSpring()
|
|
.setFinalPosition(finalY);
|
|
} else {
|
|
pipYSpring.getSpring().setFinalPosition(finalY);
|
|
}
|
|
pipYSpring.start();
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onScaleBegin(ScaleGestureDetector detector) {
|
|
if (isScrolling) {
|
|
isScrolling = false;
|
|
canLongClick = false;
|
|
cancelRewind();
|
|
AndroidUtilities.cancelRunOnUIThread(longClickCallback);
|
|
}
|
|
isScrollDisallowed = true;
|
|
windowLayoutParams.width = (int) (getSuggestedWidth() * maxScaleFactor);
|
|
windowLayoutParams.height = (int) (getSuggestedHeight() * maxScaleFactor);
|
|
windowManager.updateViewLayout(contentView, windowLayoutParams);
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void onScaleEnd(ScaleGestureDetector detector) {
|
|
if (pipXSpring.isRunning() || pipYSpring.isRunning()) {
|
|
List<SpringAnimation> springs = new ArrayList<>();
|
|
DynamicAnimation.OnAnimationEndListener endListener = new DynamicAnimation.OnAnimationEndListener() {
|
|
@Override
|
|
public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) {
|
|
animation.removeEndListener(this);
|
|
|
|
springs.add((SpringAnimation) animation);
|
|
if (springs.size() == 2) {
|
|
updateLayout();
|
|
}
|
|
}
|
|
};
|
|
if (!pipXSpring.isRunning()) {
|
|
springs.add(pipXSpring);
|
|
} else {
|
|
pipXSpring.addEndListener(endListener);
|
|
}
|
|
if (!pipYSpring.isRunning()) {
|
|
springs.add(pipYSpring);
|
|
} else {
|
|
pipYSpring.addEndListener(endListener);
|
|
}
|
|
return;
|
|
}
|
|
updateLayout();
|
|
}
|
|
|
|
private void updateLayout() {
|
|
pipWidth = windowLayoutParams.width = (int) (getSuggestedWidth() * scaleFactor);
|
|
pipHeight = windowLayoutParams.height = (int) (getSuggestedHeight() * scaleFactor);
|
|
try {
|
|
windowManager.updateViewLayout(contentView, windowLayoutParams);
|
|
} catch (IllegalArgumentException ignored) {}
|
|
}
|
|
});
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
|
scaleGestureDetector.setQuickScaleEnabled(false);
|
|
}
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
scaleGestureDetector.setStylusScaleEnabled(false);
|
|
}
|
|
gestureDetector = new GestureDetectorFixDoubleTap(context, new GestureDetectorFixDoubleTap.OnGestureListener() {
|
|
private float startPipX, startPipY;
|
|
|
|
@Override
|
|
public boolean onDown(MotionEvent e) {
|
|
if (isShowingControls) {
|
|
for (int i = 1; i < contentFrameLayout.getChildCount(); i++) {
|
|
View child = contentFrameLayout.getChildAt(i);
|
|
boolean consumed = child.dispatchTouchEvent(e);
|
|
if (consumed) {
|
|
consumingChild = child;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
startPipX = pipX;
|
|
startPipY = pipY;
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onSingleTapConfirmed(MotionEvent e) {
|
|
if (controlsAnimator != null) {
|
|
return true;
|
|
}
|
|
|
|
if (postedDismissControls) {
|
|
AndroidUtilities.cancelRunOnUIThread(dismissControlsCallback);
|
|
postedDismissControls = false;
|
|
}
|
|
|
|
isShowingControls = !isShowingControls;
|
|
toggleControls(isShowingControls);
|
|
|
|
if (isShowingControls && !postedDismissControls) {
|
|
AndroidUtilities.runOnUIThread(dismissControlsCallback, 2500);
|
|
postedDismissControls = true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onDoubleTap(MotionEvent e) {
|
|
if (photoViewer == null || photoViewer.getVideoPlayer() == null || isDismissing || isVideoCompleted || isScrolling || scaleGestureDetector.isInProgress() || !canLongClick) {
|
|
return false;
|
|
}
|
|
|
|
VideoPlayer videoPlayer = photoViewer.getVideoPlayer();
|
|
boolean forward = e.getX() >= getSuggestedWidth() * scaleFactor * 0.5f;
|
|
|
|
long current = videoPlayer.getCurrentPosition();
|
|
long total = videoPlayer.getDuration();
|
|
if (current == C.TIME_UNSET || total < 15 * 1000) {
|
|
return false;
|
|
}
|
|
|
|
long old = current;
|
|
if (forward) {
|
|
current += 10000;
|
|
} else {
|
|
current -= 10000;
|
|
}
|
|
if (old != current) {
|
|
boolean apply = true;
|
|
if (current > total) {
|
|
current = total;
|
|
} else if (current < 0) {
|
|
if (current < -9000) {
|
|
apply = false;
|
|
}
|
|
current = 0;
|
|
}
|
|
if (apply) {
|
|
videoForwardDrawable.setOneShootAnimation(true);
|
|
videoForwardDrawable.setLeftSide(!forward);
|
|
videoForwardDrawable.addTime(10000);
|
|
videoPlayer.seekTo(current);
|
|
onUpdateRewindProgressUiInternal(forward ? 10000 : -10000, current / (float) total, true);
|
|
if (!isShowingControls) {
|
|
toggleControls(isShowingControls = true);
|
|
if (!postedDismissControls) {
|
|
postedDismissControls = true;
|
|
AndroidUtilities.runOnUIThread(dismissControlsCallback, 2500);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean onSingleTapUp(MotionEvent e) {
|
|
if (!hasDoubleTap()) {
|
|
return onSingleTapConfirmed(e);
|
|
}
|
|
return super.onSingleTapUp(e);
|
|
}
|
|
|
|
@Override
|
|
public boolean hasDoubleTap() {
|
|
if (photoViewer == null || photoViewer.getVideoPlayer() == null || isDismissing || isVideoCompleted || isScrolling || scaleGestureDetector.isInProgress() || !canLongClick) {
|
|
return false;
|
|
}
|
|
|
|
VideoPlayer videoPlayer = photoViewer.getVideoPlayer();
|
|
|
|
long current = videoPlayer.getCurrentPosition();
|
|
long total = videoPlayer.getDuration();
|
|
return current != C.TIME_UNSET && total >= 15 * 1000;
|
|
}
|
|
|
|
@Override
|
|
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
|
if (isScrolling && !isScrollDisallowed) {
|
|
pipXSpring.setStartVelocity(velocityX)
|
|
.setStartValue(pipX)
|
|
.getSpring()
|
|
.setFinalPosition(pipX + pipWidth / 2f + velocityX / 7f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP));
|
|
pipXSpring.start();
|
|
|
|
pipYSpring.setStartVelocity(velocityX)
|
|
.setStartValue(pipY)
|
|
.getSpring()
|
|
.setFinalPosition(MathUtils.clamp(pipY + velocityY / 10f, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - pipHeight - AndroidUtilities.dp(SIDE_PADDING_DP)));
|
|
pipYSpring.start();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
|
if (!isScrolling && controlsAnimator == null && !isScrollDisallowed) {
|
|
if (Math.abs(distanceX) >= touchSlop || Math.abs(distanceY) >= touchSlop) {
|
|
isScrolling = true;
|
|
|
|
pipXSpring.cancel();
|
|
pipYSpring.cancel();
|
|
|
|
canLongClick = false;
|
|
cancelRewind();
|
|
AndroidUtilities.cancelRunOnUIThread(longClickCallback);
|
|
}
|
|
}
|
|
if (isScrolling) {
|
|
float wasPipX = pipX;
|
|
float newPipX = startPipX + e2.getRawX() - e1.getRawX();
|
|
pipY = startPipY + e2.getRawY() - e1.getRawY();
|
|
if (newPipX <= -pipWidth * 0.25f || newPipX >= AndroidUtilities.displaySize.x - pipWidth * 0.75f) {
|
|
if (!onSideToDismiss) {
|
|
pipXSpring.setStartValue(wasPipX)
|
|
.getSpring()
|
|
.setFinalPosition(newPipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP) - pipWidth);
|
|
pipXSpring.start();
|
|
}
|
|
onSideToDismiss = true;
|
|
} else if (onSideToDismiss) {
|
|
if (onSideToDismiss) {
|
|
pipXSpring.addEndListener((animation, canceled, value, velocity) -> {
|
|
if (!canceled) {
|
|
pipXSpring.getSpring().setFinalPosition(newPipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP));
|
|
}
|
|
});
|
|
|
|
pipXSpring.setStartValue(wasPipX)
|
|
.getSpring()
|
|
.setFinalPosition(newPipX);
|
|
pipXSpring.start();
|
|
}
|
|
onSideToDismiss = false;
|
|
} else {
|
|
if (pipXSpring.isRunning()) {
|
|
pipXSpring.getSpring().setFinalPosition(newPipX);
|
|
} else {
|
|
windowLayoutParams.x = (int) (pipX = newPipX);
|
|
getPipConfig().setPipX(newPipX);
|
|
}
|
|
windowLayoutParams.y = (int) pipY;
|
|
getPipConfig().setPipY(pipY);
|
|
windowManager.updateViewLayout(contentView, windowLayoutParams);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
contentFrameLayout = new FrameLayout(context) {
|
|
private Path path = new Path();
|
|
|
|
@Override
|
|
public boolean dispatchTouchEvent(MotionEvent ev) {
|
|
int action = ev.getActionMasked();
|
|
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
|
|
if (ev.getPointerCount() == 1) {
|
|
canLongClick = true;
|
|
longClickStartPoint = new float[]{ev.getX(), ev.getY()};
|
|
AndroidUtilities.runOnUIThread(longClickCallback, 500);
|
|
} else {
|
|
canLongClick = false;
|
|
cancelRewind();
|
|
AndroidUtilities.cancelRunOnUIThread(longClickCallback);
|
|
}
|
|
}
|
|
|
|
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_POINTER_UP) {
|
|
canLongClick = false;
|
|
cancelRewind();
|
|
AndroidUtilities.cancelRunOnUIThread(longClickCallback);
|
|
}
|
|
|
|
if (consumingChild != null) {
|
|
MotionEvent newEvent = MotionEvent.obtain(ev);
|
|
newEvent.offsetLocation(consumingChild.getX(), consumingChild.getY());
|
|
boolean consumed = consumingChild.dispatchTouchEvent(ev);
|
|
newEvent.recycle();
|
|
|
|
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_POINTER_UP) {
|
|
consumingChild = null;
|
|
}
|
|
|
|
if (consumed) {
|
|
return true;
|
|
}
|
|
}
|
|
MotionEvent temp = MotionEvent.obtain(ev);
|
|
temp.offsetLocation(ev.getRawX() - ev.getX(), ev.getRawY() - ev.getY());
|
|
boolean scaleDetector = scaleGestureDetector.onTouchEvent(temp);
|
|
temp.recycle();
|
|
boolean detector = !scaleGestureDetector.isInProgress() && gestureDetector.onTouchEvent(ev);
|
|
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_POINTER_UP) {
|
|
isScrolling = false;
|
|
isScrollDisallowed = false;
|
|
|
|
if (onSideToDismiss) {
|
|
onSideToDismiss = false;
|
|
|
|
dimissAndDestroy();
|
|
} else {
|
|
if (!pipXSpring.isRunning()) {
|
|
pipXSpring.setStartValue(pipX)
|
|
.getSpring()
|
|
.setFinalPosition(pipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP));
|
|
pipXSpring.start();
|
|
}
|
|
|
|
if (!pipYSpring.isRunning()) {
|
|
pipYSpring.setStartValue(pipY)
|
|
.getSpring()
|
|
.setFinalPosition(MathUtils.clamp(pipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - pipHeight - AndroidUtilities.dp(SIDE_PADDING_DP)));
|
|
pipYSpring.start();
|
|
}
|
|
}
|
|
}
|
|
return scaleDetector || detector;
|
|
}
|
|
|
|
@Override
|
|
protected void onConfigurationChanged(Configuration newConfig) {
|
|
AndroidUtilities.checkDisplaySize(getContext(), newConfig);
|
|
pipConfig = null;
|
|
|
|
if (pipWidth != getSuggestedWidth() * scaleFactor || pipHeight != getSuggestedHeight() * scaleFactor) {
|
|
windowLayoutParams.width = pipWidth = (int) (getSuggestedWidth() * scaleFactor);
|
|
windowLayoutParams.height = pipHeight = (int) (getSuggestedHeight() * scaleFactor);
|
|
windowManager.updateViewLayout(contentView, windowLayoutParams);
|
|
|
|
pipXSpring.setStartValue(pipX)
|
|
.getSpring()
|
|
.setFinalPosition(pipX + (getSuggestedWidth() * scaleFactor) / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - (getSuggestedWidth() * scaleFactor) - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP));
|
|
pipXSpring.start();
|
|
|
|
pipYSpring.setStartValue(pipY)
|
|
.getSpring()
|
|
.setFinalPosition(MathUtils.clamp(pipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - (getSuggestedHeight() * scaleFactor) - AndroidUtilities.dp(SIDE_PADDING_DP)));
|
|
pipYSpring.start();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void draw(Canvas canvas) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
super.draw(canvas);
|
|
} else {
|
|
canvas.save();
|
|
canvas.clipPath(path);
|
|
super.draw(canvas);
|
|
canvas.restore();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
|
super.onSizeChanged(w, h, oldw, oldh);
|
|
|
|
path.rewind();
|
|
AndroidUtilities.rectTmp.set(0, 0, w, h);
|
|
path.addRoundRect(AndroidUtilities.rectTmp, AndroidUtilities.dp(ROUNDED_CORNERS_DP), AndroidUtilities.dp(ROUNDED_CORNERS_DP), Path.Direction.CW);
|
|
}
|
|
};
|
|
contentView = new ViewGroup(context) {
|
|
@Override
|
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
contentFrameLayout.layout(0, 0, pipWidth, pipHeight);
|
|
}
|
|
|
|
@Override
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
|
|
contentFrameLayout.measure(MeasureSpec.makeMeasureSpec(pipWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(pipHeight, MeasureSpec.EXACTLY));
|
|
}
|
|
|
|
@Override
|
|
public void draw(Canvas canvas) {
|
|
canvas.save();
|
|
canvas.scale(pipWidth / (float)contentFrameLayout.getWidth(), pipHeight / (float)contentFrameLayout.getHeight());
|
|
super.draw(canvas);
|
|
canvas.restore();
|
|
}
|
|
};
|
|
contentView.addView(contentFrameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
contentFrameLayout.setOutlineProvider(new ViewOutlineProvider() {
|
|
@Override
|
|
public void getOutline(View view, Outline outline) {
|
|
outline.setRoundRect(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight(), AndroidUtilities.dp(ROUNDED_CORNERS_DP));
|
|
}
|
|
});
|
|
contentFrameLayout.setClipToOutline(true);
|
|
}
|
|
contentFrameLayout.setBackgroundColor(Theme.getColor(Theme.key_voipgroup_actionBar));
|
|
|
|
innerView = pipContentView;
|
|
if (innerView.getParent() != null) {
|
|
((ViewGroup)innerView.getParent()).removeView(innerView);
|
|
}
|
|
contentFrameLayout.addView(innerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
|
|
|
videoForwardDrawable.setDelegate(new VideoForwardDrawable.VideoForwardDrawableDelegate() {
|
|
@Override
|
|
public void onAnimationEnd() {}
|
|
|
|
@Override
|
|
public void invalidate() {
|
|
controlsView.invalidate();
|
|
}
|
|
});
|
|
controlsView = new FrameLayout(context) {
|
|
@Override
|
|
protected void onDraw(Canvas canvas) {
|
|
if (videoForwardDrawable.isAnimating()) {
|
|
videoForwardDrawable.setBounds(getLeft(), getTop(), getRight(), getBottom());
|
|
videoForwardDrawable.draw(canvas);
|
|
}
|
|
}
|
|
};
|
|
controlsView.setWillNotDraw(false);
|
|
controlsView.setAlpha(0f);
|
|
View scrim = new View(context);
|
|
scrim.setBackgroundColor(0x4C000000);
|
|
controlsView.addView(scrim, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
|
|
|
int padding = AndroidUtilities.dp(8);
|
|
int margin = 4;
|
|
int buttonSize = 38;
|
|
|
|
ImageView closeButton = new ImageView(context);
|
|
closeButton.setImageResource(R.drawable.pip_video_close);
|
|
closeButton.setColorFilter(Theme.getColor(Theme.key_voipgroup_actionBarItems), PorterDuff.Mode.MULTIPLY);
|
|
closeButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector)));
|
|
closeButton.setPadding(padding, padding, padding, padding);
|
|
closeButton.setOnClickListener(v -> dimissAndDestroy());
|
|
controlsView.addView(closeButton, LayoutHelper.createFrame(buttonSize, buttonSize, Gravity.RIGHT, 0, margin, margin, 0));
|
|
|
|
ImageView expandButton = new ImageView(context);
|
|
expandButton.setImageResource(R.drawable.pip_video_expand);
|
|
expandButton.setColorFilter(Theme.getColor(Theme.key_voipgroup_actionBarItems), PorterDuff.Mode.MULTIPLY);
|
|
expandButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector)));
|
|
expandButton.setPadding(padding, padding, padding, padding);
|
|
expandButton.setOnClickListener(v -> {
|
|
boolean isResumedByActivityManager = true;
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
ActivityManager activityManager = (ActivityManager) v.getContext().getSystemService(Context.ACTIVITY_SERVICE);
|
|
List<ActivityManager.RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses();
|
|
if (!appProcessInfos.isEmpty()) {
|
|
isResumedByActivityManager = appProcessInfos.get(0).importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
|
|
}
|
|
}
|
|
|
|
if (!inAppOnly && (!isResumedByActivityManager || !LaunchActivity.isResumed)) {
|
|
LaunchActivity.onResumeStaticCallback = v::callOnClick;
|
|
|
|
Context ctx = ApplicationLoader.applicationContext;
|
|
Intent intent = new Intent(ctx, LaunchActivity.class);
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
ctx.startActivity(intent);
|
|
} else {
|
|
if (parentSheet != null) {
|
|
parentSheet.exitFromPip();
|
|
} else if (photoViewer != null) {
|
|
photoViewer.exitFromPip();
|
|
}
|
|
}
|
|
});
|
|
controlsView.addView(expandButton, LayoutHelper.createFrame(buttonSize, buttonSize, Gravity.RIGHT, 0, margin, buttonSize + margin + 6, 0));
|
|
|
|
playPauseButton = new ImageView(context);
|
|
playPauseButton.setColorFilter(Theme.getColor(Theme.key_voipgroup_actionBarItems), PorterDuff.Mode.MULTIPLY);
|
|
playPauseButton.setBackground(Theme.createSelectorDrawable(Theme.getColor(Theme.key_listSelector)));
|
|
playPauseButton.setOnClickListener(v -> {
|
|
if (photoViewer == null) {
|
|
return;
|
|
}
|
|
VideoPlayer videoPlayer = photoViewer.getVideoPlayer();
|
|
if (videoPlayer == null) {
|
|
return;
|
|
}
|
|
if (videoPlayer.isPlaying()) {
|
|
videoPlayer.pause();
|
|
} else {
|
|
videoPlayer.play();
|
|
}
|
|
updatePlayButton();
|
|
});
|
|
playPauseButton.setVisibility(innerView instanceof WebView ? View.GONE : View.VISIBLE);
|
|
controlsView.addView(playPauseButton, LayoutHelper.createFrame(buttonSize, buttonSize, Gravity.CENTER));
|
|
|
|
videoProgressView = new VideoProgressView(context);
|
|
controlsView.addView(videoProgressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
|
|
|
contentFrameLayout.addView(controlsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
|
|
|
|
windowManager = (WindowManager) (inAppOnly ? activity : ApplicationLoader.applicationContext).getSystemService(Context.WINDOW_SERVICE);
|
|
|
|
windowLayoutParams = createWindowLayoutParams(inAppOnly);
|
|
windowLayoutParams.width = pipWidth;
|
|
windowLayoutParams.height = pipHeight;
|
|
if (savedPipX != -1) {
|
|
windowLayoutParams.x = (int) (pipX = savedPipX + pipWidth / 2f >= AndroidUtilities.displaySize.x / 2f ? AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP) : AndroidUtilities.dp(SIDE_PADDING_DP));
|
|
} else {
|
|
windowLayoutParams.x = (int) (pipX = AndroidUtilities.displaySize.x - pipWidth - AndroidUtilities.dp(SIDE_PADDING_DP));
|
|
}
|
|
if (savedPipY != -1) {
|
|
windowLayoutParams.y = (int) (pipY = MathUtils.clamp(savedPipY, AndroidUtilities.dp(SIDE_PADDING_DP), AndroidUtilities.displaySize.y - AndroidUtilities.dp(SIDE_PADDING_DP) - pipHeight));
|
|
} else {
|
|
windowLayoutParams.y = (int) (pipY = AndroidUtilities.dp(SIDE_PADDING_DP));
|
|
}
|
|
windowLayoutParams.dimAmount = 0f;
|
|
windowLayoutParams.flags = FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
|
|
|
|
// Animate is a flag for PhotoViewer transition, not ours
|
|
if (animate) {
|
|
windowManager.addView(contentView, windowLayoutParams);
|
|
} else {
|
|
contentView.setAlpha(0f);
|
|
contentView.setScaleX(0.1f);
|
|
contentView.setScaleY(0.1f);
|
|
windowManager.addView(contentView, windowLayoutParams);
|
|
|
|
AnimatorSet set = new AnimatorSet();
|
|
set.setDuration(250);
|
|
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
|
|
set.playTogether(
|
|
ObjectAnimator.ofFloat(contentView, View.ALPHA, 1f),
|
|
ObjectAnimator.ofFloat(contentView, View.SCALE_X, 1f),
|
|
ObjectAnimator.ofFloat(contentView, View.SCALE_Y, 1f)
|
|
);
|
|
set.start();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@SuppressLint("WrongConstant")
|
|
private WindowManager.LayoutParams createWindowLayoutParams(boolean inAppOnly) {
|
|
WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams();
|
|
windowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
|
windowLayoutParams.format = PixelFormat.TRANSLUCENT;
|
|
|
|
if (!inAppOnly && AndroidUtilities.checkInlinePermissions(ApplicationLoader.applicationContext)) {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
windowLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
|
} else {
|
|
windowLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
|
|
}
|
|
} else {
|
|
windowLayoutParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
|
|
}
|
|
|
|
windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
|
|
|
|
return windowLayoutParams;
|
|
}
|
|
|
|
private final class VideoProgressView extends View {
|
|
private Paint progressPaint = new Paint(), bufferPaint = new Paint();
|
|
|
|
public VideoProgressView(Context context) {
|
|
super(context);
|
|
|
|
progressPaint.setColor(Color.WHITE);
|
|
progressPaint.setStyle(Paint.Style.STROKE);
|
|
progressPaint.setStrokeCap(Paint.Cap.ROUND);
|
|
progressPaint.setStrokeWidth(AndroidUtilities.dp(2));
|
|
bufferPaint.setColor(progressPaint.getColor());
|
|
bufferPaint.setAlpha((int) (progressPaint.getAlpha() * 0.3f));
|
|
bufferPaint.setStyle(Paint.Style.STROKE);
|
|
bufferPaint.setStrokeCap(Paint.Cap.ROUND);
|
|
bufferPaint.setStrokeWidth(AndroidUtilities.dp(2));
|
|
}
|
|
|
|
@Override
|
|
protected void onDraw(Canvas canvas) {
|
|
super.onDraw(canvas);
|
|
|
|
int width = getWidth();
|
|
|
|
int progressSidePadding = AndroidUtilities.dp(10);
|
|
|
|
int progressLeft = progressSidePadding;
|
|
int progressRight = progressLeft + (int) ((width - progressLeft - progressSidePadding) * videoProgress);
|
|
float y = getHeight() - AndroidUtilities.dp(8);
|
|
if (bufferProgress != 0) {
|
|
canvas.drawLine(progressLeft, y, progressLeft + (width - progressLeft - progressSidePadding) * bufferProgress, y, bufferPaint);
|
|
}
|
|
canvas.drawLine(progressLeft, y, progressRight, y, progressPaint);
|
|
}
|
|
}
|
|
|
|
private final static class PipConfig {
|
|
private SharedPreferences mPrefs;
|
|
|
|
private PipConfig(int width, int height) {
|
|
mPrefs = ApplicationLoader.applicationContext.getSharedPreferences("pip_layout_" + width + "_" + height, Context.MODE_PRIVATE);
|
|
}
|
|
|
|
private void setPipX(float x) {
|
|
mPrefs.edit().putFloat("x", x).apply();
|
|
}
|
|
|
|
private void setPipY(float y) {
|
|
mPrefs.edit().putFloat("y", y).apply();
|
|
}
|
|
|
|
private void setScaleFactor(float scaleFactor) {
|
|
mPrefs.edit().putFloat("scale_factor", scaleFactor).apply();
|
|
}
|
|
|
|
private float getScaleFactor() {
|
|
return mPrefs.getFloat("scale_factor", 1f);
|
|
}
|
|
|
|
private float getPipX() {
|
|
return mPrefs.getFloat("x", -1);
|
|
}
|
|
|
|
private float getPipY() {
|
|
return mPrefs.getFloat("y", -1);
|
|
}
|
|
}
|
|
} |