PhotoView.java revision ec4125492f17130f65e49160a17bd437e01128a7
1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.ui; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.R; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.app.GalleryActivity; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.Path; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.PositionRepository.Position; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Color; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.RectF; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Message; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.SystemClock; 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.GestureDetector; 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.ScaleGestureDetector; 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class PhotoView extends GLView { 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "PhotoView"; 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INVALID_SIZE = -1; 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_TRANSITION_COMPLETE = 1; 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_SHOW_LOADING = 2; 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final long DELAY_SHOW_LOADING = 250; // 250ms; 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int TRANS_NONE = 0; 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int TRANS_SWITCH_NEXT = 3; 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int TRANS_SWITCH_PREVIOUS = 4; 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int TRANS_SLIDE_IN_RIGHT = 1; 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int TRANS_SLIDE_IN_LEFT = 2; 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int TRANS_OPEN_ANIMATION = 5; 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_INIT = 0; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_TIMEOUT = 1; 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_COMPLETE = 2; 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int LOADING_FAIL = 3; 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int ENTRY_PREVIOUS = 0; 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int ENTRY_NEXT = 1; 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int IMAGE_GAP = 96; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int SWITCH_THRESHOLD = 256; 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float SWIPE_THRESHOLD = 300f; 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final float DEFAULT_TEXT_SIZE = 20; 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public interface PhotoTapListener { 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onSingleTapUp(int x, int y); 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // the previous/next image entries 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ScreenNailEntry mScreenNails[] = new ScreenNailEntry[2]; 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ScaleGestureDetector mScaleDetector; 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final GestureDetector mGestureDetector; 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final DownUpDetector mDownUpDetector; 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private PhotoTapListener mPhotoTapListener; 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final PositionController mPositionController; 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Model mModel; 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mLoadingText; 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private StringTexture mNoThumbnailText; 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mTransitionMode = TRANS_NONE; 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final TileImageView mTileView; 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Texture mVideoPlayIcon; 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mShowVideoPlayIcon; 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ProgressSpinner mLoadingSpinner; 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private SynchronizedHandler mHandler; 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mLoadingState = LOADING_COMPLETE; 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mImageRotation; 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Path mOpenedItemPath; 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private GalleryActivity mActivity; 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public PhotoView(GalleryActivity activity) { 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActivity = activity; 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView = new TileImageView(activity); 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addComponent(mTileView); 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Context context = activity.getAndroidContext(); 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingSpinner = new ProgressSpinner(context); 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingText = StringTexture.newInstance( 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.loading), 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNoThumbnailText = StringTexture.newInstance( 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin context.getString(R.string.no_thumbnail), 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DEFAULT_TEXT_SIZE, Color.WHITE); 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler = new SynchronizedHandler(activity.getGLRoot()) { 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void handleMessage(Message message) { 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (message.what) { 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_TRANSITION_COMPLETE: { 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin onTransitionComplete(); 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_SHOW_LOADING: { 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mLoadingState == LOADING_INIT) { 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We don't need the opening animation 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mOpenedItemPath = null; 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingSpinner.startAnimation(); 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_TIMEOUT; 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin invalidate(); 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin default: throw new AssertionError(message.what); 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }; 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mGestureDetector = new GestureDetector(context, 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new MyGestureListener(), null, true /* ignoreMultitouch */); 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScaleDetector = new ScaleGestureDetector(context, new MyScaleListener()); 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDownUpDetector = new DownUpDetector(new MyDownUpListener()); 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = mScreenNails.length; i < n; ++i) { 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScreenNails[i] = new ScreenNailEntry(); 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController = new PositionController(this); 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVideoPlayIcon = new ResourceTexture(context, R.drawable.ic_control_play); 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setModel(Model model) { 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mModel == model) return; 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mModel = model; 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.setModel(model); 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (model != null) notifyOnNewImage(); 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setPhotoTapListener(PhotoTapListener listener) { 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPhotoTapListener = listener; 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean setTileViewPosition(int centerX, int centerY, float scale) { 165ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang int inverseX = mPositionController.getImageWidth() - centerX; 166ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang int inverseY = mPositionController.getImageHeight() - centerY; 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin TileImageView t = mTileView; 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int rotation = mImageRotation; 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (rotation) { 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case 0: return t.setPosition(centerX, centerY, scale, 0); 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case 90: return t.setPosition(centerY, inverseX, scale, 90); 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case 180: return t.setPosition(inverseX, inverseY, scale, 180); 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case 270: return t.setPosition(inverseY, centerX, scale, 270); 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin default: throw new IllegalArgumentException(String.valueOf(rotation)); 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setPosition(int centerX, int centerY, float scale) { 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (setTileViewPosition(centerX, centerY, scale)) { 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin layoutScreenNails(); 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateScreenNailEntry(int which, ImageData data) { 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTransitionMode == TRANS_SWITCH_NEXT 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin || mTransitionMode == TRANS_SWITCH_PREVIOUS) { 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // ignore screen nail updating during switching 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry entry = mScreenNails[which]; 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (data == null) { 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin entry.set(false, null, 0); 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin entry.set(true, data.bitmap, data.rotation); 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // -1 previous, 0 current, 1 next 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void notifyImageInvalidated(int which) { 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (which) { 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case -1: { 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScreenNailEntry( 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ENTRY_PREVIOUS, mModel.getPreviousImage()); 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin layoutScreenNails(); 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin invalidate(); 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case 1: { 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScreenNailEntry(ENTRY_NEXT, mModel.getNextImage()); 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin layoutScreenNails(); 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin invalidate(); 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case 0: { 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // mImageWidth and mImageHeight will get updated 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.notifyModelInvalidated(); 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageRotation = mModel.getImageRotation(); 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (((mImageRotation / 90) & 1) == 0) { 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.setImageSize( 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.mImageWidth, mTileView.mImageHeight); 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.setImageSize( 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.mImageHeight, mTileView.mImageWidth); 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoadingState(); 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateLoadingState() { 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Possible transitions of mLoadingState: 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // INIT --> TIMEOUT, COMPLETE, FAIL 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // TIMEOUT --> COMPLETE, FAIL, INIT 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // COMPLETE --> INIT 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // FAIL --> INIT 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mModel.getLevelCount() != 0 || mModel.getBackupImage() != null) { 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.removeMessages(MSG_SHOW_LOADING); 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_COMPLETE; 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (mModel.isFailedToLoad()) { 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.removeMessages(MSG_SHOW_LOADING); 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_FAIL; 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (mLoadingState != LOADING_INIT) { 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingState = LOADING_INIT; 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.removeMessages(MSG_SHOW_LOADING); 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.sendEmptyMessageDelayed( 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MSG_SHOW_LOADING, DELAY_SHOW_LOADING); 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void notifyModelInvalidated() { 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mModel == null) { 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScreenNailEntry(ENTRY_PREVIOUS, null); 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScreenNailEntry(ENTRY_NEXT, null); 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScreenNailEntry(ENTRY_PREVIOUS, mModel.getPreviousImage()); 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateScreenNailEntry(ENTRY_NEXT, mModel.getNextImage()); 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin layoutScreenNails(); 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mModel == null) { 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.notifyModelInvalidated(); 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageRotation = 0; 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.setImageSize(0, 0); 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoadingState(); 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyImageInvalidated(0); 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected boolean onTouch(MotionEvent event) { 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mGestureDetector.onTouchEvent(event); 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mScaleDetector.onTouchEvent(event); 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDownUpDetector.onTouchEvent(event); 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onLayout( 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean changeSize, int left, int top, int right, int bottom) { 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.layout(left, top, right, bottom); 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (changeSize) { 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.setViewSize(getWidth(), getHeight()); 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (ScreenNailEntry entry : mScreenNails) { 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin entry.updateDrawingSize(); 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static int gapToSide(int imageWidth, int viewWidth) { 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return Math.max(0, (viewWidth - imageWidth) / 2); 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /* 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Here is how we layout the screen nails 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * previous current next 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * ___________ ________________ __________ 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | _______ | | __________ | | ______ | 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | | | | | right->| | | | | | 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | |<-------->|<--left | | | | | | 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | |_______| | | | |__________| | | |______| | 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * |___________| | |________________| |__________| 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | <--> gapToSide() 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * IMAGE_GAP + Max(previous.gapToSide(), current.gapToSide) 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void layoutScreenNails() { 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int width = getWidth(); 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int height = getHeight(); 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Use the image width in AC, since we may fake the size if the 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // image is unavailable 316ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang RectF bounds = mPositionController.getImageBounds(); 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int left = Math.round(bounds.left); 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int right = Math.round(bounds.right); 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int gap = gapToSide(right - left, width); 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // layout the previous image 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry entry = mScreenNails[ENTRY_PREVIOUS]; 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (entry.isEnabled()) { 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin entry.layoutRightEdgeAt(left - ( 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin IMAGE_GAP + Math.max(gap, entry.gapToSide()))); 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // layout the next image 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin entry = mScreenNails[ENTRY_NEXT]; 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (entry.isEnabled()) { 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin entry.layoutLeftEdgeAt(right + ( 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin IMAGE_GAP + Math.max(gap, entry.gapToSide()))); 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void render(GLCanvas canvas) { 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin PositionController p = mPositionController; 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Draw the current photo 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mLoadingState == LOADING_COMPLETE) { 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super.render(canvas); 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Draw the previous and the next photo 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTransitionMode != TRANS_SLIDE_IN_LEFT 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && mTransitionMode != TRANS_SLIDE_IN_RIGHT 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && mTransitionMode != TRANS_OPEN_ANIMATION) { 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry prevNail = mScreenNails[ENTRY_PREVIOUS]; 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry nextNail = mScreenNails[ENTRY_NEXT]; 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (prevNail.mVisible) prevNail.draw(canvas); 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (nextNail.mVisible) nextNail.draw(canvas); 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Draw the progress spinner and the text below it 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // (x, y) is where we put the center of the spinner. 360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // s is the size of the video play icon, and we use s to layout text 361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // because we want to keep the text at the same place when the video 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // play icon is shown instead of the spinner. 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int w = getWidth(); 364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int h = getHeight(); 365ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang int x = Math.round(mPositionController.getImageBounds().centerX()); 366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int y = h / 2; 367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int s = Math.min(getWidth(), getHeight()) / 6; 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mLoadingState == LOADING_TIMEOUT) { 370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin StringTexture m = mLoadingText; 371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ProgressSpinner r = mLoadingSpinner; 372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin r.draw(canvas, x - r.getWidth() / 2, y - r.getHeight() / 2); 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin m.draw(canvas, x - m.getWidth() / 2, y + s / 2 + 5); 374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin invalidate(); // we need to keep the spinner rotating 375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (mLoadingState == LOADING_FAIL) { 376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin StringTexture m = mNoThumbnailText; 377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin m.draw(canvas, x - m.getWidth() / 2, y + s / 2 + 5); 378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Draw the video play icon (in the place where the spinner was) 381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mShowVideoPlayIcon 382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && mLoadingState != LOADING_INIT 383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && mLoadingState != LOADING_TIMEOUT) { 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVideoPlayIcon.draw(canvas, x - s / 2, y - s / 2, s, s); 385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mPositionController.advanceAnimation()) invalidate(); 388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void stopCurrentSwipingIfNeeded() { 391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Enable fast sweeping 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTransitionMode == TRANS_SWITCH_NEXT) { 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTransitionMode = TRANS_NONE; 394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.stopAnimation(); 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switchToNextImage(); 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (mTransitionMode == TRANS_SWITCH_PREVIOUS) { 397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTransitionMode = TRANS_NONE; 398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.stopAnimation(); 399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switchToPreviousImage(); 400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 402f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 403f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean swipeImages(float velocity) { 404f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTransitionMode != TRANS_NONE 405f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && mTransitionMode != TRANS_SWITCH_NEXT 406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && mTransitionMode != TRANS_SWITCH_PREVIOUS) return false; 407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 408f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry next = mScreenNails[ENTRY_NEXT]; 409f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry prev = mScreenNails[ENTRY_PREVIOUS]; 410f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 411f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int width = getWidth(); 412f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 413f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If the edge of the current photo is visible and the sweeping velocity 414f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // exceed the threshold, switch to next / previous image 415f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin PositionController controller = mPositionController; 416ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang if (controller.isAtMinimalScale()) { 417f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (velocity < -SWIPE_THRESHOLD) { 418f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin stopCurrentSwipingIfNeeded(); 419f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (next.isEnabled()) { 420f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTransitionMode = TRANS_SWITCH_NEXT; 421f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin controller.startHorizontalSlide(next.mOffsetX - width / 2); 422f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 423f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 424f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 425f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 426f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (velocity > SWIPE_THRESHOLD) { 427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin stopCurrentSwipingIfNeeded(); 428f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (prev.isEnabled()) { 429f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTransitionMode = TRANS_SWITCH_PREVIOUS; 430f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin controller.startHorizontalSlide(prev.mOffsetX - width / 2); 431f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 432f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 434f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 435f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 436f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 437f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTransitionMode != TRANS_NONE) return false; 438f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 439f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Decide whether to swiping to the next/prev image in the zoom-in case 440ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang RectF bounds = mPositionController.getImageBounds(); 441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int left = Math.round(bounds.left); 442f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int right = Math.round(bounds.right); 443f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int threshold = SWITCH_THRESHOLD + gapToSide(right - left, width); 444f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 445f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If we have moved the picture a lot, switching. 446f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (next.isEnabled() && threshold < width - right) { 447f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTransitionMode = TRANS_SWITCH_NEXT; 448f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin controller.startHorizontalSlide(next.mOffsetX - width / 2); 449f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 450f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 451f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (prev.isEnabled() && threshold < left) { 452f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTransitionMode = TRANS_SWITCH_PREVIOUS; 453f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin controller.startHorizontalSlide(prev.mOffsetX - width / 2); 454f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 455f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 456f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 457f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 458f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 459f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 460f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mIgnoreUpEvent = false; 461f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 462f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class MyGestureListener 463f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin extends GestureDetector.SimpleOnGestureListener { 464f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 465f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onScroll( 466f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MotionEvent e1, MotionEvent e2, float dx, float dy) { 467f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTransitionMode != TRANS_NONE) return true; 468ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang mPositionController.startScroll(dx, dy); 469f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 470f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 471f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 472f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 473f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onSingleTapUp(MotionEvent e) { 474f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mPhotoTapListener != null) { 475f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPhotoTapListener.onSingleTapUp((int) e.getX(), (int) e.getY()); 476f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 477f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 478f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 479f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 480f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 481f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 482f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float velocityY) { 483f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIgnoreUpEvent = true; 484f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!swipeImages(velocityX) && mTransitionMode == TRANS_NONE) { 485f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.up(); 486f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 487f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 488f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 489f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 490f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 491f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onDoubleTap(MotionEvent e) { 492f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTransitionMode != TRANS_NONE) return true; 493f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin PositionController controller = mPositionController; 494ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang float scale = controller.getCurrentScale(); 495f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // onDoubleTap happened on the second ACTION_DOWN. 496f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We need to ignore the next UP event. 497f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIgnoreUpEvent = true; 498ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang if (scale <= 1.0f || controller.isAtMinimalScale()) { 499f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin controller.zoomIn( 500f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin e.getX(), e.getY(), Math.max(1.5f, scale * 1.5f)); 501f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 502f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin controller.resetToFullView(); 503f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 504f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 505f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 506f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 507f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 508f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class MyScaleListener 509f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin extends ScaleGestureDetector.SimpleOnScaleGestureListener { 510f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 511f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 512f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onScale(ScaleGestureDetector detector) { 513f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float scale = detector.getScaleFactor(); 514f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (Float.isNaN(scale) || Float.isInfinite(scale) 515f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin || mTransitionMode != TRANS_NONE) return true; 516f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.scaleBy(scale, 517f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin detector.getFocusX(), detector.getFocusY()); 518f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 519f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 520f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 521f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 522f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean onScaleBegin(ScaleGestureDetector detector) { 523f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTransitionMode != TRANS_NONE) return false; 524f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.beginScale( 525f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin detector.getFocusX(), detector.getFocusY()); 526f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 527f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 528f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 529f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 530f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onScaleEnd(ScaleGestureDetector detector) { 531f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.endScale(); 532f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin swipeImages(0); 533f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 534f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 535f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 5363a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang public boolean jumpTo(int index) { 5373a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang if (mTransitionMode != TRANS_NONE) return false; 5383a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang mModel.jumpTo(index); 5393a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang return true; 5403a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang } 5413a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang 542f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void notifyOnNewImage() { 543f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.setImageSize(0, 0); 544f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 545f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 546f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void startSlideInAnimation(int direction) { 547f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin PositionController a = mPositionController; 548f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin a.stopAnimation(); 549f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (direction) { 550ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang case TRANS_SLIDE_IN_LEFT: 551f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case TRANS_SLIDE_IN_RIGHT: { 552ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang mTransitionMode = direction; 553ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang a.startSlideInAnimation(direction); 554f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 555f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 556f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin default: throw new IllegalArgumentException(String.valueOf(direction)); 557f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 558f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 559f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 560f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class MyDownUpListener implements DownUpDetector.DownUpListener { 561f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onDown(MotionEvent e) { 562f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 563f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 564f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onUp(MotionEvent e) { 565f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mIgnoreUpEvent) { 566f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIgnoreUpEvent = false; 567f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 568f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 569f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!swipeImages(0) && mTransitionMode == TRANS_NONE) { 570f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.up(); 571f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 572f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 573f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 574f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 575f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void switchToNextImage() { 576f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We update the texture here directly to prevent texture uploading. 577f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry prevNail = mScreenNails[ENTRY_PREVIOUS]; 578f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry nextNail = mScreenNails[ENTRY_NEXT]; 579f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.invalidateTiles(); 580f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (prevNail.mTexture != null) prevNail.mTexture.recycle(); 581f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin prevNail.mTexture = mTileView.mBackupImage; 582f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.mBackupImage = nextNail.mTexture; 583f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin nextNail.mTexture = null; 584f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mModel.next(); 585f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 586f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 587f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void switchToPreviousImage() { 588f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We update the texture here directly to prevent texture uploading. 589f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry prevNail = mScreenNails[ENTRY_PREVIOUS]; 590f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ScreenNailEntry nextNail = mScreenNails[ENTRY_NEXT]; 591f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.invalidateTiles(); 592f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (nextNail.mTexture != null) nextNail.mTexture.recycle(); 593f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin nextNail.mTexture = mTileView.mBackupImage; 594f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.mBackupImage = prevNail.mTexture; 595f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin nextNail.mTexture = null; 596f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mModel.previous(); 597f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 598f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 599ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang public void notifyTransitionComplete() { 600ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang mHandler.sendEmptyMessage(MSG_TRANSITION_COMPLETE); 601ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 602ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 603f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void onTransitionComplete() { 604f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int mode = mTransitionMode; 605f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTransitionMode = TRANS_NONE; 606f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 607f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mModel == null) return; 608f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mode == TRANS_SWITCH_NEXT) { 609f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switchToNextImage(); 610f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (mode == TRANS_SWITCH_PREVIOUS) { 611f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switchToPreviousImage(); 612f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 613f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 614f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 615ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang public boolean isDown() { 616f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mDownUpDetector.isDown(); 617f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 618f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 619f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static interface Model extends TileImageView.Model { 620f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void next(); 621f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void previous(); 6223a54b9ae67eb7b38f19ea0bdeeef26efc0a1afa1Chih-Chung Chang public void jumpTo(int index); 623f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getImageRotation(); 624f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 625f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Return null if the specified image is unavailable. 626f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public ImageData getNextImage(); 627f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public ImageData getPreviousImage(); 628f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 629f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 630f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static class ImageData { 631f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int rotation; 632f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Bitmap bitmap; 633f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 634f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public ImageData(Bitmap bitmap, int rotation) { 635f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin this.bitmap = bitmap; 636f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin this.rotation = rotation; 637f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 638f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 639f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 640f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static int getRotated(int degree, int original, int theother) { 641f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return ((degree / 90) & 1) == 0 ? original : theother; 642f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 643f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 644f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class ScreenNailEntry { 645f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mVisible; 646f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mEnabled; 647f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 648f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mRotation; 649f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mDrawWidth; 650f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mDrawHeight; 651f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mOffsetX; 652f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 653f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private BitmapTexture mTexture; 654f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 655f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void set(boolean enabled, Bitmap bitmap, int rotation) { 656f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mEnabled = enabled; 657f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRotation = rotation; 658f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (bitmap == null) { 659f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTexture != null) mTexture.recycle(); 660f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTexture = null; 661f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 662f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTexture != null) { 663f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTexture.getBitmap() != bitmap) { 664f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTexture.recycle(); 665f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTexture = new BitmapTexture(bitmap); 666f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 667f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 668f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTexture = new BitmapTexture(bitmap); 669f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 670f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateDrawingSize(); 671f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 672f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 673f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 674f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void layoutRightEdgeAt(int x) { 675f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVisible = x > 0; 676f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mOffsetX = x - getRotated( 677f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRotation, mDrawWidth, mDrawHeight) / 2; 678f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 679f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 680f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void layoutLeftEdgeAt(int x) { 681f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVisible = x < getWidth(); 682f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mOffsetX = x + getRotated( 683f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mRotation, mDrawWidth, mDrawHeight) / 2; 684f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 685f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 686f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int gapToSide() { 687f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return ((mRotation / 90) & 1) != 0 688f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ? PhotoView.gapToSide(mDrawHeight, getWidth()) 689f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin : PhotoView.gapToSide(mDrawWidth, getWidth()); 690f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 691f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 692f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void updateDrawingSize() { 693f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTexture == null) return; 694f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 695f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int width = mTexture.getWidth(); 696f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int height = mTexture.getHeight(); 697f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float s = mPositionController.getMinimalScale(width, height, mRotation); 698f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDrawWidth = Math.round(width * s); 699f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDrawHeight = Math.round(height * s); 700f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 701f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 702f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isEnabled() { 703f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mEnabled; 704f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 705f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 706f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void draw(GLCanvas canvas) { 707f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int x = mOffsetX; 708f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int y = getHeight() / 2; 709f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 710f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mTexture != null) { 711f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mRotation != 0) { 712f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.save(GLCanvas.SAVE_FLAG_MATRIX); 713f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.translate(x, y, 0); 714f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.rotate(mRotation, 0, 0, 1); //mRotation 715f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.translate(-x, -y, 0); 716f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 717f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTexture.draw(canvas, x - mDrawWidth / 2, y - mDrawHeight / 2, 718f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDrawWidth, mDrawHeight); 719f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mRotation != 0) { 720f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin canvas.restore(); 721f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 722f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 723f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 724f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 725f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 726f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void pause() { 727f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mPositionController.skipAnimation(); 728f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTransitionMode = TRANS_NONE; 729f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.freeTextures(); 730f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (ScreenNailEntry entry : mScreenNails) { 731f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin entry.set(false, null, 0); 732f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 733f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 734f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 735f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void resume() { 736f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mTileView.prepareTextures(); 737f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 738f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 739f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setOpenedItem(Path itemPath) { 740f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mOpenedItemPath = itemPath; 741f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 742f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 743f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void showVideoPlayIcon(boolean show) { 744f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mShowVideoPlayIcon = show; 745f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 746ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 747ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang public Position retrieveOldPosition() { 748ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang if (mOpenedItemPath != null) { 749ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang Position position = PositionRepository 750ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang .getInstance(mActivity).get(Long.valueOf( 751ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang System.identityHashCode(mOpenedItemPath))); 752ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang mOpenedItemPath = null; 753ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang return position; 754ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 755ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang return null; 756ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 757ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 758ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang public void openAnimationStarted() { 759ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang mTransitionMode = TRANS_OPEN_ANIMATION; 760ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 761ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang 762ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang public boolean isInTransition() { 763ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang return mTransitionMode != TRANS_NONE; 764ec4125492f17130f65e49160a17bd437e01128a7Chih-Chung Chang } 765f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 766