<!-- PiP minimize description. [CHAR LIMIT=NONE] -->
<string name="pip_minimize_description" translatable="false">Drag or fling the PIP to the edges of the screen to minimize it.</string>
+ <!-- PiP fling to dismiss title. [CHAR LIMIT=NONE]-->
+ <string name="pip_fling_dismiss_title" translatable="false">Fling to dismiss</string>
+
+ <!-- PiP fling to dismiss description. [CHAR LIMIT=NONE] -->
+ <string name="pip_fling_dismiss_description" translatable="false">Fling from anywhere on the screen to the bottom of the screen to dismiss the PIP.</string>
+
<!-- Button to play the current media on picture-in-picture (PIP) [CHAR LIMIT=30] -->
<string name="pip_play">Play</string>
}
/**
+ * @return whether the gesture it towards the dismiss area based on the velocity when
+ * dismissing.
+ */
+ public boolean isGestureToDismissArea(Rect pipBounds, float velX, float velY,
+ boolean isFling) {
+ Point endpoint = getDismissEndPoint(pipBounds, velX, velY, isFling);
+ // Center the point
+ endpoint.x += pipBounds.width() / 2;
+ endpoint.y += pipBounds.height() / 2;
+
+ // The dismiss area is the middle third of the screen, half the PIP's height from the bottom
+ Point size = new Point();
+ mContext.getDisplay().getRealSize(size);
+ final int left = size.x / 3;
+ Rect dismissArea = new Rect(left, size.y - (pipBounds.height() / 2), left * 2,
+ size.y + pipBounds.height());
+ return dismissArea.contains(endpoint.x, endpoint.y);
+ }
+
+ /**
* @return the distance between points {@param p1} and {@param p2}.
*/
private float distanceBetweenRectOffsets(Rect r1, Rect r2) {
private static final String TAG = "PipTouchHandler";
private static final String TUNER_KEY_MINIMIZE = "pip_minimize";
+ private static final String TUNER_KEY_FLING_DISMISS = "pip_fling_dismiss";
// These values are used for metrics and should never change
private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0;
// Allow the PIP to be dragged to the edge of the screen to be minimized.
private boolean mEnableMinimize = false;
+ // Allow the PIP to be flung from anywhere on the screen to the bottom to be dismissed.
+ private boolean mEnableFlingToDismiss = false;
// Behaviour states
private int mMenuState;
// Register any tuner settings changes
Dependency.get(TunerService.class).addTunable(this, TUNER_KEY_MINIMIZE);
+ Dependency.get(TunerService.class).addTunable(this, TUNER_KEY_FLING_DISMISS);
// Register the listener for input consumer touch events
inputConsumerController.setTouchListener(this::handleTouchEvent);
@Override
public void onTuningChanged(String key, String newValue) {
- if (newValue == null) {
- // Reset back to default
- mEnableMinimize = false;
- return;
- }
switch (key) {
case TUNER_KEY_MINIMIZE:
- mEnableMinimize = Integer.parseInt(newValue) != 0;
+ mEnableMinimize = newValue == null ? false : Integer.parseInt(newValue) != 0;
+ break;
+ case TUNER_KEY_FLING_DISMISS:
+ mEnableFlingToDismiss = newValue == null ? false : Integer.parseInt(newValue) != 0;
break;
}
}
final boolean isHorizontal = Math.abs(vel.x) > Math.abs(vel.y);
final float velocity = PointF.length(vel.x, vel.y);
final boolean isFling = velocity > mFlingAnimationUtils.getMinVelocityPxPerSecond();
- final boolean isFlingToBot = isFling
- && !isHorizontal && mMovementWithinDismiss && vel.y > 0;
+ final boolean isUpWithinDimiss = mEnableFlingToDismiss
+ && touchState.getLastTouchPosition().y >= mMovementBounds.bottom
+ && mMotionHelper.isGestureToDismissArea(mMotionHelper.getBounds(), vel.x,
+ vel.y, isFling);
+ final boolean isFlingToBot = isFling && vel.y > 0 && !isHorizontal
+ && (mMovementWithinDismiss || isUpWithinDimiss);
if (ENABLE_DISMISS_DRAG_TO_EDGE) {
try {
mHandler.removeCallbacks(mShowDismissAffordance);