// 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.compositor.layouts.phone.stack;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import org.chromium.chrome.browser.compositor.layouts.phone.stack.StackAnimation.OverviewAnimationType;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.ui.base.LocalizationUtils;
import org.chromium.ui.interpolators.BakedBezierInterpolator;
/**
* A factory that builds Android view animations for the tab stack.
*/
public class StackViewAnimation {
private static final int TAB_OPENED_ANIMATION_DURATION = 300;
private static final float TAB_OPENED_PIVOT_INSET_DP = 24.f;
private final float mDpToPx;
private final float mWidthDp;
/**
* Constructor.
* NOTE: Pass in height and heightMinusTopControls if they're ever needed.
*
* @param dpToPx The density of the device.
* @param widthDp The width of the layout in dp.
*/
public StackViewAnimation(float dpToPx, float widthDp) {
mDpToPx = dpToPx;
mWidthDp = widthDp;
}
/**
* The wrapper method responsible for delegating animation requests to the appropriate helper
* method.
* @param type The type of animation to be created. This is what determines which helper
* method is called.
* @param tabs The tabs that make up the current stack.
* @param container The {@link ViewGroup} that {@link View}s can be added to/removed from.
* @param model The {@link TabModel} that this animation will influence.
* @param focusIndex The index of the tab that is the focus of this animation.
* @return The resulting {@link Animator} that will animate the Android views.
*/
public Animator createAnimatorForType(OverviewAnimationType type, StackTab[] tabs,
ViewGroup container, TabModel model, int focusIndex) {
Animator animator = null;
if (model != null) {
switch (type) {
case NEW_TAB_OPENED:
animator = createNewTabOpenedAnimator(tabs, container, model, focusIndex);
break;
default:
break;
}
}
return animator;
}
private Animator createNewTabOpenedAnimator(
StackTab[] tabs, ViewGroup container, TabModel model, int focusIndex) {
Tab tab = model.getTabAt(focusIndex);
if (tab == null || !tab.isNativePage()) return null;
View view = tab.getView();
if (view == null) return null;
// Set up the view hierarchy
if (view.getParent() != null) ((ViewGroup) view.getParent()).removeView(view);
ViewGroup bgView = new FrameLayout(view.getContext());
bgView.setBackgroundColor(tab.getBackgroundColor());
bgView.addView(view);
container.addView(
bgView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
// Update any compositor state that needs to change
if (tabs != null && focusIndex >= 0 && focusIndex < tabs.length) {
tabs[focusIndex].setAlpha(0.f);
}
// Build the view animations
PropertyValuesHolder xScale = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.f, 1.f);
PropertyValuesHolder yScale = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.f, 1.f);
PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat(View.ALPHA, 0.f, 1.f);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(
bgView, xScale, yScale, alpha);
animator.setDuration(TAB_OPENED_ANIMATION_DURATION);
animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_FOLLOW_THROUGH_CURVE);
float insetPx = TAB_OPENED_PIVOT_INSET_DP * mDpToPx;
bgView.setPivotY(TAB_OPENED_PIVOT_INSET_DP);
bgView.setPivotX(LocalizationUtils.isLayoutRtl() ? mWidthDp * mDpToPx - insetPx : insetPx);
return animator;
}
}