• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ui;
18 
19 import com.android.camera.ui.Rotatable;
20 
21 import android.content.Context;
22 import android.graphics.Bitmap;
23 import android.graphics.Canvas;
24 import android.graphics.Rect;
25 import android.graphics.drawable.BitmapDrawable;
26 import android.graphics.drawable.Drawable;
27 import android.graphics.drawable.TransitionDrawable;
28 import android.media.ThumbnailUtils;
29 import android.util.AttributeSet;
30 import android.view.ViewGroup.LayoutParams;
31 import android.view.animation.AnimationUtils;
32 import android.widget.ImageView;
33 
34 /**
35  * A @{code ImageView} which can rotate it's content.
36  */
37 public class RotateImageView extends ColorFilterImageView implements Rotatable {
38 
39     @SuppressWarnings("unused")
40     private static final String TAG = "RotateImageView";
41 
42     private static final int ANIMATION_SPEED = 270; // 270 deg/sec
43 
44     private int mCurrentDegree = 0; // [0, 359]
45     private int mStartDegree = 0;
46     private int mTargetDegree = 0;
47 
48     private boolean mClockwise = false, mEnableAnimation = true;
49 
50     private long mAnimationStartTime = 0;
51     private long mAnimationEndTime = 0;
52 
RotateImageView(Context context, AttributeSet attrs)53     public RotateImageView(Context context, AttributeSet attrs) {
54         super(context, attrs);
55     }
56 
RotateImageView(Context context)57     public RotateImageView(Context context) {
58         super(context);
59     }
60 
enableAnimation(boolean enable)61     public void enableAnimation(boolean enable) {
62         mEnableAnimation = enable;
63     }
64 
getDegree()65     protected int getDegree() {
66         return mTargetDegree;
67     }
68 
setOrientation(int orientation)69     public void setOrientation(int orientation) {
70         setDegree(orientation);
71     }
72 
73     // Rotate the view counter-clockwise
setDegree(int degree)74     public void setDegree(int degree) {
75         // make sure in the range of [0, 359]
76         degree = degree >= 0 ? degree % 360 : degree % 360 + 360;
77         if (degree == mTargetDegree) return;
78 
79         mTargetDegree = degree;
80         mStartDegree = mCurrentDegree;
81         mAnimationStartTime = AnimationUtils.currentAnimationTimeMillis();
82 
83         int diff = mTargetDegree - mCurrentDegree;
84         diff = diff >= 0 ? diff : 360 + diff; // make it in range [0, 359]
85 
86         // Make it in range [-179, 180]. That's the shorted distance between the
87         // two angles
88         diff = diff > 180 ? diff - 360 : diff;
89 
90         mClockwise = diff >= 0;
91         mAnimationEndTime = mAnimationStartTime
92                 + Math.abs(diff) * 1000 / ANIMATION_SPEED;
93 
94         invalidate();
95     }
96 
97     @Override
onDraw(Canvas canvas)98     protected void onDraw(Canvas canvas) {
99         Drawable drawable = getDrawable();
100         if (drawable == null) return;
101 
102         Rect bounds = drawable.getBounds();
103         int w = bounds.right - bounds.left;
104         int h = bounds.bottom - bounds.top;
105 
106         if (w == 0 || h == 0) return; // nothing to draw
107 
108         if (mCurrentDegree != mTargetDegree) {
109             long time = AnimationUtils.currentAnimationTimeMillis();
110             if (time < mAnimationEndTime) {
111                 int deltaTime = (int)(time - mAnimationStartTime);
112                 int degree = mStartDegree + ANIMATION_SPEED
113                         * (mClockwise ? deltaTime : -deltaTime) / 1000;
114                 degree = degree >= 0 ? degree % 360 : degree % 360 + 360;
115                 mCurrentDegree = degree;
116                 invalidate();
117             } else {
118                 mCurrentDegree = mTargetDegree;
119             }
120         }
121 
122         int left = getPaddingLeft();
123         int top = getPaddingTop();
124         int right = getPaddingRight();
125         int bottom = getPaddingBottom();
126         int width = getWidth() - left - right;
127         int height = getHeight() - top - bottom;
128 
129         int saveCount = canvas.getSaveCount();
130 
131         // Scale down the image first if required.
132         if ((getScaleType() == ImageView.ScaleType.FIT_CENTER) &&
133                 ((width < w) || (height < h))) {
134             float ratio = Math.min((float) width / w, (float) height / h);
135             canvas.scale(ratio, ratio, width / 2.0f, height / 2.0f);
136         }
137         canvas.translate(left + width / 2, top + height / 2);
138         canvas.rotate(-mCurrentDegree);
139         canvas.translate(-w / 2, -h / 2);
140         drawable.draw(canvas);
141         canvas.restoreToCount(saveCount);
142     }
143 
144     private Bitmap mThumb;
145     private Drawable[] mThumbs;
146     private TransitionDrawable mThumbTransition;
147 
setBitmap(Bitmap bitmap)148     public void setBitmap(Bitmap bitmap) {
149         // Make sure uri and original are consistently both null or both
150         // non-null.
151         if (bitmap == null) {
152             mThumb = null;
153             mThumbs = null;
154             setImageDrawable(null);
155             setVisibility(GONE);
156             return;
157         }
158 
159         LayoutParams param = getLayoutParams();
160         final int miniThumbWidth = param.width
161                 - getPaddingLeft() - getPaddingRight();
162         final int miniThumbHeight = param.height
163                 - getPaddingTop() - getPaddingBottom();
164         mThumb = ThumbnailUtils.extractThumbnail(
165                 bitmap, miniThumbWidth, miniThumbHeight);
166         Drawable drawable;
167         if (mThumbs == null || !mEnableAnimation) {
168             mThumbs = new Drawable[2];
169             mThumbs[1] = new BitmapDrawable(getContext().getResources(), mThumb);
170             setImageDrawable(mThumbs[1]);
171         } else {
172             mThumbs[0] = mThumbs[1];
173             mThumbs[1] = new BitmapDrawable(getContext().getResources(), mThumb);
174             mThumbTransition = new TransitionDrawable(mThumbs);
175             setImageDrawable(mThumbTransition);
176             mThumbTransition.startTransition(500);
177         }
178         setVisibility(VISIBLE);
179     }
180 }
181