/*
 * Copyright (C) 2017 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.server.wm;

import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.platform.test.annotations.Presubmit;
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import com.android.server.wm.WindowManagerInternal.AppTransitionListener;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import com.android.server.wm.BoundsAnimationController.BoundsAnimator;

/**
 * Test class for {@link BoundsAnimationController} to ensure that it sends the right callbacks
 * depending on the various interactions.
 *
 * We are really concerned about only three of the transition states [F = fullscreen, !F = floating]
 * F->!F, !F->!F, and !F->F. Each animation can only be cancelled from the target mid-transition,
 * or if a new animation starts on the same target.  The tests below verifies that the target is
 * notified of all the cases where it is animating and cancelled so that it can respond
 * appropriately.
 *
 * Build/Install/Run:
 *  bit FrameworksServicesTests:com.android.server.wm.BoundsAnimationControllerTests
 */
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class BoundsAnimationControllerTests extends WindowTestsBase {

    /**
     * Mock value animator to simulate updates with.
     */
    private class MockValueAnimator extends ValueAnimator {

        private float mFraction;

        public MockValueAnimator getWithValue(float fraction) {
            mFraction = fraction;
            return this;
        }

        @Override
        public Object getAnimatedValue() {
            return mFraction;
        }
    }

    /**
     * Mock app transition to fire notifications to the bounds animator.
     */
    private class MockAppTransition extends AppTransition {

        private AppTransitionListener mListener;

        MockAppTransition(Context context) {
            super(context, null);
        }

        @Override
        void registerListenerLocked(AppTransitionListener listener) {
            mListener = listener;
        }

        public void notifyTransitionPending() {
            mListener.onAppTransitionPendingLocked();
        }

        public void notifyTransitionCancelled(int transit) {
            mListener.onAppTransitionCancelledLocked(transit);
        }

        public void notifyTransitionStarting(int transit) {
            mListener.onAppTransitionStartingLocked(transit, null, null, 0, 0, 0);
        }

        public void notifyTransitionFinished() {
            mListener.onAppTransitionFinishedLocked(null);
        }
    }

    /**
     * A test animate bounds user to track callbacks from the bounds animation.
     */
    private class TestBoundsAnimationTarget implements BoundsAnimationTarget {

        boolean mAwaitingAnimationStart;
        boolean mMovedToFullscreen;
        boolean mAnimationStarted;
        boolean mSchedulePipModeChangedOnStart;
        boolean mForcePipModeChangedCallback;
        boolean mAnimationEnded;
        Rect mAnimationEndFinalStackBounds;
        boolean mSchedulePipModeChangedOnEnd;
        boolean mBoundsUpdated;
        boolean mCancelRequested;
        Rect mStackBounds;
        Rect mTaskBounds;

        void initialize(Rect from) {
            mAwaitingAnimationStart = true;
            mMovedToFullscreen = false;
            mAnimationStarted = false;
            mAnimationEnded = false;
            mAnimationEndFinalStackBounds = null;
            mForcePipModeChangedCallback = false;
            mSchedulePipModeChangedOnStart = false;
            mSchedulePipModeChangedOnEnd = false;
            mStackBounds = from;
            mTaskBounds = null;
            mBoundsUpdated = false;
        }

        @Override
        public void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) {
            mAwaitingAnimationStart = false;
            mAnimationStarted = true;
            mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback;
            mForcePipModeChangedCallback = forceUpdate;
        }

        @Override
        public boolean shouldDeferStartOnMoveToFullscreen() {
            return true;
        }

        @Override
        public boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds) {
            // TODO: Once we break the runs apart, we should fail() here if this is called outside
            //       of onAnimationStart() and onAnimationEnd()
            if (mCancelRequested) {
                mCancelRequested = false;
                return false;
            } else {
                mBoundsUpdated = true;
                mStackBounds = stackBounds;
                mTaskBounds = taskBounds;
                return true;
            }
        }

        @Override
        public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackBounds,
                boolean moveToFullscreen) {
            mAnimationEnded = true;
            mAnimationEndFinalStackBounds = finalStackBounds;
            mSchedulePipModeChangedOnEnd = schedulePipModeChangedCallback;
            mMovedToFullscreen = moveToFullscreen;
            mTaskBounds = null;
        }
    }

    /**
     * Drives the animations, makes common assertions along the way.
     */
    private class BoundsAnimationDriver {

        private BoundsAnimationController mController;
        private TestBoundsAnimationTarget mTarget;
        private BoundsAnimator mAnimator;

        private Rect mFrom;
        private Rect mTo;
        private Rect mLargerBounds;
        private Rect mExpectedFinalBounds;

        BoundsAnimationDriver(BoundsAnimationController controller,
                TestBoundsAnimationTarget target) {
            mController = controller;
            mTarget = target;
        }

        BoundsAnimationDriver start(Rect from, Rect to) {
            if (mAnimator != null) {
                throw new IllegalArgumentException("Call restart() to restart an animation");
            }

            boolean fromFullscreen = from.equals(BOUNDS_FULL);
            boolean toFullscreen = to.equals(BOUNDS_FULL);

            mTarget.initialize(from);

            // Started, not running
            assertTrue(mTarget.mAwaitingAnimationStart);
            assertTrue(!mTarget.mAnimationStarted);

            startImpl(from, to);

            // Ensure that the animator is paused for the all windows drawn signal when animating
            // to/from fullscreen
            if (fromFullscreen || toFullscreen) {
                assertTrue(mAnimator.isPaused());
                mController.onAllWindowsDrawn();
            } else {
                assertTrue(!mAnimator.isPaused());
            }

            // Started and running
            assertTrue(!mTarget.mAwaitingAnimationStart);
            assertTrue(mTarget.mAnimationStarted);

            return this;
        }

        BoundsAnimationDriver restart(Rect to, boolean expectStartedAndPipModeChangedCallback) {
            if (mAnimator == null) {
                throw new IllegalArgumentException("Call start() to start a new animation");
            }

            BoundsAnimator oldAnimator = mAnimator;
            boolean toSameBounds = mAnimator.isStarted() && to.equals(mTo);

            // Reset the animation start state
            mTarget.mAnimationStarted = false;

            // Start animation
            startImpl(mTarget.mStackBounds, to);

            if (toSameBounds) {
                // Same animator if same final bounds
                assertSame(oldAnimator, mAnimator);
            }

            if (expectStartedAndPipModeChangedCallback) {
                // Replacing animation with pending pip mode changed callback, ensure we update
                assertTrue(mTarget.mAnimationStarted);
                assertTrue(mTarget.mSchedulePipModeChangedOnStart);
                assertTrue(mTarget.mForcePipModeChangedCallback);
            } else {
                // No animation start for replacing animation
                assertTrue(!mTarget.mAnimationStarted);
            }
            mTarget.mAnimationStarted = true;
            return this;
        }

        private BoundsAnimationDriver startImpl(Rect from, Rect to) {
            boolean fromFullscreen = from.equals(BOUNDS_FULL);
            boolean toFullscreen = to.equals(BOUNDS_FULL);
            mFrom = new Rect(from);
            mTo = new Rect(to);
            mExpectedFinalBounds = new Rect(to);
            mLargerBounds = getLargerBounds(mFrom, mTo);

            // Start animation
            final @SchedulePipModeChangedState int schedulePipModeChangedState = toFullscreen
                    ? SCHEDULE_PIP_MODE_CHANGED_ON_START
                    : fromFullscreen
                            ? SCHEDULE_PIP_MODE_CHANGED_ON_END
                            : NO_PIP_MODE_CHANGED_CALLBACKS;
            mAnimator = mController.animateBoundsImpl(mTarget, from, to, DURATION,
                    schedulePipModeChangedState, fromFullscreen, toFullscreen);

            // Original stack bounds, frozen task bounds
            assertEquals(mFrom, mTarget.mStackBounds);
            assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);

            // Animating to larger size
            if (mFrom.equals(mLargerBounds)) {
                assertTrue(!mAnimator.animatingToLargerSize());
            } else if (mTo.equals(mLargerBounds)) {
                assertTrue(mAnimator.animatingToLargerSize());
            }

            return this;
        }

        BoundsAnimationDriver expectStarted(boolean schedulePipModeChanged) {
            // Callback made
            assertTrue(mTarget.mAnimationStarted);

            assertEquals(schedulePipModeChanged, mTarget.mSchedulePipModeChangedOnStart);
            return this;
        }

        BoundsAnimationDriver update(float t) {
            mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(t));

            // Temporary stack bounds, frozen task bounds
            if (t == 0f) {
                assertEquals(mFrom, mTarget.mStackBounds);
            } else if (t == 1f) {
                assertEquals(mTo, mTarget.mStackBounds);
            } else {
                assertNotEquals(mFrom, mTarget.mStackBounds);
                assertNotEquals(mTo, mTarget.mStackBounds);
            }
            assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
            return this;
        }

        BoundsAnimationDriver cancel() {
            // Cancel
            mTarget.mCancelRequested = true;
            mTarget.mBoundsUpdated = false;
            mExpectedFinalBounds = null;

            // Update
            mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(0.5f));

            // Not started, not running, cancel reset
            assertTrue(!mTarget.mCancelRequested);

            // Stack/task bounds not updated
            assertTrue(!mTarget.mBoundsUpdated);

            // Callback made
            assertTrue(mTarget.mAnimationEnded);
            assertNull(mTarget.mAnimationEndFinalStackBounds);

            return this;
        }

        BoundsAnimationDriver end() {
            mAnimator.end();

            // Final stack bounds
            assertEquals(mTo, mTarget.mStackBounds);
            assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds);
            assertNull(mTarget.mTaskBounds);

            return this;
        }

        BoundsAnimationDriver expectEnded(boolean schedulePipModeChanged,
                boolean moveToFullscreen) {
            // Callback made
            assertTrue(mTarget.mAnimationEnded);

            assertEquals(schedulePipModeChanged, mTarget.mSchedulePipModeChangedOnEnd);
            assertEquals(moveToFullscreen, mTarget.mMovedToFullscreen);
            return this;
        }

        private Rect getLargerBounds(Rect r1, Rect r2) {
            int r1Area = r1.width() * r1.height();
            int r2Area = r2.width() * r2.height();
            if (r1Area <= r2Area) {
                return r2;
            } else {
                return r1;
            }
        }
    }

    // Constants
    private static final boolean SCHEDULE_PIP_MODE_CHANGED = true;
    private static final boolean MOVE_TO_FULLSCREEN = true;
    private static final int DURATION = 100;

    // Some dummy bounds to represent fullscreen and floating bounds
    private static final Rect BOUNDS_FULL = new Rect(0, 0, 100, 100);
    private static final Rect BOUNDS_FLOATING = new Rect(60, 60, 95, 95);
    private static final Rect BOUNDS_SMALLER_FLOATING = new Rect(80, 80, 95, 95);

    // Common
    private MockAppTransition mMockAppTransition;
    private MockValueAnimator mMockAnimator;
    private TestBoundsAnimationTarget mTarget;
    private BoundsAnimationController mController;
    private BoundsAnimationDriver mDriver;

    // Temp
    private Rect mTmpRect = new Rect();

    @Override
    public void setUp() throws Exception {
        super.setUp();

        final Context context = InstrumentationRegistry.getTargetContext();
        final Handler handler = new Handler(Looper.getMainLooper());
        mMockAppTransition = new MockAppTransition(context);
        mMockAnimator = new MockValueAnimator();
        mTarget = new TestBoundsAnimationTarget();
        mController = new BoundsAnimationController(context, mMockAppTransition, handler, null);
        mDriver = new BoundsAnimationDriver(mController, mTarget);
    }

    /** BASE TRANSITIONS **/

    @UiThreadTest
    @Test
    public void testFullscreenToFloatingTransition() throws Exception {
        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                .update(0f)
                .update(0.5f)
                .update(1f)
                .end()
                .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
    }

    @UiThreadTest
    @Test
    public void testFloatingToFullscreenTransition() throws Exception {
        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
                .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                .update(0f)
                .update(0.5f)
                .update(1f)
                .end()
                .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN);
    }

    @UiThreadTest
    @Test
    public void testFloatingToSmallerFloatingTransition() throws Exception {
        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                .update(0f)
                .update(0.5f)
                .update(1f)
                .end()
                .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
    }

    @UiThreadTest
    @Test
    public void testFloatingToLargerFloatingTransition() throws Exception {
        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                .update(0f)
                .update(0.5f)
                .update(1f)
                .end()
                .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
    }

    /** F->!F w/ CANCEL **/

    @UiThreadTest
    @Test
    public void testFullscreenToFloatingCancelFromTarget() throws Exception {
        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                .update(0.25f)
                .cancel()
                .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
    }

    @UiThreadTest
    @Test
    public void testFullscreenToFloatingCancelFromAnimationToSameBounds() throws Exception {
        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                .update(0.25f)
                .restart(BOUNDS_FLOATING, false /* expectStartedAndPipModeChangedCallback */)
                .end()
                .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
    }

    @UiThreadTest
    @Test
    public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() throws Exception {
        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                .update(0.25f)
                .restart(BOUNDS_SMALLER_FLOATING,
                        false /* expectStartedAndPipModeChangedCallback */)
                .end()
                .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
    }

    @UiThreadTest
    @Test
    public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() throws Exception {
        // When animating from fullscreen and the animation is interruped, we expect the animation
        // start callback to be made, with a forced pip mode change callback
        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                .update(0.25f)
                .restart(BOUNDS_FULL, true /* expectStartedAndPipModeChangedCallback */)
                .end()
                .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN);
    }

    /** !F->F w/ CANCEL **/

    @UiThreadTest
    @Test
    public void testFloatingToFullscreenCancelFromTarget() throws Exception {
        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
                .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                .update(0.25f)
                .cancel()
                .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
    }

    @UiThreadTest
    @Test
    public void testFloatingToFullscreenCancelFromAnimationToSameBounds() throws Exception {
        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
                .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                .update(0.25f)
                .restart(BOUNDS_FULL, false /* expectStartedAndPipModeChangedCallback */)
                .end()
                .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN);
    }

    @UiThreadTest
    @Test
    public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() throws Exception {
        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
                .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                .update(0.25f)
                .restart(BOUNDS_SMALLER_FLOATING,
                        false /* expectStartedAndPipModeChangedCallback */)
                .end()
                .expectEnded(SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN);
    }

    /** !F->!F w/ CANCEL **/

    @UiThreadTest
    @Test
    public void testFloatingToSmallerFloatingCancelFromTarget() throws Exception {
        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                .update(0.25f)
                .cancel()
                .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
    }

    @UiThreadTest
    @Test
    public void testFloatingToLargerFloatingCancelFromTarget() throws Exception {
        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                .update(0.25f)
                .cancel()
                .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
    }

    /** MISC **/

    @UiThreadTest
    @Test
    public void testBoundsAreCopied() throws Exception {
        Rect from = new Rect(0, 0, 100, 100);
        Rect to = new Rect(25, 25, 75, 75);
        mDriver.start(from, to)
                .update(0.25f)
                .end();
        assertEquals(new Rect(0, 0, 100, 100), from);
        assertEquals(new Rect(25, 25, 75, 75), to);
    }

    /**
     * @return whether the task and stack bounds would be the same if they were at the same offset.
     */
    private boolean assertEqualSizeAtOffset(Rect stackBounds, Rect taskBounds) {
        mTmpRect.set(taskBounds);
        mTmpRect.offsetTo(stackBounds.left, stackBounds.top);
        return stackBounds.equals(mTmpRect);
    }
}
