1ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi/*
2ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * Copyright (C) 2009 The Android Open Source Project
3ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *
4ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * Licensed under the Apache License, Version 2.0 (the "License");
5ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * you may not use this file except in compliance with the License.
6ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * You may obtain a copy of the License at
7ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *
8ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *      http://www.apache.org/licenses/LICENSE-2.0
9ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi *
10ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * Unless required by applicable law or agreed to in writing, software
11ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * distributed under the License is distributed on an "AS IS" BASIS,
12ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * See the License for the specific language governing permissions and
14ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * limitations under the License.
15ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi */
16ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
1781393d6dc5767f7784a00958095614a37bf1a91aGil Dobjanschipackage com.android.videoeditor.widgets;
18ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
19ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
20ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.content.Context;
21ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Bitmap;
22ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.Matrix;
23ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.RectF;
24ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.graphics.drawable.Drawable;
25ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.util.AttributeSet;
26ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.view.MotionEvent;
27ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschiimport android.widget.ImageView;
28ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
29ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi/**
30ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi * An image view which can be panned and zoomed.
31ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi */
32ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschipublic class ImageViewTouchBase extends ImageView {
33ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private static final float SCALE_RATE = 1.25F;
34ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // Zoom scale is applied after the transform that fits the image screen,
35ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // so 1.0 is a perfect fit and it doesn't make sense to allow smaller
36ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // values.
37ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private static final float MIN_ZOOM_SCALE = 1.0f;
38ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
39ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // This is the base transformation which is used to show the image
40ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // initially.  The current computation for this shows the image in
41ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // it's entirety, letterboxing as needed.  One could choose to
42ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // show the image as cropped instead.
43ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    //
44ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // This matrix is recomputed when we go from the thumbnail image to
45ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // the full size image.
46ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private Matrix mBaseMatrix = new Matrix();
47ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
48ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // This is the supplementary transformation which reflects what
49ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // the user has done in terms of zooming and panning.
50ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    //
51ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // This matrix remains the same when we go from the thumbnail image
52ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // to the full size image.
53ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private Matrix mSuppMatrix = new Matrix();
54ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
55ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // This is the final matrix which is computed as the concatenation
56ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // of the base matrix and the supplementary matrix.
57ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private final Matrix mDisplayMatrix = new Matrix();
58ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
59ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // Temporary buffer used for getting the values out of a matrix.
60ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private final float[] mMatrixValues = new float[9];
61ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
62ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // The current bitmap being displayed.
63ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private Bitmap mBitmapDisplayed;
64ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
65ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // The width and height of the view
66ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private int mThisWidth = -1, mThisHeight = -1;
67ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
68ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private boolean mStretch = true;
69ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    // The zoom scale
70ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private float mMaxZoom;
71ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private Runnable mOnLayoutRunnable = null;
72ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private ImageTouchEventListener mEventListener;
73ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
74ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
75ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Touch interface
76ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
77ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public interface ImageTouchEventListener {
78ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        public boolean onImageTouchEvent(MotionEvent ev);
79ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
80ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
81ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Constructor
82ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
83ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param context The context
84ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
85ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public ImageViewTouchBase(Context context) {
86ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super(context);
87ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        setScaleType(ImageView.ScaleType.MATRIX);
88ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
89ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
90ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
91ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Constructor
92ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
93ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param context The context
94ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param attrs The attributes
95ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
96ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public ImageViewTouchBase(Context context, AttributeSet attrs) {
97ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super(context, attrs);
98ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        setScaleType(ImageView.ScaleType.MATRIX);
99ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
100ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
101ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
102ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Constructor
103ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
104ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param context The context
105ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param attrs The attributes
106ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param defStyle The default style
107ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
108ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public ImageViewTouchBase(Context context, AttributeSet attrs, int defStyle) {
109ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super(context, attrs, defStyle);
110ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        setScaleType(ImageView.ScaleType.MATRIX);
111ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
112ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
113ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /*
114ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * {@inheritDoc}
115ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
116ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
117ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
118ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super.onLayout(changed, left, top, right, bottom);
119ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
120ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mThisWidth = right - left;
121ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mThisHeight = bottom - top;
122ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final Runnable r = mOnLayoutRunnable;
123ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (r != null) {
124ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            mOnLayoutRunnable = null;
125ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            r.run();
126ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        } else {
127ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            if (mBitmapDisplayed != null) {
128ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                getProperBaseMatrix(mBitmapDisplayed, mBaseMatrix);
129ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                setImageMatrix(getImageViewMatrix());
130ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
131ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
132ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
133ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
134ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /*
135ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * {@inheritDoc}
136ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
137ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
138ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public boolean dispatchTouchEvent(MotionEvent ev) {
139ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (mEventListener != null) {
140ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return mEventListener.onImageTouchEvent(ev);
141ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        } else {
142ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return false;
143ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
144ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
145ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
146ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /*
147ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * {@inheritDoc}
148ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
149ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    @Override
150ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void setImageBitmap(Bitmap bitmap) {
151ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        super.setImageBitmap(bitmap);
152ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
153ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final Drawable d = getDrawable();
154ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (d != null) {
155ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            d.setDither(true);
156ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
157ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
158ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mBitmapDisplayed = bitmap;
159ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
160ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
161ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
162ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param listener The listener
163ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
164ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void setEventListener(ImageTouchEventListener listener) {
165ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mEventListener = listener;
166ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
167ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
168ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
169ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The image bitmap
170ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
171ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public Bitmap getImageBitmap() {
172ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return mBitmapDisplayed;
173ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
174ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
175ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
176ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * If the view has not yet been measured delay the method
177ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
178ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param bitmap The bitmap
179ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param resetSupp true to reset the transform matrix
180ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
181ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void setImageBitmapResetBase(final Bitmap bitmap, final boolean resetSupp) {
182ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mStretch = true;
183ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final int viewWidth = getWidth();
184ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (viewWidth <= 0) {
185ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            mOnLayoutRunnable = new Runnable() {
186fe7b065c18808ac3bd15ea5a1248b3af66b50fb7Shih-chia Cheng                @Override
187ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                public void run() {
188ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                    setImageBitmapResetBase(bitmap, resetSupp);
189ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                }
190ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            };
191ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return;
192ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
193ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
194ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (bitmap != null) {
195ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            getProperBaseMatrix(bitmap, mBaseMatrix);
196ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            setImageBitmap(bitmap);
197ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        } else {
198ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            mBaseMatrix.reset();
199ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            setImageBitmap(null);
200ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
201ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
202ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (resetSupp) {
203ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            mSuppMatrix.reset();
204ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
205ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
206ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        setImageMatrix(getImageViewMatrix());
207ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mMaxZoom = maxZoom();
208ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
209ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
210ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
211ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Reset the transform of the current image
212ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
213ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void reset() {
214ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (mBitmapDisplayed != null) {
215ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            setImageBitmapResetBase(mBitmapDisplayed, true);
216ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
217ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
218ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
219ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
220ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Pan
221ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
222ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param dx The horizontal offset
223ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param dy The vertical offset
224ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
225ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void postTranslateCenter(float dx, float dy) {
226ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mSuppMatrix.postTranslate(dx, dy);
227ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
228ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        center(true, true);
229ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
230ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
231ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
232ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Pan by the specified horizontal and vertical amount
233ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
234ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param dx Pan by this horizontal amount
235ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param dy Pan by this vertical amount
236ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
237ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private void panBy(float dx, float dy) {
238ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mSuppMatrix.postTranslate(dx, dy);
239ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
240ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        setImageMatrix(getImageViewMatrix());
241ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
242ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
243ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
244ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The scale
245ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
246ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public float getScale() {
247ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return getValue(mSuppMatrix, Matrix.MSCALE_X);
248ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
249ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
250ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
251ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param rect The input/output rectangle
252ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
253ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void mapRect(RectF rect) {
254ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mSuppMatrix.mapRect(rect);
255ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
256ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
257ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
258ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Setup the base matrix so that the image is centered and scaled properly.
259ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
260ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param bitmap The bitmap
261ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param matrix The matrix
262ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
263ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private void getProperBaseMatrix(Bitmap bitmap, Matrix matrix) {
264ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float viewWidth = getWidth();
265ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float viewHeight = getHeight();
266ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
267ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float w = bitmap.getWidth();
268ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float h = bitmap.getHeight();
269ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        matrix.reset();
270ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
271ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (mStretch) {
272ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            // We limit up-scaling to 10x otherwise the result may look bad if
273ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            // it's a small icon.
274ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            float widthScale = Math.min(viewWidth / w, 10.0f);
275ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            float heightScale = Math.min(viewHeight / h, 10.0f);
276ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            float scale = Math.min(widthScale, heightScale);
277ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            matrix.postScale(scale, scale);
278ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            matrix.postTranslate((viewWidth - w * scale) / 2F, (viewHeight - h * scale) / 2F);
279ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        } else {
280ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            matrix.postTranslate((viewWidth - w) / 2F, (viewHeight - h) / 2F);
281ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
282ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
283ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
284ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
285ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Combine the base matrix and the supp matrix to make the final matrix.
286ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
287ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private Matrix getImageViewMatrix() {
288ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        // The final matrix is computed as the concatenation of the base matrix
289ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        // and the supplementary matrix.
290ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mDisplayMatrix.set(mBaseMatrix);
291ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mDisplayMatrix.postConcat(mSuppMatrix);
292ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return mDisplayMatrix;
293ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
294ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
295ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
296ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The maximum zoom
297ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
298ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public float getMaxZoom() {
299ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return mMaxZoom;
300ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
301ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
302ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
303ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Sets the maximum zoom, which is a scale relative to the base matrix. It
304ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * is calculated to show the image at 400% zoom regardless of screen or
305ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * image orientation. If in the future we decode the full 3 megapixel
306ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * image, rather than the current 1024x768, this should be changed down
307ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * to 200%.
308ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
309ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private float maxZoom() {
310ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (mBitmapDisplayed == null) {
311ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return 1F;
312ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
313ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
314ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float fw = (float)mBitmapDisplayed.getWidth() / mThisWidth;
315ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float fh = (float)mBitmapDisplayed.getHeight() / mThisHeight;
316ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
317ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return Math.max(fw, fh) * 4;
318ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
319ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
320ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
321ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Sets the maximum zoom, which is a scale relative to the base matrix. It
322ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * is calculated to show the image at 400% zoom regardless of screen or
323ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * image orientation. If in the future we decode the full 3 megapixel
324ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * image, rather than the current 1024x768, this should be changed down
325ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * to 200%.
326ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
327ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public static float maxZoom(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight) {
328ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float fw = (float)bitmapWidth / viewWidth;
329ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float fh = (float)bitmapHeight / viewHeight;
330ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
331ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return Math.max(fw, fh) * 4;
332ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
333ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
334ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
335ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Ensure the scale factor is within limits
336ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
337ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param scale The scale factor
338ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
339ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The corrected scaled factor
340ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
341ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private float correctedZoomScale(float scale) {
342ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        float result = scale;
343ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (result > mMaxZoom) {
344ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            result = mMaxZoom;
345ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        } else if (result < MIN_ZOOM_SCALE) {
346ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            result = MIN_ZOOM_SCALE;
347ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
348ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
349ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return result;
350ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
351ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
352ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
353ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Zoom to the specified scale factor
354ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
355ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param scale The scale factor
356ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param centerX The horizontal center
357ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param centerY The vertical center
358ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
359ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void zoomTo(float scale, float centerX, float centerY) {
360ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        float correctedScale = correctedZoomScale(scale);
361ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
362ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        float oldScale = getScale();
363ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        float deltaScale = correctedScale / oldScale;
364ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
365ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY);
366ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        setImageMatrix(getImageViewMatrix());
367ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        center(true, true);
368ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
369ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
370ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
371ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Zoom to the specified scale factor
372ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
373ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param scale The scale factor
374ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
375ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void zoomTo(float scale) {
376ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float cx = getWidth() / 2F;
377ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float cy = getHeight() / 2F;
378ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
379ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        zoomTo(scale, cx, cy);
380ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
381ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
382ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
383ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Zoom to the specified scale factor and center point
384ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
385ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param scale The scale factor
386ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param pointX The horizontal position
387ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param pointY The vertical position
388ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
389ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void zoomToPoint(float scale, float pointX, float pointY) {
390ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float cx = getWidth() / 2F;
391ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float cy = getHeight() / 2F;
392ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
393ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        panBy(cx - pointX, cy - pointY);
394ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        zoomTo(scale, cx, cy);
395ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
396ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
397ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
398ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Zoom to the specified scale factor and point
399ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
400ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param scale The scale factor
401ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param pointX The horizontal position
402ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param pointY The vertical position
403ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
404ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void zoomToOffset(float scale, float pointX, float pointY) {
405ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
406ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        float correctedScale = correctedZoomScale(scale);
407ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
408ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        float oldScale = getScale();
409ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        float deltaScale = correctedScale / oldScale;
410ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
411ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mSuppMatrix.postScale(deltaScale, deltaScale);
412ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        setImageMatrix(getImageViewMatrix());
413ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
414ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        panBy(-pointX, -pointY);
415ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
416ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
417ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
418ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Zoom in by a preset scale rate
419ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
420ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void zoomIn() {
421ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        zoomIn(SCALE_RATE);
422ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
423ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
424ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
425ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Zoom in by the specified scale rate
426ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
427ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param rate The scale rate
428ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
429ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void zoomIn(float rate) {
430ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (getScale() < mMaxZoom && mBitmapDisplayed != null) {
431ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            float cx = getWidth() / 2F;
432ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            float cy = getHeight() / 2F;
433ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
434ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            mSuppMatrix.postScale(rate, rate, cx, cy);
435ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            setImageMatrix(getImageViewMatrix());
436ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
437ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
438ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
439ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
440ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Zoom out by a preset scale rate
441ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
442ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void zoomOut() {
443ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        zoomOut(SCALE_RATE);
444ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
445ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
446ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
447ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Zoom out by the specified scale rate
448ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
449ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param rate The scale rate
450ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
451ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    public void zoomOut(float rate) {
452ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (getScale() > MIN_ZOOM_SCALE && mBitmapDisplayed != null) {
453ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            float cx = getWidth() / 2F;
454ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            float cy = getHeight() / 2F;
455ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
456ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            // Zoom out to at most 1x.
457ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            Matrix tmp = new Matrix(mSuppMatrix);
458ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            tmp.postScale(1F / rate, 1F / rate, cx, cy);
459ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
460ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            if (getValue(tmp, Matrix.MSCALE_X) < 1F) {
461ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                mSuppMatrix.setScale(1F, 1F, cx, cy);
462ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            } else {
463ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                mSuppMatrix.postScale(1F / rate, 1F / rate, cx, cy);
464ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
465ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            setImageMatrix(getImageViewMatrix());
466ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            center(true, true);
467ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
468ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
469ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
470ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
471ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Center as much as possible in one or both axis. Centering is
472ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * defined as follows: if the image is scaled down below the
473ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * view's dimensions then center it (literally). If the image
474ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * is scaled larger than the view and is translated out of view
475ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * then translate it back into view (i.e. eliminate black bars).
476ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
477ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private void center(boolean horizontal, boolean vertical) {
478ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (mBitmapDisplayed == null) {
479ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            return;
480ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
481ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
482ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final Matrix m = getImageViewMatrix();
483ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final RectF rect = new RectF(0, 0, mBitmapDisplayed.getWidth(),
484ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                mBitmapDisplayed.getHeight());
485ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
486ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        m.mapRect(rect);
487ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
488ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float height = rect.height();
489ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        final float width = rect.width();
490ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        float deltaX = 0, deltaY = 0;
491ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
492ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (vertical) {
493ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            int viewHeight = getHeight();
494ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            if (height < viewHeight) {
495ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                deltaY = (viewHeight - height) / 2 - rect.top;
496ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            } else if (rect.top > 0) {
497ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                deltaY = -rect.top;
498ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            } else if (rect.bottom < viewHeight) {
499ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                deltaY = getHeight() - rect.bottom;
500ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
501ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
502ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
503ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        if (horizontal) {
504ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            int viewWidth = getWidth();
505ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            if (width < viewWidth) {
506ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                deltaX = (viewWidth - width) / 2 - rect.left;
507ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            } else if (rect.left > 0) {
508ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                deltaX = -rect.left;
509ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            } else if (rect.right < viewWidth) {
510ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi                deltaX = viewWidth - rect.right;
511ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi            }
512ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        }
513ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
514ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        mSuppMatrix.postTranslate(deltaX, deltaY);
515ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
516ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        setImageMatrix(getImageViewMatrix());
517ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
518ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi
519ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    /**
520ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * Get a matrix transform value
521ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     *
522ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param matrix The matrix
523ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @param whichValue Which value
524ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     * @return The value
525ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi     */
526ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    private float getValue(Matrix matrix, int whichValue) {
527ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        matrix.getValues(mMatrixValues);
528ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi        return mMatrixValues[whichValue];
529ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi    }
530ace3cdb462fef9563a0470223c62a7e80e6d587aGil Dobjanschi}
531