/*
 * Copyright (C) 2018 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.launcher3.allapps;

import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.HOTSEAT;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.PREDICTION;

import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.os.Handler;
import android.view.MotionEvent;

import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.states.InternalStateHandler;

/**
 * 首次安装在桌面 抖动Hotseat的动画
 * Abstract base class of floating view responsible for showing discovery bounce animation
 */
public class DiscoveryBounce extends AbstractFloatingView {

    private static final long DELAY_MS = 450;

    public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
    public static final String SHELF_BOUNCE_SEEN = "launcher.shelf_bounce_seen";

    private final Launcher mLauncher;
    private final Animator mDiscoBounceAnimation;

    public DiscoveryBounce(Launcher launcher, float delta) {
        super(launcher, null);
        mLauncher = launcher;
        AllAppsTransitionController controller = mLauncher.getAllAppsController();

        mDiscoBounceAnimation =
                AnimatorInflater.loadAnimator(launcher, R.animator.discovery_bounce);
        mDiscoBounceAnimation.setTarget(new VerticalProgressWrapper(controller, delta));
        mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                handleClose(false);
            }
        });
        mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mDiscoBounceAnimation.start();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mDiscoBounceAnimation.isRunning()) {
            mDiscoBounceAnimation.end();
        }
    }

    @Override
    public boolean onBackPressed() {
        super.onBackPressed();
        // Go back to the previous state (from a user's perspective this floating view isn't
        // something to go back from).
        return false;
    }

    @Override
    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
        handleClose(false);
        return false;
    }

    @Override
    protected void handleClose(boolean animate) {
        if (mIsOpen) {
            mIsOpen = false;
            mLauncher.getDragLayer().removeView(this);
            // Reset the all-apps progress to what ever it was previously.
            mLauncher.getAllAppsController().setProgress(mLauncher.getStateManager()
                    .getState().getVerticalProgress(mLauncher));
        }
    }

    @Override
    public void logActionCommand(int command) {
        // Since this is on-boarding popup, it is not a user controlled action.
    }

    @Override
    protected boolean isOfType(int type) {
        return (type & TYPE_DISCOVERY_BOUNCE) != 0;
    }

    private void show(int containerType) {
        mIsOpen = true;
        mLauncher.getDragLayer().addView(this);
        mLauncher.getUserEventDispatcher().logActionBounceTip(containerType);
    }

    public static void showForHomeIfNeeded(Launcher launcher) {
        showForHomeIfNeeded(launcher, true);
    }

    private static void showForHomeIfNeeded(Launcher launcher, boolean withDelay) {
        if (!launcher.isInState(NORMAL)
                || launcher.getSharedPrefs().getBoolean(HOME_BOUNCE_SEEN, false)
                || AbstractFloatingView.getTopOpenView(launcher) != null
                || UserManagerCompat.getInstance(launcher).isDemoUser()
                || ActivityManager.isRunningInTestHarness()) {
            return;
        }

        if (withDelay) {
            new Handler().postDelayed(() -> showForHomeIfNeeded(launcher, false), DELAY_MS);
            return;
        }

//        new DiscoveryBounce(launcher, 0).show(HOTSEAT);
    }

    public static void showForOverviewIfNeeded(Launcher launcher) {
        showForOverviewIfNeeded(launcher, true);
    }

    private static void showForOverviewIfNeeded(Launcher launcher, boolean withDelay) {
        if (!launcher.isInState(OVERVIEW)
                || !launcher.hasBeenResumed()
                || launcher.isForceInvisible()
                || launcher.getDeviceProfile().isVerticalBarLayout()
                || launcher.getSharedPrefs().getBoolean(SHELF_BOUNCE_SEEN, false)
                || UserManagerCompat.getInstance(launcher).isDemoUser()
                || ActivityManager.isRunningInTestHarness()) {
            return;
        }

        if (withDelay) {
            new Handler().postDelayed(() -> showForOverviewIfNeeded(launcher, false), DELAY_MS);
            return;
        } else if (InternalStateHandler.hasPending()
                || AbstractFloatingView.getTopOpenView(launcher) != null) {
            // TODO: Move these checks to the top and call this method after invalidate handler.
            return;
        }

        new DiscoveryBounce(launcher, (1 - OVERVIEW.getVerticalProgress(launcher)))
                .show(PREDICTION);
    }

    /**
     * A wrapper around {@link AllAppsTransitionController} allowing a fixed shift in the value.
     */
    public static class VerticalProgressWrapper {

        private final float mDelta;
        private final AllAppsTransitionController mController;

        private VerticalProgressWrapper(AllAppsTransitionController controller, float delta) {
            mController = controller;
            mDelta = delta;
        }

        public float getProgress() {
            return mController.getProgress() + mDelta;
        }

        public void setProgress(float progress) {
            mController.setProgress(progress - mDelta);
        }
    }
}
