ActivityBase.java revision 72fe79a040df8f01b03a39bec2473f7b0de8228d
14d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang/* 24d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * Copyright (C) 2009 The Android Open Source Project 34d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * 44d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * Licensed under the Apache License, Version 2.0 (the "License"); 54d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * you may not use this file except in compliance with the License. 64d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * You may obtain a copy of the License at 74d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * 84d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * http://www.apache.org/licenses/LICENSE-2.0 94d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * 104d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * Unless required by applicable law or agreed to in writing, software 114d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * distributed under the License is distributed on an "AS IS" BASIS, 124d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * See the License for the specific language governing permissions and 144d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang * limitations under the License. 154d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang */ 164d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang 174d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Changpackage com.android.camera; 184d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang 197d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Millerimport android.app.KeyguardManager; 20c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Liimport android.content.ContentResolver; 21892781804513066b68b4a2fa6f846e862dac252aOwen Linimport android.content.Context; 225df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Liimport android.content.Intent; 234c7b291018e08dbb4bc1712d95117a294fa1416cWu-cheng Liimport android.content.pm.ActivityInfo; 242eaabf9cca4528b01e414c384a039c10907c9d0bPin Tingimport android.content.res.Configuration; 25296d27772b9543d55820e1d24d900fea959f1b7aPin Tingimport android.hardware.Camera.Parameters; 26c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Liimport android.os.AsyncTask; 278608b577921acf67a5a7b7968cb3633b8f94714dChih-Chung Changimport android.os.Bundle; 287d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Millerimport android.util.Log; 291cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Liimport android.view.animation.DecelerateInterpolator; 304c7b291018e08dbb4bc1712d95117a294fa1416cWu-cheng Liimport android.view.KeyEvent; 3124e4e6cc25b7628ef15eff703f70b2872575a4ccWu-cheng Liimport android.view.Menu; 32c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Liimport android.view.View; 33a6b966047b6215b02c502a3f143106070abf6009Angus Kongimport android.view.Window; 34892781804513066b68b4a2fa6f846e862dac252aOwen Linimport android.view.WindowManager; 35892781804513066b68b4a2fa6f846e862dac252aOwen Lin 36892781804513066b68b4a2fa6f846e862dac252aOwen Linimport com.android.camera.ui.PopupManager; 37892781804513066b68b4a2fa6f846e862dac252aOwen Linimport com.android.camera.ui.RotateImageView; 38a6b966047b6215b02c502a3f143106070abf6009Angus Kongimport com.android.gallery3d.app.AbstractGalleryActivity; 39a6b966047b6215b02c502a3f143106070abf6009Angus Kongimport com.android.gallery3d.app.PhotoPage; 40bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Liimport com.android.gallery3d.app.PhotoPage.PageTapListener; 41a6b966047b6215b02c502a3f143106070abf6009Angus Kongimport com.android.gallery3d.app.GalleryActionBar; 42bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Liimport com.android.gallery3d.app.StateManager; 43a6b966047b6215b02c502a3f143106070abf6009Angus Kongimport com.android.gallery3d.util.MediaSetUtils; 444d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang 45aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Liimport java.io.File; 46aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li 4777c1cdc8f2cda250b1db842204efb49f87e094aeChih-Chung Chang/** 487673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li * Superclass of Camera and VideoCamera activities. 4977c1cdc8f2cda250b1db842204efb49f87e094aeChih-Chung Chang */ 50a6b966047b6215b02c502a3f143106070abf6009Angus Kongabstract public class ActivityBase extends AbstractGalleryActivity 518a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li implements CameraScreenNail.PositionChangedListener, 52bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li View.OnLayoutChangeListener, PageTapListener { 53a6b966047b6215b02c502a3f143106070abf6009Angus Kong 547d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller private static final String TAG = "ActivityBase"; 557d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller private static boolean LOGV = false; 56c38faeb66a3f2cc96e4c5e951228d9b01e12edb3Chih-Chung Chang private static final int CAMERA_APP_VIEW_TOGGLE_TIME = 100; // milliseconds 575df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li private int mResultCodeForTesting; 585df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li private Intent mResultDataForTesting; 594edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong private OnScreenHint mStorageHint; 601cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li private UpdateCameraAppView mUpdateCameraAppView; 611cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li private HideCameraAppView mHideCameraAppView; 62bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li private View mSingleTapArea; 63a6b966047b6215b02c502a3f143106070abf6009Angus Kong 64c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li // The bitmap of the last captured picture thumbnail and the URI of the 65c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li // original picture. 66c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li protected Thumbnail mThumbnail; 67c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li // An imageview showing showing the last captured picture thumbnail. 68c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li protected RotateImageView mThumbnailView; 698a674bebfba0c4dd4b01018276d20f198f65f19eWu-cheng Li protected int mThumbnailViewWidth; // layout width of the thumbnail 70c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li protected AsyncTask<Void, Void, Thumbnail> mLoadThumbnailTask; 71475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting protected boolean mOpenCameraFail; 72475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting protected boolean mCameraDisabled; 73475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting protected CameraManager.CameraProxy mCameraDevice; 74296d27772b9543d55820e1d24d900fea959f1b7aPin Ting protected Parameters mParameters; 755c17d7a077acd1f84bdcb7579f7d02a1094602bcWu-cheng Li // The activity is paused. The classes that extend this class should set 765c17d7a077acd1f84bdcb7579f7d02a1094602bcWu-cheng Li // mPaused the first thing in onResume/onPause. 775c17d7a077acd1f84bdcb7579f7d02a1094602bcWu-cheng Li protected boolean mPaused; 78a6b966047b6215b02c502a3f143106070abf6009Angus Kong protected GalleryActionBar mActionBar; 79475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting 80475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting // multiple cameras support 81475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting protected int mNumberOfCameras; 82475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting protected int mCameraId; 83475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting 84a6b966047b6215b02c502a3f143106070abf6009Angus Kong protected CameraScreenNail mCameraScreenNail; // This shows camera preview. 85a6b966047b6215b02c502a3f143106070abf6009Angus Kong // The view containing only camera related widgets like control panel, 86a6b966047b6215b02c502a3f143106070abf6009Angus Kong // indicator bar, focus indicator and etc. 87a6b966047b6215b02c502a3f143106070abf6009Angus Kong protected View mCameraAppView; 881cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li protected boolean mShowCameraAppView = true; 89a6b966047b6215b02c502a3f143106070abf6009Angus Kong 90475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting protected class CameraOpenThread extends Thread { 91475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting @Override 92475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting public void run() { 93475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting try { 94475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting mCameraDevice = Util.openCamera(ActivityBase.this, mCameraId); 95296d27772b9543d55820e1d24d900fea959f1b7aPin Ting mParameters = mCameraDevice.getParameters(); 96475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting } catch (CameraHardwareException e) { 97475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting mOpenCameraFail = true; 98475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting } catch (CameraDisabledException e) { 99475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting mCameraDisabled = true; 100475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting } 101475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting } 102475b4c6eca6f7e7ca0e4b3ee0ee234c6fe079687Pin Ting } 1035df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li 1044d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang @Override 1058608b577921acf67a5a7b7968cb3633b8f94714dChih-Chung Chang public void onCreate(Bundle icicle) { 1062eaabf9cca4528b01e414c384a039c10907c9d0bPin Ting if (getResources().getConfiguration().orientation 1072eaabf9cca4528b01e414c384a039c10907c9d0bPin Ting == Configuration.ORIENTATION_LANDSCAPE) { 1084c7b291018e08dbb4bc1712d95117a294fa1416cWu-cheng Li setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 109d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang } else { 110d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 1114c7b291018e08dbb4bc1712d95117a294fa1416cWu-cheng Li } 112e5b6a36e64ef2c2cb1435c138a5fc179e9a6bc9aWu-cheng Li getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); 1136a4a72b643929701c5d7c8b68b91d762c7277c20Wu-cheng Li super.disableToggleStatusBar(); 1148608b577921acf67a5a7b7968cb3633b8f94714dChih-Chung Chang super.onCreate(icicle); 1158608b577921acf67a5a7b7968cb3633b8f94714dChih-Chung Chang } 1168608b577921acf67a5a7b7968cb3633b8f94714dChih-Chung Chang 1178608b577921acf67a5a7b7968cb3633b8f94714dChih-Chung Chang @Override 1187d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller protected void onPause() { 1195c17d7a077acd1f84bdcb7579f7d02a1094602bcWu-cheng Li super.onPause(); 1207d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller if (LOGV) Log.v(TAG, "onPause"); 121aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li saveThumbnailToFile(); 1224edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong 123c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li if (mLoadThumbnailTask != null) { 124c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li mLoadThumbnailTask.cancel(true); 125c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li mLoadThumbnailTask = null; 126c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } 127c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li 1284edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong if (mStorageHint != null) { 1294edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong mStorageHint.cancel(); 1304edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong mStorageHint = null; 1314edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } 1327d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller } 1337d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller 1347d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller @Override 13572fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li public void setContentView(int layoutResID) { 13672fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li // Set a theme with action bar. It is not specified in manifest because 13772fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li // we want to hide it by default. setTheme must happen before 13872fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li // setContentView. 13972fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li setTheme(android.R.style.Theme_Holo); 14072fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 14172fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); 14272fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li 14372fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li super.setContentView(layoutResID); 14472fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li // getActionBar() should be after setContentView 14572fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li mActionBar = new GalleryActionBar(this); 14672fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li mActionBar.hide(); 14772fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li } 14872fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li 14972fe79a040df8f01b03a39bec2473f7b0de8228dWu-cheng Li @Override 1504d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang public boolean onSearchRequested() { 1514d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang return false; 1524d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang } 1537673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li 1547673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li @Override 1557673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li public boolean onKeyDown(int keyCode, KeyEvent event) { 1567673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li // Prevent software keyboard or voice search from showing up. 1577673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li if (keyCode == KeyEvent.KEYCODE_SEARCH 1587673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li || keyCode == KeyEvent.KEYCODE_MENU) { 1597673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li if (event.isLongPress()) return true; 1607673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li } 1617673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li 1627673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li return super.onKeyDown(keyCode, event); 1637673ada94b5e2263e7190ca246694cdee31ed03eWu-cheng Li } 1645df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li 1655df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li protected void setResultEx(int resultCode) { 1665df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li mResultCodeForTesting = resultCode; 1675df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li setResult(resultCode); 1685df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li } 1695df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li 1705df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li protected void setResultEx(int resultCode, Intent data) { 1715df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li mResultCodeForTesting = resultCode; 1725df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li mResultDataForTesting = data; 1735df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li setResult(resultCode, data); 1745df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li } 1755df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li 1765df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li public int getResultCode() { 1775df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li return mResultCodeForTesting; 1785df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li } 1795df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li 1805df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li public Intent getResultData() { 1815df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li return mResultDataForTesting; 1825df067af93e6b386167f11cdf12701b7905ee444Wu-cheng Li } 1835f6e354a6e2a77aa935fcefeb33a9baa67d48aafChung-yih Wang 1845f6e354a6e2a77aa935fcefeb33a9baa67d48aafChung-yih Wang @Override 1855f6e354a6e2a77aa935fcefeb33a9baa67d48aafChung-yih Wang protected void onDestroy() { 1865f6e354a6e2a77aa935fcefeb33a9baa67d48aafChung-yih Wang PopupManager.removeInstance(this); 1875f6e354a6e2a77aa935fcefeb33a9baa67d48aafChung-yih Wang super.onDestroy(); 1885f6e354a6e2a77aa935fcefeb33a9baa67d48aafChung-yih Wang } 1897d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller 19024e4e6cc25b7628ef15eff703f70b2872575a4ccWu-cheng Li @Override 19124e4e6cc25b7628ef15eff703f70b2872575a4ccWu-cheng Li public boolean onCreateOptionsMenu(Menu menu) { 19224e4e6cc25b7628ef15eff703f70b2872575a4ccWu-cheng Li super.onCreateOptionsMenu(menu); 19324e4e6cc25b7628ef15eff703f70b2872575a4ccWu-cheng Li return getStateManager().createOptionsMenu(menu); 19424e4e6cc25b7628ef15eff703f70b2872575a4ccWu-cheng Li } 19524e4e6cc25b7628ef15eff703f70b2872575a4ccWu-cheng Li 1964edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong protected void updateStorageHint(long storageSpace) { 1974edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong String message = null; 1984edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong if (storageSpace == Storage.UNAVAILABLE) { 1994edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong message = getString(R.string.no_storage); 2004edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } else if (storageSpace == Storage.PREPARING) { 2014edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong message = getString(R.string.preparing_sd); 2024edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } else if (storageSpace == Storage.UNKNOWN_SIZE) { 2034edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong message = getString(R.string.access_sd_fail); 2044edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } else if (storageSpace < Storage.LOW_STORAGE_THRESHOLD) { 2054edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong message = getString(R.string.spaceIsLow_content); 2064edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } 2074edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong 2084edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong if (message != null) { 2094edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong if (mStorageHint == null) { 2104edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong mStorageHint = OnScreenHint.makeText(this, message); 2114edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } else { 2124edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong mStorageHint.setText(message); 2134edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } 2144edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong mStorageHint.show(); 2154edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } else if (mStorageHint != null) { 2164edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong mStorageHint.cancel(); 2174edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong mStorageHint = null; 2184edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } 2194edaf0cbbb5d9cfeae786b6fd0560240947f6585Angus Kong } 220c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li 221c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li private void updateThumbnailView() { 222c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li if (mThumbnail != null) { 223c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li mThumbnailView.setBitmap(mThumbnail.getBitmap()); 224c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li mThumbnailView.setVisibility(View.VISIBLE); 225c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } else { 226c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li mThumbnailView.setBitmap(null); 227c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li mThumbnailView.setVisibility(View.GONE); 228c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } 229c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } 230c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li 231c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li protected void getLastThumbnail() { 232c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li mThumbnail = ThumbnailHolder.getLastThumbnail(getContentResolver()); 233c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li // Suppose users tap the thumbnail view, go to the gallery, delete the 234c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li // image, and coming back to the camera. Thumbnail file will be invalid. 235c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li // Since the new thumbnail will be loaded in another thread later, the 236c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li // view should be set to gone to prevent from opening the invalid image. 237c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li updateThumbnailView(); 238c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li if (mThumbnail == null) { 239c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li mLoadThumbnailTask = new LoadThumbnailTask().execute(); 240c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } 241c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } 242c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li 243aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li private class LoadThumbnailTask extends AsyncTask<Void, Void, Thumbnail> { 244c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li @Override 245c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li protected Thumbnail doInBackground(Void... params) { 246c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li // Load the thumbnail from the file. 247c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li ContentResolver resolver = getContentResolver(); 248c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li Thumbnail t = Thumbnail.getLastThumbnailFromFile(getFilesDir(), resolver); 249c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li 250c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li if (isCancelled()) return null; 251c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li 252c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li if (t == null) { 253c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li // Load the thumbnail from the media provider. 254c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li t = Thumbnail.getLastThumbnailFromContentResolver(resolver); 255c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } 256c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li return t; 257c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } 258c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li 259c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li @Override 260c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li protected void onPostExecute(Thumbnail thumbnail) { 261c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li mThumbnail = thumbnail; 262c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li updateThumbnailView(); 263c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } 264c24a2a83df9b54297995c5270d015bb7fdd85fabWu-cheng Li } 265aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li 2666899a30e3a89ad4b455978140682d5ba871c1b33Pin Ting protected void gotoGallery() { 26771bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li // TODO: remove this after panorama has swipe UI. 26871bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li if (getStateManager().getStateCount() > 0) { 26971bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li PhotoPage photoPage = (PhotoPage) getStateManager().getTopState(); 27071bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li // Move the next picture with capture animation. "1" means next. 27171bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li photoPage.switchWithCaptureAnimation(1); 27271bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li } else { 27371bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li Util.viewUri(mThumbnail.getUri(), this); 27471bf9ebe0f207c1af741e3b76d84dde1358faa1bWu-cheng Li } 2756899a30e3a89ad4b455978140682d5ba871c1b33Pin Ting } 2766899a30e3a89ad4b455978140682d5ba871c1b33Pin Ting 277aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li protected void saveThumbnailToFile() { 278aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li if (mThumbnail != null && !mThumbnail.fromFile()) { 279aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li new SaveThumbnailTask().execute(mThumbnail); 280aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li } 281aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li } 282aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li 283aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li private class SaveThumbnailTask extends AsyncTask<Thumbnail, Void, Void> { 284aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li @Override 285aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li protected Void doInBackground(Thumbnail... params) { 286aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li final int n = params.length; 287aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li final File filesDir = getFilesDir(); 288aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li for (int i = 0; i < n; i++) { 289aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li params[i].saveLastThumbnailToFile(filesDir); 290aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li } 291aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li return null; 292aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li } 293aef5310d25537494679f9ec6b9d7a1a9cb60887dWu-cheng Li } 294a6b966047b6215b02c502a3f143106070abf6009Angus Kong 295a6b966047b6215b02c502a3f143106070abf6009Angus Kong // Call this after setContentView. 296a6b966047b6215b02c502a3f143106070abf6009Angus Kong protected void createCameraScreenNail(boolean getPictures) { 297a6b966047b6215b02c502a3f143106070abf6009Angus Kong mCameraAppView = findViewById(R.id.camera_app_root); 298a6b966047b6215b02c502a3f143106070abf6009Angus Kong Bundle data = new Bundle(); 299a6b966047b6215b02c502a3f143106070abf6009Angus Kong String path = "/local/all/"; 300a6b966047b6215b02c502a3f143106070abf6009Angus Kong // Intent mode does not show camera roll. Use 0 as a work around for 301a6b966047b6215b02c502a3f143106070abf6009Angus Kong // invalid bucket id. 302a6b966047b6215b02c502a3f143106070abf6009Angus Kong // TODO: add support of empty media set in gallery. 303a6b966047b6215b02c502a3f143106070abf6009Angus Kong path += (getPictures ? MediaSetUtils.CAMERA_BUCKET_ID : "0"); 304a6b966047b6215b02c502a3f143106070abf6009Angus Kong data.putString(PhotoPage.KEY_MEDIA_SET_PATH, path); 305a6b966047b6215b02c502a3f143106070abf6009Angus Kong data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, path); 306a6b966047b6215b02c502a3f143106070abf6009Angus Kong 307a6b966047b6215b02c502a3f143106070abf6009Angus Kong // Send a CameraScreenNail to gallery to enable the camera preview. 308a6b966047b6215b02c502a3f143106070abf6009Angus Kong CameraScreenNailHolder holder = new CameraScreenNailHolder(this); 309a6b966047b6215b02c502a3f143106070abf6009Angus Kong data.putParcelable(PhotoPage.KEY_SCREENNAIL_HOLDER, holder); 310a6b966047b6215b02c502a3f143106070abf6009Angus Kong getStateManager().startState(PhotoPage.class, data); 311a6b966047b6215b02c502a3f143106070abf6009Angus Kong mCameraScreenNail = holder.getCameraScreenNail(); 312a6b966047b6215b02c502a3f143106070abf6009Angus Kong mCameraScreenNail.setPositionChangedListener(this); 313a6b966047b6215b02c502a3f143106070abf6009Angus Kong } 314a6b966047b6215b02c502a3f143106070abf6009Angus Kong 3151cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li private class HideCameraAppView implements Runnable { 3161cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li @Override 3171cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li public void run() { 3181cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li mCameraAppView.setVisibility(View.GONE); 3191cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li } 3201cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li } 321a6b966047b6215b02c502a3f143106070abf6009Angus Kong private class UpdateCameraAppView implements Runnable { 322a6b966047b6215b02c502a3f143106070abf6009Angus Kong @Override 323a6b966047b6215b02c502a3f143106070abf6009Angus Kong public void run() { 3241cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li if (mShowCameraAppView) { 325a6b966047b6215b02c502a3f143106070abf6009Angus Kong mCameraAppView.setVisibility(View.VISIBLE); 326c38faeb66a3f2cc96e4c5e951228d9b01e12edb3Chih-Chung Chang mCameraAppView.animate() 327c38faeb66a3f2cc96e4c5e951228d9b01e12edb3Chih-Chung Chang .setDuration(CAMERA_APP_VIEW_TOGGLE_TIME) 328c38faeb66a3f2cc96e4c5e951228d9b01e12edb3Chih-Chung Chang .withLayer().alpha(1); 3291cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li } else { 330c38faeb66a3f2cc96e4c5e951228d9b01e12edb3Chih-Chung Chang mCameraAppView.animate() 331c38faeb66a3f2cc96e4c5e951228d9b01e12edb3Chih-Chung Chang .setDuration(CAMERA_APP_VIEW_TOGGLE_TIME) 332c38faeb66a3f2cc96e4c5e951228d9b01e12edb3Chih-Chung Chang .withLayer().alpha(0).withEndAction(mHideCameraAppView); 333a6b966047b6215b02c502a3f143106070abf6009Angus Kong } 334a6b966047b6215b02c502a3f143106070abf6009Angus Kong } 335a6b966047b6215b02c502a3f143106070abf6009Angus Kong } 336a6b966047b6215b02c502a3f143106070abf6009Angus Kong 337a6b966047b6215b02c502a3f143106070abf6009Angus Kong @Override 3381cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li public void onPositionChanged(int x, int y, int width, int height, boolean visible) { 339a6b966047b6215b02c502a3f143106070abf6009Angus Kong if (!mPaused && !isFinishing()) { 3401cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li View rootView = (View) getGLRoot(); 3411cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li int rootWidth = rootView.getWidth(); 3421cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li int rootHeight = rootView.getHeight(); 3431cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li boolean showCameraAppView; 3441cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li // Check if the camera preview is in the center. 3451cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li if (visible && (x == 0 && width == rootWidth) || 3461cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li (y == 0 && height == rootHeight && Math.abs(x - (rootWidth - width) / 2) <= 1)) { 3471cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li showCameraAppView = true; 348a6b966047b6215b02c502a3f143106070abf6009Angus Kong } else { 3491cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li showCameraAppView = false; 3501cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li } 3511cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li 3521cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li if (mShowCameraAppView != showCameraAppView) { 3531cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li mShowCameraAppView = showCameraAppView; 3541cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li // Initialize the animation. 3551cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li if (mUpdateCameraAppView == null) { 3561cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li mUpdateCameraAppView = new UpdateCameraAppView(); 3571cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li mHideCameraAppView = new HideCameraAppView(); 358c38faeb66a3f2cc96e4c5e951228d9b01e12edb3Chih-Chung Chang mCameraAppView.animate() 359c38faeb66a3f2cc96e4c5e951228d9b01e12edb3Chih-Chung Chang .setInterpolator(new DecelerateInterpolator()); 3601cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li } 3611cc3a3466c8e9f30f13b81a88d8b2f31050c599cWu-cheng Li runOnUiThread(mUpdateCameraAppView); 362a6b966047b6215b02c502a3f143106070abf6009Angus Kong } 363a6b966047b6215b02c502a3f143106070abf6009Angus Kong } 364a6b966047b6215b02c502a3f143106070abf6009Angus Kong } 365a6b966047b6215b02c502a3f143106070abf6009Angus Kong 366a6b966047b6215b02c502a3f143106070abf6009Angus Kong @Override 367a6b966047b6215b02c502a3f143106070abf6009Angus Kong public GalleryActionBar getGalleryActionBar() { 368a6b966047b6215b02c502a3f143106070abf6009Angus Kong return mActionBar; 369a6b966047b6215b02c502a3f143106070abf6009Angus Kong } 3708a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li 3718a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li // Preview frame layout has changed. Move the preview to the center of the 3728a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li // layout. 3738a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li @Override 3748a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li public void onLayoutChange(View v, int left, int top, int right, int bottom, 3758a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li int oldLeft, int oldTop, int oldRight, int oldBottom) { 3768a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li // Find out the left and top of the preview frame layout relative to GL 3778a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li // root view. 3788a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li View root = (View) getGLRoot(); 3798a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li int[] rootLocation = new int[2]; 3808a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li int[] viewLocation = new int[2]; 3818a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li root.getLocationInWindow(rootLocation); 3828a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li v.getLocationInWindow(viewLocation); 3838a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li int relativeLeft = viewLocation[0] - rootLocation[0]; 3848a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li int relativeTop = viewLocation[1] - rootLocation[1]; 3858a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li 3868a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li // Calculate the scale ratio between preview frame layout and GL root 3878a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li // view. 3888a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li int width = root.getWidth(); 3898a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li int height = root.getHeight(); 3908a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li float scale = Math.max((float) (right - left) / width, 3918a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li (float) (bottom - top) / height); 3928a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li float scalePx = width / 2f; 3938a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li float scalePy = height / 2f; 3948a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li 3958a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li // Calculate the translate distance. 3968a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li float translateX = relativeLeft + (right - left - width) / 2f; 3978a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li float translateY = relativeTop + (bottom - top - height) / 2f; 3988a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li 3998a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li mCameraScreenNail.setMatrix(scale, scalePx, scalePy, translateX, translateY); 4008a79ddc5827de54a33d8fbef0e467da2266342cbWu-cheng Li } 401bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li 402bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li protected void setSingleTapUpListener(View singleTapArea) { 403bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li PhotoPage photoPage = (PhotoPage) getStateManager().getTopState(); 404bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li photoPage.setPageTapListener(this); 405bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li mSingleTapArea = singleTapArea; 406bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li } 407bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li 408bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li // Single tap up from PhotoPage. 409bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li @Override 410bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li public boolean onSingleTapUp(int x, int y) { 411bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li // Camera control is invisible. Ignore. 412bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li if (!mShowCameraAppView) return false; 413bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li 414bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li int[] relativeLocation = Util.getRelativeLocation((View) getGLRoot(), 415bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li mSingleTapArea); 416bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li x -= relativeLocation[0]; 417bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li y -= relativeLocation[1]; 418bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li if (x >= 0 && x < mSingleTapArea.getWidth() && y >= 0 419bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li && y < mSingleTapArea.getHeight()) { 420bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li onSingleTapUp(mSingleTapArea, x, y); 421bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li return true; 422bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li } 423bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li return false; 424bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li } 425bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li 426bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li protected void onSingleTapUp(View view, int x, int y) { 427bfaab736a344641a63170ebdcd9d5377779d3a15Wu-cheng Li } 4284d2aefbe7c108bae9e4ae735c7cd230792201098Chih-Chung Chang} 429