// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.toolbar;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v7.app.ActionBar;
import android.util.Property;
import org.chromium.chrome.R;
/**
* This class controls the how toolbar animates while the action mode bar is being shown. It also
* manages a {@link ToolbarActionModeCallback}.
*/
public class ActionModeController {
private static final int SLIDE_DURATION_MS = 200;
private ToolbarActionModeCallback mToolbarActionModeCallback;
private ObjectAnimator mCurrentAnimation = null;
private boolean mShowingActionMode = false;
private float mTabStripHeight;
private final Context mContext;
private final ActionBarDelegate mActionBarDelegate;
/** Property for animating the top margin of ActionBarDelegate. */
public static final Property<ActionBarDelegate, Integer> TOP_MARGIN_ANIM_PROPERTY =
new Property<ActionBarDelegate, Integer>(Integer.class, "controlTopMargin") {
@Override
public Integer get(ActionBarDelegate delegate) {
return delegate.getControlTopMargin();
}
@Override
public void set(ActionBarDelegate delegate, Integer value) {
delegate.setControlTopMargin(value);
}
};
/**
* This is an interface for to let the controller animate the position of {@link Toolbar}, while
* action mode is showing.
*/
public interface ActionBarDelegate {
/**
* Sets the top margin of the control container.
* @param margin The new top margin of the control container.
*/
public void setControlTopMargin(int margin);
/**
* @return The top margin of the control container.
*/
public int getControlTopMargin();
/**
* @return The action bar that will be animated in and out.
*/
public ActionBar getSupportActionBar();
/**
* Change the background visibility for the action bar.
* @param visible Whether the background should be visible.
*/
public void setActionBarBackgroundVisibility(boolean visible);
}
/**
* Creates the {@link ActionModeController} and ties it to an action bar using the given action
* bar delegate.
* @param actionBarDelegate The delegate for communicating with toolbar for animation.
*/
public ActionModeController(Context context, ActionBarDelegate actionBarDelegate) {
mActionBarDelegate = actionBarDelegate;
mContext = context;
mTabStripHeight = mContext.getResources().getDimension(R.dimen.tab_strip_height);
}
/**
* Overrides the preset height of the tab strip.
*/
public void setTabStripHeight(int tabStripHeight) {
mTabStripHeight = tabStripHeight;
}
/**
* @return The delegate handling action bar positioning for the custom action bar.
*/
public ActionBarDelegate getActionBarDelegate() {
return mActionBarDelegate;
}
/**
* Sets the custom ActionMode.Callback
*/
public void setCustomSelectionActionModeCallback(
ToolbarActionModeCallback toolbarActionModeCallback) {
if (toolbarActionModeCallback.equals(mToolbarActionModeCallback)) return;
mToolbarActionModeCallback = toolbarActionModeCallback;
mToolbarActionModeCallback.setActionModeController(this);
}
/**
* @return The custom ActionMode.Callback.
*/
public ToolbarActionModeCallback getActionModeCallback() {
return mToolbarActionModeCallback;
}
/**
* @return The current action bar height.
*/
private int queryCurrentActionBarHeight() {
ActionBar actionBar = mActionBarDelegate.getSupportActionBar();
if (actionBar != null) return actionBar.getHeight();
TypedArray styledAttributes =
mContext.obtainStyledAttributes(new int[] {R.attr.actionBarSize});
int height = styledAttributes.getDimensionPixelSize(0, 0);
styledAttributes.recycle();
return height;
}
/**
* Show controls after orientation change if previously visible.
*/
public void showControlsOnOrientationChange() {
if (mShowingActionMode && mCurrentAnimation == null) {
startShowAnimation();
}
}
/**
* Animation for the textview if the action bar is visible.
*/
public void startShowAnimation() {
if (mCurrentAnimation != null) mCurrentAnimation.cancel();
mCurrentAnimation = ObjectAnimator.ofInt(mActionBarDelegate, TOP_MARGIN_ANIM_PROPERTY,
(int) (Math.max(0, queryCurrentActionBarHeight() - mTabStripHeight))).setDuration(
SLIDE_DURATION_MS);
mCurrentAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentAnimation = null;
}
});
mCurrentAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
ActionBar actionBar = mActionBarDelegate.getSupportActionBar();
if (actionBar != null) {
animation.setIntValues((int) (Math.max(0,
queryCurrentActionBarHeight() - mTabStripHeight)));
}
}
});
mActionBarDelegate.setActionBarBackgroundVisibility(true);
mCurrentAnimation.start();
mShowingActionMode = true;
}
/**
* Hide animation for the textview if the action bar is not visible.
*/
public void startHideAnimation() {
if (mCurrentAnimation != null) mCurrentAnimation.cancel();
mCurrentAnimation = ObjectAnimator.ofInt(mActionBarDelegate, TOP_MARGIN_ANIM_PROPERTY,
0).setDuration(SLIDE_DURATION_MS);
mCurrentAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentAnimation = null;
mActionBarDelegate.setActionBarBackgroundVisibility(false);
}
});
mCurrentAnimation.start();
mShowingActionMode = false;
}
}