| /* |
| * Copyright (C) 2009 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.ui; |
| |
| import android.content.Context; |
| import android.graphics.Bitmap; |
| import android.graphics.Canvas; |
| import android.graphics.Rect; |
| import android.graphics.drawable.BitmapDrawable; |
| import android.graphics.drawable.Drawable; |
| import android.graphics.drawable.TransitionDrawable; |
| import android.media.ThumbnailUtils; |
| import android.util.AttributeSet; |
| import android.view.ViewGroup.LayoutParams; |
| import android.view.animation.AnimationUtils; |
| import android.widget.ImageView; |
| |
| /** |
| * A @{code ImageView} which can rotate it's content. |
| */ |
| public class RotateImageView extends TwoStateImageView implements Rotatable { |
| |
| @SuppressWarnings("unused") |
| private static final String TAG = "RotateImageView"; |
| |
| private static final int ANIMATION_SPEED = 270; // 270 deg/sec |
| |
| private int mCurrentDegree = 0; // [0, 359] |
| private int mStartDegree = 0; |
| private int mTargetDegree = 0; |
| |
| private boolean mClockwise = false, mEnableAnimation = true; |
| |
| private long mAnimationStartTime = 0; |
| private long mAnimationEndTime = 0; |
| |
| public RotateImageView(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| } |
| |
| public RotateImageView(Context context) { |
| super(context); |
| } |
| |
| protected int getDegree() { |
| return mTargetDegree; |
| } |
| |
| // Rotate the view counter-clockwise |
| @Override |
| public void setOrientation(int degree, boolean animation) { |
| mEnableAnimation = animation; |
| // make sure in the range of [0, 359] |
| degree = degree >= 0 ? degree % 360 : degree % 360 + 360; |
| if (degree == mTargetDegree) return; |
| |
| mTargetDegree = degree; |
| if (mEnableAnimation) { |
| mStartDegree = mCurrentDegree; |
| mAnimationStartTime = AnimationUtils.currentAnimationTimeMillis(); |
| |
| int diff = mTargetDegree - mCurrentDegree; |
| diff = diff >= 0 ? diff : 360 + diff; // make it in range [0, 359] |
| |
| // Make it in range [-179, 180]. That's the shorted distance between the |
| // two angles |
| diff = diff > 180 ? diff - 360 : diff; |
| |
| mClockwise = diff >= 0; |
| mAnimationEndTime = mAnimationStartTime |
| + Math.abs(diff) * 1000 / ANIMATION_SPEED; |
| } else { |
| mCurrentDegree = mTargetDegree; |
| } |
| |
| invalidate(); |
| } |
| |
| @Override |
| protected void onDraw(Canvas canvas) { |
| Drawable drawable = getDrawable(); |
| if (drawable == null) return; |
| |
| Rect bounds = drawable.getBounds(); |
| int w = bounds.right - bounds.left; |
| int h = bounds.bottom - bounds.top; |
| |
| if (w == 0 || h == 0) return; // nothing to draw |
| |
| if (mCurrentDegree != mTargetDegree) { |
| long time = AnimationUtils.currentAnimationTimeMillis(); |
| if (time < mAnimationEndTime) { |
| int deltaTime = (int)(time - mAnimationStartTime); |
| int degree = mStartDegree + ANIMATION_SPEED |
| * (mClockwise ? deltaTime : -deltaTime) / 1000; |
| degree = degree >= 0 ? degree % 360 : degree % 360 + 360; |
| mCurrentDegree = degree; |
| invalidate(); |
| } else { |
| mCurrentDegree = mTargetDegree; |
| } |
| } |
| |
| int left = getPaddingLeft(); |
| int top = getPaddingTop(); |
| int right = getPaddingRight(); |
| int bottom = getPaddingBottom(); |
| int width = getWidth() - left - right; |
| int height = getHeight() - top - bottom; |
| |
| int saveCount = canvas.getSaveCount(); |
| |
| // Scale down the image first if required. |
| if ((getScaleType() == ImageView.ScaleType.FIT_CENTER) && |
| ((width < w) || (height < h))) { |
| float ratio = Math.min((float) width / w, (float) height / h); |
| canvas.scale(ratio, ratio, width / 2.0f, height / 2.0f); |
| } |
| canvas.translate(left + width / 2, top + height / 2); |
| canvas.rotate(-mCurrentDegree); |
| canvas.translate(-w / 2, -h / 2); |
| drawable.draw(canvas); |
| canvas.restoreToCount(saveCount); |
| } |
| |
| private Bitmap mThumb; |
| private Drawable[] mThumbs; |
| private TransitionDrawable mThumbTransition; |
| |
| public void setBitmap(Bitmap bitmap) { |
| // Make sure uri and original are consistently both null or both |
| // non-null. |
| if (bitmap == null) { |
| mThumb = null; |
| mThumbs = null; |
| setImageDrawable(null); |
| setVisibility(GONE); |
| return; |
| } |
| |
| LayoutParams param = getLayoutParams(); |
| final int miniThumbWidth = param.width |
| - getPaddingLeft() - getPaddingRight(); |
| final int miniThumbHeight = param.height |
| - getPaddingTop() - getPaddingBottom(); |
| mThumb = ThumbnailUtils.extractThumbnail( |
| bitmap, miniThumbWidth, miniThumbHeight); |
| Drawable drawable; |
| if (mThumbs == null || !mEnableAnimation) { |
| mThumbs = new Drawable[2]; |
| mThumbs[1] = new BitmapDrawable(getContext().getResources(), mThumb); |
| setImageDrawable(mThumbs[1]); |
| } else { |
| mThumbs[0] = mThumbs[1]; |
| mThumbs[1] = new BitmapDrawable(getContext().getResources(), mThumb); |
| mThumbTransition = new TransitionDrawable(mThumbs); |
| setImageDrawable(mThumbTransition); |
| mThumbTransition.startTransition(500); |
| } |
| setVisibility(VISIBLE); |
| } |
| } |