1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.camera; 18 19 import android.content.Context; 20 import android.graphics.Canvas; 21 import android.graphics.Rect; 22 import android.graphics.drawable.Drawable; 23 import android.util.AttributeSet; 24 import android.view.animation.AnimationUtils; 25 import android.widget.ImageView; 26 27 /** 28 * A @{code ImageView} which can rotate it's content. 29 */ 30 public class RotateImageView extends ImageView { 31 32 @SuppressWarnings("unused") 33 private static final String TAG = "RotateImageView"; 34 35 private static final int ANIMATION_SPEED = 180; // 180 deg/sec 36 37 private int mCurrentDegree = 0; // [0, 359] 38 private int mStartDegree = 0; 39 private int mTargetDegree = 0; 40 41 private boolean mClockwise = false; 42 43 private long mAnimationStartTime = 0; 44 private long mAnimationEndTime = 0; 45 46 public RotateImageView(Context context, AttributeSet attrs) { 47 super(context, attrs); 48 } 49 50 public void setDegree(int degree) { 51 // make sure in the range of [0, 359] 52 degree = degree >= 0 ? degree % 360 : degree % 360 + 360; 53 if (degree == mTargetDegree) return; 54 55 mTargetDegree = degree; 56 mStartDegree = mCurrentDegree; 57 mAnimationStartTime = AnimationUtils.currentAnimationTimeMillis(); 58 59 int diff = mTargetDegree - mCurrentDegree; 60 diff = diff >= 0 ? diff : 360 + diff; // make it in range [0, 359] 61 62 // Make it in range [-179, 180]. That's the shorted distance between the 63 // two angles 64 diff = diff > 180 ? diff - 360 : diff; 65 66 mClockwise = diff >= 0; 67 mAnimationEndTime = mAnimationStartTime 68 + Math.abs(diff) * 1000 / ANIMATION_SPEED; 69 70 invalidate(); 71 } 72 73 @Override 74 protected void onDraw(Canvas canvas) { 75 76 Drawable drawable = getDrawable(); 77 if (drawable == null) return; 78 79 Rect bounds = drawable.getBounds(); 80 int w = bounds.right - bounds.left; 81 int h = bounds.bottom - bounds.top; 82 83 if (w == 0 || h == 0) return; // nothing to draw 84 85 if (mCurrentDegree != mTargetDegree) { 86 long time = AnimationUtils.currentAnimationTimeMillis(); 87 if (time < mAnimationEndTime) { 88 int deltaTime = (int)(time - mAnimationStartTime); 89 int degree = mStartDegree + ANIMATION_SPEED 90 * (mClockwise ? deltaTime : -deltaTime) / 1000; 91 degree = degree >= 0 ? degree % 360 : degree % 360 + 360; 92 mCurrentDegree = degree; 93 invalidate(); 94 } else { 95 mCurrentDegree = mTargetDegree; 96 } 97 } 98 99 int left = getPaddingLeft(); 100 int top = getPaddingTop(); 101 int right = getPaddingRight(); 102 int bottom = getPaddingBottom(); 103 int width = getWidth() - left - right; 104 int height = getHeight() - top - bottom; 105 106 int saveCount = canvas.getSaveCount(); 107 canvas.translate(left + width / 2, top + height / 2); 108 canvas.rotate(-mCurrentDegree); 109 canvas.translate(-w / 2, -h / 2); 110 drawable.draw(canvas); 111 canvas.restoreToCount(saveCount); 112 } 113 } 114