images = TransitionImage.readMultipleFromIntent(
activity, activity.getIntent());
TransitionImageAnimation ltransitionAnimation = null;
final Uri iconUri;
final int color;
if (images != null && images.size() > 0) {
if (iconResourceId != 0) {
iconUri = Uri.parse(UriUtils.getAndroidResourceUri(
activity, iconResourceId));
} else if (iconResourceUri != null) {
iconUri = iconResourceUri;
} else {
iconUri = null;
}
TransitionImage src = images.get(0);
color = src.getBackground();
if (iconUri != null) {
ltransitionAnimation = new TransitionImageAnimation(contentView);
ltransitionAnimation.addTransitionSource(src);
ltransitionAnimation.transitionDurationMs(ANIMATE_IN_DURATION)
.transitionStartDelayMs(0)
.interpolator(new DecelerateInterpolator(1f));
}
} else {
iconUri = null;
color = 0;
}
final TransitionImageAnimation transitionAnimation = ltransitionAnimation;
// Fade out the old activity, and hard cut the new activity.
activity.overridePendingTransition(R.anim.hard_cut_in, R.anim.fade_out);
int bgColor = mFragment.getResources().getColor(R.color.dialog_activity_background);
mBgDrawable.setColor(bgColor);
mBgDrawable.setAlpha(0);
twoPane.setBackground(mBgDrawable);
// If we're animating the icon, we create a new ImageView in which to place the embedded
// bitmap. We place it in the root layout to match its location in the previous activity.
mShadowLayer = (FrameLayoutWithShadows) twoPane.findViewById(R.id.shadow_layout);
if (transitionAnimation != null) {
transitionAnimation.listener(new TransitionImageAnimation.Listener() {
@Override
public void onRemovedView(TransitionImage src, TransitionImage dst) {
if (icon != null) {
//want to make sure that users still see at least the source image
// if the dst image is too large to finish downloading before the
// animation is done. Check if the icon is not visible. This mean
// BaseContentFragement have not finish downloading the image yet.
if (icon.getVisibility() != View.VISIBLE) {
icon.setImageDrawable(src.getBitmap());
int intrinsicWidth = icon.getDrawable().getIntrinsicWidth();
LayoutParams lp = icon.getLayoutParams();
lp.height = lp.width * icon.getDrawable().getIntrinsicHeight()
/ intrinsicWidth;
icon.setVisibility(View.VISIBLE);
}
icon.setAlpha(1f);
}
if (mShadowLayer != null) {
mShadowLayer.setShadowsAlpha(1f);
}
onIntroAnimationFinished();
}
});
icon.setAlpha(0f);
if (mShadowLayer != null) {
mShadowLayer.setShadowsAlpha(0f);
}
}
// We need to defer the remainder of the animation preparation until the first
// layout has occurred, as we don't yet know the final location of the icon.
twoPane.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
twoPane.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// if we buildLayer() at this time, the texture is actually not created
// delay a little so we can make sure all hardware layer is created before
// animation, in that way we can avoid the jittering of start animation
twoPane.postOnAnimationDelayed(mEntryAnimationRunnable, ANIMATE_DELAY);
}
final Runnable mEntryAnimationRunnable = new Runnable() {
@Override
public void run() {
if (!mFragment.isAdded()) {
// We have been detached before this could run, so just bail
return;
}
twoPane.setVisibility(View.VISIBLE);
final int secondaryDelay = SLIDE_IN_DISTANCE;
// Fade in the activity background protection
ObjectAnimator oa = ObjectAnimator.ofInt(mBgDrawable, "alpha", 255);
oa.setDuration(ANIMATE_IN_DURATION);
oa.setStartDelay(secondaryDelay);
oa.setInterpolator(new DecelerateInterpolator(1.0f));
oa.start();
View actionFragmentView = activity.findViewById(mActionAreaId);
boolean isRtl = ViewCompat.getLayoutDirection(contentView) ==
ViewCompat.LAYOUT_DIRECTION_RTL;
int startDist = isRtl ? SLIDE_IN_DISTANCE : -SLIDE_IN_DISTANCE;
int endDist = isRtl ? -actionFragmentView.getMeasuredWidth() :
actionFragmentView.getMeasuredWidth();
// Fade in and slide in the ContentFragment TextViews from the start.
prepareAndAnimateView(title, 0, startDist,
secondaryDelay, ANIMATE_IN_DURATION,
new DecelerateInterpolator(1.0f),
false);
prepareAndAnimateView(breadcrumb, 0, startDist,
secondaryDelay, ANIMATE_IN_DURATION,
new DecelerateInterpolator(1.0f),
false);
prepareAndAnimateView(description, 0,
startDist,
secondaryDelay, ANIMATE_IN_DURATION,
new DecelerateInterpolator(1.0f),
false);
// Fade in and slide in the ActionFragment from the end.
prepareAndAnimateView(actionFragmentView, 0,
endDist, secondaryDelay,
ANIMATE_IN_DURATION, new DecelerateInterpolator(1.0f),
false);
if (icon != null && transitionAnimation != null) {
// now we get the icon view in place, update the transition target
TransitionImage target = new TransitionImage();
target.setUri(iconUri);
target.createFromImageView(icon);
if (icon.getBackground() instanceof ColorDrawable) {
ColorDrawable d = (ColorDrawable) icon.getBackground();
target.setBackground(d.getColor());
}
transitionAnimation.addTransitionTarget(target);
transitionAnimation.startTransition();
} else if (icon != null) {
prepareAndAnimateView(icon, 0, startDist,
secondaryDelay, ANIMATE_IN_DURATION,
new DecelerateInterpolator(1.0f), true /* is the icon */);
if (mShadowLayer != null) {
mShadowLayer.setShadowsAlpha(0f);
}
}
}
};
});
}
/**
* Animates a view.
*
* @param v view to animate
* @param initAlpha initial alpha
* @param initTransX initial translation in the X
* @param delay delay in ms
* @param duration duration in ms
* @param interpolator interpolator to be used, can be null
* @param isIcon if {@code true}, this is the main icon being moved
*/
public void prepareAndAnimateView(final View v, float initAlpha, float initTransX, int delay,
int duration, Interpolator interpolator, final boolean isIcon) {
if (v != null && v.getWindowToken() != null) {
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
v.buildLayer();
v.setAlpha(initAlpha);
v.setTranslationX(initTransX);
v.animate().alpha(1f).translationX(0).setDuration(duration).setStartDelay(delay);
if (interpolator != null) {
v.animate().setInterpolator(interpolator);
}
v.animate().setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
v.setLayerType(View.LAYER_TYPE_NONE, null);
if (isIcon) {
if (mShadowLayer != null) {
mShadowLayer.setShadowsAlpha(1f);
}
onIntroAnimationFinished();
}
}
});
v.animate().start();
}
}
/**
* Called when intro animation is finished.
*
* If a subclass is going to alter the view, should wait until this is called.
*/
public void onIntroAnimationFinished() {
mIntroAnimationInProgress = false;
}
public boolean isIntroAnimationInProgress() {
return mIntroAnimationInProgress;
}
public ColorDrawable getBackgroundDrawable() {
return mBgDrawable;
}
public void setBackgroundDrawable(ColorDrawable drawable) {
mBgDrawable = drawable;
}
}