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

Commit d8b3f2e8 authored by Adam Powell's avatar Adam Powell
Browse files

Action mode animations

Change-Id: I132791217a38257e4fe730f2dd364cf48069c75d
parent 26e30bb7
Loading
Loading
Loading
Loading
+118 −29
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@ import com.android.internal.view.menu.SubMenuBuilder;
import com.android.internal.widget.ActionBarContextView;
import com.android.internal.widget.ActionBarView;

import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.app.ActionBar;
import android.app.Activity;
import android.app.Dialog;
@@ -36,6 +40,7 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.SpinnerAdapter;
import android.widget.ViewAnimator;
@@ -58,7 +63,7 @@ public class ActionBarImpl extends ActionBar {
    private Activity mActivity;
    private Dialog mDialog;

    private ViewAnimator mAnimatorView;
    private FrameLayout mContainerView;
    private ActionBarView mActionView;
    private ActionBarContextView mUpperContextView;
    private LinearLayout mLowerContextView;
@@ -81,16 +86,51 @@ public class ActionBarImpl extends ActionBar {

    private int mContextDisplayMode;

    private boolean mClosingContext;

    final Handler mHandler = new Handler();
    final Runnable mCloseContext = new Runnable() {
        public void run() {
            mUpperContextView.closeMode();

    private Animator mCurrentAnimation;

    final AnimatorListener[] mAfterAnimation = new AnimatorListener[] {
            new AnimatorListener() { // NORMAL_VIEW
                @Override
                public void onAnimationStart(Animator animation) {
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    if (mLowerContextView != null) {
                        mLowerContextView.removeAllViews();
                    }
            mClosingContext = false;
                    mCurrentAnimation = null;
                    hideAllExcept(NORMAL_VIEW);
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                }

                @Override
                public void onAnimationRepeat(Animator animation) {
                }
            },
            new AnimatorListener() { // CONTEXT_VIEW
                @Override
                public void onAnimationStart(Animator animation) {
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    mCurrentAnimation = null;
                    hideAllExcept(CONTEXT_VIEW);
                }

                @Override
                public void onAnimationCancel(Animator animation) {
                }

                @Override
                public void onAnimationRepeat(Animator animation) {
                }
            }
    };

@@ -111,10 +151,10 @@ public class ActionBarImpl extends ActionBar {
                com.android.internal.R.id.action_context_bar);
        mLowerContextView = (LinearLayout) decor.findViewById(
                com.android.internal.R.id.lower_action_context_bar);
        mAnimatorView = (ViewAnimator) decor.findViewById(
                com.android.internal.R.id.action_bar_animator);
        mContainerView = (FrameLayout) decor.findViewById(
                com.android.internal.R.id.action_bar_container);

        if (mActionView == null || mUpperContextView == null || mAnimatorView == null) {
        if (mActionView == null || mUpperContextView == null || mContainerView == null) {
            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
                    "with a compatible window decor layout");
        }
@@ -265,18 +305,11 @@ public class ActionBarImpl extends ActionBar {
            mActionMode.finish();
        }

        // Don't wait for the close context mode animation to finish.
        if (mClosingContext) {
            mAnimatorView.clearAnimation();
            mHandler.removeCallbacks(mCloseContext);
            mCloseContext.run();
        }

        ActionMode mode = new ActionModeImpl(callback);
        if (callback.onCreateActionMode(mode, mode.getMenu())) {
            mode.invalidate();
            mUpperContextView.initForMode(mode);
            mAnimatorView.setDisplayedChild(CONTEXT_VIEW);
            animateTo(CONTEXT_VIEW);
            if (mLowerContextView != null) {
                // TODO animate this
                mLowerContextView.setVisibility(View.VISIBLE);
@@ -412,17 +445,63 @@ public class ActionBarImpl extends ActionBar {
    @Override
    public void show() {
        // TODO animate!
        mAnimatorView.setVisibility(View.VISIBLE);
        mContainerView.setVisibility(View.VISIBLE);
    }

    @Override
    public void hide() {
        // TODO animate!
        mAnimatorView.setVisibility(View.GONE);
        mContainerView.setVisibility(View.GONE);
    }

    public boolean isShowing() {
        return mAnimatorView.getVisibility() == View.VISIBLE;
        return mContainerView.getVisibility() == View.VISIBLE;
    }

    private long animateTo(int viewIndex) {
        // Don't wait for the current animation to finish.
        if (mCurrentAnimation != null) {
            mCurrentAnimation.end();
        }

        AnimatorSet set = new AnimatorSet();

        final View targetChild = mContainerView.getChildAt(viewIndex);
        targetChild.setVisibility(View.VISIBLE);
        AnimatorSet.Builder b = set.play(ObjectAnimator.ofFloat(targetChild, "alpha", 1));
        if (viewIndex == NORMAL_VIEW) {
            targetChild.setScaleY(0);
            b.with(ObjectAnimator.ofFloat(targetChild, "scaleY", 1));
        }

        final int count = mContainerView.getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = mContainerView.getChildAt(i);
            if (i == viewIndex) {
                continue;
            }

            if (child.getVisibility() != View.GONE) {
                ObjectAnimator a = ObjectAnimator.ofFloat(child, "alpha", 0);
                b.with(a);
                if (viewIndex == CONTEXT_VIEW) {
                    b.with(ObjectAnimator.ofFloat(child, "scaleY", 0));
                }
            }
        }

        set.addListener(mAfterAnimation[viewIndex]);

        mCurrentAnimation = set;
        set.start();
        return set.getDuration();
    }

    private void hideAllExcept(int viewIndex) {
        final int count = mContainerView.getChildCount();
        for (int i = 0; i < count; i++) {
            mContainerView.getChildAt(i).setVisibility(i == viewIndex ? View.VISIBLE : View.GONE);
        }
    }

    /**
@@ -458,12 +537,11 @@ public class ActionBarImpl extends ActionBar {
            }

            mCallback.onDestroyActionMode(this);
            mAnimatorView.setDisplayedChild(NORMAL_VIEW);
            mCallback = null;
            animateTo(NORMAL_VIEW);

            // Clear out the context mode views after the animation finishes
            mClosingContext = true;
            mHandler.postDelayed(mCloseContext, mAnimatorView.getOutAnimation().getDuration());

            mUpperContextView.closeMode();
            if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) {
                // TODO Animate this
                mLowerContextView.setVisibility(View.GONE);
@@ -520,13 +598,21 @@ public class ActionBarImpl extends ActionBar {
        }

        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
            if (mCallback != null) {
                return mCallback.onActionItemClicked(this, item);
            } else {
                return false;
            }
        }

        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
        }

        public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
            if (mCallback == null) {
                return false;
            }

            if (!subMenu.hasVisibleItems()) {
                return true;
            }
@@ -539,6 +625,9 @@ public class ActionBarImpl extends ActionBar {
        }

        public void onMenuModeChange(MenuBuilder menu) {
            if (mCallback == null) {
                return;
            }
            invalidate();
            mUpperContextView.openOverflowMenu();
        }
+123 −3
Original line number Diff line number Diff line
@@ -19,20 +19,26 @@ import com.android.internal.R;
import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.MenuBuilder;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * @hide
 */
public class ActionBarContextView extends ViewGroup {
public class ActionBarContextView extends ViewGroup implements AnimatorListener {
    private int mContentHeight;
    
    private CharSequence mTitle;
@@ -47,6 +53,14 @@ public class ActionBarContextView extends ViewGroup {
    private int mSubtitleStyleRes;
    private ActionMenuView mMenuView;

    private Animator mCurrentAnimation;
    private boolean mAnimateInOnLayout;
    private int mAnimationMode;

    private static final int ANIMATE_IDLE = 0;
    private static final int ANIMATE_IN = 1;
    private static final int ANIMATE_OUT = 2;
    
    public ActionBarContextView(Context context) {
        this(context, null);
    }
@@ -145,10 +159,14 @@ public class ActionBarContextView extends ViewGroup {
    }

    public void initForMode(final ActionMode mode) {
        if (mCurrentAnimation != null && mCurrentAnimation.isRunning()) {
            mCurrentAnimation.end();
            killMode();
        }
        if (mClose == null) {
            LayoutInflater inflater = LayoutInflater.from(mContext);
            inflater.inflate(R.layout.action_mode_close_item, this);
            mClose = getChildAt(getChildCount() - 1);
            mClose = inflater.inflate(R.layout.action_mode_close_item, this, false);
            addView(mClose);
        } else {
            addView(mClose);
        }
@@ -165,9 +183,30 @@ public class ActionBarContextView extends ViewGroup {
        mMenuView.setOverflowReserved(true);
        mMenuView.updateChildren(false);
        addView(mMenuView);

        mAnimateInOnLayout = true;
    }

    public void closeMode() {
        if (mClose == null) {
            killMode();
            return;
        }

        mAnimationMode = ANIMATE_OUT;
        finishAnimation();
        mCurrentAnimation = makeOutAnimation();
        mCurrentAnimation.start();
    }

    private void finishAnimation() {
        if (mCurrentAnimation != null && mCurrentAnimation.isRunning()) {
            mCurrentAnimation.end();
        }
    }

    public void killMode() {
        finishAnimation();
        removeAllViews();
        mCustomView = null;
        mMenuView = null;
@@ -279,6 +318,60 @@ public class ActionBarContextView extends ViewGroup {
        }
    }

    private Animator makeInAnimation() {
        mClose.setTranslationX(-mClose.getWidth());
        ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", 0);
        buttonAnimator.setDuration(200);
        buttonAnimator.addListener(this);
        buttonAnimator.setInterpolator(new DecelerateInterpolator());

        AnimatorSet set = new AnimatorSet();
        AnimatorSet.Builder b = set.play(buttonAnimator);

        if (mMenuView != null) {
            final int count = mMenuView.getChildCount();
            if (count > 0) {
                for (int i = count - 1, j = 0; i >= 0; i--, j++) {
                    View child = mMenuView.getChildAt(i);
                    child.setScaleY(0);
                    ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0, 1);
                    a.setDuration(100);
                    a.setStartDelay(j * 70);
                    b.with(a);
                }
            }
        }

        return set;
    }

    private Animator makeOutAnimation() {
        ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
                0, -mClose.getWidth());
        buttonAnimator.setDuration(200);
        buttonAnimator.addListener(this);
        buttonAnimator.setInterpolator(new DecelerateInterpolator());

        AnimatorSet set = new AnimatorSet();
        AnimatorSet.Builder b = set.play(buttonAnimator);

        if (mMenuView != null) {
            final int count = mMenuView.getChildCount();
            if (count > 0) {
                for (int i = 0; i < 0; i++) {
                    View child = mMenuView.getChildAt(i);
                    child.setScaleY(0);
                    ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 1, 0);
                    a.setDuration(100);
                    a.setStartDelay(i * 70);
                    b.with(a);
                }
            }
        }

        return set;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int x = getPaddingLeft();
@@ -287,6 +380,13 @@ public class ActionBarContextView extends ViewGroup {
        
        if (mClose != null && mClose.getVisibility() != GONE) {
            x += positionChild(mClose, x, y, contentHeight);

            if (mAnimateInOnLayout) {
                mAnimationMode = ANIMATE_IN;
                mCurrentAnimation = makeInAnimation();
                mCurrentAnimation.start();
                mAnimateInOnLayout = false;
            }
        }
        
        if (mTitleLayout != null && mCustomView == null) {
@@ -333,4 +433,24 @@ public class ActionBarContextView extends ViewGroup {

        return childWidth;
    }

    @Override
    public void onAnimationStart(Animator animation) {
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        if (mAnimationMode == ANIMATE_OUT) {
            killMode();
        }
        mAnimationMode = ANIMATE_IDLE;
    }

    @Override
    public void onAnimationCancel(Animator animation) {
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
    }
}
+2.41 KiB
Loading image diff...
+2.75 KiB
Loading image diff...
+2.41 KiB
Loading image diff...
Loading