gt:         int endY = getSideCoord(false, 1, 0, videoHeight);
context: /*
   * This is the source code of Telegram for Android v. 3.x.x.
   * It is licensed under GNU GPL v. 2 or later.
   * You should have received a copy of the license in this archive (see LICENSE).
   *
   * Copyright Nikolai Kudashov, 2013-2017.
   */
  
  package org.telegram.ui.Components;
  
  import android.animation.Animator;
  import android.animation.AnimatorListenerAdapter;
  import android.animation.AnimatorSet;
  import android.animation.ObjectAnimator;
  import android.annotation.SuppressLint;
  import android.annotation.TargetApi;
  import android.app.Activity;
  import android.content.Context;
  import android.content.SharedPreferences;
  import android.graphics.Bitmap;
  import android.graphics.Canvas;
  import android.graphics.Outline;
  import android.graphics.Paint;
  import android.graphics.Path;
  import android.graphics.PixelFormat;
  import android.graphics.PorterDuff;
  import android.graphics.PorterDuffXfermode;
  import android.graphics.RectF;
  import android.os.Build;
  import android.view.Gravity;
  import android.view.MotionEvent;
  import android.view.TextureView;
  import android.view.View;
  import android.view.ViewOutlineProvider;
  import android.view.WindowManager;
  import android.view.animation.DecelerateInterpolator;
  import android.widget.FrameLayout;
  import android.widget.ImageView;
  
  import org.telegram.messenger.AndroidUtilities;
  import org.telegram.messenger.ApplicationLoader;
  import org.telegram.messenger.Bitmaps;
  import org.telegram.messenger.FileLog;
  import org.telegram.messenger.MediaController;
  import org.telegram.messenger.MessageObject;
  import org.telegram.messenger.NotificationCenter;
  import org.telegram.messenger.exoplayer2.ui.AspectRatioFrameLayout;
  import org.telegram.ui.ActionBar.ActionBar;
  import org.telegram.ui.ActionBar.Theme;
  
  import java.util.ArrayList;
  
  public class PipRoundVideoView implements NotificationCenter.NotificationCenterDelegate {
  
      private FrameLayout windowView;
      private Activity parentActivity;
      private TextureView textureView;
      private ImageView imageView;
      private AspectRatioFrameLayout aspectRatioFrameLayout;
      private Bitmap bitmap;
      private int videoWidth;
      private int videoHeight;
      private AnimatorSet hideShowAnimation;
      private Runnable onCloseRunnable;
  
      private WindowManager.LayoutParams windowLayoutParams;
      private WindowManager windowManager;
      private SharedPreferences preferences;
      private DecelerateInterpolator decelerateInterpolator;
  
      private RectF rect = new RectF();
  
      @SuppressLint("StaticFieldLeak")
      private static PipRoundVideoView instance;
  
      public void show(Activity activity, Runnable closeRunnable) {
          if (activity == null) {
              return;
          }
          instance = this;
          onCloseRunnable = closeRunnable;
          windowView = new FrameLayout(activity) {
  
              private float startX;
              private float startY;
              private boolean dragging;
              private boolean startDragging;
  
              @Override
              public boolean onInterceptTouchEvent(MotionEvent event) {
                  if (event.getAction() == MotionEvent.ACTION_DOWN) {
                      startX = event.getRawX();
                      startY = event.getRawY();
                      startDragging = true;
                  }
                  return true;
              }
  
              @Override
              public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
                  super.requestDisallowInterceptTouchEvent(disallowIntercept);
              }
  
              @Override
              public boolean onTouchEvent(MotionEvent event) {
                  if (!startDragging && !dragging) {
                      return false;
                  }
                  float x = event.getRawX();
                  float y = event.getRawY();
                  if (event.getAction() == MotionEvent.ACTION_MOVE) {
                      float dx = (x - startX);
                      float dy = (y - startY);
                      if (startDragging) {
                          if (Math.abs(dx) >= AndroidUtilities.getPixelsInCM(0.3f, true) || Math.abs(dy) >= AndroidUtilities.getPixelsInCM(0.3f, false)) {
                              dragging = true;
                              startDragging = false;
                          }
                      } else if (dragging) {
                          windowLayoutParams.x += dx;
                          windowLayoutParams.y += dy;
                          int maxDiff = videoWidth / 2;
                          if (windowLayoutParams.x < -maxDiff) {
                              windowLayoutParams.x = -maxDiff;
                          } else if (windowLayoutParams.x > AndroidUtilities.displaySize.x - windowLayoutParams.width + maxDiff) {
                              windowLayoutParams.x = AndroidUtilities.displaySize.x - windowLayoutParams.width + maxDiff;
                          }
                          float alpha = 1.0f;
                          if (windowLayoutParams.x < 0) {
                              alpha = 1.0f + windowLayoutParams.x / (float) maxDiff * 0.5f;
                          } else if (windowLayoutParams.x > AndroidUtilities.displaySize.x - windowLayoutParams.width) {
                              alpha = 1.0f - (windowLayoutParams.x - AndroidUtilities.displaySize.x + windowLayoutParams.width) / (float) maxDiff * 0.5f;
                          }
                          if (windowView.getAlpha() != alpha) {
                              windowView.setAlpha(alpha);
                          }
                          maxDiff = 0;
                          if (windowLayoutParams.y < -maxDiff) {
                              windowLayoutParams.y = -maxDiff;
                          } else if (windowLayoutParams.y > AndroidUtilities.displaySize.y - windowLayoutParams.height + maxDiff) {
                              windowLayoutParams.y = AndroidUtilities.displaySize.y - windowLayoutParams.height + maxDiff;
                          }
                          windowManager.updateViewLayout(windowView, windowLayoutParams);
                          startX = x;
                          startY = y;
                      }
                  } else if (event.getAction() == MotionEvent.ACTION_UP) {
                      if (startDragging && !dragging) {
                          MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject();
                          if (messageObject != null) {
                              if (MediaController.getInstance().isMessagePaused()) {
                                  MediaController.getInstance().playMessage(messageObject);
                              } else {
                                  MediaController.getInstance().pauseMessage(messageObject);
                              }
                          }
                      }
                      dragging = false;
                      startDragging = false;
                      animateToBoundsMaybe();
                  }
                  return true;
              }
  
              @Override
              protected void onDraw(Canvas canvas) {
                  if (Theme.chat_roundVideoShadow != null/* && aspectRatioFrameLayout.isDrawingReady()*/) {
                      Theme.chat_roundVideoShadow.setAlpha((int) (getAlpha() * 255));
                      Theme.chat_roundVideoShadow.setBounds(AndroidUtilities.dp(1), AndroidUtilities.dp(2), AndroidUtilities.dp(125), AndroidUtilities.dp(125));
                      Theme.chat_roundVideoShadow.draw(canvas);
                  }
              }
          };
          windowView.setWillNotDraw(false);
  
          videoWidth = AndroidUtilities.dp(120 + 6);
          videoHeight = AndroidUtilities.dp(120 + 6);
  
          if (Build.VERSION.SDK_INT >= 21) {
              aspectRatioFrameLayout = new AspectRatioFrameLayout(activity) {
                  @Override
                  protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
                      boolean result = super.drawChild(canvas, child, drawingTime);
                      if (child == textureView) {
                          MessageObject currentMessageObject = MediaController.getInstance().getPlayingMessageObject();
                          if (currentMessageObject != null) {
                              rect.set(AndroidUtilities.dpf2(1.5f), AndroidUtilities.dpf2(1.5f), getMeasuredWidth() - AndroidUtilities.dpf2(1.5f), getMeasuredHeight() - AndroidUtilities.dpf2(1.5f));
                              canvas.drawArc(rect, -90, 360 * currentMessageObject.audioProgress, false, Theme.chat_radialProgressPaint);
                          }
                      }
                      return result;
                  }
              };
              aspectRatioFrameLayout.setOutlineProvider(new ViewOutlineProvider() {
                  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
                  @Override
                  public void getOutline(View view, Outline outline) {
                      outline.setOval(0, 0, AndroidUtilities.dp(120), AndroidUtilities.dp(120));
                  }
              });
              aspectRatioFrameLayout.setClipToOutline(true);
          } else {
              final Paint aspectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
              aspectPaint.setColor(0xff000000);
              aspectPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
              aspectRatioFrameLayout = new AspectRatioFrameLayout(activity) {
  
                  private Path aspectPath = new Path();
  
                  @Override
                  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
                      super.onSizeChanged(w, h, oldw, oldh);
                      aspectPath.reset();
                      aspectPath.addCircle(w / 2, h / 2, w / 2, Path.Direction.CW);
                      aspectPath.toggleInverseFillType();
                  }
  
                  @Override
                  protected void dispatchDraw(Canvas canvas) {
                      super.dispatchDraw(canvas);
                      canvas.drawPath(aspectPath, aspectPaint);
                  }
  
                  @Override
                  protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
                      boolean result;
                      try {
                          result = super.drawChild(canvas, child, drawingTime);
                      } catch (Throwable ignore) {
                          result = false;
                      }
                      if (child == textureView) {
                          MessageObject currentMessageObject = MediaController.getInstance().getPlayingMessageObject();
                          if (currentMessageObject != null) {
                              rect.set(AndroidUtilities.dpf2(1.5f), AndroidUtilities.dpf2(1.5f), getMeasuredWidth() - AndroidUtilities.dpf2(1.5f), getMeasuredHeight() - AndroidUtilities.dpf2(1.5f));
                              canvas.drawArc(rect, -90, 360 * currentMessageObject.audioProgress, false, Theme.chat_radialProgressPaint);
                          }
                      }
                      return result;
                  }
              };
              aspectRatioFrameLayout.setLayerType(View.LAYER_TYPE_HARDWARE, null);
          }
          aspectRatioFrameLayout.setAspectRatio(1.0f, 0);
          windowView.addView(aspectRatioFrameLayout, LayoutHelper.createFrame(120, 120, Gravity.LEFT | Gravity.TOP, 3, 3, 0, 0));
          windowView.setAlpha(1.0f);
          windowView.setScaleX(0.8f);
          windowView.setScaleY(0.8f);
  
          textureView = new TextureView(activity);
          aspectRatioFrameLayout.addView(textureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
  
          imageView = new ImageView(activity);
          aspectRatioFrameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
          imageView.setVisibility(View.INVISIBLE);
  
          windowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
  
          preferences = ApplicationLoader.applicationContext.getSharedPreferences("pipconfig", Context.MODE_PRIVATE);
  
          int sidex = preferences.getInt("sidex", 1);
          int sidey = preferences.getInt("sidey", 0);
          float px = preferences.getFloat("px", 0);
          float py = preferences.getFloat("py", 0);
  
          try {
              windowLayoutParams = new WindowManager.LayoutParams();
              windowLayoutParams.width = videoWidth;
              windowLayoutParams.height = videoHeight;
              windowLayoutParams.x = getSideCoord(true, sidex, px, videoWidth);
              windowLayoutParams.y = getSideCoord(false, sidey, py, videoHeight);
              windowLayoutParams.format = PixelFormat.TRANSLUCENT;
              windowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
              windowLayoutParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
              windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
              windowManager.addView(windowView, windowLayoutParams);
          } catch (Exception e) {
              FileLog.e(e);
              return;
          }
          parentActivity = activity;
          NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagePlayingProgressDidChanged);
          runShowHideAnimation(true);
      }
  
      private static int getSideCoord(boolean isX, int side, float p, int sideSize) {
          int total;
          if (isX) {
              total = AndroidUtilities.displaySize.x - sideSize;
          } else {
              total = AndroidUtilities.displaySize.y - sideSize - ActionBar.getCurrentActionBarHeight();
          }
          int result;
          if (side == 0) {
              result = AndroidUtilities.dp(10);
          } else if (side == 1) {
              result = total - AndroidUtilities.dp(10);
          } else {
              result = Math.round((total - AndroidUtilities.dp(20)) * p) + AndroidUtilities.dp(10);
          }
          if (!isX) {
              result += ActionBar.getCurrentActionBarHeight();
          }
          return result;
      }
  
      @Override
      public void didReceivedNotification(int id, Object... args) {
          if (id == NotificationCenter.messagePlayingProgressDidChanged) {
              if (aspectRatioFrameLayout != null) {
                  aspectRatioFrameLayout.invalidate();
              }
          }
      }
  
      public TextureView getTextureView() {
          return textureView;
      }
  
      public void close(boolean animated) {
          if (animated) {
              if (textureView != null && textureView.getParent() != null) {
                  if (textureView.getWidth() > 0 && textureView.getHeight() > 0) {
                      bitmap = Bitmaps.createBitmap(textureView.getWidth(), textureView.getHeight(), Bitmap.Config.ARGB_8888);
                  }
                  try {
                      textureView.getBitmap(bitmap);
                  } catch (Throwable e) {
                      bitmap = null;
                  }
                  imageView.setImageBitmap(bitmap);
                  try {
                      aspectRatioFrameLayout.removeView(textureView);
                  } catch (Exception ignore) {
  
                  }
                  imageView.setVisibility(View.VISIBLE);
                  runShowHideAnimation(false);
              }
          } else {
              if (bitmap != null) {
                  imageView.setImageDrawable(null);
                  bitmap.recycle();
                  bitmap = null;
              }
              try {
                  windowManager.removeView(windowView);
              } catch (Exception e) {
                  //don't promt
              }
              if (instance == this) {
                  instance = null;
              }
              parentActivity = null;
              NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagePlayingProgressDidChanged);
          }
      }
  
      public void onConfigurationChanged() {
          int sidex = preferences.getInt("sidex", 1);
          int sidey = preferences.getInt("sidey", 0);
          float px = preferences.getFloat("px", 0);
          float py = preferences.getFloat("py", 0);
          windowLayoutParams.x = getSideCoord(true, sidex, px, videoWidth);
          windowLayoutParams.y = getSideCoord(false, sidey, py, videoHeight);
          windowManager.updateViewLayout(windowView, windowLayoutParams);
      }
  
      public void showTemporary(boolean show) {
          if (hideShowAnimation != null) {
              hideShowAnimation.cancel();
          }
          hideShowAnimation = new AnimatorSet();
          hideShowAnimation.playTogether(
                  ObjectAnimator.ofFloat(windowView, "alpha", show ? 1.0f : 0.0f),
                  ObjectAnimator.ofFloat(windowView, "scaleX", show ? 1.0f : 0.8f),
                  ObjectAnimator.ofFloat(windowView, "scaleY", show ? 1.0f : 0.8f));
          hideShowAnimation.setDuration(150);
          if (decelerateInterpolator == null) {
              decelerateInterpolator = new DecelerateInterpolator();
          }
          hideShowAnimation.addListener(new AnimatorListenerAdapter() {
              @Override
              public void onAnimationEnd(Animator animation) {
                  if (animation.equals(hideShowAnimation)) {
                      hideShowAnimation = null;
                  }
              }
          });
          hideShowAnimation.setInterpolator(decelerateInterpolator);
          hideShowAnimation.start();
      }
  
      private void runShowHideAnimation(final boolean show) {
          if (hideShowAnimation != null) {
              hideShowAnimation.cancel();
          }
          hideShowAnimation = new AnimatorSet();
          hideShowAnimation.playTogether(
                  ObjectAnimator.ofFloat(windowView, "alpha", show ? 1.0f : 0.0f),
                  ObjectAnimator.ofFloat(windowView, "scaleX", show ? 1.0f : 0.8f),
                  ObjectAnimator.ofFloat(windowView, "scaleY", show ? 1.0f : 0.8f));
          hideShowAnimation.setDuration(150);
          if (decelerateInterpolator == null) {
              decelerateInterpolator = new DecelerateInterpolator();
          }
          hideShowAnimation.addListener(new AnimatorListenerAdapter() {
              @Override
              public void onAnimationEnd(Animator animation) {
                  if (animation.equals(hideShowAnimation)) {
                      if (!show) {
                          close(false);
                      }
                      hideShowAnimation = null;
                  }
              }
  
              @Override
              public void onAnimationCancel(Animator animation) {
                  if (animation.equals(hideShowAnimation)) {
                      hideShowAnimation = null;
                  }
              }
          });
          hideShowAnimation.setInterpolator(decelerateInterpolator);
          hideShowAnimation.start();
      }
  
      private void animateToBoundsMaybe() {
          int startX = getSideCoord(true, 0, 0, videoWidth);
          int endX = getSideCoord(true, 1, 0, videoWidth);
          int startY = getSideCoord(false, 0, 0, videoHeight);
  