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