Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c8f8ec8e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Revert "Track current resized bounds for resized PIP."" into rvc-dev

parents 6f0c1bc1 06dc41f9
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -225,8 +225,8 @@ public class PipBoundsHandler {
     */
     */
    Rect getDestinationBounds(float aspectRatio, Rect bounds) {
    Rect getDestinationBounds(float aspectRatio, Rect bounds) {
        final Rect destinationBounds;
        final Rect destinationBounds;
        if (bounds == null) {
        final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
        final Rect defaultBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
        if (bounds == null) {
            destinationBounds = new Rect(defaultBounds);
            destinationBounds = new Rect(defaultBounds);
        } else {
        } else {
            destinationBounds = new Rect(bounds);
            destinationBounds = new Rect(bounds);
+1 −1
Original line number Original line Diff line number Diff line
@@ -168,7 +168,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
                // bounds. We want to restore to the unexpanded bounds when re-entering pip,
                // bounds. We want to restore to the unexpanded bounds when re-entering pip,
                // so we save the bounds before expansion (normal) instead of the current
                // so we save the bounds before expansion (normal) instead of the current
                // bounds.
                // bounds.
                mReentryBounds.set(mTouchHandler.getMinBounds());
                mReentryBounds.set(mTouchHandler.getNormalBounds());
                // Apply the snap fraction of the current bounds to the normal bounds.
                // Apply the snap fraction of the current bounds to the normal bounds.
                float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
                float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
                mPipBoundsHandler.applySnapFraction(mReentryBounds, snapFraction);
                mPipBoundsHandler.applySnapFraction(mReentryBounds, snapFraction);
+9 −12
Original line number Original line Diff line number Diff line
@@ -65,7 +65,6 @@ public class PipResizeGestureHandler {
    private final PointF mDownPoint = new PointF();
    private final PointF mDownPoint = new PointF();
    private final Point mMaxSize = new Point();
    private final Point mMaxSize = new Point();
    private final Point mMinSize = new Point();
    private final Point mMinSize = new Point();
    private final Rect mLastResizeBounds = new Rect();
    private final Rect mTmpBounds = new Rect();
    private final Rect mTmpBounds = new Rect();
    private final int mDelta;
    private final int mDelta;


@@ -194,7 +193,11 @@ public class PipResizeGestureHandler {
            }
            }


        } else if (mAllowGesture) {
        } else if (mAllowGesture) {

            final Rect currentPipBounds = mMotionHelper.getBounds();
            Rect newSize = TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(), mDownPoint.x,
                    mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x, mMinSize.y, mMaxSize,
                    true, true);
            mPipBoundsHandler.transformBoundsToAspectRatio(newSize);
            switch (action) {
            switch (action) {
                case MotionEvent.ACTION_POINTER_DOWN:
                case MotionEvent.ACTION_POINTER_DOWN:
                    // We do not support multi touch for resizing via drag
                    // We do not support multi touch for resizing via drag
@@ -203,18 +206,12 @@ public class PipResizeGestureHandler {
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_MOVE:
                    // Capture inputs
                    // Capture inputs
                    mInputMonitor.pilferPointers();
                    mInputMonitor.pilferPointers();
                    final Rect currentPipBounds = mMotionHelper.getBounds();
                    //TODO: Actually do resize here.
                    mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(),
                            mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x,
                            mMinSize.y, mMaxSize, true, true));
                    mPipBoundsHandler.transformBoundsToAspectRatio(mLastResizeBounds);
                    mPipTaskOrganizer.resizePip(mLastResizeBounds);

                    break;
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_CANCEL:
                    mPipTaskOrganizer.finishResize(mLastResizeBounds);
                    //TODO: Finish resize operation here.
                    mLastResizeBounds.setEmpty();
                    mMotionHelper.synchronizePinnedStackBounds();
                    mCtrlType = CTRL_NONE;
                    mCtrlType = CTRL_NONE;
                    mAllowGesture = false;
                    mAllowGesture = false;
                    break;
                    break;
@@ -226,7 +223,7 @@ public class PipResizeGestureHandler {
        mMaxSize.set(maxX, maxY);
        mMaxSize.set(maxX, maxY);
    }
    }


    void updateMinSize(int minX, int minY) {
    void updateMiniSize(int minX, int minY) {
        mMinSize.set(minX, minY);
        mMinSize.set(minX, minY);
    }
    }


+50 −83
Original line number Original line Diff line number Diff line
@@ -41,7 +41,6 @@ import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.AccessibilityWindowInfo;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.systemui.R;
import com.android.systemui.R;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipBoundsHandler;
@@ -74,7 +73,7 @@ public class PipTouchHandler {
    private final Context mContext;
    private final Context mContext;
    private final IActivityManager mActivityManager;
    private final IActivityManager mActivityManager;
    private final PipBoundsHandler mPipBoundsHandler;
    private final PipBoundsHandler mPipBoundsHandler;
    private PipResizeGestureHandler mPipResizeGestureHandler;
    private final PipResizeGestureHandler mPipResizeGestureHandler;
    private IPinnedStackController mPinnedStackController;
    private IPinnedStackController mPinnedStackController;


    private final PipMenuActivityController mMenuController;
    private final PipMenuActivityController mMenuController;
@@ -85,22 +84,14 @@ public class PipTouchHandler {


    // The current movement bounds
    // The current movement bounds
    private Rect mMovementBounds = new Rect();
    private Rect mMovementBounds = new Rect();
    // The current resized bounds, changed by user resize.
    // Note that this is not necessarily the same as PipMotionHelper#getBounds, since it's possible
    // that PIP is currently is in a expanded state (max size) but we still need mResizeBounds to
    // know what size to restore to once expand animation times out.
    @VisibleForTesting Rect mResizedBounds = new Rect();


    // The reference inset bounds, used to determine the dismiss fraction
    // The reference inset bounds, used to determine the dismiss fraction
    private Rect mInsetBounds = new Rect();
    private Rect mInsetBounds = new Rect();

    // The reference bounds used to calculate the normal/expanded target bounds
    // The reference bounds used to calculate the minimum/maximum target bounds
    private Rect mNormalBounds = new Rect();
    // The bound in which PIP enters is the starting/minimum bound, while the expanded/auto-resized
    private Rect mNormalMovementBounds = new Rect();
    // bound is the maximum bound.
    private Rect mExpandedBounds = new Rect();
    private Rect mMinBounds = new Rect();
    private Rect mExpandedMovementBounds = new Rect();
    @VisibleForTesting Rect mMinMovementBounds = new Rect();
    private Rect mMaxBounds = new Rect();
    @VisibleForTesting Rect mMaxMovementBounds = new Rect();
    private int mExpandedShortestEdgeSize;
    private int mExpandedShortestEdgeSize;


    // Used to workaround an issue where the WM rotation happens before we are notified, allowing
    // Used to workaround an issue where the WM rotation happens before we are notified, allowing
@@ -135,7 +126,7 @@ public class PipTouchHandler {
    private final PipTouchState mTouchState;
    private final PipTouchState mTouchState;
    private final FlingAnimationUtils mFlingAnimationUtils;
    private final FlingAnimationUtils mFlingAnimationUtils;
    private final FloatingContentCoordinator mFloatingContentCoordinator;
    private final FloatingContentCoordinator mFloatingContentCoordinator;
    private PipMotionHelper mMotionHelper;
    private final PipMotionHelper mMotionHelper;
    private PipTouchGesture mGesture;
    private PipTouchGesture mGesture;


    // Temp vars
    // Temp vars
@@ -244,16 +235,14 @@ public class PipTouchHandler {


            mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
            mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
        }
        }
        mResizedBounds.setEmpty();
        mPipResizeGestureHandler.onActivityUnpinned();
        mPipResizeGestureHandler.onActivityUnpinned();
    }
    }


    public void onPinnedStackAnimationEnded() {
    public void onPinnedStackAnimationEnded() {
        // Always synchronize the motion helper bounds once PiP animations finish
        // Always synchronize the motion helper bounds once PiP animations finish
        mMotionHelper.synchronizePinnedStackBounds();
        mMotionHelper.synchronizePinnedStackBounds();

        mPipResizeGestureHandler.updateMiniSize(mMotionHelper.getBounds().width(),
        updateMovementBounds();
                mMotionHelper.getBounds().height());
        mResizedBounds.set(mMinBounds);


        if (mShowPipMenuOnAnimationEnd) {
        if (mShowPipMenuOnAnimationEnd) {
            mMenuController.showMenu(MENU_STATE_CLOSE, mMotionHelper.getBounds(),
            mMenuController.showMenu(MENU_STATE_CLOSE, mMotionHelper.getBounds(),
@@ -277,10 +266,7 @@ public class PipTouchHandler {
        mShelfHeight = shelfHeight;
        mShelfHeight = shelfHeight;
    }
    }


    /**
    public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect curBounds,
     * Update all the cached bounds (movement, min, max, etc.)
     */
    public void onMovementBoundsChanged(Rect insetBounds, Rect minBounds, Rect curBounds,
            boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation) {
            boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation) {
        final int bottomOffset = mIsImeShowing ? mImeHeight : 0;
        final int bottomOffset = mIsImeShowing ? mImeHeight : 0;
        final boolean fromDisplayRotationChanged = (mDisplayRotation != displayRotation);
        final boolean fromDisplayRotationChanged = (mDisplayRotation != displayRotation);
@@ -289,25 +275,23 @@ public class PipTouchHandler {
        }
        }


        // Re-calculate the expanded bounds
        // Re-calculate the expanded bounds
        mMinBounds.set(minBounds);
        mNormalBounds = normalBounds;
        Rect minMovementBounds = new Rect();
        Rect normalMovementBounds = new Rect();
        mSnapAlgorithm.getMovementBounds(mMinBounds, insetBounds, minMovementBounds,
        mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds,
                bottomOffset);
                bottomOffset);


        // Calculate the expanded size
        // Calculate the expanded size
        float aspectRatio = (float) minBounds.width() / minBounds.height();
        float aspectRatio = (float) normalBounds.width() / normalBounds.height();
        Point displaySize = new Point();
        Point displaySize = new Point();
        mContext.getDisplay().getRealSize(displaySize);
        mContext.getDisplay().getRealSize(displaySize);
        Size maxSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio,
        Size expandedSize = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio,
                mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
                mExpandedShortestEdgeSize, displaySize.x, displaySize.y);
        mMaxBounds.set(0, 0, maxSize.getWidth(), maxSize.getHeight());
        mExpandedBounds.set(0, 0, expandedSize.getWidth(), expandedSize.getHeight());
        Rect maxMovementBounds = new Rect();
        mPipResizeGestureHandler.updateMaxSize(expandedSize.getWidth(), expandedSize.getHeight());
        mSnapAlgorithm.getMovementBounds(mMaxBounds, insetBounds, maxMovementBounds,
        Rect expandedMovementBounds = new Rect();
        mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds, expandedMovementBounds,
                bottomOffset);
                bottomOffset);


        mPipResizeGestureHandler.updateMinSize(minBounds.width(), minBounds.height());
        mPipResizeGestureHandler.updateMaxSize(mMaxBounds.width(), mMaxBounds.height());

        // The extra offset does not really affect the movement bounds, but are applied based on the
        // The extra offset does not really affect the movement bounds, but are applied based on the
        // current state (ime showing, or shelf offset) when we need to actually shift
        // current state (ime showing, or shelf offset) when we need to actually shift
        int extraOffset = Math.max(
        int extraOffset = Math.max(
@@ -324,8 +308,8 @@ public class PipTouchHandler {
                final float offsetBufferPx = BOTTOM_OFFSET_BUFFER_DP
                final float offsetBufferPx = BOTTOM_OFFSET_BUFFER_DP
                        * mContext.getResources().getDisplayMetrics().density;
                        * mContext.getResources().getDisplayMetrics().density;
                final Rect toMovementBounds = mMenuState == MENU_STATE_FULL && willResizeMenu()
                final Rect toMovementBounds = mMenuState == MENU_STATE_FULL && willResizeMenu()
                        ? new Rect(maxMovementBounds)
                        ? new Rect(expandedMovementBounds)
                        : new Rect(minMovementBounds);
                        : new Rect(normalMovementBounds);
                final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
                final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets;
                final int toBottom = toMovementBounds.bottom < toMovementBounds.top
                final int toBottom = toMovementBounds.bottom < toMovementBounds.top
                        ? toMovementBounds.bottom
                        ? toMovementBounds.bottom
@@ -339,17 +323,17 @@ public class PipTouchHandler {


        // Update the movement bounds after doing the calculations based on the old movement bounds
        // Update the movement bounds after doing the calculations based on the old movement bounds
        // above
        // above
        mMinMovementBounds = minMovementBounds;
        mNormalMovementBounds = normalMovementBounds;
        mMaxMovementBounds = maxMovementBounds;
        mExpandedMovementBounds = expandedMovementBounds;
        mDisplayRotation = displayRotation;
        mDisplayRotation = displayRotation;
        mInsetBounds.set(insetBounds);
        mInsetBounds.set(insetBounds);
        updateMovementBounds();
        updateMovementBounds(mMenuState);
        mMovementBoundsExtraOffsets = extraOffset;
        mMovementBoundsExtraOffsets = extraOffset;


        // If we have a deferred resize, apply it now
        // If we have a deferred resize, apply it now
        if (mDeferResizeToNormalBoundsUntilRotation == displayRotation) {
        if (mDeferResizeToNormalBoundsUntilRotation == displayRotation) {
            mMotionHelper.animateToUnexpandedState(minBounds, mSavedSnapFraction,
            mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
                    mMinMovementBounds, mMovementBounds, true /* immediate */);
                    mNormalMovementBounds, mMovementBounds, true /* immediate */);
            mSavedSnapFraction = -1f;
            mSavedSnapFraction = -1f;
            mDeferResizeToNormalBoundsUntilRotation = -1;
            mDeferResizeToNormalBoundsUntilRotation = -1;
        }
        }
@@ -403,7 +387,7 @@ public class PipTouchHandler {
            case MotionEvent.ACTION_UP: {
            case MotionEvent.ACTION_UP: {
                // Update the movement bounds again if the state has changed since the user started
                // Update the movement bounds again if the state has changed since the user started
                // dragging (ie. when the IME shows)
                // dragging (ie. when the IME shows)
                updateMovementBounds();
                updateMovementBounds(mMenuState);


                if (mGesture.onUp(mTouchState)) {
                if (mGesture.onUp(mTouchState)) {
                    break;
                    break;
@@ -501,13 +485,11 @@ public class PipTouchHandler {
        if (menuState == MENU_STATE_FULL && mMenuState != MENU_STATE_FULL) {
        if (menuState == MENU_STATE_FULL && mMenuState != MENU_STATE_FULL) {
            // Save the current snap fraction and if we do not drag or move the PiP, then
            // Save the current snap fraction and if we do not drag or move the PiP, then
            // we store back to this snap fraction.  Otherwise, we'll reset the snap
            // we store back to this snap fraction.  Otherwise, we'll reset the snap
            // fraction and snap to the closest edge.
            // fraction and snap to the closest edge
            // Also save the current resized bounds so when the menu disappears, we can restore it.
            Rect expandedBounds = new Rect(mExpandedBounds);
            if (resize) {
            if (resize) {
                mResizedBounds.set(mMotionHelper.getBounds());
                Rect expandedBounds = new Rect(mMaxBounds);
                mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
                mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
                        mMovementBounds, mMaxMovementBounds);
                        mMovementBounds, mExpandedMovementBounds);
            }
            }
        } else if (menuState == MENU_STATE_NONE && mMenuState == MENU_STATE_FULL) {
        } else if (menuState == MENU_STATE_NONE && mMenuState == MENU_STATE_FULL) {
            // Try and restore the PiP to the closest edge, using the saved snap fraction
            // Try and restore the PiP to the closest edge, using the saved snap fraction
@@ -533,9 +515,9 @@ public class PipTouchHandler {
                }
                }


                if (mDeferResizeToNormalBoundsUntilRotation == -1) {
                if (mDeferResizeToNormalBoundsUntilRotation == -1) {
                    Rect normalBounds = new Rect(mResizedBounds);
                    Rect normalBounds = new Rect(mNormalBounds);
                    mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
                    mMotionHelper.animateToUnexpandedState(normalBounds, mSavedSnapFraction,
                            mMinMovementBounds, mMovementBounds, false /* immediate */);
                            mNormalMovementBounds, mMovementBounds, false /* immediate */);
                    mSavedSnapFraction = -1f;
                    mSavedSnapFraction = -1f;
                }
                }
            } else {
            } else {
@@ -546,7 +528,7 @@ public class PipTouchHandler {
            }
            }
        }
        }
        mMenuState = menuState;
        mMenuState = menuState;
        updateMovementBounds();
        updateMovementBounds(menuState);
        // If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
        // If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
        // as well, or it can't handle a11y focus and pip menu can't perform any action.
        // as well, or it can't handle a11y focus and pip menu can't perform any action.
        onRegistrationChanged(menuState == MENU_STATE_NONE);
        onRegistrationChanged(menuState == MENU_STATE_NONE);
@@ -562,26 +544,11 @@ public class PipTouchHandler {
        return mMotionHelper;
        return mMotionHelper;
    }
    }


    @VisibleForTesting
    PipResizeGestureHandler getPipResizeGestureHandler() {
        return mPipResizeGestureHandler;
    }

    @VisibleForTesting
    void setPipResizeGestureHandler(PipResizeGestureHandler pipResizeGestureHandler) {
        mPipResizeGestureHandler = pipResizeGestureHandler;
    }

    @VisibleForTesting
    void setPipMotionHelper(PipMotionHelper pipMotionHelper) {
        mMotionHelper = pipMotionHelper;
    }

    /**
    /**
     * @return the unexpanded bounds.
     * @return the unexpanded bounds.
     */
     */
    public Rect getMinBounds() {
    public Rect getNormalBounds() {
        return mMinBounds;
        return mNormalBounds;
    }
    }


    /**
    /**
@@ -734,17 +701,17 @@ public class PipTouchHandler {
    };
    };


    /**
    /**
     * Updates the current movement bounds based on the current PIP size.
     * Updates the current movement bounds based on whether the menu is currently visible and
     * resized.
     */
     */
    private void updateMovementBounds() {
    private void updateMovementBounds(int menuState) {
        Rect movementBounds = new Rect();
        boolean isMenuExpanded = menuState == MENU_STATE_FULL;
        mSnapAlgorithm.getMovementBounds(mMotionHelper.getBounds(), mInsetBounds,
        mMovementBounds = isMenuExpanded && willResizeMenu()
                movementBounds, mIsImeShowing ? mImeHeight : 0);
                ? mExpandedMovementBounds
        mMotionHelper.setCurrentMovementBounds(movementBounds);
                : mNormalMovementBounds;

        boolean isMenuExpanded = mMenuState == MENU_STATE_FULL;
        mPipBoundsHandler.setMinEdgeSize(
        mPipBoundsHandler.setMinEdgeSize(
                isMenuExpanded  && willResizeMenu() ? mExpandedShortestEdgeSize : 0);
                isMenuExpanded ? mExpandedShortestEdgeSize : 0);
        mMotionHelper.setCurrentMovementBounds(mMovementBounds);
    }
    }


    /**
    /**
@@ -762,18 +729,18 @@ public class PipTouchHandler {
        if (!mEnableResize) {
        if (!mEnableResize) {
            return false;
            return false;
        }
        }
        return mMaxBounds.width() != mMinBounds.width()
        return mExpandedBounds.width() != mNormalBounds.width()
                || mMaxBounds.height() != mMinBounds.height();
                || mExpandedBounds.height() != mNormalBounds.height();
    }
    }


    public void dump(PrintWriter pw, String prefix) {
    public void dump(PrintWriter pw, String prefix) {
        final String innerPrefix = prefix + "  ";
        final String innerPrefix = prefix + "  ";
        pw.println(prefix + TAG);
        pw.println(prefix + TAG);
        pw.println(innerPrefix + "mMovementBounds=" + mMovementBounds);
        pw.println(innerPrefix + "mMovementBounds=" + mMovementBounds);
        pw.println(innerPrefix + "mMinBounds=" + mMinBounds);
        pw.println(innerPrefix + "mNormalBounds=" + mNormalBounds);
        pw.println(innerPrefix + "mMinMovementBounds=" + mMinMovementBounds);
        pw.println(innerPrefix + "mNormalMovementBounds=" + mNormalMovementBounds);
        pw.println(innerPrefix + "mMaxBounds=" + mMaxBounds);
        pw.println(innerPrefix + "mExpandedBounds=" + mExpandedBounds);
        pw.println(innerPrefix + "mMaxMovementBounds=" + mMaxMovementBounds);
        pw.println(innerPrefix + "mExpandedMovementBounds=" + mExpandedMovementBounds);
        pw.println(innerPrefix + "mMenuState=" + mMenuState);
        pw.println(innerPrefix + "mMenuState=" + mMenuState);
        pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
        pw.println(innerPrefix + "mIsImeShowing=" + mIsImeShowing);
        pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
        pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
+0 −168
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.pip.phone;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.graphics.Point;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Size;
import android.view.DisplayInfo;

import androidx.test.filters.SmallTest;

import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

/**
 * Unit tests against {@link PipTouchHandler}, including but not limited to:
 * - Update movement bounds based on new bounds
 * - Update movement bounds based on IME/shelf
 * - Update movement bounds to PipResizeHandler
 */
@RunWith(AndroidTestingRunner.class)
@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class PipTouchHandlerTest extends SysuiTestCase {
    private static final int ROUNDING_ERROR_MARGIN = 10;
    private static final float DEFAULT_ASPECT_RATIO = 1f;
    private static final Rect EMPTY_CURRENT_BOUNDS = null;

    private PipTouchHandler mPipTouchHandler;
    private DisplayInfo mDefaultDisplayInfo;

    @Mock
    private IActivityManager mActivityManager;

    @Mock
    private IActivityTaskManager mIActivityTaskManager;

    @Mock
    private PipMenuActivityController mPipMenuActivityController;

    @Mock
    private InputConsumerController mInputConsumerController;

    @Mock
    private PipBoundsHandler mPipBoundsHandler;

    @Mock
    private PipTaskOrganizer mPipTaskOrganizer;

    @Mock
    private FloatingContentCoordinator mFloatingContentCoordinator;

    @Mock
    private DeviceConfigProxy mDeviceConfigProxy;

    private PipSnapAlgorithm mPipSnapAlgorithm;
    private PipMotionHelper mMotionHelper;
    private PipResizeGestureHandler mPipResizeGestureHandler;

    Rect mInsetBounds;
    Rect mMinBounds;
    Rect mCurBounds;
    boolean mFromImeAdjustment;
    boolean mFromShelfAdjustment;
    int mDisplayRotation;


    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager, mIActivityTaskManager,
                mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
                mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy);
        mPipSnapAlgorithm = new PipSnapAlgorithm(mContext);
        mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
        mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
        mPipTouchHandler.setPipMotionHelper(mMotionHelper);
        mPipTouchHandler.setPipResizeGestureHandler(mPipResizeGestureHandler);

        // Assume a display of 1000 x 1000
        // inset of 10
        mInsetBounds = new Rect(10, 10, 990, 990);
        // minBounds of 100x100 bottom right corner
        mMinBounds = new Rect(890, 890, 990, 990);
        mCurBounds = new Rect();
        mFromImeAdjustment = false;
        mFromShelfAdjustment = false;
        mDisplayRotation = 0;
    }

    @Test
    public void updateMovementBounds_minBounds() {
        Rect expectedMinMovementBounds = new Rect();
        mPipSnapAlgorithm.getMovementBounds(mMinBounds, mInsetBounds, expectedMinMovementBounds, 0);

        mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
                mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);

        assertEquals(expectedMinMovementBounds, mPipTouchHandler.mMinMovementBounds);
        verify(mPipResizeGestureHandler, times(1))
                .updateMinSize(mMinBounds.width(), mMinBounds.height());
    }

    @Test
    public void updateMovementBounds_maxBounds() {
        Point displaySize = new Point();
        mContext.getDisplay().getRealSize(displaySize);
        Size maxSize = mPipSnapAlgorithm.getSizeForAspectRatio(1,
                mContext.getResources().getDimensionPixelSize(
                        R.dimen.pip_expanded_shortest_edge_size), displaySize.x, displaySize.y);
        Rect maxBounds = new Rect(0, 0, maxSize.getWidth(), maxSize.getHeight());
        Rect expectedMaxMovementBounds = new Rect();
        mPipSnapAlgorithm.getMovementBounds(maxBounds, mInsetBounds, expectedMaxMovementBounds, 0);

        mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
                mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);

        assertEquals(expectedMaxMovementBounds, mPipTouchHandler.mMaxMovementBounds);
        verify(mPipResizeGestureHandler, times(1))
                .updateMaxSize(maxBounds.width(), maxBounds.height());
    }

    @Test
    public void updateMovementBounds_withImeAdjustment_movesPip() {
        mFromImeAdjustment = true;
        mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds,
                mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation);

        verify(mMotionHelper, times(1)).animateToOffset(any(), anyInt());
    }
}