RotateImageView.java revision 94ca8baae7e6e3885d895c095890eabf30d922e2
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
17package com.android.camera.ui;
18
19import com.android.camera.ui.Rotatable;
20
21import android.content.Context;
22import android.graphics.Bitmap;
23import android.graphics.Canvas;
24import android.graphics.Rect;
25import android.graphics.drawable.BitmapDrawable;
26import android.graphics.drawable.Drawable;
27import android.graphics.drawable.TransitionDrawable;
28import android.media.ThumbnailUtils;
29import android.util.AttributeSet;
30import android.view.ViewGroup.LayoutParams;
31import android.view.animation.AnimationUtils;
32import android.widget.ImageView;
33
34/**
35 * A @{code ImageView} which can rotate it's content.
36 */
37public 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
53    public RotateImageView(Context context, AttributeSet attrs) {
54        super(context, attrs);
55    }
56
57    public RotateImageView(Context context) {
58        super(context);
59    }
60
61    public void enableAnimation(boolean enable) {
62        mEnableAnimation = enable;
63    }
64
65    protected int getDegree() {
66        return mTargetDegree;
67    }
68
69    public void setOrientation(int orientation) {
70        setDegree(orientation);
71    }
72
73    // Rotate the view counter-clockwise
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
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
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