1666ea1b28a76aeba74744148b15099254d918671Owen Lin/* 2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2009 The Android Open Source Project 3666ea1b28a76aeba74744148b15099254d918671Owen Lin * 4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License. 6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at 7666ea1b28a76aeba74744148b15099254d918671Owen Lin * 8666ea1b28a76aeba74744148b15099254d918671Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9666ea1b28a76aeba74744148b15099254d918671Owen Lin * 10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software 11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and 14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License. 15666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 16666ea1b28a76aeba74744148b15099254d918671Owen Lin 17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera; 18666ea1b28a76aeba74744148b15099254d918671Owen Lin 19666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Context; 20666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap; 21666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Matrix; 22666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.RectF; 23666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.drawable.Drawable; 24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Handler; 25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.AttributeSet; 26666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.KeyEvent; 27666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.ImageView; 28666ea1b28a76aeba74744148b15099254d918671Owen Lin 29666ea1b28a76aeba74744148b15099254d918671Owen Linabstract class ImageViewTouchBase extends ImageView { 30666ea1b28a76aeba74744148b15099254d918671Owen Lin 31666ea1b28a76aeba74744148b15099254d918671Owen Lin @SuppressWarnings("unused") 32666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String TAG = "ImageViewTouchBase"; 33666ea1b28a76aeba74744148b15099254d918671Owen Lin 34666ea1b28a76aeba74744148b15099254d918671Owen Lin // This is the base transformation which is used to show the image 35666ea1b28a76aeba74744148b15099254d918671Owen Lin // initially. The current computation for this shows the image in 36666ea1b28a76aeba74744148b15099254d918671Owen Lin // it's entirety, letterboxing as needed. One could choose to 37666ea1b28a76aeba74744148b15099254d918671Owen Lin // show the image as cropped instead. 38666ea1b28a76aeba74744148b15099254d918671Owen Lin // 39666ea1b28a76aeba74744148b15099254d918671Owen Lin // This matrix is recomputed when we go from the thumbnail image to 40666ea1b28a76aeba74744148b15099254d918671Owen Lin // the full size image. 41666ea1b28a76aeba74744148b15099254d918671Owen Lin protected Matrix mBaseMatrix = new Matrix(); 42666ea1b28a76aeba74744148b15099254d918671Owen Lin 43666ea1b28a76aeba74744148b15099254d918671Owen Lin // This is the supplementary transformation which reflects what 44666ea1b28a76aeba74744148b15099254d918671Owen Lin // the user has done in terms of zooming and panning. 45666ea1b28a76aeba74744148b15099254d918671Owen Lin // 46666ea1b28a76aeba74744148b15099254d918671Owen Lin // This matrix remains the same when we go from the thumbnail image 47666ea1b28a76aeba74744148b15099254d918671Owen Lin // to the full size image. 48666ea1b28a76aeba74744148b15099254d918671Owen Lin protected Matrix mSuppMatrix = new Matrix(); 49666ea1b28a76aeba74744148b15099254d918671Owen Lin 50666ea1b28a76aeba74744148b15099254d918671Owen Lin // This is the final matrix which is computed as the concatentation 51666ea1b28a76aeba74744148b15099254d918671Owen Lin // of the base matrix and the supplementary matrix. 52666ea1b28a76aeba74744148b15099254d918671Owen Lin private final Matrix mDisplayMatrix = new Matrix(); 53666ea1b28a76aeba74744148b15099254d918671Owen Lin 54666ea1b28a76aeba74744148b15099254d918671Owen Lin // Temporary buffer used for getting the values out of a matrix. 55666ea1b28a76aeba74744148b15099254d918671Owen Lin private final float[] mMatrixValues = new float[9]; 56666ea1b28a76aeba74744148b15099254d918671Owen Lin 57666ea1b28a76aeba74744148b15099254d918671Owen Lin // The current bitmap being displayed. 58666ea1b28a76aeba74744148b15099254d918671Owen Lin protected final RotateBitmap mBitmapDisplayed = new RotateBitmap(null); 59666ea1b28a76aeba74744148b15099254d918671Owen Lin 60666ea1b28a76aeba74744148b15099254d918671Owen Lin int mThisWidth = -1, mThisHeight = -1; 61666ea1b28a76aeba74744148b15099254d918671Owen Lin 62666ea1b28a76aeba74744148b15099254d918671Owen Lin float mMaxZoom; 63666ea1b28a76aeba74744148b15099254d918671Owen Lin 64666ea1b28a76aeba74744148b15099254d918671Owen Lin // ImageViewTouchBase will pass a Bitmap to the Recycler if it has finished 65666ea1b28a76aeba74744148b15099254d918671Owen Lin // its use of that Bitmap. 66666ea1b28a76aeba74744148b15099254d918671Owen Lin public interface Recycler { 67666ea1b28a76aeba74744148b15099254d918671Owen Lin public void recycle(Bitmap b); 68666ea1b28a76aeba74744148b15099254d918671Owen Lin } 69666ea1b28a76aeba74744148b15099254d918671Owen Lin 70666ea1b28a76aeba74744148b15099254d918671Owen Lin public void setRecycler(Recycler r) { 71666ea1b28a76aeba74744148b15099254d918671Owen Lin mRecycler = r; 72666ea1b28a76aeba74744148b15099254d918671Owen Lin } 73666ea1b28a76aeba74744148b15099254d918671Owen Lin 74666ea1b28a76aeba74744148b15099254d918671Owen Lin private Recycler mRecycler; 75666ea1b28a76aeba74744148b15099254d918671Owen Lin 76666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 77666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void onLayout(boolean changed, int left, int top, 78666ea1b28a76aeba74744148b15099254d918671Owen Lin int right, int bottom) { 79666ea1b28a76aeba74744148b15099254d918671Owen Lin super.onLayout(changed, left, top, right, bottom); 80666ea1b28a76aeba74744148b15099254d918671Owen Lin mThisWidth = right - left; 81666ea1b28a76aeba74744148b15099254d918671Owen Lin mThisHeight = bottom - top; 82666ea1b28a76aeba74744148b15099254d918671Owen Lin Runnable r = mOnLayoutRunnable; 83666ea1b28a76aeba74744148b15099254d918671Owen Lin if (r != null) { 84666ea1b28a76aeba74744148b15099254d918671Owen Lin mOnLayoutRunnable = null; 85666ea1b28a76aeba74744148b15099254d918671Owen Lin r.run(); 86666ea1b28a76aeba74744148b15099254d918671Owen Lin } 87666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmapDisplayed.getBitmap() != null) { 88666ea1b28a76aeba74744148b15099254d918671Owen Lin getProperBaseMatrix(mBitmapDisplayed, mBaseMatrix); 89666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageMatrix(getImageViewMatrix()); 90666ea1b28a76aeba74744148b15099254d918671Owen Lin } 91666ea1b28a76aeba74744148b15099254d918671Owen Lin } 92666ea1b28a76aeba74744148b15099254d918671Owen Lin 93666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 94666ea1b28a76aeba74744148b15099254d918671Owen Lin public boolean onKeyDown(int keyCode, KeyEvent event) { 95666ea1b28a76aeba74744148b15099254d918671Owen Lin if (keyCode == KeyEvent.KEYCODE_BACK 96666ea1b28a76aeba74744148b15099254d918671Owen Lin && event.getRepeatCount() == 0) { 97666ea1b28a76aeba74744148b15099254d918671Owen Lin event.startTracking(); 98666ea1b28a76aeba74744148b15099254d918671Owen Lin return true; 99666ea1b28a76aeba74744148b15099254d918671Owen Lin } 100666ea1b28a76aeba74744148b15099254d918671Owen Lin return super.onKeyDown(keyCode, event); 101666ea1b28a76aeba74744148b15099254d918671Owen Lin } 102666ea1b28a76aeba74744148b15099254d918671Owen Lin 103666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 104666ea1b28a76aeba74744148b15099254d918671Owen Lin public boolean onKeyUp(int keyCode, KeyEvent event) { 105666ea1b28a76aeba74744148b15099254d918671Owen Lin if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() 106666ea1b28a76aeba74744148b15099254d918671Owen Lin && !event.isCanceled()) { 107666ea1b28a76aeba74744148b15099254d918671Owen Lin if (getScale() > 1.0f) { 108666ea1b28a76aeba74744148b15099254d918671Owen Lin // If we're zoomed in, pressing Back jumps out to show the 109666ea1b28a76aeba74744148b15099254d918671Owen Lin // entire image, otherwise Back returns the user to the gallery. 110666ea1b28a76aeba74744148b15099254d918671Owen Lin zoomTo(1.0f); 111666ea1b28a76aeba74744148b15099254d918671Owen Lin return true; 112666ea1b28a76aeba74744148b15099254d918671Owen Lin } 113666ea1b28a76aeba74744148b15099254d918671Owen Lin } 114666ea1b28a76aeba74744148b15099254d918671Owen Lin return super.onKeyUp(keyCode, event); 115666ea1b28a76aeba74744148b15099254d918671Owen Lin } 116666ea1b28a76aeba74744148b15099254d918671Owen Lin 117666ea1b28a76aeba74744148b15099254d918671Owen Lin protected Handler mHandler = new Handler(); 118666ea1b28a76aeba74744148b15099254d918671Owen Lin 119666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 120666ea1b28a76aeba74744148b15099254d918671Owen Lin public void setImageBitmap(Bitmap bitmap) { 121666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageBitmap(bitmap, 0); 122666ea1b28a76aeba74744148b15099254d918671Owen Lin } 123666ea1b28a76aeba74744148b15099254d918671Owen Lin 124666ea1b28a76aeba74744148b15099254d918671Owen Lin private void setImageBitmap(Bitmap bitmap, int rotation) { 125666ea1b28a76aeba74744148b15099254d918671Owen Lin super.setImageBitmap(bitmap); 126666ea1b28a76aeba74744148b15099254d918671Owen Lin Drawable d = getDrawable(); 127666ea1b28a76aeba74744148b15099254d918671Owen Lin if (d != null) { 128666ea1b28a76aeba74744148b15099254d918671Owen Lin d.setDither(true); 129666ea1b28a76aeba74744148b15099254d918671Owen Lin } 130666ea1b28a76aeba74744148b15099254d918671Owen Lin 131666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap old = mBitmapDisplayed.getBitmap(); 132666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmapDisplayed.setBitmap(bitmap); 133666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmapDisplayed.setRotation(rotation); 134666ea1b28a76aeba74744148b15099254d918671Owen Lin 135666ea1b28a76aeba74744148b15099254d918671Owen Lin if (old != null && old != bitmap && mRecycler != null) { 136666ea1b28a76aeba74744148b15099254d918671Owen Lin mRecycler.recycle(old); 137666ea1b28a76aeba74744148b15099254d918671Owen Lin } 138666ea1b28a76aeba74744148b15099254d918671Owen Lin } 139666ea1b28a76aeba74744148b15099254d918671Owen Lin 140666ea1b28a76aeba74744148b15099254d918671Owen Lin public void clear() { 141666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageBitmapResetBase(null, true); 142666ea1b28a76aeba74744148b15099254d918671Owen Lin } 143666ea1b28a76aeba74744148b15099254d918671Owen Lin 144666ea1b28a76aeba74744148b15099254d918671Owen Lin private Runnable mOnLayoutRunnable = null; 145666ea1b28a76aeba74744148b15099254d918671Owen Lin 146666ea1b28a76aeba74744148b15099254d918671Owen Lin // This function changes bitmap, reset base matrix according to the size 147666ea1b28a76aeba74744148b15099254d918671Owen Lin // of the bitmap, and optionally reset the supplementary matrix. 148666ea1b28a76aeba74744148b15099254d918671Owen Lin public void setImageBitmapResetBase(final Bitmap bitmap, 149666ea1b28a76aeba74744148b15099254d918671Owen Lin final boolean resetSupp) { 150666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageRotateBitmapResetBase(new RotateBitmap(bitmap), resetSupp); 151666ea1b28a76aeba74744148b15099254d918671Owen Lin } 152666ea1b28a76aeba74744148b15099254d918671Owen Lin 153666ea1b28a76aeba74744148b15099254d918671Owen Lin public void setImageRotateBitmapResetBase(final RotateBitmap bitmap, 154666ea1b28a76aeba74744148b15099254d918671Owen Lin final boolean resetSupp) { 155666ea1b28a76aeba74744148b15099254d918671Owen Lin final int viewWidth = getWidth(); 156666ea1b28a76aeba74744148b15099254d918671Owen Lin 157666ea1b28a76aeba74744148b15099254d918671Owen Lin if (viewWidth <= 0) { 158666ea1b28a76aeba74744148b15099254d918671Owen Lin mOnLayoutRunnable = new Runnable() { 159666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 160666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageRotateBitmapResetBase(bitmap, resetSupp); 161666ea1b28a76aeba74744148b15099254d918671Owen Lin } 162666ea1b28a76aeba74744148b15099254d918671Owen Lin }; 163666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 164666ea1b28a76aeba74744148b15099254d918671Owen Lin } 165666ea1b28a76aeba74744148b15099254d918671Owen Lin 166666ea1b28a76aeba74744148b15099254d918671Owen Lin if (bitmap.getBitmap() != null) { 167666ea1b28a76aeba74744148b15099254d918671Owen Lin getProperBaseMatrix(bitmap, mBaseMatrix); 168666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageBitmap(bitmap.getBitmap(), bitmap.getRotation()); 169666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 170666ea1b28a76aeba74744148b15099254d918671Owen Lin mBaseMatrix.reset(); 171666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageBitmap(null); 172666ea1b28a76aeba74744148b15099254d918671Owen Lin } 173666ea1b28a76aeba74744148b15099254d918671Owen Lin 174666ea1b28a76aeba74744148b15099254d918671Owen Lin if (resetSupp) { 175666ea1b28a76aeba74744148b15099254d918671Owen Lin mSuppMatrix.reset(); 176666ea1b28a76aeba74744148b15099254d918671Owen Lin } 177666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageMatrix(getImageViewMatrix()); 178666ea1b28a76aeba74744148b15099254d918671Owen Lin mMaxZoom = maxZoom(); 179666ea1b28a76aeba74744148b15099254d918671Owen Lin } 180666ea1b28a76aeba74744148b15099254d918671Owen Lin 181666ea1b28a76aeba74744148b15099254d918671Owen Lin // Center as much as possible in one or both axis. Centering is 182666ea1b28a76aeba74744148b15099254d918671Owen Lin // defined as follows: if the image is scaled down below the 183666ea1b28a76aeba74744148b15099254d918671Owen Lin // view's dimensions then center it (literally). If the image 184666ea1b28a76aeba74744148b15099254d918671Owen Lin // is scaled larger than the view and is translated out of view 185666ea1b28a76aeba74744148b15099254d918671Owen Lin // then translate it back into view (i.e. eliminate black bars). 186666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void center(boolean horizontal, boolean vertical) { 187666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmapDisplayed.getBitmap() == null) { 188666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 189666ea1b28a76aeba74744148b15099254d918671Owen Lin } 190666ea1b28a76aeba74744148b15099254d918671Owen Lin 191666ea1b28a76aeba74744148b15099254d918671Owen Lin Matrix m = getImageViewMatrix(); 192666ea1b28a76aeba74744148b15099254d918671Owen Lin 193666ea1b28a76aeba74744148b15099254d918671Owen Lin RectF rect = new RectF(0, 0, 194666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmapDisplayed.getBitmap().getWidth(), 195666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmapDisplayed.getBitmap().getHeight()); 196666ea1b28a76aeba74744148b15099254d918671Owen Lin 197666ea1b28a76aeba74744148b15099254d918671Owen Lin m.mapRect(rect); 198666ea1b28a76aeba74744148b15099254d918671Owen Lin 199666ea1b28a76aeba74744148b15099254d918671Owen Lin float height = rect.height(); 200666ea1b28a76aeba74744148b15099254d918671Owen Lin float width = rect.width(); 201666ea1b28a76aeba74744148b15099254d918671Owen Lin 202666ea1b28a76aeba74744148b15099254d918671Owen Lin float deltaX = 0, deltaY = 0; 203666ea1b28a76aeba74744148b15099254d918671Owen Lin 204666ea1b28a76aeba74744148b15099254d918671Owen Lin if (vertical) { 205666ea1b28a76aeba74744148b15099254d918671Owen Lin int viewHeight = getHeight(); 206666ea1b28a76aeba74744148b15099254d918671Owen Lin if (height < viewHeight) { 207666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaY = (viewHeight - height) / 2 - rect.top; 208666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (rect.top > 0) { 209666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaY = -rect.top; 210666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (rect.bottom < viewHeight) { 211666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaY = getHeight() - rect.bottom; 212666ea1b28a76aeba74744148b15099254d918671Owen Lin } 213666ea1b28a76aeba74744148b15099254d918671Owen Lin } 214666ea1b28a76aeba74744148b15099254d918671Owen Lin 215666ea1b28a76aeba74744148b15099254d918671Owen Lin if (horizontal) { 216666ea1b28a76aeba74744148b15099254d918671Owen Lin int viewWidth = getWidth(); 217666ea1b28a76aeba74744148b15099254d918671Owen Lin if (width < viewWidth) { 218666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaX = (viewWidth - width) / 2 - rect.left; 219666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (rect.left > 0) { 220666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaX = -rect.left; 221666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (rect.right < viewWidth) { 222666ea1b28a76aeba74744148b15099254d918671Owen Lin deltaX = viewWidth - rect.right; 223666ea1b28a76aeba74744148b15099254d918671Owen Lin } 224666ea1b28a76aeba74744148b15099254d918671Owen Lin } 225666ea1b28a76aeba74744148b15099254d918671Owen Lin 226666ea1b28a76aeba74744148b15099254d918671Owen Lin postTranslate(deltaX, deltaY); 227666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageMatrix(getImageViewMatrix()); 228666ea1b28a76aeba74744148b15099254d918671Owen Lin } 229666ea1b28a76aeba74744148b15099254d918671Owen Lin 230666ea1b28a76aeba74744148b15099254d918671Owen Lin public ImageViewTouchBase(Context context) { 231666ea1b28a76aeba74744148b15099254d918671Owen Lin super(context); 232666ea1b28a76aeba74744148b15099254d918671Owen Lin init(); 233666ea1b28a76aeba74744148b15099254d918671Owen Lin } 234666ea1b28a76aeba74744148b15099254d918671Owen Lin 235666ea1b28a76aeba74744148b15099254d918671Owen Lin public ImageViewTouchBase(Context context, AttributeSet attrs) { 236666ea1b28a76aeba74744148b15099254d918671Owen Lin super(context, attrs); 237666ea1b28a76aeba74744148b15099254d918671Owen Lin init(); 238666ea1b28a76aeba74744148b15099254d918671Owen Lin } 239666ea1b28a76aeba74744148b15099254d918671Owen Lin 240666ea1b28a76aeba74744148b15099254d918671Owen Lin private void init() { 241666ea1b28a76aeba74744148b15099254d918671Owen Lin setScaleType(ImageView.ScaleType.MATRIX); 242666ea1b28a76aeba74744148b15099254d918671Owen Lin } 243666ea1b28a76aeba74744148b15099254d918671Owen Lin 244666ea1b28a76aeba74744148b15099254d918671Owen Lin protected float getValue(Matrix matrix, int whichValue) { 245666ea1b28a76aeba74744148b15099254d918671Owen Lin matrix.getValues(mMatrixValues); 246666ea1b28a76aeba74744148b15099254d918671Owen Lin return mMatrixValues[whichValue]; 247666ea1b28a76aeba74744148b15099254d918671Owen Lin } 248666ea1b28a76aeba74744148b15099254d918671Owen Lin 249666ea1b28a76aeba74744148b15099254d918671Owen Lin // Get the scale factor out of the matrix. 250666ea1b28a76aeba74744148b15099254d918671Owen Lin protected float getScale(Matrix matrix) { 251666ea1b28a76aeba74744148b15099254d918671Owen Lin return getValue(matrix, Matrix.MSCALE_X); 252666ea1b28a76aeba74744148b15099254d918671Owen Lin } 253666ea1b28a76aeba74744148b15099254d918671Owen Lin 254666ea1b28a76aeba74744148b15099254d918671Owen Lin protected float getScale() { 255666ea1b28a76aeba74744148b15099254d918671Owen Lin return getScale(mSuppMatrix); 256666ea1b28a76aeba74744148b15099254d918671Owen Lin } 257666ea1b28a76aeba74744148b15099254d918671Owen Lin 258666ea1b28a76aeba74744148b15099254d918671Owen Lin // Setup the base matrix so that the image is centered and scaled properly. 259666ea1b28a76aeba74744148b15099254d918671Owen Lin private void getProperBaseMatrix(RotateBitmap bitmap, Matrix matrix) { 260666ea1b28a76aeba74744148b15099254d918671Owen Lin float viewWidth = getWidth(); 261666ea1b28a76aeba74744148b15099254d918671Owen Lin float viewHeight = getHeight(); 262666ea1b28a76aeba74744148b15099254d918671Owen Lin 263666ea1b28a76aeba74744148b15099254d918671Owen Lin float w = bitmap.getWidth(); 264666ea1b28a76aeba74744148b15099254d918671Owen Lin float h = bitmap.getHeight(); 265666ea1b28a76aeba74744148b15099254d918671Owen Lin matrix.reset(); 266666ea1b28a76aeba74744148b15099254d918671Owen Lin 267be2f475fe49538e38753ad391fb3176f9b0d1c69Owen Lin // We limit up-scaling to 3x otherwise the result may look bad if it's 268666ea1b28a76aeba74744148b15099254d918671Owen Lin // a small icon. 269be2f475fe49538e38753ad391fb3176f9b0d1c69Owen Lin float widthScale = Math.min(viewWidth / w, 3.0f); 270be2f475fe49538e38753ad391fb3176f9b0d1c69Owen Lin float heightScale = Math.min(viewHeight / h, 3.0f); 271666ea1b28a76aeba74744148b15099254d918671Owen Lin float scale = Math.min(widthScale, heightScale); 272666ea1b28a76aeba74744148b15099254d918671Owen Lin 273666ea1b28a76aeba74744148b15099254d918671Owen Lin matrix.postConcat(bitmap.getRotateMatrix()); 274666ea1b28a76aeba74744148b15099254d918671Owen Lin matrix.postScale(scale, scale); 275666ea1b28a76aeba74744148b15099254d918671Owen Lin 276666ea1b28a76aeba74744148b15099254d918671Owen Lin matrix.postTranslate( 277666ea1b28a76aeba74744148b15099254d918671Owen Lin (viewWidth - w * scale) / 2F, 278666ea1b28a76aeba74744148b15099254d918671Owen Lin (viewHeight - h * scale) / 2F); 279666ea1b28a76aeba74744148b15099254d918671Owen Lin } 280666ea1b28a76aeba74744148b15099254d918671Owen Lin 281666ea1b28a76aeba74744148b15099254d918671Owen Lin // Combine the base matrix and the supp matrix to make the final matrix. 282666ea1b28a76aeba74744148b15099254d918671Owen Lin protected Matrix getImageViewMatrix() { 283666ea1b28a76aeba74744148b15099254d918671Owen Lin // The final matrix is computed as the concatentation of the base matrix 284666ea1b28a76aeba74744148b15099254d918671Owen Lin // and the supplementary matrix. 285666ea1b28a76aeba74744148b15099254d918671Owen Lin mDisplayMatrix.set(mBaseMatrix); 286666ea1b28a76aeba74744148b15099254d918671Owen Lin mDisplayMatrix.postConcat(mSuppMatrix); 287666ea1b28a76aeba74744148b15099254d918671Owen Lin return mDisplayMatrix; 288666ea1b28a76aeba74744148b15099254d918671Owen Lin } 289666ea1b28a76aeba74744148b15099254d918671Owen Lin 290666ea1b28a76aeba74744148b15099254d918671Owen Lin static final float SCALE_RATE = 1.25F; 291666ea1b28a76aeba74744148b15099254d918671Owen Lin 292666ea1b28a76aeba74744148b15099254d918671Owen Lin // Sets the maximum zoom, which is a scale relative to the base matrix. It 293666ea1b28a76aeba74744148b15099254d918671Owen Lin // is calculated to show the image at 400% zoom regardless of screen or 294666ea1b28a76aeba74744148b15099254d918671Owen Lin // image orientation. If in the future we decode the full 3 megapixel image, 295666ea1b28a76aeba74744148b15099254d918671Owen Lin // rather than the current 1024x768, this should be changed down to 200%. 296666ea1b28a76aeba74744148b15099254d918671Owen Lin protected float maxZoom() { 297666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmapDisplayed.getBitmap() == null) { 298666ea1b28a76aeba74744148b15099254d918671Owen Lin return 1F; 299666ea1b28a76aeba74744148b15099254d918671Owen Lin } 300666ea1b28a76aeba74744148b15099254d918671Owen Lin 301666ea1b28a76aeba74744148b15099254d918671Owen Lin float fw = (float) mBitmapDisplayed.getWidth() / (float) mThisWidth; 302666ea1b28a76aeba74744148b15099254d918671Owen Lin float fh = (float) mBitmapDisplayed.getHeight() / (float) mThisHeight; 303666ea1b28a76aeba74744148b15099254d918671Owen Lin float max = Math.max(fw, fh) * 4; 304666ea1b28a76aeba74744148b15099254d918671Owen Lin return max; 305666ea1b28a76aeba74744148b15099254d918671Owen Lin } 306666ea1b28a76aeba74744148b15099254d918671Owen Lin 307666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomTo(float scale, float centerX, float centerY) { 308666ea1b28a76aeba74744148b15099254d918671Owen Lin if (scale > mMaxZoom) { 309666ea1b28a76aeba74744148b15099254d918671Owen Lin scale = mMaxZoom; 310666ea1b28a76aeba74744148b15099254d918671Owen Lin } 311666ea1b28a76aeba74744148b15099254d918671Owen Lin 312666ea1b28a76aeba74744148b15099254d918671Owen Lin float oldScale = getScale(); 313666ea1b28a76aeba74744148b15099254d918671Owen Lin float deltaScale = scale / oldScale; 314666ea1b28a76aeba74744148b15099254d918671Owen Lin 315666ea1b28a76aeba74744148b15099254d918671Owen Lin mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY); 316666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageMatrix(getImageViewMatrix()); 317666ea1b28a76aeba74744148b15099254d918671Owen Lin center(true, true); 318666ea1b28a76aeba74744148b15099254d918671Owen Lin } 319666ea1b28a76aeba74744148b15099254d918671Owen Lin 320666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomTo(final float scale, final float centerX, 321666ea1b28a76aeba74744148b15099254d918671Owen Lin final float centerY, final float durationMs) { 322666ea1b28a76aeba74744148b15099254d918671Owen Lin final float incrementPerMs = (scale - getScale()) / durationMs; 323666ea1b28a76aeba74744148b15099254d918671Owen Lin final float oldScale = getScale(); 324666ea1b28a76aeba74744148b15099254d918671Owen Lin final long startTime = System.currentTimeMillis(); 325666ea1b28a76aeba74744148b15099254d918671Owen Lin 326666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.post(new Runnable() { 327666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 328666ea1b28a76aeba74744148b15099254d918671Owen Lin long now = System.currentTimeMillis(); 329666ea1b28a76aeba74744148b15099254d918671Owen Lin float currentMs = Math.min(durationMs, now - startTime); 330666ea1b28a76aeba74744148b15099254d918671Owen Lin float target = oldScale + (incrementPerMs * currentMs); 331666ea1b28a76aeba74744148b15099254d918671Owen Lin zoomTo(target, centerX, centerY); 332666ea1b28a76aeba74744148b15099254d918671Owen Lin 333666ea1b28a76aeba74744148b15099254d918671Owen Lin if (currentMs < durationMs) { 334666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.post(this); 335666ea1b28a76aeba74744148b15099254d918671Owen Lin } 336666ea1b28a76aeba74744148b15099254d918671Owen Lin } 337666ea1b28a76aeba74744148b15099254d918671Owen Lin }); 338666ea1b28a76aeba74744148b15099254d918671Owen Lin } 339666ea1b28a76aeba74744148b15099254d918671Owen Lin 340666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomTo(float scale) { 341666ea1b28a76aeba74744148b15099254d918671Owen Lin float cx = getWidth() / 2F; 342666ea1b28a76aeba74744148b15099254d918671Owen Lin float cy = getHeight() / 2F; 343666ea1b28a76aeba74744148b15099254d918671Owen Lin 344666ea1b28a76aeba74744148b15099254d918671Owen Lin zoomTo(scale, cx, cy); 345666ea1b28a76aeba74744148b15099254d918671Owen Lin } 346666ea1b28a76aeba74744148b15099254d918671Owen Lin 347666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomToPoint(float scale, float pointX, float pointY) { 348666ea1b28a76aeba74744148b15099254d918671Owen Lin float cx = getWidth() / 2F; 349666ea1b28a76aeba74744148b15099254d918671Owen Lin float cy = getHeight() / 2F; 350666ea1b28a76aeba74744148b15099254d918671Owen Lin 351666ea1b28a76aeba74744148b15099254d918671Owen Lin panBy(cx - pointX, cy - pointY); 352666ea1b28a76aeba74744148b15099254d918671Owen Lin zoomTo(scale, cx, cy); 353666ea1b28a76aeba74744148b15099254d918671Owen Lin } 354666ea1b28a76aeba74744148b15099254d918671Owen Lin 355666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomIn() { 356666ea1b28a76aeba74744148b15099254d918671Owen Lin zoomIn(SCALE_RATE); 357666ea1b28a76aeba74744148b15099254d918671Owen Lin } 358666ea1b28a76aeba74744148b15099254d918671Owen Lin 359666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomOut() { 360666ea1b28a76aeba74744148b15099254d918671Owen Lin zoomOut(SCALE_RATE); 361666ea1b28a76aeba74744148b15099254d918671Owen Lin } 362666ea1b28a76aeba74744148b15099254d918671Owen Lin 363666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomIn(float rate) { 364666ea1b28a76aeba74744148b15099254d918671Owen Lin if (getScale() >= mMaxZoom) { 365666ea1b28a76aeba74744148b15099254d918671Owen Lin return; // Don't let the user zoom into the molecular level. 366666ea1b28a76aeba74744148b15099254d918671Owen Lin } 367666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmapDisplayed.getBitmap() == null) { 368666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 369666ea1b28a76aeba74744148b15099254d918671Owen Lin } 370666ea1b28a76aeba74744148b15099254d918671Owen Lin 371666ea1b28a76aeba74744148b15099254d918671Owen Lin float cx = getWidth() / 2F; 372666ea1b28a76aeba74744148b15099254d918671Owen Lin float cy = getHeight() / 2F; 373666ea1b28a76aeba74744148b15099254d918671Owen Lin 374666ea1b28a76aeba74744148b15099254d918671Owen Lin mSuppMatrix.postScale(rate, rate, cx, cy); 375666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageMatrix(getImageViewMatrix()); 376666ea1b28a76aeba74744148b15099254d918671Owen Lin } 377666ea1b28a76aeba74744148b15099254d918671Owen Lin 378666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomOut(float rate) { 379666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmapDisplayed.getBitmap() == null) { 380666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 381666ea1b28a76aeba74744148b15099254d918671Owen Lin } 382666ea1b28a76aeba74744148b15099254d918671Owen Lin 383666ea1b28a76aeba74744148b15099254d918671Owen Lin float cx = getWidth() / 2F; 384666ea1b28a76aeba74744148b15099254d918671Owen Lin float cy = getHeight() / 2F; 385666ea1b28a76aeba74744148b15099254d918671Owen Lin 386666ea1b28a76aeba74744148b15099254d918671Owen Lin // Zoom out to at most 1x. 387666ea1b28a76aeba74744148b15099254d918671Owen Lin Matrix tmp = new Matrix(mSuppMatrix); 388666ea1b28a76aeba74744148b15099254d918671Owen Lin tmp.postScale(1F / rate, 1F / rate, cx, cy); 389666ea1b28a76aeba74744148b15099254d918671Owen Lin 390666ea1b28a76aeba74744148b15099254d918671Owen Lin if (getScale(tmp) < 1F) { 391666ea1b28a76aeba74744148b15099254d918671Owen Lin mSuppMatrix.setScale(1F, 1F, cx, cy); 392666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 393666ea1b28a76aeba74744148b15099254d918671Owen Lin mSuppMatrix.postScale(1F / rate, 1F / rate, cx, cy); 394666ea1b28a76aeba74744148b15099254d918671Owen Lin } 395666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageMatrix(getImageViewMatrix()); 396666ea1b28a76aeba74744148b15099254d918671Owen Lin center(true, true); 397666ea1b28a76aeba74744148b15099254d918671Owen Lin } 398666ea1b28a76aeba74744148b15099254d918671Owen Lin 399666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void postTranslate(float dx, float dy) { 400666ea1b28a76aeba74744148b15099254d918671Owen Lin mSuppMatrix.postTranslate(dx, dy); 401666ea1b28a76aeba74744148b15099254d918671Owen Lin } 402666ea1b28a76aeba74744148b15099254d918671Owen Lin 403666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void panBy(float dx, float dy) { 404666ea1b28a76aeba74744148b15099254d918671Owen Lin postTranslate(dx, dy); 405666ea1b28a76aeba74744148b15099254d918671Owen Lin setImageMatrix(getImageViewMatrix()); 406666ea1b28a76aeba74744148b15099254d918671Owen Lin } 407666ea1b28a76aeba74744148b15099254d918671Owen Lin} 408