blob: 0215a2f23b1d7d092d9cc164ddaa2814a73b01a0 [file] [log] [blame]
/*
* Copyright (C) 2014 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.camera.widget;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import com.android.camera.util.CameraUtil;
import com.android.camera2.R;
/**
* An ImageView which has the built-in peek animation support.
*/
public class PeekView extends ImageView {
private static final float ROTATE_ANGLE = -7f;
private static final long PEEK_IN_DURATION_MS = 200;
private static final long PEEK_STAY_DURATION_MS = 100;
private static final long PEEK_OUT_DURATION_MS = 200;
private static final float FILMSTRIP_SCALE = 0.7f;
private AnimatorSet mPeekAnimator;
private float mPeekRotateAngle;
private Point mRotationPivot;
private float mRotateScale;
private boolean mAnimationCanceled;
private Drawable mImageDrawable;
private Rect mDrawableBound;
public PeekView(Context context) {
super(context);
init();
}
public PeekView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PeekView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mRotationPivot = new Point();
}
@Override
protected void onDraw(Canvas c) {
super.onDraw(c);
if (mImageDrawable == null) {
return;
}
c.save();
c.rotate(mPeekRotateAngle, mRotationPivot.x, mRotationPivot.y);
mImageDrawable.setBounds(mDrawableBound);
mImageDrawable.draw(c);
c.restore();
}
/**
* Starts the peek animation.
*
* @param bitmap The bitmap for the animation.
* @param strong {@code true} if the animation is the strong version which
* shows more portion of the bitmap.
* @param accessibilityString An accessibility String to be announced
during the peek animation.
*/
public void startPeekAnimation(final Bitmap bitmap, boolean strong,
String accessibilityString) {
ValueAnimator.AnimatorUpdateListener updateListener =
new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mPeekRotateAngle = mRotateScale * (Float) valueAnimator.getAnimatedValue();
invalidate();
}
};
ValueAnimator peekAnimateIn = ValueAnimator.ofFloat(0f, ROTATE_ANGLE);
ValueAnimator peekAnimateStay = ValueAnimator.ofFloat(ROTATE_ANGLE, ROTATE_ANGLE);
ValueAnimator peekAnimateOut = ValueAnimator.ofFloat(ROTATE_ANGLE, 0f);
peekAnimateIn.addUpdateListener(updateListener);
peekAnimateOut.addUpdateListener(updateListener);
peekAnimateIn.setDuration(PEEK_IN_DURATION_MS);
peekAnimateStay.setDuration(PEEK_STAY_DURATION_MS);
peekAnimateOut.setDuration(PEEK_OUT_DURATION_MS);
peekAnimateIn.setInterpolator(new DecelerateInterpolator());
peekAnimateOut.setInterpolator(new AccelerateInterpolator());
mPeekAnimator = new AnimatorSet();
mPeekAnimator.playSequentially(peekAnimateIn, peekAnimateStay, peekAnimateOut);
mPeekAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
setVisibility(VISIBLE);
mAnimationCanceled = false;
invalidate();
}
@Override
public void onAnimationEnd(Animator animator) {
if (!mAnimationCanceled) {
clear();
}
}
@Override
public void onAnimationCancel(Animator animator) {
mAnimationCanceled = true;
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mRotateScale = (strong ? 1.0f : 0.5f);
mImageDrawable = new BitmapDrawable(getResources(), bitmap);
Point drawDim = CameraUtil.resizeToFill(mImageDrawable.getIntrinsicWidth(),
mImageDrawable.getIntrinsicHeight(), 0, (int) (getWidth() * FILMSTRIP_SCALE),
(int) (getHeight() * FILMSTRIP_SCALE));
int x = getMeasuredWidth();
int y = (getMeasuredHeight() - drawDim.y) / 2;
mDrawableBound = new Rect(x, y, x + drawDim.x, y + drawDim.y);
mRotationPivot.set(x, (int) (y + drawDim.y * 1.1));
mPeekAnimator.start();
announceForAccessibility(accessibilityString);
}
/**
* @return whether the animation is running.
*/
public boolean isPeekAnimationRunning() {
return mPeekAnimator.isRunning();
}
/**
* Stops the animation. See {@link android.animation.Animator#end()}.
*/
public void stopPeekAnimation() {
if (isPeekAnimationRunning()) {
mPeekAnimator.end();
} else {
clear();
}
}
/**
* Cancels the animation. See {@link android.animation.Animator#cancel()}.
*/
public void cancelPeekAnimation() {
if (isPeekAnimationRunning()) {
mPeekAnimator.cancel();
} else {
clear();
}
}
private void clear() {
setVisibility(INVISIBLE);
setImageDrawable(null);
}
}