From 6432cd65159731a28d9239426b0f0f4d7c44fa98 Mon Sep 17 00:00:00 2001 From: Doris Liu Date: Thu, 13 Jun 2013 17:20:31 -0700 Subject: Switch over to use new camera activity Change-Id: Ib907b5ab5d0e818261e95edd182f2e20c3bbebe0 --- src/com/android/camera/CameraActivity.java | 650 +++---- src/com/android/camera/CameraModule.java | 10 +- src/com/android/camera/NewCameraActivity.java | 456 ----- src/com/android/camera/NewCameraModule.java | 74 - src/com/android/camera/NewPhotoMenu.java | 200 -- src/com/android/camera/NewPhotoModule.java | 2037 ------------------- src/com/android/camera/NewPhotoUI.java | 793 -------- src/com/android/camera/NewPreviewGestures.java | 263 --- src/com/android/camera/NewVideoMenu.java | 205 -- src/com/android/camera/NewVideoModule.java | 2261 ---------------------- src/com/android/camera/NewVideoUI.java | 713 ------- src/com/android/camera/PanoramaModule.java | 1304 ------------- src/com/android/camera/PhotoMenu.java | 2 - src/com/android/camera/PhotoModule.java | 214 +- src/com/android/camera/PhotoUI.java | 366 ++-- src/com/android/camera/PreviewGestures.java | 293 +-- src/com/android/camera/VideoMenu.java | 3 +- src/com/android/camera/VideoModule.java | 307 ++- src/com/android/camera/VideoUI.java | 387 ++-- src/com/android/camera/ui/CameraRootView.java | 67 +- src/com/android/camera/ui/FaceView.java | 18 +- src/com/android/camera/ui/NewCameraRootView.java | 184 -- src/com/android/camera/ui/RenderOverlay.java | 6 +- src/com/android/gallery3d/app/StateManager.java | 12 +- 24 files changed, 1137 insertions(+), 9688 deletions(-) delete mode 100644 src/com/android/camera/NewCameraActivity.java delete mode 100644 src/com/android/camera/NewCameraModule.java delete mode 100644 src/com/android/camera/NewPhotoMenu.java delete mode 100644 src/com/android/camera/NewPhotoModule.java delete mode 100644 src/com/android/camera/NewPhotoUI.java delete mode 100644 src/com/android/camera/NewPreviewGestures.java delete mode 100644 src/com/android/camera/NewVideoMenu.java delete mode 100644 src/com/android/camera/NewVideoModule.java delete mode 100644 src/com/android/camera/NewVideoUI.java delete mode 100644 src/com/android/camera/PanoramaModule.java delete mode 100644 src/com/android/camera/ui/NewCameraRootView.java (limited to 'src') diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java index 5ba769a62..baa1e7e19 100644 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -16,146 +16,78 @@ package com.android.camera; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; +import android.app.Activity; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.res.Configuration; -import android.graphics.drawable.Drawable; +import android.graphics.drawable.ColorDrawable; +import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; -import android.provider.MediaStore; import android.provider.Settings; import android.view.KeyEvent; +import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.OrientationEventListener; import android.view.View; +import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; -import android.widget.FrameLayout; +import android.widget.ImageView; -import com.android.camera.ui.CameraSwitcher; +import com.android.camera.data.CameraDataAdapter; +import com.android.camera.data.LocalData; +import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; +import com.android.camera.ui.FilmStripView; import com.android.gallery3d.R; -import com.android.gallery3d.app.PhotoPage; import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.util.LightCycleHelper; -public class CameraActivity extends ActivityBase - implements CameraSwitcher.CameraSwitchListener { +public class CameraActivity extends Activity + implements CameraSwitchListener { + + private static final String TAG = "CAM_Activity"; + public static final int PHOTO_MODULE_INDEX = 0; public static final int VIDEO_MODULE_INDEX = 1; public static final int PANORAMA_MODULE_INDEX = 2; public static final int LIGHTCYCLE_MODULE_INDEX = 3; - CameraModule mCurrentModule; - private FrameLayout mFrame; - private ShutterButton mShutter; - private CameraSwitcher mSwitcher; - private View mCameraControls; - private View mControlsBackground; - private View mPieMenuButton; - private Drawable[] mDrawables; + private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE = + "android.media.action.STILL_IMAGE_CAMERA_SECURE"; + public static final String ACTION_IMAGE_CAPTURE_SECURE = + "android.media.action.IMAGE_CAPTURE_SECURE"; + + // The intent extra for camera from secure lock screen. True if the gallery + // should only show newly captured pictures. sSecureAlbumId does not + // increment. This is used when switching between camera, camcorder, and + // panorama. If the extra is not set, it is in the normal camera mode. + public static final String SECURE_CAMERA_EXTRA = "secure_camera"; + + private CameraDataAdapter mDataAdapter; private int mCurrentModuleIndex; - private MotionEvent mDown; + private CameraModule mCurrentModule; + private View mRootView; + private FilmStripView mFilmStripView; + private int mResultCodeForTesting; + private Intent mResultDataForTesting; + private OnScreenHint mStorageHint; + private long mStorageSpace = Storage.LOW_STORAGE_THRESHOLD; + private PhotoModule mController; private boolean mAutoRotateScreen; - private int mHeightOrWidth = -1; - + private boolean mSecureCamera; + private boolean mShowCameraPreview; + private int mLastRawOrientation; private MyOrientationEventListener mOrientationListener; - // The degrees of the device rotated clockwise from its natural orientation. - private int mLastRawOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; - - private MediaSaveService mMediaSaveService; - private ServiceConnection mConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName className, IBinder b) { - mMediaSaveService = ((MediaSaveService.LocalBinder) b).getService(); - mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); - } - @Override - public void onServiceDisconnected(ComponentName className) { - mMediaSaveService = null; - }}; - - private static final String TAG = "CAM_activity"; - - private static final int[] DRAW_IDS = { - R.drawable.ic_switch_camera, - R.drawable.ic_switch_video, - R.drawable.ic_switch_pan, - R.drawable.ic_switch_photosphere - }; - - @Override - public void onCreate(Bundle state) { - super.onCreate(state); - setContentView(R.layout.camera_main); - mFrame = (FrameLayout) findViewById(R.id.camera_app_root); - mDrawables = new Drawable[DRAW_IDS.length]; - for (int i = 0; i < DRAW_IDS.length; i++) { - mDrawables[i] = getResources().getDrawable(DRAW_IDS[i]); - } - init(); - if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction()) - || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) { - mCurrentModule = new VideoModule(); - mCurrentModuleIndex = VIDEO_MODULE_INDEX; - } else { - mCurrentModule = new PhotoModule(); - mCurrentModuleIndex = PHOTO_MODULE_INDEX; - } - mCurrentModule.init(this, mFrame, true); - mSwitcher.setCurrentIndex(mCurrentModuleIndex); - mOrientationListener = new MyOrientationEventListener(this); - bindMediaSaveService(); - } - - public void init() { - boolean landscape = Util.getDisplayRotation(this) % 180 == 90; - mControlsBackground = findViewById(R.id.blocker); - mCameraControls = findViewById(R.id.camera_controls); - mShutter = (ShutterButton) findViewById(R.id.shutter_button); - mSwitcher = (CameraSwitcher) findViewById(R.id.camera_switcher); - mPieMenuButton = findViewById(R.id.menu); - int totaldrawid = (LightCycleHelper.hasLightCycleCapture(this) - ? DRAW_IDS.length : DRAW_IDS.length - 1); - if (!ApiHelper.HAS_OLD_PANORAMA) totaldrawid--; - - int[] drawids = new int[totaldrawid]; - int[] moduleids = new int[totaldrawid]; - int ix = 0; - for (int i = 0; i < mDrawables.length; i++) { - if (i == PANORAMA_MODULE_INDEX && !ApiHelper.HAS_OLD_PANORAMA) { - continue; // not enabled, so don't add to UI - } - if (i == LIGHTCYCLE_MODULE_INDEX && !LightCycleHelper.hasLightCycleCapture(this)) { - continue; // not enabled, so don't add to UI - } - moduleids[ix] = i; - drawids[ix++] = DRAW_IDS[i]; - } - mSwitcher.setIds(moduleids, drawids); - mSwitcher.setSwitchListener(this); - mSwitcher.setCurrentIndex(mCurrentModuleIndex); - } - - @Override - public void onDestroy() { - unbindMediaSaveService(); - super.onDestroy(); - } - - // Return whether the auto-rotate screen in system settings - // is turned on. - public boolean isAutoRotateScreen() { - return mAutoRotateScreen; - } + private Handler mMainHandler; private class MyOrientationEventListener - extends OrientationEventListener { + extends OrientationEventListener { public MyOrientationEventListener(Context context) { super(context); } @@ -171,155 +103,149 @@ public class CameraActivity extends ActivityBase } } - private ObjectAnimator mCameraSwitchAnimator; - - @Override - public void onCameraSelected(final int i) { - if (mPaused) return; - if (i != mCurrentModuleIndex) { - mPaused = true; - CameraScreenNail screenNail = getCameraScreenNail(); - if (screenNail != null) { - if (mCameraSwitchAnimator != null && mCameraSwitchAnimator.isRunning()) { - mCameraSwitchAnimator.cancel(); - } - mCameraSwitchAnimator = ObjectAnimator.ofFloat( - screenNail, "alpha", screenNail.getAlpha(), 0f); - mCameraSwitchAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - doChangeCamera(i); - } - }); - mCameraSwitchAnimator.start(); - } else { - doChangeCamera(i); + private MediaSaveService mMediaSaveService; + private ServiceConnection mConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName className, IBinder b) { + mMediaSaveService = ((MediaSaveService.LocalBinder) b).getService(); + mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); } - } - } - - private void doChangeCamera(int i) { - boolean canReuse = canReuseScreenNail(); - CameraHolder.instance().keep(); - closeModule(mCurrentModule); - mCurrentModuleIndex = i; - switch (i) { - case VIDEO_MODULE_INDEX: - mCurrentModule = new VideoModule(); - break; - case PHOTO_MODULE_INDEX: - mCurrentModule = new PhotoModule(); - break; - case PANORAMA_MODULE_INDEX: - mCurrentModule = new PanoramaModule(); - break; - case LIGHTCYCLE_MODULE_INDEX: - mCurrentModule = LightCycleHelper.createPanoramaModule(); - break; - } - showPieMenuButton(mCurrentModule.needsPieMenu()); - - openModule(mCurrentModule, canReuse); - mCurrentModule.onOrientationChanged(mLastRawOrientation); - if (mMediaSaveService != null) { - mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); - } - getCameraScreenNail().setAlpha(0f); - getCameraScreenNail().setOnFrameDrawnOneShot(mOnFrameDrawn); - } - - public void showPieMenuButton(boolean show) { - if (show) { - findViewById(R.id.blocker).setVisibility(View.VISIBLE); - findViewById(R.id.menu).setVisibility(View.VISIBLE); - findViewById(R.id.on_screen_indicators).setVisibility(View.VISIBLE); - } else { - findViewById(R.id.blocker).setVisibility(View.INVISIBLE); - findViewById(R.id.menu).setVisibility(View.INVISIBLE); - findViewById(R.id.on_screen_indicators).setVisibility(View.INVISIBLE); - } - } - - private Runnable mOnFrameDrawn = new Runnable() { + @Override + public void onServiceDisconnected(ComponentName className) { + mMediaSaveService = null; + }}; - @Override - public void run() { - runOnUiThread(mFadeInCameraScreenNail); - } - }; + private FilmStripView.Listener mFilmStripListener = new FilmStripView.Listener() { + @Override + public void onDataPromoted(int dataID) { + removeData(dataID); + } - private Runnable mFadeInCameraScreenNail = new Runnable() { + @Override + public void onDataDemoted(int dataID) { + removeData(dataID); + } - @Override - public void run() { - mCameraSwitchAnimator = ObjectAnimator.ofFloat( - getCameraScreenNail(), "alpha", 0f, 1f); - mCameraSwitchAnimator.setStartDelay(50); - mCameraSwitchAnimator.start(); - } - }; + @Override + public void onDataFullScreenChange(int dataID, boolean full) { + } - @Override - public void onShowSwitcherPopup() { - mCurrentModule.onShowSwitcherPopup(); - } + @Override + public void onSwitchMode(boolean toCamera) { + mCurrentModule.onSwitchMode(toCamera); + } + }; - private void openModule(CameraModule module, boolean canReuse) { - module.init(this, mFrame, canReuse && canReuseScreenNail()); - mPaused = false; - module.onResumeBeforeSuper(); - module.onResumeAfterSuper(); - } + private Runnable mDeletionRunnable = new Runnable() { + @Override + public void run() { + mDataAdapter.executeDeletion(CameraActivity.this); + } + }; - private void closeModule(CameraModule module) { - module.onPauseBeforeSuper(); - module.onPauseAfterSuper(); - mFrame.removeAllViews(); + public MediaSaveService getMediaSaveService() { + return mMediaSaveService; } - public ShutterButton getShutterButton() { - return mShutter; + public void notifyNewMedia(Uri uri) { + ContentResolver cr = getContentResolver(); + String mimeType = cr.getType(uri); + if (mimeType.startsWith("video/")) { + sendBroadcast(new Intent(Util.ACTION_NEW_VIDEO, uri)); + mDataAdapter.addNewVideo(cr, uri); + } else if (mimeType.startsWith("image/")) { + Util.broadcastNewPicture(this, uri); + mDataAdapter.addNewPhoto(cr, uri); + } else { + android.util.Log.w(TAG, "Unknown new media with MIME type:" + + mimeType + ", uri:" + uri); + } } - public void hideUI() { - mCameraControls.setVisibility(View.INVISIBLE); - hideSwitcher(); - mShutter.setVisibility(View.GONE); + private void removeData(int dataID) { + mDataAdapter.removeData(CameraActivity.this, dataID); + mMainHandler.removeCallbacks(mDeletionRunnable); + mMainHandler.postDelayed(mDeletionRunnable, 3000); } - public void showUI() { - mCameraControls.setVisibility(View.VISIBLE); - showSwitcher(); - mShutter.setVisibility(View.VISIBLE); - // Force a layout change to show shutter button - mShutter.requestLayout(); + private void bindMediaSaveService() { + Intent intent = new Intent(this, MediaSaveService.class); + startService(intent); // start service before binding it so the + // service won't be killed if we unbind it. + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } - public void hideSwitcher() { - mSwitcher.closePopup(); - mSwitcher.setVisibility(View.INVISIBLE); + private void unbindMediaSaveService() { + if (mMediaSaveService != null) { + mMediaSaveService.setListener(null); + } + if (mConnection != null) { + unbindService(mConnection); + } } - public void showSwitcher() { - if (mCurrentModule.needsSwitcher()) { - mSwitcher.setVisibility(View.VISIBLE); + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + setContentView(R.layout.camera_filmstrip); + if (ApiHelper.HAS_ROTATION_ANIMATION) { + setRotationAnimation(); + } + // Check if this is in the secure camera mode. + Intent intent = getIntent(); + String action = intent.getAction(); + if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) { + mSecureCamera = true; + } else if (ACTION_IMAGE_CAPTURE_SECURE.equals(action)) { + mSecureCamera = true; + } else { + mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false); } + /*TODO: if (mSecureCamera) { + IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); + registerReceiver(mScreenOffReceiver, filter); + if (sScreenOffReceiver == null) { + sScreenOffReceiver = new ScreenOffReceiver(); + getApplicationContext().registerReceiver(sScreenOffReceiver, filter); + } + }*/ + LayoutInflater inflater = getLayoutInflater(); + View rootLayout = inflater.inflate(R.layout.camera, null, false); + mRootView = rootLayout.findViewById(R.id.camera_app_root); + mDataAdapter = new CameraDataAdapter( + new ColorDrawable(getResources().getColor(R.color.photo_placeholder))); + mFilmStripView = (FilmStripView) findViewById(R.id.filmstrip_view); + mFilmStripView.setViewGap( + getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap)); + // Set up the camera preview first so the preview shows up ASAP. + mDataAdapter.setCameraPreviewInfo(rootLayout, + FilmStripView.ImageData.SIZE_FULL, FilmStripView.ImageData.SIZE_FULL); + mFilmStripView.setDataAdapter(mDataAdapter); + mFilmStripView.setListener(mFilmStripListener); + mCurrentModule = new PhotoModule(); + mCurrentModule.init(this, mRootView); + mOrientationListener = new MyOrientationEventListener(this); + mMainHandler = new Handler(getMainLooper()); + bindMediaSaveService(); } - public boolean isInCameraApp() { - return mShowCameraAppView; + private void setRotationAnimation() { + int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; + rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; + Window win = getWindow(); + WindowManager.LayoutParams winParams = win.getAttributes(); + winParams.rotationAnimation = rotationAnimation; + win.setAttributes(winParams); } @Override - public void onConfigurationChanged(Configuration config) { - super.onConfigurationChanged(config); - mCurrentModule.onConfigurationChanged(config); + public void onUserInteraction() { + super.onUserInteraction(); + mCurrentModule.onUserInteraction(); } @Override public void onPause() { - mPaused = true; mOrientationListener.disable(); mCurrentModule.onPauseBeforeSuper(); super.onPause(); @@ -328,7 +254,6 @@ public class CameraActivity extends ActivityBase @Override public void onResume() { - mPaused = false; if (Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {// auto-rotate off setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); @@ -341,180 +266,185 @@ public class CameraActivity extends ActivityBase mCurrentModule.onResumeBeforeSuper(); super.onResume(); mCurrentModule.onResumeAfterSuper(); - } - private void bindMediaSaveService() { - Intent intent = new Intent(this, MediaSaveService.class); - bindService(intent, mConnection, Context.BIND_AUTO_CREATE); - } - - private void unbindMediaSaveService() { - if (mMediaSaveService != null) { - mMediaSaveService.setListener(null); - } - if (mConnection != null) { - unbindService(mConnection); - } - } - - @Override - protected void onFullScreenChanged(boolean full) { - if (full) { - showUI(); + // The loading is done in background and will update the filmstrip later. + if (!mSecureCamera) { + mDataAdapter.requestLoad(getContentResolver()); } else { - hideUI(); + // Flush out all the original data first. + mDataAdapter.flush(); + ImageView v = (ImageView) getLayoutInflater().inflate( + R.layout.secure_album_placeholder, null); + // Put a lock placeholder as the last image by setting its date to 0. + mDataAdapter.addLocalData( + new LocalData.LocalViewData( + v, + v.getDrawable().getIntrinsicWidth(), + v.getDrawable().getIntrinsicHeight(), + 0, 0)); } - super.onFullScreenChanged(full); - if (ApiHelper.HAS_ROTATION_ANIMATION) { - setRotationAnimation(full); - } - mCurrentModule.onFullScreenChanged(full); - } - - private void setRotationAnimation(boolean fullscreen) { - int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; - if (fullscreen) { - rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; - } - Window win = getWindow(); - WindowManager.LayoutParams winParams = win.getAttributes(); - winParams.rotationAnimation = rotationAnimation; - win.setAttributes(winParams); + setSwipingEnabled(true); } @Override - protected void onStop() { - super.onStop(); - mCurrentModule.onStop(); - getStateManager().clearTasks(); + public void onDestroy() { + unbindMediaSaveService(); + super.onDestroy(); } @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - getStateManager().clearActivityResult(); + public void onConfigurationChanged(Configuration config) { + super.onConfigurationChanged(config); + mCurrentModule.onConfigurationChanged(config); } @Override - protected void installIntentFilter() { - super.installIntentFilter(); - mCurrentModule.installIntentFilter(); + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (mCurrentModule.onKeyDown(keyCode, event)) return true; + // Prevent software keyboard or voice search from showing up. + if (keyCode == KeyEvent.KEYCODE_SEARCH + || keyCode == KeyEvent.KEYCODE_MENU) { + if (event.isLongPress()) return true; + } + if (keyCode == KeyEvent.KEYCODE_MENU && mShowCameraPreview) { + return true; + } + + return super.onKeyDown(keyCode, event); } @Override - protected void onActivityResult( - int requestCode, int resultCode, Intent data) { - // Only PhotoPage understands ProxyLauncher.RESULT_USER_CANCELED - if (resultCode == ProxyLauncher.RESULT_USER_CANCELED - && !(getStateManager().getTopState() instanceof PhotoPage)) { - resultCode = RESULT_CANCELED; - } - super.onActivityResult(requestCode, resultCode, data); - // Unmap cancel vs. reset - if (resultCode == ProxyLauncher.RESULT_USER_CANCELED) { - resultCode = RESULT_CANCELED; + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (mCurrentModule.onKeyUp(keyCode, event)) return true; + if (keyCode == KeyEvent.KEYCODE_MENU && mShowCameraPreview) { + return true; } - mCurrentModule.onActivityResult(requestCode, resultCode, data); + return super.onKeyUp(keyCode, event); } - // Preview area is touched. Handle touch focus. - // Touch to focus is handled by PreviewGestures, this function call - // is no longer needed. TODO: Clean it up in the next refactor @Override - protected void onSingleTapUp(View view, int x, int y) { + public boolean dispatchTouchEvent(MotionEvent m) { + return mFilmStripView.dispatchTouchEvent(m); + } + public boolean isAutoRotateScreen() { + return mAutoRotateScreen; } - @Override - public void onBackPressed() { - if (!mCurrentModule.onBackPressed()) { - super.onBackPressed(); - } + protected void updateStorageSpace() { + mStorageSpace = Storage.getAvailableSpace(); } - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return mCurrentModule.onKeyDown(keyCode, event) - || super.onKeyDown(keyCode, event); + protected long getStorageSpace() { + return mStorageSpace; } - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - return mCurrentModule.onKeyUp(keyCode, event) - || super.onKeyUp(keyCode, event); + protected void updateStorageSpaceAndHint() { + updateStorageSpace(); + updateStorageHint(mStorageSpace); } - public void cancelActivityTouchHandling() { - if (mDown != null) { - MotionEvent cancel = MotionEvent.obtain(mDown); - cancel.setAction(MotionEvent.ACTION_CANCEL); - super.dispatchTouchEvent(cancel); - } + protected void updateStorageHint() { + updateStorageHint(mStorageSpace); } - @Override - public boolean dispatchTouchEvent(MotionEvent m) { - if (m.getActionMasked() == MotionEvent.ACTION_DOWN) { - mDown = m; + protected boolean updateStorageHintOnResume() { + return true; + } + + protected void updateStorageHint(long storageSpace) { + String message = null; + if (storageSpace == Storage.UNAVAILABLE) { + message = getString(R.string.no_storage); + } else if (storageSpace == Storage.PREPARING) { + message = getString(R.string.preparing_sd); + } else if (storageSpace == Storage.UNKNOWN_SIZE) { + message = getString(R.string.access_sd_fail); + } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD) { + message = getString(R.string.spaceIsLow_content); } - if ((mSwitcher != null) && mSwitcher.showsPopup() && !mSwitcher.isInsidePopup(m)) { - return mSwitcher.onTouch(null, m); - } else if ((mSwitcher != null) && mSwitcher.isInsidePopup(m)) { - return superDispatchTouchEvent(m); - } else { - return mCurrentModule.dispatchTouchEvent(m); + + if (message != null) { + if (mStorageHint == null) { + mStorageHint = OnScreenHint.makeText(this, message); + } else { + mStorageHint.setText(message); + } + mStorageHint.show(); + } else if (mStorageHint != null) { + mStorageHint.cancel(); + mStorageHint = null; } } - @Override - public void startActivityForResult(Intent intent, int requestCode) { - Intent proxyIntent = new Intent(this, ProxyLauncher.class); - proxyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); - proxyIntent.putExtra(Intent.EXTRA_INTENT, intent); - super.startActivityForResult(proxyIntent, requestCode); + protected void setResultEx(int resultCode) { + mResultCodeForTesting = resultCode; + setResult(resultCode); } - public boolean superDispatchTouchEvent(MotionEvent m) { - return super.dispatchTouchEvent(m); + protected void setResultEx(int resultCode, Intent data) { + mResultCodeForTesting = resultCode; + mResultDataForTesting = data; + setResult(resultCode, data); } - // Preview texture has been copied. Now camera can be released and the - // animation can be started. - @Override - public void onPreviewTextureCopied() { - mCurrentModule.onPreviewTextureCopied(); + public int getResultCode() { + return mResultCodeForTesting; } - @Override - public void onCaptureTextureCopied() { - mCurrentModule.onCaptureTextureCopied(); + public Intent getResultData() { + return mResultDataForTesting; } - @Override - public void onUserInteraction() { - super.onUserInteraction(); - mCurrentModule.onUserInteraction(); + public boolean isSecureCamera() { + return mSecureCamera; } @Override - protected boolean updateStorageHintOnResume() { - return mCurrentModule.updateStorageHintOnResume(); + public void onCameraSelected(int i) { + if (mCurrentModuleIndex == i) return; + + CameraHolder.instance().keep(); + closeModule(mCurrentModule); + mCurrentModuleIndex = i; + switch (i) { + case VIDEO_MODULE_INDEX: + mCurrentModule = new VideoModule(); + break; + case PHOTO_MODULE_INDEX: + mCurrentModule = new PhotoModule(); + break; + case LIGHTCYCLE_MODULE_INDEX: + mCurrentModule = LightCycleHelper.createPanoramaModule(); + break; + default: + break; + } + + openModule(mCurrentModule); + mCurrentModule.onOrientationChanged(mLastRawOrientation); + if (mMediaSaveService != null) { + mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); + } } - @Override - public void updateCameraAppView() { - super.updateCameraAppView(); - mCurrentModule.updateCameraAppView(); + private void openModule(CameraModule module) { + module.init(this, mRootView); + module.onResumeBeforeSuper(); + module.onResumeAfterSuper(); } - private boolean canReuseScreenNail() { - return mCurrentModuleIndex == PHOTO_MODULE_INDEX - || mCurrentModuleIndex == VIDEO_MODULE_INDEX - || mCurrentModuleIndex == LIGHTCYCLE_MODULE_INDEX; + private void closeModule(CameraModule module) { + module.onPauseBeforeSuper(); + module.onPauseAfterSuper(); + ((ViewGroup) mRootView).removeAllViews(); } @Override - public boolean isPanoramaActivity() { - return (mCurrentModuleIndex == PANORAMA_MODULE_INDEX); + public void onShowSwitcherPopup() { + } + + public void setSwipingEnabled(boolean enable) { + mDataAdapter.setCameraPreviewLock(!enable); } // Accessor methods for getting latency times used in performance testing @@ -552,12 +482,4 @@ public class CameraActivity extends ActivityBase return (mCurrentModule instanceof VideoModule) ? ((VideoModule) mCurrentModule).isRecording() : false; } - - public CameraScreenNail getCameraScreenNail() { - return (CameraScreenNail) mCameraScreenNail; - } - - public MediaSaveService getMediaSaveService() { - return mMediaSaveService; - } } diff --git a/src/com/android/camera/CameraModule.java b/src/com/android/camera/CameraModule.java index 3275d5f51..bcfe98d65 100644 --- a/src/com/android/camera/CameraModule.java +++ b/src/com/android/camera/CameraModule.java @@ -24,9 +24,9 @@ import android.view.View; public interface CameraModule { - public void init(CameraActivity activity, View frame, boolean reuseScreenNail); + public void init(CameraActivity activity, View frame); - public void onFullScreenChanged(boolean full); + public void onSwitchMode(boolean toCamera); public void onPauseBeforeSuper(); @@ -52,8 +52,6 @@ public interface CameraModule { public void onSingleTapUp(View view, int x, int y); - public boolean dispatchTouchEvent(MotionEvent m); - public void onPreviewTextureCopied(); public void onCaptureTextureCopied(); @@ -64,10 +62,6 @@ public interface CameraModule { public void updateCameraAppView(); - public boolean needsSwitcher(); - - public boolean needsPieMenu(); - public void onOrientationChanged(int orientation); public void onShowSwitcherPopup(); diff --git a/src/com/android/camera/NewCameraActivity.java b/src/com/android/camera/NewCameraActivity.java deleted file mode 100644 index 8985f7f58..000000000 --- a/src/com/android/camera/NewCameraActivity.java +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.content.pm.ActivityInfo; -import android.content.res.Configuration; -import android.graphics.drawable.ColorDrawable; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.provider.Settings; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.OrientationEventListener; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.widget.ImageView; - -import com.android.camera.data.CameraDataAdapter; -import com.android.camera.data.LocalData; -import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; -import com.android.camera.ui.FilmStripView; -import com.android.camera.ui.NewCameraRootView; -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.util.LightCycleHelper; - -public class NewCameraActivity extends Activity - implements CameraSwitchListener { - public static final int PHOTO_MODULE_INDEX = 0; - public static final int VIDEO_MODULE_INDEX = 1; - public static final int PANORAMA_MODULE_INDEX = 2; - public static final int LIGHTCYCLE_MODULE_INDEX = 3; - private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE = - "android.media.action.STILL_IMAGE_CAMERA_SECURE"; - public static final String ACTION_IMAGE_CAPTURE_SECURE = - "android.media.action.IMAGE_CAPTURE_SECURE"; - // The intent extra for camera from secure lock screen. True if the gallery - // should only show newly captured pictures. sSecureAlbumId does not - // increment. This is used when switching between camera, camcorder, and - // panorama. If the extra is not set, it is in the normal camera mode. - public static final String SECURE_CAMERA_EXTRA = "secure_camera"; - - private static final String TAG = "CAM_Activity"; - private CameraDataAdapter mDataAdapter; - private int mCurrentModuleIndex; - private NewCameraModule mCurrentModule; - private View mRootView; - private FilmStripView mFilmStripView; - private int mResultCodeForTesting; - private Intent mResultDataForTesting; - private OnScreenHint mStorageHint; - private long mStorageSpace = Storage.LOW_STORAGE_THRESHOLD; - private PhotoModule mController; - private boolean mAutoRotateScreen; - private boolean mSecureCamera; - private int mLastRawOrientation; - private MyOrientationEventListener mOrientationListener; - private Handler mMainHandler; - private class MyOrientationEventListener - extends OrientationEventListener { - public MyOrientationEventListener(Context context) { - super(context); - } - - @Override - public void onOrientationChanged(int orientation) { - // We keep the last known orientation. So if the user first orient - // the camera then point the camera to floor or sky, we still have - // the correct orientation. - if (orientation == ORIENTATION_UNKNOWN) return; - mLastRawOrientation = orientation; - mCurrentModule.onOrientationChanged(orientation); - } - } - private MediaSaveService mMediaSaveService; - private ServiceConnection mConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName className, IBinder b) { - mMediaSaveService = ((MediaSaveService.LocalBinder) b).getService(); - mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); - } - @Override - public void onServiceDisconnected(ComponentName className) { - mMediaSaveService = null; - }}; - - private FilmStripView.Listener mFilmStripListener = new FilmStripView.Listener() { - @Override - public void onDataPromoted(int dataID) { - removeData(dataID); - } - - @Override - public void onDataDemoted(int dataID) { - removeData(dataID); - } - - @Override - public void onDataFullScreenChange(int dataID, boolean full) { - } - - @Override - public void onSwitchMode(boolean toCamera) { - mCurrentModule.onSwitchMode(toCamera); - } - }; - - private Runnable mDeletionRunnable = new Runnable() { - @Override - public void run() { - mDataAdapter.executeDeletion(NewCameraActivity.this); - } - }; - - public MediaSaveService getMediaSaveService() { - return mMediaSaveService; - } - - public void notifyNewMedia(Uri uri) { - ContentResolver cr = getContentResolver(); - String mimeType = cr.getType(uri); - if (mimeType.startsWith("video/")) { - sendBroadcast(new Intent(Util.ACTION_NEW_VIDEO, uri)); - mDataAdapter.addNewVideo(cr, uri); - } else if (mimeType.startsWith("image/")) { - Util.broadcastNewPicture(this, uri); - mDataAdapter.addNewPhoto(cr, uri); - } else { - android.util.Log.w(TAG, "Unknown new media with MIME type:" - + mimeType + ", uri:" + uri); - } - } - - private void removeData(int dataID) { - mDataAdapter.removeData(NewCameraActivity.this, dataID); - mMainHandler.removeCallbacks(mDeletionRunnable); - mMainHandler.postDelayed(mDeletionRunnable, 3000); - } - - private void bindMediaSaveService() { - Intent intent = new Intent(this, MediaSaveService.class); - startService(intent); // start service before binding it so the - // service won't be killed if we unbind it. - bindService(intent, mConnection, Context.BIND_AUTO_CREATE); - } - - private void unbindMediaSaveService() { - if (mMediaSaveService != null) { - mMediaSaveService.setListener(null); - } - if (mConnection != null) { - unbindService(mConnection); - } - } - - @Override - public void onCreate(Bundle state) { - super.onCreate(state); - setContentView(R.layout.camera_filmstrip); - if (ApiHelper.HAS_ROTATION_ANIMATION) { - setRotationAnimation(); - } - // Check if this is in the secure camera mode. - Intent intent = getIntent(); - String action = intent.getAction(); - if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) { - mSecureCamera = true; - } else if (ACTION_IMAGE_CAPTURE_SECURE.equals(action)) { - mSecureCamera = true; - } else { - mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false); - } - /*TODO: if (mSecureCamera) { - IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); - registerReceiver(mScreenOffReceiver, filter); - if (sScreenOffReceiver == null) { - sScreenOffReceiver = new ScreenOffReceiver(); - getApplicationContext().registerReceiver(sScreenOffReceiver, filter); - } - }*/ - LayoutInflater inflater = getLayoutInflater(); - View rootLayout = inflater.inflate(R.layout.camera, null, false); - mRootView = rootLayout.findViewById(R.id.camera_app_root); - mDataAdapter = new CameraDataAdapter( - new ColorDrawable(getResources().getColor(R.color.photo_placeholder))); - mFilmStripView = (FilmStripView) findViewById(R.id.filmstrip_view); - mFilmStripView.setViewGap( - getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap)); - // Set up the camera preview first so the preview shows up ASAP. - mDataAdapter.setCameraPreviewInfo(rootLayout, - FilmStripView.ImageData.SIZE_FULL, FilmStripView.ImageData.SIZE_FULL); - mFilmStripView.setDataAdapter(mDataAdapter); - mFilmStripView.setListener(mFilmStripListener); - mCurrentModule = new NewPhotoModule(); - mCurrentModule.init(this, mRootView); - mOrientationListener = new MyOrientationEventListener(this); - mMainHandler = new Handler(getMainLooper()); - bindMediaSaveService(); - } - - private void setRotationAnimation() { - int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; - rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; - Window win = getWindow(); - WindowManager.LayoutParams winParams = win.getAttributes(); - winParams.rotationAnimation = rotationAnimation; - win.setAttributes(winParams); - } - - @Override - public void onUserInteraction() { - super.onUserInteraction(); - mCurrentModule.onUserInteraction(); - } - - @Override - public void onPause() { - mOrientationListener.disable(); - mCurrentModule.onPauseBeforeSuper(); - super.onPause(); - mCurrentModule.onPauseAfterSuper(); - } - - @Override - public void onResume() { - if (Settings.System.getInt(getContentResolver(), - Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {// auto-rotate off - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); - mAutoRotateScreen = false; - } else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); - mAutoRotateScreen = true; - } - mOrientationListener.enable(); - mCurrentModule.onResumeBeforeSuper(); - super.onResume(); - mCurrentModule.onResumeAfterSuper(); - - // The loading is done in background and will update the filmstrip later. - if (!mSecureCamera) { - mDataAdapter.requestLoad(getContentResolver()); - } else { - // Flush out all the original data first. - mDataAdapter.flush(); - ImageView v = (ImageView) getLayoutInflater().inflate( - R.layout.secure_album_placeholder, null); - // Put a lock placeholder as the last image by setting its date to 0. - mDataAdapter.addLocalData( - new LocalData.LocalViewData( - v, - v.getDrawable().getIntrinsicWidth(), - v.getDrawable().getIntrinsicHeight(), - 0, 0)); - } - setSwipingEnabled(true); - } - - @Override - public void onDestroy() { - unbindMediaSaveService(); - super.onDestroy(); - } - - @Override - public void onConfigurationChanged(Configuration config) { - super.onConfigurationChanged(config); - mCurrentModule.onConfigurationChanged(config); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent m) { - return mFilmStripView.dispatchTouchEvent(m); - } - public boolean isAutoRotateScreen() { - return mAutoRotateScreen; - } - - protected void updateStorageSpace() { - mStorageSpace = Storage.getAvailableSpace(); - } - - protected long getStorageSpace() { - return mStorageSpace; - } - - protected void updateStorageSpaceAndHint() { - updateStorageSpace(); - updateStorageHint(mStorageSpace); - } - - protected void updateStorageHint() { - updateStorageHint(mStorageSpace); - } - - protected boolean updateStorageHintOnResume() { - return true; - } - - protected void updateStorageHint(long storageSpace) { - String message = null; - if (storageSpace == Storage.UNAVAILABLE) { - message = getString(R.string.no_storage); - } else if (storageSpace == Storage.PREPARING) { - message = getString(R.string.preparing_sd); - } else if (storageSpace == Storage.UNKNOWN_SIZE) { - message = getString(R.string.access_sd_fail); - } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD) { - message = getString(R.string.spaceIsLow_content); - } - - if (message != null) { - if (mStorageHint == null) { - mStorageHint = OnScreenHint.makeText(this, message); - } else { - mStorageHint.setText(message); - } - mStorageHint.show(); - } else if (mStorageHint != null) { - mStorageHint.cancel(); - mStorageHint = null; - } - } - - protected void setResultEx(int resultCode) { - mResultCodeForTesting = resultCode; - setResult(resultCode); - } - - protected void setResultEx(int resultCode, Intent data) { - mResultCodeForTesting = resultCode; - mResultDataForTesting = data; - setResult(resultCode, data); - } - - public int getResultCode() { - return mResultCodeForTesting; - } - - public Intent getResultData() { - return mResultDataForTesting; - } - - public boolean isSecureCamera() { - return mSecureCamera; - } - - @Override - public void onCameraSelected(int i) { - if (mCurrentModuleIndex == i) return; - - CameraHolder.instance().keep(); - closeModule(mCurrentModule); - mCurrentModuleIndex = i; - switch (i) { - case VIDEO_MODULE_INDEX: - mCurrentModule = new NewVideoModule(); - break; - case PHOTO_MODULE_INDEX: - mCurrentModule = new NewPhotoModule(); - break; - /* TODO: - case LIGHTCYCLE_MODULE_INDEX: - mCurrentModule = LightCycleHelper.createNewPanoramaModule(); - break; */ - default: - break; - } - - openModule(mCurrentModule); - mCurrentModule.onOrientationChanged(mLastRawOrientation); - if (mMediaSaveService != null) { - mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); - } - } - - private void openModule(NewCameraModule module) { - module.init(this, mRootView); - module.onResumeBeforeSuper(); - module.onResumeAfterSuper(); - } - - private void closeModule(NewCameraModule module) { - module.onPauseBeforeSuper(); - module.onPauseAfterSuper(); - ((ViewGroup) mRootView).removeAllViews(); - } - - @Override - public void onShowSwitcherPopup() { - } - - public void setSwipingEnabled(boolean enable) { - mDataAdapter.setCameraPreviewLock(!enable); - } - - // Accessor methods for getting latency times used in performance testing - public long getAutoFocusTime() { - return (mCurrentModule instanceof PhotoModule) ? - ((PhotoModule) mCurrentModule).mAutoFocusTime : -1; - } - - public long getShutterLag() { - return (mCurrentModule instanceof PhotoModule) ? - ((PhotoModule) mCurrentModule).mShutterLag : -1; - } - - public long getShutterToPictureDisplayedTime() { - return (mCurrentModule instanceof PhotoModule) ? - ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1; - } - - public long getPictureDisplayedToJpegCallbackTime() { - return (mCurrentModule instanceof PhotoModule) ? - ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1; - } - - public long getJpegCallbackFinishTime() { - return (mCurrentModule instanceof PhotoModule) ? - ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1; - } - - public long getCaptureStartTime() { - return (mCurrentModule instanceof PhotoModule) ? - ((PhotoModule) mCurrentModule).mCaptureStartTime : -1; - } - - public boolean isRecording() { - return (mCurrentModule instanceof VideoModule) ? - ((VideoModule) mCurrentModule).isRecording() : false; - } -} diff --git a/src/com/android/camera/NewCameraModule.java b/src/com/android/camera/NewCameraModule.java deleted file mode 100644 index a98c95247..000000000 --- a/src/com/android/camera/NewCameraModule.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.content.Intent; -import android.content.res.Configuration; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; - -public interface NewCameraModule { - - public void init(NewCameraActivity activity, View frame); - - public void onSwitchMode(boolean toCamera); - - public void onPauseBeforeSuper(); - - public void onPauseAfterSuper(); - - public void onResumeBeforeSuper(); - - public void onResumeAfterSuper(); - - public void onConfigurationChanged(Configuration config); - - public void onStop(); - - public void installIntentFilter(); - - public void onActivityResult(int requestCode, int resultCode, Intent data); - - public boolean onBackPressed(); - - public boolean onKeyDown(int keyCode, KeyEvent event); - - public boolean onKeyUp(int keyCode, KeyEvent event); - - public void onSingleTapUp(View view, int x, int y); - - public void onPreviewTextureCopied(); - - public void onCaptureTextureCopied(); - - public void onUserInteraction(); - - public boolean updateStorageHintOnResume(); - - public void updateCameraAppView(); - - public boolean needsSwitcher(); - - public boolean needsPieMenu(); - - public void onOrientationChanged(int orientation); - - public void onShowSwitcherPopup(); - - public void onMediaSaveServiceConnected(MediaSaveService s); -} diff --git a/src/com/android/camera/NewPhotoMenu.java b/src/com/android/camera/NewPhotoMenu.java deleted file mode 100644 index c63aff458..000000000 --- a/src/com/android/camera/NewPhotoMenu.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.content.res.Resources; -import android.hardware.Camera.Parameters; - -import com.android.camera.ui.AbstractSettingPopup; -import com.android.camera.ui.CountdownTimerPopup; -import com.android.camera.ui.ListPrefSettingPopup; -import com.android.camera.ui.PieItem; -import com.android.camera.ui.PieItem.OnClickListener; -import com.android.camera.ui.PieRenderer; -import com.android.gallery3d.R; - -import java.util.Locale; - -public class NewPhotoMenu extends PieController - implements CountdownTimerPopup.Listener, - ListPrefSettingPopup.Listener { - private static String TAG = "CAM_photomenu"; - - private final String mSettingOff; - - private NewPhotoUI mUI; - private AbstractSettingPopup mPopup; - private NewCameraActivity mActivity; - - public NewPhotoMenu(NewCameraActivity activity, NewPhotoUI ui, PieRenderer pie) { - super(activity, pie); - mUI = ui; - mSettingOff = activity.getString(R.string.setting_off_value); - mActivity = activity; - } - - public void initialize(PreferenceGroup group) { - super.initialize(group); - mPopup = null; - PieItem item = null; - final Resources res = mActivity.getResources(); - Locale locale = res.getConfiguration().locale; - // the order is from left to right in the menu - - // hdr - if (group.findPreference(CameraSettings.KEY_CAMERA_HDR) != null) { - item = makeSwitchItem(CameraSettings.KEY_CAMERA_HDR, true); - mRenderer.addItem(item); - } - // exposure compensation - if (group.findPreference(CameraSettings.KEY_EXPOSURE) != null) { - item = makeItem(CameraSettings.KEY_EXPOSURE); - item.setLabel(res.getString(R.string.pref_exposure_label)); - mRenderer.addItem(item); - } - // more settings - PieItem more = makeItem(R.drawable.ic_settings_holo_light); - more.setLabel(res.getString(R.string.camera_menu_more_label)); - mRenderer.addItem(more); - // flash - if (group.findPreference(CameraSettings.KEY_FLASH_MODE) != null) { - item = makeItem(CameraSettings.KEY_FLASH_MODE); - item.setLabel(res.getString(R.string.pref_camera_flashmode_label)); - mRenderer.addItem(item); - } - // camera switcher - if (group.findPreference(CameraSettings.KEY_CAMERA_ID) != null) { - item = makeSwitchItem(CameraSettings.KEY_CAMERA_ID, false); - final PieItem fitem = item; - item.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - // Find the index of next camera. - ListPreference pref = mPreferenceGroup - .findPreference(CameraSettings.KEY_CAMERA_ID); - if (pref != null) { - int index = pref.findIndexOfValue(pref.getValue()); - CharSequence[] values = pref.getEntryValues(); - index = (index + 1) % values.length; - pref.setValueIndex(index); - mListener.onCameraPickerClicked(index); - } - updateItem(fitem, CameraSettings.KEY_CAMERA_ID); - } - }); - mRenderer.addItem(item); - } - // location - if (group.findPreference(CameraSettings.KEY_RECORD_LOCATION) != null) { - item = makeSwitchItem(CameraSettings.KEY_RECORD_LOCATION, true); - more.addItem(item); - if (mActivity.isSecureCamera()) { - // Prevent location preference from getting changed in secure camera mode - item.setEnabled(false); - } - } - // countdown timer - final ListPreference ctpref = group.findPreference(CameraSettings.KEY_TIMER); - final ListPreference beeppref = group.findPreference(CameraSettings.KEY_TIMER_SOUND_EFFECTS); - item = makeItem(R.drawable.ic_timer); - item.setLabel(res.getString(R.string.pref_camera_timer_title).toUpperCase(locale)); - item.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - CountdownTimerPopup timerPopup = (CountdownTimerPopup) mActivity.getLayoutInflater().inflate( - R.layout.countdown_setting_popup, null, false); - timerPopup.initialize(ctpref, beeppref); - timerPopup.setSettingChangedListener(NewPhotoMenu.this); - mUI.dismissPopup(); - mPopup = timerPopup; - mUI.showPopup(mPopup); - } - }); - more.addItem(item); - // image size - item = makeItem(R.drawable.ic_imagesize); - final ListPreference sizePref = group.findPreference(CameraSettings.KEY_PICTURE_SIZE); - item.setLabel(res.getString(R.string.pref_camera_picturesize_title).toUpperCase(locale)); - item.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - ListPrefSettingPopup popup = (ListPrefSettingPopup) mActivity.getLayoutInflater().inflate( - R.layout.list_pref_setting_popup, null, false); - popup.initialize(sizePref); - popup.setSettingChangedListener(NewPhotoMenu.this); - mUI.dismissPopup(); - mPopup = popup; - mUI.showPopup(mPopup); - } - }); - more.addItem(item); - // white balance - if (group.findPreference(CameraSettings.KEY_WHITE_BALANCE) != null) { - item = makeItem(CameraSettings.KEY_WHITE_BALANCE); - item.setLabel(res.getString(R.string.pref_camera_whitebalance_label)); - more.addItem(item); - } - // scene mode - if (group.findPreference(CameraSettings.KEY_SCENE_MODE) != null) { - IconListPreference pref = (IconListPreference) group.findPreference( - CameraSettings.KEY_SCENE_MODE); - pref.setUseSingleIcon(true); - item = makeItem(CameraSettings.KEY_SCENE_MODE); - more.addItem(item); - } - } - - @Override - // Hit when an item in a popup gets selected - public void onListPrefChanged(ListPreference pref) { - if (mPopup != null) { - mUI.dismissPopup(); - } - onSettingChanged(pref); - } - - public void popupDismissed() { - if (mPopup != null) { - mPopup = null; - } - } - - // Return true if the preference has the specified key but not the value. - private static boolean notSame(ListPreference pref, String key, String value) { - return (key.equals(pref.getKey()) && !value.equals(pref.getValue())); - } - - private void setPreference(String key, String value) { - ListPreference pref = mPreferenceGroup.findPreference(key); - if (pref != null && !value.equals(pref.getValue())) { - pref.setValue(value); - reloadPreferences(); - } - } - - @Override - public void onSettingChanged(ListPreference pref) { - // Reset the scene mode if HDR is set to on. Reset HDR if scene mode is - // set to non-auto. - if (notSame(pref, CameraSettings.KEY_CAMERA_HDR, mSettingOff)) { - setPreference(CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO); - } else if (notSame(pref, CameraSettings.KEY_SCENE_MODE, Parameters.SCENE_MODE_AUTO)) { - setPreference(CameraSettings.KEY_CAMERA_HDR, mSettingOff); - } - super.onSettingChanged(pref); - } -} diff --git a/src/com/android/camera/NewPhotoModule.java b/src/com/android/camera/NewPhotoModule.java deleted file mode 100644 index 6e306e48f..000000000 --- a/src/com/android/camera/NewPhotoModule.java +++ /dev/null @@ -1,2037 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.content.ContentProviderClient; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences.Editor; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.SurfaceTexture; -import android.hardware.Camera.CameraInfo; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.PictureCallback; -import android.hardware.Camera.Size; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.location.Location; -import android.media.CameraProfile; -import android.net.Uri; -import android.os.Bundle; -import android.os.ConditionVariable; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.MessageQueue; -import android.os.SystemClock; -import android.provider.MediaStore; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.OrientationEventListener; -import android.view.SurfaceHolder; -import android.view.View; -import android.view.WindowManager; - -import com.android.camera.CameraManager.CameraProxy; -import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; -import com.android.camera.ui.PopupManager; -import com.android.camera.ui.RotateTextToast; -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.exif.ExifInterface; -import com.android.gallery3d.exif.ExifTag; -import com.android.gallery3d.exif.Rational; -import com.android.gallery3d.filtershow.crop.CropActivity; -import com.android.gallery3d.filtershow.crop.CropExtras; -import com.android.gallery3d.util.UsageStatistics; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Formatter; -import java.util.List; - -public class NewPhotoModule - implements NewCameraModule, - PhotoController, - FocusOverlayManager.Listener, - CameraPreference.OnPreferenceChangedListener, - ShutterButton.OnShutterButtonListener, - MediaSaveService.Listener, - OnCountDownFinishedListener, - SensorEventListener { - - private static final String TAG = "CAM_PhotoModule"; - - // We number the request code from 1000 to avoid collision with Gallery. - private static final int REQUEST_CROP = 1000; - - private static final int SETUP_PREVIEW = 1; - private static final int FIRST_TIME_INIT = 2; - private static final int CLEAR_SCREEN_DELAY = 3; - private static final int SET_CAMERA_PARAMETERS_WHEN_IDLE = 4; - private static final int CHECK_DISPLAY_ROTATION = 5; - private static final int SHOW_TAP_TO_FOCUS_TOAST = 6; - private static final int SWITCH_CAMERA = 7; - private static final int SWITCH_CAMERA_START_ANIMATION = 8; - private static final int CAMERA_OPEN_DONE = 9; - private static final int START_PREVIEW_DONE = 10; - private static final int OPEN_CAMERA_FAIL = 11; - private static final int CAMERA_DISABLED = 12; - private static final int CAPTURE_ANIMATION_DONE = 13; - - // The subset of parameters we need to update in setCameraParameters(). - private static final int UPDATE_PARAM_INITIALIZE = 1; - private static final int UPDATE_PARAM_ZOOM = 2; - private static final int UPDATE_PARAM_PREFERENCE = 4; - private static final int UPDATE_PARAM_ALL = -1; - - // This is the timeout to keep the camera in onPause for the first time - // after screen on if the activity is started from secure lock screen. - private static final int KEEP_CAMERA_TIMEOUT = 1000; // ms - - // copied from Camera hierarchy - private NewCameraActivity mActivity; - private CameraProxy mCameraDevice; - private int mCameraId; - private Parameters mParameters; - private boolean mPaused; - - private NewPhotoUI mUI; - - // The activity is going to switch to the specified camera id. This is - // needed because texture copy is done in GL thread. -1 means camera is not - // switching. - protected int mPendingSwitchCameraId = -1; - private boolean mOpenCameraFail; - private boolean mCameraDisabled; - - // When setCameraParametersWhenIdle() is called, we accumulate the subsets - // needed to be updated in mUpdateSet. - private int mUpdateSet; - - private static final int SCREEN_DELAY = 2 * 60 * 1000; - - private int mZoomValue; // The current zoom value. - - private Parameters mInitialParams; - private boolean mFocusAreaSupported; - private boolean mMeteringAreaSupported; - private boolean mAeLockSupported; - private boolean mAwbLockSupported; - private boolean mContinousFocusSupported; - - // The degrees of the device rotated clockwise from its natural orientation. - private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; - private ComboPreferences mPreferences; - - private static final String sTempCropFilename = "crop-temp"; - - private ContentProviderClient mMediaProviderClient; - private boolean mFaceDetectionStarted = false; - - // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true. - private String mCropValue; - private Uri mSaveUri; - - // We use a queue to generated names of the images to be used later - // when the image is ready to be saved. - private NamedImages mNamedImages; - - private Runnable mDoSnapRunnable = new Runnable() { - @Override - public void run() { - onShutterButtonClick(); - } - }; - - private Runnable mFlashRunnable = new Runnable() { - @Override - public void run() { - animateFlash(); - } - }; - - private final StringBuilder mBuilder = new StringBuilder(); - private final Formatter mFormatter = new Formatter(mBuilder); - private final Object[] mFormatterArgs = new Object[1]; - - /** - * An unpublished intent flag requesting to return as soon as capturing - * is completed. - * - * TODO: consider publishing by moving into MediaStore. - */ - private static final String EXTRA_QUICK_CAPTURE = - "android.intent.extra.quickCapture"; - - // The display rotation in degrees. This is only valid when mCameraState is - // not PREVIEW_STOPPED. - private int mDisplayRotation; - // The value for android.hardware.Camera.setDisplayOrientation. - private int mCameraDisplayOrientation; - // The value for UI components like indicators. - private int mDisplayOrientation; - // The value for android.hardware.Camera.Parameters.setRotation. - private int mJpegRotation; - private boolean mFirstTimeInitialized; - private boolean mIsImageCaptureIntent; - - private int mCameraState = PREVIEW_STOPPED; - private boolean mSnapshotOnIdle = false; - - private ContentResolver mContentResolver; - - private LocationManager mLocationManager; - - private final PostViewPictureCallback mPostViewPictureCallback = - new PostViewPictureCallback(); - private final RawPictureCallback mRawPictureCallback = - new RawPictureCallback(); - private final AutoFocusCallback mAutoFocusCallback = - new AutoFocusCallback(); - private final Object mAutoFocusMoveCallback = - ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK - ? new AutoFocusMoveCallback() - : null; - - private final CameraErrorCallback mErrorCallback = new CameraErrorCallback(); - - private long mFocusStartTime; - private long mShutterCallbackTime; - private long mPostViewPictureCallbackTime; - private long mRawPictureCallbackTime; - private long mJpegPictureCallbackTime; - private long mOnResumeTime; - private byte[] mJpegImageData; - - // These latency time are for the CameraLatency test. - public long mAutoFocusTime; - public long mShutterLag; - public long mShutterToPictureDisplayedTime; - public long mPictureDisplayedToJpegCallbackTime; - public long mJpegCallbackFinishTime; - public long mCaptureStartTime; - - // This handles everything about focus. - private FocusOverlayManager mFocusManager; - - private String mSceneMode; - - private final Handler mHandler = new MainHandler(); - private PreferenceGroup mPreferenceGroup; - - private boolean mQuickCapture; - private SensorManager mSensorManager; - private float[] mGData = new float[3]; - private float[] mMData = new float[3]; - private float[] mR = new float[16]; - private int mHeading = -1; - - CameraStartUpThread mCameraStartUpThread; - ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable(); - - private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = - new MediaSaveService.OnMediaSavedListener() { - @Override - public void onMediaSaved(Uri uri) { - if (uri != null) { - mActivity.notifyNewMedia(uri); - } - } - }; - - // The purpose is not to block the main thread in onCreate and onResume. - private class CameraStartUpThread extends Thread { - private volatile boolean mCancelled; - - public void cancel() { - mCancelled = true; - interrupt(); - } - - public boolean isCanceled() { - return mCancelled; - } - - @Override - public void run() { - try { - // We need to check whether the activity is paused before long - // operations to ensure that onPause() can be done ASAP. - if (mCancelled) return; - mCameraDevice = Util.openCamera(mActivity, mCameraId); - mParameters = mCameraDevice.getParameters(); - // Wait until all the initialization needed by startPreview are - // done. - mStartPreviewPrerequisiteReady.block(); - - initializeCapabilities(); - if (mFocusManager == null) initializeFocusManager(); - if (mCancelled) return; - setCameraParameters(UPDATE_PARAM_ALL); - mHandler.sendEmptyMessage(CAMERA_OPEN_DONE); - if (mCancelled) return; - startPreview(); - mHandler.sendEmptyMessage(START_PREVIEW_DONE); - mOnResumeTime = SystemClock.uptimeMillis(); - mHandler.sendEmptyMessage(CHECK_DISPLAY_ROTATION); - } catch (CameraHardwareException e) { - mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL); - } catch (CameraDisabledException e) { - mHandler.sendEmptyMessage(CAMERA_DISABLED); - } - } - } - - /** - * This Handler is used to post message back onto the main thread of the - * application - */ - private class MainHandler extends Handler { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case SETUP_PREVIEW: { - setupPreview(); - break; - } - - case CLEAR_SCREEN_DELAY: { - mActivity.getWindow().clearFlags( - WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - break; - } - - case FIRST_TIME_INIT: { - initializeFirstTime(); - break; - } - - case SET_CAMERA_PARAMETERS_WHEN_IDLE: { - setCameraParametersWhenIdle(0); - break; - } - - case CHECK_DISPLAY_ROTATION: { - // Set the display orientation if display rotation has changed. - // Sometimes this happens when the device is held upside - // down and camera app is opened. Rotation animation will - // take some time and the rotation value we have got may be - // wrong. Framework does not have a callback for this now. - if (Util.getDisplayRotation(mActivity) != mDisplayRotation) { - setDisplayOrientation(); - } - if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) { - mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100); - } - break; - } - - case SHOW_TAP_TO_FOCUS_TOAST: { - showTapToFocusToast(); - break; - } - - case SWITCH_CAMERA: { - switchCamera(); - break; - } - - case SWITCH_CAMERA_START_ANIMATION: { - // TODO: Need to revisit - // ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera(); - break; - } - - case CAMERA_OPEN_DONE: { - onCameraOpened(); - break; - } - - case START_PREVIEW_DONE: { - onPreviewStarted(); - break; - } - - case OPEN_CAMERA_FAIL: { - mCameraStartUpThread = null; - mOpenCameraFail = true; - Util.showErrorAndFinish(mActivity, - R.string.cannot_connect_camera); - break; - } - - case CAMERA_DISABLED: { - mCameraStartUpThread = null; - mCameraDisabled = true; - Util.showErrorAndFinish(mActivity, - R.string.camera_disabled); - break; - } - case CAPTURE_ANIMATION_DONE: { - mUI.enablePreviewThumb(false); - break; - } - } - } - } - - @Override - public void init(NewCameraActivity activity, View parent) { - mActivity = activity; - mUI = new NewPhotoUI(activity, this, parent); - mPreferences = new ComboPreferences(mActivity); - CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal()); - mCameraId = getPreferredCameraId(mPreferences); - - mContentResolver = mActivity.getContentResolver(); - - // To reduce startup time, open the camera and start the preview in - // another thread. - mCameraStartUpThread = new CameraStartUpThread(); - mCameraStartUpThread.start(); - - // Surface texture is from camera screen nail and startPreview needs it. - // This must be done before startPreview. - mIsImageCaptureIntent = isImageCaptureIntent(); - - mPreferences.setLocalId(mActivity, mCameraId); - CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - // we need to reset exposure for the preview - resetExposureCompensation(); - // Starting the preview needs preferences, camera screen nail, and - // focus area indicator. - mStartPreviewPrerequisiteReady.open(); - - initializeControlByIntent(); - mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); - mLocationManager = new LocationManager(mActivity, mUI); - mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE)); - } - - private void initializeControlByIntent() { - mUI.initializeControlByIntent(); - if (mIsImageCaptureIntent) { - setupCaptureParams(); - } - } - - private void onPreviewStarted() { - mCameraStartUpThread = null; - setCameraState(IDLE); - startFaceDetection(); - locationFirstRun(); - } - - // Prompt the user to pick to record location for the very first run of - // camera only - private void locationFirstRun() { - if (RecordLocationPreference.isSet(mPreferences)) { - return; - } - if (mActivity.isSecureCamera()) return; - // Check if the back camera exists - int backCameraId = CameraHolder.instance().getBackCameraId(); - if (backCameraId == -1) { - // If there is no back camera, do not show the prompt. - return; - } - - new AlertDialog.Builder(mActivity) - .setTitle(R.string.remember_location_title) - .setMessage(R.string.remember_location_prompt) - .setPositiveButton(R.string.remember_location_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int arg1) { - setLocationPreference(RecordLocationPreference.VALUE_ON); - } - }) - .setNegativeButton(R.string.remember_location_no, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int arg1) { - dialog.cancel(); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - setLocationPreference(RecordLocationPreference.VALUE_OFF); - } - }) - .show(); - } - - private void setLocationPreference(String value) { - mPreferences.edit() - .putString(CameraSettings.KEY_RECORD_LOCATION, value) - .apply(); - // TODO: Fix this to use the actual onSharedPreferencesChanged listener - // instead of invoking manually - onSharedPreferenceChanged(); - } - - private void onCameraOpened() { - View root = mUI.getRootView(); - // These depend on camera parameters. - - int width = root.getWidth(); - int height = root.getHeight(); - mFocusManager.setPreviewSize(width, height); - openCameraCommon(); - } - - private void switchCamera() { - if (mPaused) return; - - Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId); - mCameraId = mPendingSwitchCameraId; - mPendingSwitchCameraId = -1; - setCameraId(mCameraId); - - // from onPause - closeCamera(); - mUI.collapseCameraControls(); - mUI.clearFaces(); - if (mFocusManager != null) mFocusManager.removeMessages(); - - // Restart the camera and initialize the UI. From onCreate. - mPreferences.setLocalId(mActivity, mCameraId); - CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - try { - mCameraDevice = Util.openCamera(mActivity, mCameraId); - mParameters = mCameraDevice.getParameters(); - } catch (CameraHardwareException e) { - Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); - return; - } catch (CameraDisabledException e) { - Util.showErrorAndFinish(mActivity, R.string.camera_disabled); - return; - } - initializeCapabilities(); - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT); - mFocusManager.setMirror(mirror); - mFocusManager.setParameters(mInitialParams); - setupPreview(); - - // reset zoom value index - mZoomValue = 0; - openCameraCommon(); - - if (ApiHelper.HAS_SURFACE_TEXTURE) { - // Start switch camera animation. Post a message because - // onFrameAvailable from the old camera may already exist. - mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION); - } - } - - protected void setCameraId(int cameraId) { - ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); - pref.setValue("" + cameraId); - } - - // either open a new camera or switch cameras - private void openCameraCommon() { - loadCameraPreferences(); - - mUI.onCameraOpened(mPreferenceGroup, mPreferences, mParameters, this); - updateSceneMode(); - showTapToFocusToastIfNeeded(); - - - } - - public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { - if (mFocusManager != null) mFocusManager.setPreviewSize(width, height); - } - - private void resetExposureCompensation() { - String value = mPreferences.getString(CameraSettings.KEY_EXPOSURE, - CameraSettings.EXPOSURE_DEFAULT_VALUE); - if (!CameraSettings.EXPOSURE_DEFAULT_VALUE.equals(value)) { - Editor editor = mPreferences.edit(); - editor.putString(CameraSettings.KEY_EXPOSURE, "0"); - editor.apply(); - } - } - - private void keepMediaProviderInstance() { - // We want to keep a reference to MediaProvider in camera's lifecycle. - // TODO: Utilize mMediaProviderClient instance to replace - // ContentResolver calls. - if (mMediaProviderClient == null) { - mMediaProviderClient = mContentResolver - .acquireContentProviderClient(MediaStore.AUTHORITY); - } - } - - // Snapshots can only be taken after this is called. It should be called - // once only. We could have done these things in onCreate() but we want to - // make preview screen appear as soon as possible. - private void initializeFirstTime() { - if (mFirstTimeInitialized) return; - - // Initialize location service. - boolean recordLocation = RecordLocationPreference.get( - mPreferences, mContentResolver); - mLocationManager.recordLocation(recordLocation); - - keepMediaProviderInstance(); - - mUI.initializeFirstTime(); - MediaSaveService s = mActivity.getMediaSaveService(); - // We set the listener only when both service and shutterbutton - // are initialized. - if (s != null) { - s.setListener(this); - } - - mNamedImages = new NamedImages(); - - mFirstTimeInitialized = true; - addIdleHandler(); - - mActivity.updateStorageSpaceAndHint(); - } - - // If the activity is paused and resumed, this method will be called in - // onResume. - private void initializeSecondTime() { - // Start location update if needed. - boolean recordLocation = RecordLocationPreference.get( - mPreferences, mContentResolver); - mLocationManager.recordLocation(recordLocation); - MediaSaveService s = mActivity.getMediaSaveService(); - if (s != null) { - s.setListener(this); - } - mNamedImages = new NamedImages(); - mUI.initializeSecondTime(mParameters); - keepMediaProviderInstance(); - } - - @Override - public void onSurfaceCreated(SurfaceHolder holder) { - // Do not access the camera if camera start up thread is not finished. - if (mCameraDevice == null || mCameraStartUpThread != null) - return; - - mCameraDevice.setPreviewDisplayAsync(holder); - // This happens when onConfigurationChanged arrives, surface has been - // destroyed, and there is no onFullScreenChanged. - if (mCameraState == PREVIEW_STOPPED) { - setupPreview(); - } - } - - private void showTapToFocusToastIfNeeded() { - // Show the tap to focus toast if this is the first start. - if (mFocusAreaSupported && - mPreferences.getBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, true)) { - // Delay the toast for one second to wait for orientation. - mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_FOCUS_TOAST, 1000); - } - } - - private void addIdleHandler() { - MessageQueue queue = Looper.myQueue(); - queue.addIdleHandler(new MessageQueue.IdleHandler() { - @Override - public boolean queueIdle() { - Storage.ensureOSXCompatible(); - return false; - } - }); - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - @Override - public void startFaceDetection() { - if (!ApiHelper.HAS_FACE_DETECTION) return; - if (mFaceDetectionStarted) return; - if (mParameters.getMaxNumDetectedFaces() > 0) { - mFaceDetectionStarted = true; - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - mUI.onStartFaceDetection(mDisplayOrientation, - (info.facing == CameraInfo.CAMERA_FACING_FRONT)); - mCameraDevice.setFaceDetectionListener(mUI); - mCameraDevice.startFaceDetection(); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - @Override - public void stopFaceDetection() { - if (!ApiHelper.HAS_FACE_DETECTION) return; - if (!mFaceDetectionStarted) return; - if (mParameters.getMaxNumDetectedFaces() > 0) { - mFaceDetectionStarted = false; - mCameraDevice.setFaceDetectionListener(null); - mCameraDevice.stopFaceDetection(); - mUI.clearFaces(); - } - } - - private final class ShutterCallback - implements android.hardware.Camera.ShutterCallback { - - private boolean mAnimateFlash; - - public ShutterCallback(boolean animateFlash) { - mAnimateFlash = animateFlash; - } - - @Override - public void onShutter() { - mShutterCallbackTime = System.currentTimeMillis(); - mShutterLag = mShutterCallbackTime - mCaptureStartTime; - Log.v(TAG, "mShutterLag = " + mShutterLag + "ms"); - if (mAnimateFlash) { - mActivity.runOnUiThread(mFlashRunnable); - } - } - } - - private final class PostViewPictureCallback implements PictureCallback { - @Override - public void onPictureTaken( - byte [] data, android.hardware.Camera camera) { - mPostViewPictureCallbackTime = System.currentTimeMillis(); - Log.v(TAG, "mShutterToPostViewCallbackTime = " - + (mPostViewPictureCallbackTime - mShutterCallbackTime) - + "ms"); - } - } - - private final class RawPictureCallback implements PictureCallback { - @Override - public void onPictureTaken( - byte [] rawData, android.hardware.Camera camera) { - mRawPictureCallbackTime = System.currentTimeMillis(); - Log.v(TAG, "mShutterToRawCallbackTime = " - + (mRawPictureCallbackTime - mShutterCallbackTime) + "ms"); - } - } - - private final class JpegPictureCallback implements PictureCallback { - Location mLocation; - - public JpegPictureCallback(Location loc) { - mLocation = loc; - } - - @Override - public void onPictureTaken( - final byte [] jpegData, final android.hardware.Camera camera) { - if (mPaused) { - return; - } - //TODO: We should show the picture taken rather than frozen preview here - if (mIsImageCaptureIntent) { - stopPreview(); - } - if (mSceneMode == Util.SCENE_MODE_HDR) { - mUI.showSwitcher(); - mUI.setSwipingEnabled(true); - } - - mJpegPictureCallbackTime = System.currentTimeMillis(); - // If postview callback has arrived, the captured image is displayed - // in postview callback. If not, the captured image is displayed in - // raw picture callback. - if (mPostViewPictureCallbackTime != 0) { - mShutterToPictureDisplayedTime = - mPostViewPictureCallbackTime - mShutterCallbackTime; - mPictureDisplayedToJpegCallbackTime = - mJpegPictureCallbackTime - mPostViewPictureCallbackTime; - } else { - mShutterToPictureDisplayedTime = - mRawPictureCallbackTime - mShutterCallbackTime; - mPictureDisplayedToJpegCallbackTime = - mJpegPictureCallbackTime - mRawPictureCallbackTime; - } - Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = " - + mPictureDisplayedToJpegCallbackTime + "ms"); - - /*TODO: - // Only animate when in full screen capture mode - // i.e. If monkey/a user swipes to the gallery during picture taking, - // don't show animation - if (ApiHelper.HAS_SURFACE_TEXTURE && !mIsImageCaptureIntent - && mActivity.mShowCameraAppView) { - // Finish capture animation - mHandler.removeMessages(CAPTURE_ANIMATION_DONE); - ((CameraScreenNail) mActivity.mCameraScreenNail).animateSlide(); - mHandler.sendEmptyMessageDelayed(CAPTURE_ANIMATION_DONE, - CaptureAnimManager.getAnimationDuration()); - } */ - mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden. - if (!mIsImageCaptureIntent) { - if (ApiHelper.CAN_START_PREVIEW_IN_JPEG_CALLBACK) { - setupPreview(); - } else { - // Camera HAL of some devices have a bug. Starting preview - // immediately after taking a picture will fail. Wait some - // time before starting the preview. - mHandler.sendEmptyMessageDelayed(SETUP_PREVIEW, 300); - } - } - - if (!mIsImageCaptureIntent) { - // Calculate the width and the height of the jpeg. - Size s = mParameters.getPictureSize(); - ExifInterface exif = Exif.getExif(jpegData); - int orientation = Exif.getOrientation(exif); - int width, height; - if ((mJpegRotation + orientation) % 180 == 0) { - width = s.width; - height = s.height; - } else { - width = s.height; - height = s.width; - } - String title = mNamedImages.getTitle(); - long date = mNamedImages.getDate(); - if (title == null) { - Log.e(TAG, "Unbalanced name/data pair"); - } else { - if (date == -1) date = mCaptureStartTime; - if (mHeading >= 0) { - // heading direction has been updated by the sensor. - ExifTag directionRefTag = exif.buildTag( - ExifInterface.TAG_GPS_IMG_DIRECTION_REF, - ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION); - ExifTag directionTag = exif.buildTag( - ExifInterface.TAG_GPS_IMG_DIRECTION, - new Rational(mHeading, 1)); - exif.setTag(directionRefTag); - exif.setTag(directionTag); - } - mActivity.getMediaSaveService().addImage( - jpegData, title, date, mLocation, width, height, - orientation, exif, mOnMediaSavedListener, mContentResolver); - } - } else { - mJpegImageData = jpegData; - if (!mQuickCapture) { - mUI.showPostCaptureAlert(); - } else { - onCaptureDone(); - } - } - - // Check this in advance of each shot so we don't add to shutter - // latency. It's true that someone else could write to the SD card in - // the mean time and fill it, but that could have happened between the - // shutter press and saving the JPEG too. - mActivity.updateStorageSpaceAndHint(); - - long now = System.currentTimeMillis(); - mJpegCallbackFinishTime = now - mJpegPictureCallbackTime; - Log.v(TAG, "mJpegCallbackFinishTime = " - + mJpegCallbackFinishTime + "ms"); - mJpegPictureCallbackTime = 0; - } - } - - private final class AutoFocusCallback - implements android.hardware.Camera.AutoFocusCallback { - @Override - public void onAutoFocus( - boolean focused, android.hardware.Camera camera) { - if (mPaused) return; - - mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime; - Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms"); - setCameraState(IDLE); - mFocusManager.onAutoFocus(focused, mUI.isShutterPressed()); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private final class AutoFocusMoveCallback - implements android.hardware.Camera.AutoFocusMoveCallback { - @Override - public void onAutoFocusMoving( - boolean moving, android.hardware.Camera camera) { - mFocusManager.onAutoFocusMoving(moving); - } - } - - private static class NamedImages { - private ArrayList mQueue; - private boolean mStop; - private NamedEntity mNamedEntity; - - public NamedImages() { - mQueue = new ArrayList(); - } - - public void nameNewImage(ContentResolver resolver, long date) { - NamedEntity r = new NamedEntity(); - r.title = Util.createJpegName(date); - r.date = date; - mQueue.add(r); - } - - public String getTitle() { - if (mQueue.isEmpty()) { - mNamedEntity = null; - return null; - } - mNamedEntity = mQueue.get(0); - mQueue.remove(0); - - return mNamedEntity.title; - } - - // Must be called after getTitle(). - public long getDate() { - if (mNamedEntity == null) return -1; - return mNamedEntity.date; - } - - private static class NamedEntity { - String title; - long date; - } - } - - private void setCameraState(int state) { - mCameraState = state; - switch (state) { - case PhotoController.PREVIEW_STOPPED: - case PhotoController.SNAPSHOT_IN_PROGRESS: - case PhotoController.SWITCHING_CAMERA: - mUI.enableGestures(false); - break; - case PhotoController.IDLE: - mUI.enableGestures(true); - break; - } - } - - private void animateFlash() { - /* //TODO: - // Only animate when in full screen capture mode - // i.e. If monkey/a user swipes to the gallery during picture taking, - // don't show animation - if (ApiHelper.HAS_SURFACE_TEXTURE && !mIsImageCaptureIntent - && mActivity.mShowCameraAppView) { - // Start capture animation. - ((CameraScreenNail) mActivity.mCameraScreenNail).animateFlash(mDisplayRotation); - mUI.enablePreviewThumb(true); - mHandler.sendEmptyMessageDelayed(CAPTURE_ANIMATION_DONE, - CaptureAnimManager.getAnimationDuration()); - } */ - } - - @Override - public boolean capture() { - // If we are already in the middle of taking a snapshot or the image save request - // is full then ignore. - if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS - || mCameraState == SWITCHING_CAMERA - || mActivity.getMediaSaveService().isQueueFull()) { - return false; - } - mCaptureStartTime = System.currentTimeMillis(); - mPostViewPictureCallbackTime = 0; - mJpegImageData = null; - - final boolean animateBefore = (mSceneMode == Util.SCENE_MODE_HDR); - - if (animateBefore) { - animateFlash(); - } - - // Set rotation and gps data. - int orientation; - // We need to be consistent with the framework orientation (i.e. the - // orientation of the UI.) when the auto-rotate screen setting is on. - if (mActivity.isAutoRotateScreen()) { - orientation = (360 - mDisplayRotation) % 360; - } else { - orientation = mOrientation; - } - mJpegRotation = Util.getJpegRotation(mCameraId, orientation); - mParameters.setRotation(mJpegRotation); - Location loc = mLocationManager.getCurrentLocation(); - Util.setGpsParameters(mParameters, loc); - mCameraDevice.setParameters(mParameters); - - mCameraDevice.takePicture2(new ShutterCallback(!animateBefore), - mRawPictureCallback, mPostViewPictureCallback, - new JpegPictureCallback(loc), mCameraState, - mFocusManager.getFocusState()); - - mNamedImages.nameNewImage(mContentResolver, mCaptureStartTime); - - mFaceDetectionStarted = false; - setCameraState(SNAPSHOT_IN_PROGRESS); - UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, - UsageStatistics.ACTION_CAPTURE_DONE, "Photo"); - return true; - } - - @Override - public void setFocusParameters() { - setCameraParameters(UPDATE_PARAM_PREFERENCE); - } - - private int getPreferredCameraId(ComboPreferences preferences) { - int intentCameraId = Util.getCameraFacingIntentExtras(mActivity); - if (intentCameraId != -1) { - // Testing purpose. Launch a specific camera through the intent - // extras. - return intentCameraId; - } else { - return CameraSettings.readPreferredCameraId(preferences); - } - } - - private void updateSceneMode() { - // If scene mode is set, we cannot set flash mode, white balance, and - // focus mode, instead, we read it from driver - if (!Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) { - overrideCameraSettings(mParameters.getFlashMode(), - mParameters.getWhiteBalance(), mParameters.getFocusMode()); - } else { - overrideCameraSettings(null, null, null); - } - } - - private void overrideCameraSettings(final String flashMode, - final String whiteBalance, final String focusMode) { - mUI.overrideSettings( - CameraSettings.KEY_FLASH_MODE, flashMode, - CameraSettings.KEY_WHITE_BALANCE, whiteBalance, - CameraSettings.KEY_FOCUS_MODE, focusMode); - } - - private void loadCameraPreferences() { - CameraSettings settings = new CameraSettings(mActivity, mInitialParams, - mCameraId, CameraHolder.instance().getCameraInfo()); - mPreferenceGroup = settings.getPreferenceGroup(R.xml.camera_preferences); - } - - @Override - public void onOrientationChanged(int orientation) { - // We keep the last known orientation. So if the user first orient - // the camera then point the camera to floor or sky, we still have - // the correct orientation. - if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return; - mOrientation = Util.roundOrientation(orientation, mOrientation); - - // Show the toast after getting the first orientation changed. - if (mHandler.hasMessages(SHOW_TAP_TO_FOCUS_TOAST)) { - mHandler.removeMessages(SHOW_TAP_TO_FOCUS_TOAST); - showTapToFocusToast(); - } - } - - @Override - public void onStop() { - if (mMediaProviderClient != null) { - mMediaProviderClient.release(); - mMediaProviderClient = null; - } - } - - @Override - public void onCaptureCancelled() { - mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent()); - mActivity.finish(); - } - - @Override - public void onCaptureRetake() { - if (mPaused) - return; - mUI.hidePostCaptureAlert(); - setupPreview(); - } - - @Override - public void onCaptureDone() { - if (mPaused) { - return; - } - - byte[] data = mJpegImageData; - - if (mCropValue == null) { - // First handle the no crop case -- just return the value. If the - // caller specifies a "save uri" then write the data to its - // stream. Otherwise, pass back a scaled down version of the bitmap - // directly in the extras. - if (mSaveUri != null) { - OutputStream outputStream = null; - try { - outputStream = mContentResolver.openOutputStream(mSaveUri); - outputStream.write(data); - outputStream.close(); - - mActivity.setResultEx(Activity.RESULT_OK); - mActivity.finish(); - } catch (IOException ex) { - // ignore exception - } finally { - Util.closeSilently(outputStream); - } - } else { - ExifInterface exif = Exif.getExif(data); - int orientation = Exif.getOrientation(exif); - Bitmap bitmap = Util.makeBitmap(data, 50 * 1024); - bitmap = Util.rotate(bitmap, orientation); - mActivity.setResultEx(Activity.RESULT_OK, - new Intent("inline-data").putExtra("data", bitmap)); - mActivity.finish(); - } - } else { - // Save the image to a temp file and invoke the cropper - Uri tempUri = null; - FileOutputStream tempStream = null; - try { - File path = mActivity.getFileStreamPath(sTempCropFilename); - path.delete(); - tempStream = mActivity.openFileOutput(sTempCropFilename, 0); - tempStream.write(data); - tempStream.close(); - tempUri = Uri.fromFile(path); - } catch (FileNotFoundException ex) { - mActivity.setResultEx(Activity.RESULT_CANCELED); - mActivity.finish(); - return; - } catch (IOException ex) { - mActivity.setResultEx(Activity.RESULT_CANCELED); - mActivity.finish(); - return; - } finally { - Util.closeSilently(tempStream); - } - - Bundle newExtras = new Bundle(); - if (mCropValue.equals("circle")) { - newExtras.putString("circleCrop", "true"); - } - if (mSaveUri != null) { - newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri); - } else { - newExtras.putBoolean(CropExtras.KEY_RETURN_DATA, true); - } - if (mActivity.isSecureCamera()) { - newExtras.putBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, true); - } - - Intent cropIntent = new Intent(CropActivity.CROP_ACTION); - - cropIntent.setData(tempUri); - cropIntent.putExtras(newExtras); - - mActivity.startActivityForResult(cropIntent, REQUEST_CROP); - } - } - - @Override - public void onShutterButtonFocus(boolean pressed) { - if (mPaused || mUI.collapseCameraControls() - || (mCameraState == SNAPSHOT_IN_PROGRESS) - || (mCameraState == PREVIEW_STOPPED)) return; - - // Do not do focus if there is not enough storage. - if (pressed && !canTakePicture()) return; - - if (pressed) { - mFocusManager.onShutterDown(); - } else { - // for countdown mode, we need to postpone the shutter release - // i.e. lock the focus during countdown. - if (!mUI.isCountingDown()) { - mFocusManager.onShutterUp(); - } - } - } - - @Override - public void onShutterButtonClick() { - if (mPaused || mUI.collapseCameraControls() - || (mCameraState == SWITCHING_CAMERA) - || (mCameraState == PREVIEW_STOPPED)) return; - - // Do not take the picture if there is not enough storage. - if (mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) { - Log.i(TAG, "Not enough space or storage not ready. remaining=" - + mActivity.getStorageSpace()); - return; - } - Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState); - - if (mSceneMode == Util.SCENE_MODE_HDR) { - mUI.hideSwitcher(); - mUI.setSwipingEnabled(false); - } - // If the user wants to do a snapshot while the previous one is still - // in progress, remember the fact and do it after we finish the previous - // one and re-start the preview. Snapshot in progress also includes the - // state that autofocus is focusing and a picture will be taken when - // focus callback arrives. - if ((mFocusManager.isFocusingSnapOnFinish() || mCameraState == SNAPSHOT_IN_PROGRESS) - && !mIsImageCaptureIntent) { - mSnapshotOnIdle = true; - return; - } - - String timer = mPreferences.getString( - CameraSettings.KEY_TIMER, - mActivity.getString(R.string.pref_camera_timer_default)); - boolean playSound = mPreferences.getString(CameraSettings.KEY_TIMER_SOUND_EFFECTS, - mActivity.getString(R.string.pref_camera_timer_sound_default)) - .equals(mActivity.getString(R.string.setting_on_value)); - - int seconds = Integer.parseInt(timer); - // When shutter button is pressed, check whether the previous countdown is - // finished. If not, cancel the previous countdown and start a new one. - if (mUI.isCountingDown()) { - mUI.cancelCountDown(); - } - if (seconds > 0) { - mUI.startCountDown(seconds, playSound); - } else { - mSnapshotOnIdle = false; - mFocusManager.doSnap(); - } - } - - @Override - public void installIntentFilter() { - } - - @Override - public boolean updateStorageHintOnResume() { - return mFirstTimeInitialized; - } - - @Override - public void updateCameraAppView() { - } - - @Override - public void onResumeBeforeSuper() { - mPaused = false; - } - - @Override - public void onResumeAfterSuper() { - if (mOpenCameraFail || mCameraDisabled) return; - - mJpegPictureCallbackTime = 0; - mZoomValue = 0; - // Start the preview if it is not started. - if (mCameraState == PREVIEW_STOPPED && mCameraStartUpThread == null) { - resetExposureCompensation(); - mCameraStartUpThread = new CameraStartUpThread(); - mCameraStartUpThread.start(); - } - - // If first time initialization is not finished, put it in the - // message queue. - if (!mFirstTimeInitialized) { - mHandler.sendEmptyMessage(FIRST_TIME_INIT); - } else { - initializeSecondTime(); - } - keepScreenOnAwhile(); - - // Dismiss open menu if exists. - PopupManager.getInstance(mActivity).notifyShowPopup(null); - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_CAMERA, "PhotoModule"); - - Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - if (gsensor != null) { - mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL); - } - - Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); - if (msensor != null) { - mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL); - } - } - - void waitCameraStartUpThread() { - try { - if (mCameraStartUpThread != null) { - mCameraStartUpThread.cancel(); - mCameraStartUpThread.join(); - mCameraStartUpThread = null; - setCameraState(IDLE); - } - } catch (InterruptedException e) { - // ignore - } - } - - @Override - public void onPauseBeforeSuper() { - mPaused = true; - Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); - if (gsensor != null) { - mSensorManager.unregisterListener(this, gsensor); - } - - Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); - if (msensor != null) { - mSensorManager.unregisterListener(this, msensor); - } - } - - @Override - public void onPauseAfterSuper() { - // Wait the camera start up thread to finish. - waitCameraStartUpThread(); - - // When camera is started from secure lock screen for the first time - // after screen on, the activity gets onCreate->onResume->onPause->onResume. - // To reduce the latency, keep the camera for a short time so it does - // not need to be opened again. - if (mCameraDevice != null && mActivity.isSecureCamera() - && ActivityBase.isFirstStartAfterScreenOn()) { - ActivityBase.resetFirstStartAfterScreenOn(); - CameraHolder.instance().keep(KEEP_CAMERA_TIMEOUT); - } - // Reset the focus first. Camera CTS does not guarantee that - // cancelAutoFocus is allowed after preview stops. - if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { - mCameraDevice.cancelAutoFocus(); - } - stopPreview(); - - mNamedImages = null; - - if (mLocationManager != null) mLocationManager.recordLocation(false); - - // If we are in an image capture intent and has taken - // a picture, we just clear it in onPause. - mJpegImageData = null; - - // Remove the messages in the event queue. - mHandler.removeMessages(SETUP_PREVIEW); - mHandler.removeMessages(FIRST_TIME_INIT); - mHandler.removeMessages(CHECK_DISPLAY_ROTATION); - mHandler.removeMessages(SWITCH_CAMERA); - mHandler.removeMessages(SWITCH_CAMERA_START_ANIMATION); - mHandler.removeMessages(CAMERA_OPEN_DONE); - mHandler.removeMessages(START_PREVIEW_DONE); - mHandler.removeMessages(OPEN_CAMERA_FAIL); - mHandler.removeMessages(CAMERA_DISABLED); - - closeCamera(); - - resetScreenOn(); - mUI.onPause(); - - mPendingSwitchCameraId = -1; - if (mFocusManager != null) mFocusManager.removeMessages(); - MediaSaveService s = mActivity.getMediaSaveService(); - if (s != null) { - s.setListener(null); - } - } - - /** - * The focus manager is the first UI related element to get initialized, - * and it requires the RenderOverlay, so initialize it here - */ - private void initializeFocusManager() { - // Create FocusManager object. startPreview needs it. - // if mFocusManager not null, reuse it - // otherwise create a new instance - if (mFocusManager != null) { - mFocusManager.removeMessages(); - } else { - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - boolean mirror = (info.facing == CameraInfo.CAMERA_FACING_FRONT); - String[] defaultFocusModes = mActivity.getResources().getStringArray( - R.array.pref_camera_focusmode_default_array); - mFocusManager = new FocusOverlayManager(mPreferences, defaultFocusModes, - mInitialParams, this, mirror, - mActivity.getMainLooper(), mUI); - } - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - Log.v(TAG, "onConfigurationChanged"); - setDisplayOrientation(); - } - - @Override - public void updateCameraOrientation() { - if (mDisplayRotation != Util.getDisplayRotation(mActivity)) { - setDisplayOrientation(); - } - } - - @Override - public void onActivityResult( - int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CROP: { - Intent intent = new Intent(); - if (data != null) { - Bundle extras = data.getExtras(); - if (extras != null) { - intent.putExtras(extras); - } - } - mActivity.setResultEx(resultCode, intent); - mActivity.finish(); - - File path = mActivity.getFileStreamPath(sTempCropFilename); - path.delete(); - - break; - } - } - } - - private boolean canTakePicture() { - return isCameraIdle() && (mActivity.getStorageSpace() > Storage.LOW_STORAGE_THRESHOLD); - } - - @Override - public void autoFocus() { - mFocusStartTime = System.currentTimeMillis(); - mCameraDevice.autoFocus(mAutoFocusCallback); - setCameraState(FOCUSING); - } - - @Override - public void cancelAutoFocus() { - mCameraDevice.cancelAutoFocus(); - setCameraState(IDLE); - setCameraParameters(UPDATE_PARAM_PREFERENCE); - } - - // Preview area is touched. Handle touch focus. - @Override - public void onSingleTapUp(View view, int x, int y) { - if (mPaused || mCameraDevice == null || !mFirstTimeInitialized - || mCameraState == SNAPSHOT_IN_PROGRESS - || mCameraState == SWITCHING_CAMERA - || mCameraState == PREVIEW_STOPPED) { - return; - } - - // Do not trigger touch focus if popup window is opened. - if (mUI.removeTopLevelPopup()) return; - - // Check if metering area or focus area is supported. - if (!mFocusAreaSupported && !mMeteringAreaSupported) return; - mFocusManager.onSingleTapUp(x, y); - } - - @Override - public boolean onBackPressed() { - return mUI.onBackPressed(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - case KeyEvent.KEYCODE_FOCUS: - if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) { - if (event.getRepeatCount() == 0) { - onShutterButtonFocus(true); - } - return true; - } - return false; - case KeyEvent.KEYCODE_CAMERA: - if (mFirstTimeInitialized && event.getRepeatCount() == 0) { - onShutterButtonClick(); - } - return true; - case KeyEvent.KEYCODE_DPAD_CENTER: - // If we get a dpad center event without any focused view, move - // the focus to the shutter button and press it. - if (mFirstTimeInitialized && event.getRepeatCount() == 0) { - // Start auto-focus immediately to reduce shutter lag. After - // the shutter button gets the focus, onShutterButtonFocus() - // will be called again but it is fine. - if (mUI.removeTopLevelPopup()) return true; - onShutterButtonFocus(true); - mUI.pressShutterButton(); - } - return true; - } - return false; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_DOWN: - if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) { - onShutterButtonClick(); - return true; - } - return false; - case KeyEvent.KEYCODE_FOCUS: - if (mFirstTimeInitialized) { - onShutterButtonFocus(false); - } - return true; - } - return false; - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - private void closeCamera() { - if (mCameraDevice != null) { - mCameraDevice.setZoomChangeListener(null); - if(ApiHelper.HAS_FACE_DETECTION) { - mCameraDevice.setFaceDetectionListener(null); - } - mCameraDevice.setErrorCallback(null); - CameraHolder.instance().release(); - mFaceDetectionStarted = false; - mCameraDevice = null; - setCameraState(PREVIEW_STOPPED); - mFocusManager.onCameraReleased(); - } - } - - private void setDisplayOrientation() { - mDisplayRotation = Util.getDisplayRotation(mActivity); - mDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId); - mCameraDisplayOrientation = mDisplayOrientation; - mUI.setDisplayOrientation(mDisplayOrientation); - if (mFocusManager != null) { - mFocusManager.setDisplayOrientation(mDisplayOrientation); - } - // Change the camera display orientation - if (mCameraDevice != null) { - mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); - } - } - - // Only called by UI thread. - private void setupPreview() { - mFocusManager.resetTouchFocus(); - startPreview(); - setCameraState(IDLE); - startFaceDetection(); - } - - // This can be called by UI Thread or CameraStartUpThread. So this should - // not modify the views. - private void startPreview() { - mCameraDevice.setErrorCallback(mErrorCallback); - - // ICS camera frameworks has a bug. Face detection state is not cleared - // after taking a picture. Stop the preview to work around it. The bug - // was fixed in JB. - if (mCameraState != PREVIEW_STOPPED) stopPreview(); - - setDisplayOrientation(); - - if (!mSnapshotOnIdle) { - // If the focus mode is continuous autofocus, call cancelAutoFocus to - // resume it because it may have been paused by autoFocus call. - if (Util.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusManager.getFocusMode())) { - mCameraDevice.cancelAutoFocus(); - } - mFocusManager.setAeAwbLock(false); // Unlock AE and AWB. - } - setCameraParameters(UPDATE_PARAM_ALL); - // Let UI set its expected aspect ratio - mUI.setPreviewSize(mParameters.getPreviewSize()); - Object st = mUI.getSurfaceTexture(); - if (st != null) { - mCameraDevice.setPreviewTextureAsync((SurfaceTexture) st); - } - - Log.v(TAG, "startPreview"); - mCameraDevice.startPreviewAsync(); - mFocusManager.onPreviewStarted(); - - if (mSnapshotOnIdle) { - mHandler.post(mDoSnapRunnable); - } - } - - @Override - public void stopPreview() { - if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { - Log.v(TAG, "stopPreview"); - mCameraDevice.stopPreview(); - mFaceDetectionStarted = false; - } - setCameraState(PREVIEW_STOPPED); - if (mFocusManager != null) mFocusManager.onPreviewStopped(); - } - - @SuppressWarnings("deprecation") - private void updateCameraParametersInitialize() { - // Reset preview frame rate to the maximum because it may be lowered by - // video camera application. - int[] fpsRange = Util.getMaxPreviewFpsRange(mParameters); - if (fpsRange.length > 0) { - mParameters.setPreviewFpsRange( - fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX], - fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]); - } - - mParameters.set(Util.RECORDING_HINT, Util.FALSE); - - // Disable video stabilization. Convenience methods not available in API - // level <= 14 - String vstabSupported = mParameters.get("video-stabilization-supported"); - if ("true".equals(vstabSupported)) { - mParameters.set("video-stabilization", "false"); - } - } - - private void updateCameraParametersZoom() { - // Set zoom. - if (mParameters.isZoomSupported()) { - mParameters.setZoom(mZoomValue); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private void setAutoExposureLockIfSupported() { - if (mAeLockSupported) { - mParameters.setAutoExposureLock(mFocusManager.getAeAwbLock()); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private void setAutoWhiteBalanceLockIfSupported() { - if (mAwbLockSupported) { - mParameters.setAutoWhiteBalanceLock(mFocusManager.getAeAwbLock()); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - private void setFocusAreasIfSupported() { - if (mFocusAreaSupported) { - mParameters.setFocusAreas(mFocusManager.getFocusAreas()); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - private void setMeteringAreasIfSupported() { - if (mMeteringAreaSupported) { - // Use the same area for focus and metering. - mParameters.setMeteringAreas(mFocusManager.getMeteringAreas()); - } - } - - private void updateCameraParametersPreference() { - setAutoExposureLockIfSupported(); - setAutoWhiteBalanceLockIfSupported(); - setFocusAreasIfSupported(); - setMeteringAreasIfSupported(); - - // Set picture size. - String pictureSize = mPreferences.getString( - CameraSettings.KEY_PICTURE_SIZE, null); - if (pictureSize == null) { - CameraSettings.initialCameraPictureSize(mActivity, mParameters); - } else { - List supported = mParameters.getSupportedPictureSizes(); - CameraSettings.setCameraPictureSize( - pictureSize, supported, mParameters); - } - Size size = mParameters.getPictureSize(); - - // Set a preview size that is closest to the viewfinder height and has - // the right aspect ratio. - List sizes = mParameters.getSupportedPreviewSizes(); - Size optimalSize = Util.getOptimalPreviewSize(mActivity, sizes, - (double) size.width / size.height); - Size original = mParameters.getPreviewSize(); - if (!original.equals(optimalSize)) { - mParameters.setPreviewSize(optimalSize.width, optimalSize.height); - - // Zoom related settings will be changed for different preview - // sizes, so set and read the parameters to get latest values - if (mHandler.getLooper() == Looper.myLooper()) { - // On UI thread only, not when camera starts up - setupPreview(); - } else { - mCameraDevice.setParameters(mParameters); - } - mParameters = mCameraDevice.getParameters(); - } - Log.v(TAG, "Preview size is " + optimalSize.width + "x" + optimalSize.height); - - // Since changing scene mode may change supported values, set scene mode - // first. HDR is a scene mode. To promote it in UI, it is stored in a - // separate preference. - String hdr = mPreferences.getString(CameraSettings.KEY_CAMERA_HDR, - mActivity.getString(R.string.pref_camera_hdr_default)); - if (mActivity.getString(R.string.setting_on_value).equals(hdr)) { - mSceneMode = Util.SCENE_MODE_HDR; - } else { - mSceneMode = mPreferences.getString( - CameraSettings.KEY_SCENE_MODE, - mActivity.getString(R.string.pref_camera_scenemode_default)); - } - if (Util.isSupported(mSceneMode, mParameters.getSupportedSceneModes())) { - if (!mParameters.getSceneMode().equals(mSceneMode)) { - mParameters.setSceneMode(mSceneMode); - - // Setting scene mode will change the settings of flash mode, - // white balance, and focus mode. Here we read back the - // parameters, so we can know those settings. - mCameraDevice.setParameters(mParameters); - mParameters = mCameraDevice.getParameters(); - } - } else { - mSceneMode = mParameters.getSceneMode(); - if (mSceneMode == null) { - mSceneMode = Parameters.SCENE_MODE_AUTO; - } - } - - // Set JPEG quality. - int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId, - CameraProfile.QUALITY_HIGH); - mParameters.setJpegQuality(jpegQuality); - - // For the following settings, we need to check if the settings are - // still supported by latest driver, if not, ignore the settings. - - // Set exposure compensation - int value = CameraSettings.readExposure(mPreferences); - int max = mParameters.getMaxExposureCompensation(); - int min = mParameters.getMinExposureCompensation(); - if (value >= min && value <= max) { - mParameters.setExposureCompensation(value); - } else { - Log.w(TAG, "invalid exposure range: " + value); - } - - if (Parameters.SCENE_MODE_AUTO.equals(mSceneMode)) { - // Set flash mode. - String flashMode = mPreferences.getString( - CameraSettings.KEY_FLASH_MODE, - mActivity.getString(R.string.pref_camera_flashmode_default)); - List supportedFlash = mParameters.getSupportedFlashModes(); - if (Util.isSupported(flashMode, supportedFlash)) { - mParameters.setFlashMode(flashMode); - } else { - flashMode = mParameters.getFlashMode(); - if (flashMode == null) { - flashMode = mActivity.getString( - R.string.pref_camera_flashmode_no_flash); - } - } - - // Set white balance parameter. - String whiteBalance = mPreferences.getString( - CameraSettings.KEY_WHITE_BALANCE, - mActivity.getString(R.string.pref_camera_whitebalance_default)); - if (Util.isSupported(whiteBalance, - mParameters.getSupportedWhiteBalance())) { - mParameters.setWhiteBalance(whiteBalance); - } else { - whiteBalance = mParameters.getWhiteBalance(); - if (whiteBalance == null) { - whiteBalance = Parameters.WHITE_BALANCE_AUTO; - } - } - - // Set focus mode. - mFocusManager.overrideFocusMode(null); - mParameters.setFocusMode(mFocusManager.getFocusMode()); - } else { - mFocusManager.overrideFocusMode(mParameters.getFocusMode()); - } - - if (mContinousFocusSupported && ApiHelper.HAS_AUTO_FOCUS_MOVE_CALLBACK) { - updateAutoFocusMoveCallback(); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private void updateAutoFocusMoveCallback() { - if (mParameters.getFocusMode().equals(Util.FOCUS_MODE_CONTINUOUS_PICTURE)) { - mCameraDevice.setAutoFocusMoveCallback( - (AutoFocusMoveCallback) mAutoFocusMoveCallback); - } else { - mCameraDevice.setAutoFocusMoveCallback(null); - } - } - - // We separate the parameters into several subsets, so we can update only - // the subsets actually need updating. The PREFERENCE set needs extra - // locking because the preference can be changed from GLThread as well. - private void setCameraParameters(int updateSet) { - if ((updateSet & UPDATE_PARAM_INITIALIZE) != 0) { - updateCameraParametersInitialize(); - } - - if ((updateSet & UPDATE_PARAM_ZOOM) != 0) { - updateCameraParametersZoom(); - } - - if ((updateSet & UPDATE_PARAM_PREFERENCE) != 0) { - updateCameraParametersPreference(); - } - - mCameraDevice.setParameters(mParameters); - } - - // If the Camera is idle, update the parameters immediately, otherwise - // accumulate them in mUpdateSet and update later. - private void setCameraParametersWhenIdle(int additionalUpdateSet) { - mUpdateSet |= additionalUpdateSet; - if (mCameraDevice == null) { - // We will update all the parameters when we open the device, so - // we don't need to do anything now. - mUpdateSet = 0; - return; - } else if (isCameraIdle()) { - setCameraParameters(mUpdateSet); - updateSceneMode(); - mUpdateSet = 0; - } else { - if (!mHandler.hasMessages(SET_CAMERA_PARAMETERS_WHEN_IDLE)) { - mHandler.sendEmptyMessageDelayed( - SET_CAMERA_PARAMETERS_WHEN_IDLE, 1000); - } - } - } - - public boolean isCameraIdle() { - return (mCameraState == IDLE) || - (mCameraState == PREVIEW_STOPPED) || - ((mFocusManager != null) && mFocusManager.isFocusCompleted() - && (mCameraState != SWITCHING_CAMERA)); - } - - public boolean isImageCaptureIntent() { - String action = mActivity.getIntent().getAction(); - return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action) - || ActivityBase.ACTION_IMAGE_CAPTURE_SECURE.equals(action)); - } - - private void setupCaptureParams() { - Bundle myExtras = mActivity.getIntent().getExtras(); - if (myExtras != null) { - mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT); - mCropValue = myExtras.getString("crop"); - } - } - - @Override - public void onSharedPreferenceChanged() { - // ignore the events after "onPause()" - if (mPaused) return; - - boolean recordLocation = RecordLocationPreference.get( - mPreferences, mContentResolver); - mLocationManager.recordLocation(recordLocation); - - setCameraParametersWhenIdle(UPDATE_PARAM_PREFERENCE); - mUI.updateOnScreenIndicators(mParameters, mPreferenceGroup, mPreferences); - } - - @Override - public void onCameraPickerClicked(int cameraId) { - if (mPaused || mPendingSwitchCameraId != -1) return; - - mPendingSwitchCameraId = cameraId; - - Log.v(TAG, "Start to switch camera. cameraId=" + cameraId); - // We need to keep a preview frame for the animation before - // releasing the camera. This will trigger onPreviewTextureCopied. - //TODO: Need to animate the camera switch - switchCamera(); - } - - // Preview texture has been copied. Now camera can be released and the - // animation can be started. - @Override - public void onPreviewTextureCopied() { - mHandler.sendEmptyMessage(SWITCH_CAMERA); - } - - @Override - public void onCaptureTextureCopied() { - } - - @Override - public void onUserInteraction() { - if (!mActivity.isFinishing()) keepScreenOnAwhile(); - } - - private void resetScreenOn() { - mHandler.removeMessages(CLEAR_SCREEN_DELAY); - mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - private void keepScreenOnAwhile() { - mHandler.removeMessages(CLEAR_SCREEN_DELAY); - mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY); - } - - @Override - public void onOverriddenPreferencesClicked() { - if (mPaused) return; - mUI.showPreferencesToast(); - } - - private void showTapToFocusToast() { - // TODO: Use a toast? - new RotateTextToast(mActivity, R.string.tap_to_focus, 0).show(); - // Clear the preference. - Editor editor = mPreferences.edit(); - editor.putBoolean(CameraSettings.KEY_CAMERA_FIRST_USE_HINT_SHOWN, false); - editor.apply(); - } - - private void initializeCapabilities() { - mInitialParams = mCameraDevice.getParameters(); - mFocusAreaSupported = Util.isFocusAreaSupported(mInitialParams); - mMeteringAreaSupported = Util.isMeteringAreaSupported(mInitialParams); - mAeLockSupported = Util.isAutoExposureLockSupported(mInitialParams); - mAwbLockSupported = Util.isAutoWhiteBalanceLockSupported(mInitialParams); - mContinousFocusSupported = mInitialParams.getSupportedFocusModes().contains( - Util.FOCUS_MODE_CONTINUOUS_PICTURE); - } - - @Override - public void onCountDownFinished() { - mSnapshotOnIdle = false; - mFocusManager.doSnap(); - mFocusManager.onShutterUp(); - } - - @Override - public boolean needsSwitcher() { - return !mIsImageCaptureIntent; - } - - @Override - public boolean needsPieMenu() { - return true; - } - - @Override - public void onShowSwitcherPopup() { - mUI.onShowSwitcherPopup(); - } - - @Override - public int onZoomChanged(int index) { - // Not useful to change zoom value when the activity is paused. - if (mPaused) return index; - mZoomValue = index; - if (mParameters == null || mCameraDevice == null) return index; - // Set zoom parameters asynchronously - mParameters.setZoom(mZoomValue); - mCameraDevice.setParameters(mParameters); - Parameters p = mCameraDevice.getParameters(); - if (p != null) return p.getZoom(); - return index; - } - - @Override - public int getCameraState() { - return mCameraState; - } - - @Override - public void onQueueStatus(boolean full) { - mUI.enableShutter(!full); - } - - @Override - public void onMediaSaveServiceConnected(MediaSaveService s) { - // We set the listener only when both service and shutterbutton - // are initialized. - if (mFirstTimeInitialized) { - s.setListener(this); - } - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } - - @Override - public void onSensorChanged(SensorEvent event) { - int type = event.sensor.getType(); - float[] data; - if (type == Sensor.TYPE_ACCELEROMETER) { - data = mGData; - } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { - data = mMData; - } else { - // we should not be here. - return; - } - for (int i = 0; i < 3 ; i++) { - data[i] = event.values[i]; - } - float[] orientation = new float[3]; - SensorManager.getRotationMatrix(mR, null, mGData, mMData); - SensorManager.getOrientation(mR, orientation); - mHeading = (int) (orientation[0] * 180f / Math.PI) % 360; - if (mHeading < 0) { - mHeading += 360; - } - } - - @Override - public void onSwitchMode(boolean toCamera) { - mUI.onSwitchMode(toCamera); - } - -/* Below is no longer needed, except to get rid of compile error - * TODO: Remove these - */ - - // TODO: Delete this function after old camera code is removed - @Override - public void onRestorePreferencesClicked() {} - -} diff --git a/src/com/android/camera/NewPhotoUI.java b/src/com/android/camera/NewPhotoUI.java deleted file mode 100644 index a049787b1..000000000 --- a/src/com/android/camera/NewPhotoUI.java +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package com.android.camera; - -import android.graphics.Matrix; -import android.graphics.SurfaceTexture; -import android.hardware.Camera; -import android.hardware.Camera.Face; -import android.hardware.Camera.FaceDetectionListener; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.Size; -import android.os.Handler; -import android.os.Message; -import android.util.Log; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.TextureView; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnLayoutChangeListener; -import android.view.ViewGroup; -import android.view.ViewStub; -import android.widget.FrameLayout; -import android.widget.FrameLayout.LayoutParams; -import android.widget.ImageView; -import android.widget.Toast; - -import com.android.camera.CameraPreference.OnPreferenceChangedListener; -import com.android.camera.FocusOverlayManager.FocusUI; -import com.android.camera.ui.AbstractSettingPopup; -import com.android.camera.ui.CameraControls; -import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; -import com.android.camera.ui.CountDownView; -import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; -import com.android.camera.ui.CameraSwitcher; -import com.android.camera.ui.FaceView; -import com.android.camera.ui.FocusIndicator; -import com.android.camera.ui.NewCameraRootView; -import com.android.camera.ui.PieRenderer; -import com.android.camera.ui.PieRenderer.PieListener; -import com.android.camera.ui.RenderOverlay; -import com.android.camera.ui.ZoomRenderer; -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; - -import java.io.IOException; -import java.util.List; - -public class NewPhotoUI implements PieListener, - NewPreviewGestures.SingleTapListener, - FocusUI, TextureView.SurfaceTextureListener, - LocationManager.Listener, NewCameraRootView.MyDisplayListener, - FaceDetectionListener { - - private static final String TAG = "CAM_UI"; - private static final int UPDATE_TRANSFORM_MATRIX = 1; - private NewCameraActivity mActivity; - private PhotoController mController; - private NewPreviewGestures mGestures; - - private View mRootView; - private Object mSurfaceTexture; - - private AbstractSettingPopup mPopup; - private ShutterButton mShutterButton; - private CountDownView mCountDownView; - - private FaceView mFaceView; - private RenderOverlay mRenderOverlay; - private View mReviewCancelButton; - private View mReviewDoneButton; - private View mReviewRetakeButton; - - private View mMenuButton; - private View mBlocker; - private NewPhotoMenu mMenu; - private CameraSwitcher mSwitcher; - private CameraControls mCameraControls; - - // Small indicators which show the camera settings in the viewfinder. - private OnScreenIndicators mOnScreenIndicators; - - private PieRenderer mPieRenderer; - private ZoomRenderer mZoomRenderer; - private Toast mNotSelectableToast; - - private int mZoomMax; - private List mZoomRatios; - - private int mPreviewWidth = 0; - private int mPreviewHeight = 0; - private float mSurfaceTextureUncroppedWidth; - private float mSurfaceTextureUncroppedHeight; - - private View mPreviewThumb; - - private SurfaceTextureSizeChangedListener mSurfaceTextureSizeListener; - private TextureView mTextureView; - private Matrix mMatrix = null; - private float mAspectRatio = 4f / 3f; - private final Object mLock = new Object(); - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case UPDATE_TRANSFORM_MATRIX: - setTransformMatrix(mPreviewWidth, mPreviewHeight); - break; - default: - break; - } - } - }; - - public interface SurfaceTextureSizeChangedListener { - public void onSurfaceTextureSizeChanged(int uncroppedWidth, int uncroppedHeight); - } - - private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, - int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - int width = right - left; - int height = bottom - top; - // Full-screen screennail - int w = width; - int h = height; - if (Util.getDisplayRotation(mActivity) % 180 != 0) { - w = height; - h = width; - } - if (mPreviewWidth != width || mPreviewHeight != height) { - mPreviewWidth = width; - mPreviewHeight = height; - onScreenSizeChanged(width, height, w, h); - mController.onScreenSizeChanged(width, height, w, h); - } - } - }; - - public NewPhotoUI(NewCameraActivity activity, PhotoController controller, View parent) { - mActivity = activity; - mController = controller; - mRootView = parent; - - mActivity.getLayoutInflater().inflate(R.layout.new_photo_module, - (ViewGroup) mRootView, true); - mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay); - // display the view - mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content); - mTextureView.setSurfaceTextureListener(this); - mTextureView.addOnLayoutChangeListener(mLayoutListener); - initIndicators(); - - mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button); - mSwitcher = (CameraSwitcher) mRootView.findViewById(R.id.camera_switcher); - mSwitcher.setCurrentIndex(0); - mSwitcher.setSwitchListener((CameraSwitchListener) mActivity); - mMenuButton = mRootView.findViewById(R.id.menu); - if (ApiHelper.HAS_FACE_DETECTION) { - ViewStub faceViewStub = (ViewStub) mRootView - .findViewById(R.id.face_view_stub); - if (faceViewStub != null) { - faceViewStub.inflate(); - mFaceView = (FaceView) mRootView.findViewById(R.id.face_view); - setSurfaceTextureSizeChangedListener( - (SurfaceTextureSizeChangedListener) mFaceView); - } - } - mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls); - ((NewCameraRootView) mRootView).setDisplayChangeListener(this); - } - - public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { - setTransformMatrix(width, height); - } - - public void setSurfaceTextureSizeChangedListener(SurfaceTextureSizeChangedListener listener) { - mSurfaceTextureSizeListener = listener; - } - - public void setPreviewSize(Size size) { - int width = size.width; - int height = size.height; - if (width == 0 || height == 0) { - Log.w(TAG, "Preview size should not be 0."); - return; - } - if (width > height) { - mAspectRatio = (float) width / height; - } else { - mAspectRatio = (float) height / width; - } - mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX); - } - - private void setTransformMatrix(int width, int height) { - mMatrix = mTextureView.getTransform(mMatrix); - int orientation = Util.getDisplayRotation(mActivity); - float scaleX = 1f, scaleY = 1f; - float scaledTextureWidth, scaledTextureHeight; - if (width > height) { - scaledTextureWidth = Math.max(width, - (int) (height * mAspectRatio)); - scaledTextureHeight = Math.max(height, - (int)(width / mAspectRatio)); - } else { - scaledTextureWidth = Math.max(width, - (int) (height / mAspectRatio)); - scaledTextureHeight = Math.max(height, - (int) (width * mAspectRatio)); - } - - if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || - mSurfaceTextureUncroppedHeight != scaledTextureHeight) { - mSurfaceTextureUncroppedWidth = scaledTextureWidth; - mSurfaceTextureUncroppedHeight = scaledTextureHeight; - if (mSurfaceTextureSizeListener != null) { - mSurfaceTextureSizeListener.onSurfaceTextureSizeChanged( - (int) mSurfaceTextureUncroppedWidth, (int) mSurfaceTextureUncroppedHeight); - } - } - scaleX = scaledTextureWidth / width; - scaleY = scaledTextureHeight / height; - mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2); - mTextureView.setTransform(mMatrix); - } - - public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { - synchronized (mLock) { - mSurfaceTexture = surface; - mLock.notifyAll(); - } - } - - public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { - // Ignored, Camera does all the work for us - } - - public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { - mSurfaceTexture = null; - mController.stopPreview(); - Log.w(TAG, "surfaceTexture is destroyed"); - return true; - } - - public void onSurfaceTextureUpdated(SurfaceTexture surface) { - // Invoked every time there's a new Camera preview frame - } - - public View getRootView() { - return mRootView; - } - - private void initIndicators() { - mOnScreenIndicators = new OnScreenIndicators(mActivity, - mRootView.findViewById(R.id.on_screen_indicators)); - } - - public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs, - Camera.Parameters params, OnPreferenceChangedListener listener) { - if (mPieRenderer == null) { - mPieRenderer = new PieRenderer(mActivity); - mPieRenderer.setPieListener(this); - mRenderOverlay.addRenderer(mPieRenderer); - } - - if (mMenu == null) { - mMenu = new NewPhotoMenu(mActivity, this, mPieRenderer); - mMenu.setListener(listener); - } - mMenu.initialize(prefGroup); - - if (mZoomRenderer == null) { - mZoomRenderer = new ZoomRenderer(mActivity); - mRenderOverlay.addRenderer(mZoomRenderer); - } - - if (mGestures == null) { - // this will handle gesture disambiguation and dispatching - mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer); - mRenderOverlay.setGestures(mGestures); - } - mGestures.setZoomEnabled(params.isZoomSupported()); - mGestures.setRenderOverlay(mRenderOverlay); - mRenderOverlay.requestLayout(); - - initializeZoom(params); - updateOnScreenIndicators(params, prefGroup, prefs); - } - - private void openMenu() { - if (mPieRenderer != null) { - // If autofocus is not finished, cancel autofocus so that the - // subsequent touch can be handled by PreviewGestures - if (mController.getCameraState() == PhotoController.FOCUSING) { - mController.cancelAutoFocus(); - } - mPieRenderer.showInCenter(); - } - } - - public void initializeControlByIntent() { - mBlocker = mRootView.findViewById(R.id.blocker); - mPreviewThumb = mActivity.findViewById(R.id.preview_thumb); - mPreviewThumb.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - // TODO: go to filmstrip - // mActivity.gotoGallery(); - } - }); - mMenuButton = mRootView.findViewById(R.id.menu); - mMenuButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - openMenu(); - } - }); - if (mController.isImageCaptureIntent()) { - hideSwitcher(); - ViewGroup cameraControls = (ViewGroup) mRootView.findViewById(R.id.camera_controls); - mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls); - - mReviewDoneButton = mRootView.findViewById(R.id.btn_done); - mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel); - mReviewRetakeButton = mRootView.findViewById(R.id.btn_retake); - mReviewCancelButton.setVisibility(View.VISIBLE); - - mReviewDoneButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mController.onCaptureDone(); - } - }); - mReviewCancelButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mController.onCaptureCancelled(); - } - }); - - mReviewRetakeButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mController.onCaptureRetake(); - } - }); - } - } - - public void hideUI() { - mCameraControls.setVisibility(View.INVISIBLE); - mSwitcher.closePopup(); - } - - public void showUI() { - mCameraControls.setVisibility(View.VISIBLE); - } - - public void hideSwitcher() { - mSwitcher.closePopup(); - mSwitcher.setVisibility(View.INVISIBLE); - } - - public void showSwitcher() { - mSwitcher.setVisibility(View.VISIBLE); - } - // called from onResume but only the first time - public void initializeFirstTime() { - // Initialize shutter button. - mShutterButton.setImageResource(R.drawable.btn_new_shutter); - mShutterButton.setOnShutterButtonListener(mController); - mShutterButton.setVisibility(View.VISIBLE); - } - - // called from onResume every other time - public void initializeSecondTime(Camera.Parameters params) { - initializeZoom(params); - if (mController.isImageCaptureIntent()) { - hidePostCaptureAlert(); - } - if (mMenu != null) { - mMenu.reloadPreferences(); - } - } - - public void initializeZoom(Camera.Parameters params) { - if ((params == null) || !params.isZoomSupported() - || (mZoomRenderer == null)) return; - mZoomMax = params.getMaxZoom(); - mZoomRatios = params.getZoomRatios(); - // Currently we use immediate zoom for fast zooming to get better UX and - // there is no plan to take advantage of the smooth zoom. - if (mZoomRenderer != null) { - mZoomRenderer.setZoomMax(mZoomMax); - mZoomRenderer.setZoom(params.getZoom()); - mZoomRenderer.setZoomValue(mZoomRatios.get(params.getZoom())); - mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener()); - } - } - - public void showGpsOnScreenIndicator(boolean hasSignal) { } - - public void hideGpsOnScreenIndicator() { } - - public void overrideSettings(final String ... keyvalues) { - mMenu.overrideSettings(keyvalues); - } - - public void updateOnScreenIndicators(Camera.Parameters params, - PreferenceGroup group, ComboPreferences prefs) { - if (params == null) return; - mOnScreenIndicators.updateSceneOnScreenIndicator(params.getSceneMode()); - mOnScreenIndicators.updateExposureOnScreenIndicator(params, - CameraSettings.readExposure(prefs)); - mOnScreenIndicators.updateFlashOnScreenIndicator(params.getFlashMode()); - int wbIndex = 2; - ListPreference pref = group.findPreference(CameraSettings.KEY_WHITE_BALANCE); - if (pref != null) { - wbIndex = pref.getCurrentIndex(); - } - mOnScreenIndicators.updateWBIndicator(wbIndex); - boolean location = RecordLocationPreference.get( - prefs, mActivity.getContentResolver()); - mOnScreenIndicators.updateLocationIndicator(location); - } - - public void setCameraState(int state) { - } - - public void enableGestures(boolean enable) { - if (mGestures != null) { - mGestures.setEnabled(enable); - } - } - - // forward from preview gestures to controller - @Override - public void onSingleTapUp(View view, int x, int y) { - mController.onSingleTapUp(view, x, y); - } - - public boolean onBackPressed() { - if (mPieRenderer != null && mPieRenderer.showsItems()) { - mPieRenderer.hide(); - return true; - } - // In image capture mode, back button should: - // 1) if there is any popup, dismiss them, 2) otherwise, get out of - // image capture - if (mController.isImageCaptureIntent()) { - if (!removeTopLevelPopup()) { - // no popup to dismiss, cancel image capture - mController.onCaptureCancelled(); - } - return true; - } else if (!mController.isCameraIdle()) { - // ignore backs while we're taking a picture - return true; - } else { - return removeTopLevelPopup(); - } - } - - public void onSwitchMode(boolean toCamera) { - if (toCamera) { - showUI(); - } else { - hideUI(); - } - if (mFaceView != null) { - mFaceView.setBlockDraw(!toCamera); - } - if (mPopup != null) { - dismissPopup(toCamera); - } - if (mGestures != null) { - mGestures.setEnabled(toCamera); - } - if (mRenderOverlay != null) { - // this can not happen in capture mode - mRenderOverlay.setVisibility(toCamera ? View.VISIBLE : View.GONE); - } - if (mPieRenderer != null) { - mPieRenderer.setBlockFocus(!toCamera); - } - setShowMenu(toCamera); - if (!toCamera && mCountDownView != null) mCountDownView.cancelCountDown(); - } - - public void enablePreviewThumb(boolean enabled) { - if (enabled) { - mPreviewThumb.setVisibility(View.VISIBLE); - } else { - mPreviewThumb.setVisibility(View.GONE); - } - } - - public boolean removeTopLevelPopup() { - // Remove the top level popup or dialog box and return true if there's any - if (mPopup != null) { - dismissPopup(); - return true; - } - return false; - } - - public void showPopup(AbstractSettingPopup popup) { - hideUI(); - mBlocker.setVisibility(View.INVISIBLE); - setShowMenu(false); - mPopup = popup; - mPopup.setVisibility(View.VISIBLE); - FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT); - lp.gravity = Gravity.CENTER; - ((FrameLayout) mRootView).addView(mPopup, lp); - } - - public void dismissPopup() { - dismissPopup(true); - } - - private void dismissPopup(boolean fullScreen) { - if (fullScreen) { - showUI(); - mBlocker.setVisibility(View.VISIBLE); - } - setShowMenu(fullScreen); - if (mPopup != null) { - ((FrameLayout) mRootView).removeView(mPopup); - mPopup = null; - } - mMenu.popupDismissed(); - } - - public void onShowSwitcherPopup() { - if (mPieRenderer != null && mPieRenderer.showsItems()) { - mPieRenderer.hide(); - } - } - - private void setShowMenu(boolean show) { - if (mOnScreenIndicators != null) { - mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE); - } - if (mMenuButton != null) { - mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE); - } - } - - public boolean collapseCameraControls() { - // Remove all the popups/dialog boxes - boolean ret = false; - if (mPopup != null) { - dismissPopup(); - ret = true; - } - onShowSwitcherPopup(); - return ret; - } - - protected void showPostCaptureAlert() { - mOnScreenIndicators.setVisibility(View.GONE); - mMenuButton.setVisibility(View.GONE); - Util.fadeIn(mReviewDoneButton); - mShutterButton.setVisibility(View.INVISIBLE); - Util.fadeIn(mReviewRetakeButton); - pauseFaceDetection(); - } - - protected void hidePostCaptureAlert() { - mOnScreenIndicators.setVisibility(View.VISIBLE); - mMenuButton.setVisibility(View.VISIBLE); - Util.fadeOut(mReviewDoneButton); - mShutterButton.setVisibility(View.VISIBLE); - Util.fadeOut(mReviewRetakeButton); - resumeFaceDetection(); - } - - public void setDisplayOrientation(int orientation) { - if (mFaceView != null) { - mFaceView.setDisplayOrientation(orientation); - } - } - - // shutter button handling - - public boolean isShutterPressed() { - return mShutterButton.isPressed(); - } - - public void enableShutter(boolean enabled) { - if (mShutterButton != null) { - mShutterButton.setEnabled(enabled); - } - } - - public void pressShutterButton() { - if (mShutterButton.isInTouchMode()) { - mShutterButton.requestFocusFromTouch(); - } else { - mShutterButton.requestFocus(); - } - mShutterButton.setPressed(true); - } - - private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { - @Override - public void onZoomValueChanged(int index) { - int newZoom = mController.onZoomChanged(index); - if (mZoomRenderer != null) { - mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom)); - } - } - - @Override - public void onZoomStart() { - if (mPieRenderer != null) { - mPieRenderer.setBlockFocus(true); - } - } - - @Override - public void onZoomEnd() { - if (mPieRenderer != null) { - mPieRenderer.setBlockFocus(false); - } - } - } - - @Override - public void onPieOpened(int centerX, int centerY) { - setSwipingEnabled(false); - dismissPopup(); - if (mFaceView != null) { - mFaceView.setBlockDraw(true); - } - } - - @Override - public void onPieClosed() { - setSwipingEnabled(true); - if (mFaceView != null) { - mFaceView.setBlockDraw(false); - } - } - - public void setSwipingEnabled(boolean enable) { - mActivity.setSwipingEnabled(enable); - } - - public Object getSurfaceTexture() { - synchronized (mLock) { - if (mSurfaceTexture == null) { - try { - mLock.wait(); - } catch (InterruptedException e) { - Log.w(TAG, "Unexpected interruption when waiting to get surface texture"); - } - } - } - return mSurfaceTexture; - } - - // Countdown timer - - private void initializeCountDown() { - mActivity.getLayoutInflater().inflate(R.layout.count_down_to_capture, - (ViewGroup) mRootView, true); - mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture)); - mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController); - } - - public boolean isCountingDown() { - return mCountDownView != null && mCountDownView.isCountingDown(); - } - - public void cancelCountDown() { - if (mCountDownView == null) return; - mCountDownView.cancelCountDown(); - } - - public void startCountDown(int sec, boolean playSound) { - if (mCountDownView == null) initializeCountDown(); - mCountDownView.startCountDown(sec, playSound); - } - - public void showPreferencesToast() { - if (mNotSelectableToast == null) { - String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode); - mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT); - } - mNotSelectableToast.show(); - } - - public void onPause() { - cancelCountDown(); - - // Clear UI. - collapseCameraControls(); - if (mFaceView != null) mFaceView.clear(); - - mPreviewWidth = 0; - mPreviewHeight = 0; - } - - // focus UI implementation - - private FocusIndicator getFocusIndicator() { - return (mFaceView != null && mFaceView.faceExists()) ? mFaceView : mPieRenderer; - } - - @Override - public boolean hasFaces() { - return (mFaceView != null && mFaceView.faceExists()); - } - - public void clearFaces() { - if (mFaceView != null) mFaceView.clear(); - } - - @Override - public void clearFocus() { - FocusIndicator indicator = getFocusIndicator(); - if (indicator != null) indicator.clear(); - } - - @Override - public void setFocusPosition(int x, int y) { - mPieRenderer.setFocus(x, y); - } - - @Override - public void onFocusStarted() { - getFocusIndicator().showStart(); - } - - @Override - public void onFocusSucceeded(boolean timeout) { - getFocusIndicator().showSuccess(timeout); - } - - @Override - public void onFocusFailed(boolean timeout) { - getFocusIndicator().showFail(timeout); - } - - @Override - public void pauseFaceDetection() { - if (mFaceView != null) mFaceView.pause(); - } - - @Override - public void resumeFaceDetection() { - if (mFaceView != null) mFaceView.resume(); - } - - public void onStartFaceDetection(int orientation, boolean mirror) { - mFaceView.clear(); - mFaceView.setVisibility(View.VISIBLE); - mFaceView.setDisplayOrientation(orientation); - mFaceView.setMirror(mirror); - mFaceView.resume(); - } - - @Override - public void onFaceDetection(Face[] faces, android.hardware.Camera camera) { - mFaceView.setFaces(faces); - } - - public void onDisplayChanged() { - mCameraControls.checkLayoutFlip(); - mController.updateCameraOrientation(); - } - -} diff --git a/src/com/android/camera/NewPreviewGestures.java b/src/com/android/camera/NewPreviewGestures.java deleted file mode 100644 index 339c4b33f..000000000 --- a/src/com/android/camera/NewPreviewGestures.java +++ /dev/null @@ -1,263 +0,0 @@ -package com.android.camera; - -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import android.os.Handler; -import android.os.Message; -import android.util.Log; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.ScaleGestureDetector; -import android.view.View; -import android.view.ViewConfiguration; - -import com.android.camera.PreviewGestures.SingleTapListener; -import com.android.camera.PreviewGestures.SwipeListener; -import com.android.camera.ui.PieRenderer; -import com.android.camera.ui.RenderOverlay; -import com.android.camera.ui.ZoomRenderer; -import com.android.gallery3d.R; - -import java.util.ArrayList; -import java.util.List; - -/* NewPreviewGestures disambiguates touch events received on RenderOverlay - * and dispatch them to the proper recipient (i.e. zoom renderer or pie renderer). - * Touch events on CameraControls will be handled by framework. - * */ -public class NewPreviewGestures - implements ScaleGestureDetector.OnScaleGestureListener { - - private static final String TAG = "CAM_gestures"; - - private static final long TIMEOUT_PIE = 200; - private static final int MSG_PIE = 1; - private static final int MODE_NONE = 0; - private static final int MODE_PIE = 1; - private static final int MODE_ZOOM = 2; - private static final int MODE_MODULE = 3; - private static final int MODE_ALL = 4; - private static final int MODE_SWIPE = 5; - - public static final int DIR_UP = 0; - public static final int DIR_DOWN = 1; - public static final int DIR_LEFT = 2; - public static final int DIR_RIGHT = 3; - - private NewCameraActivity mActivity; - private SingleTapListener mTapListener; - private RenderOverlay mOverlay; - private PieRenderer mPie; - private ZoomRenderer mZoom; - private MotionEvent mDown; - private MotionEvent mCurrent; - private ScaleGestureDetector mScale; - private int mMode; - private int mSlop; - private int mTapTimeout; - private boolean mZoomEnabled; - private boolean mEnabled; - private boolean mZoomOnly; - private int mOrientation; - private GestureDetector mGestureDetector; - - private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { - @Override - public void onLongPress (MotionEvent e) { - // Open pie - if (mPie != null && !mPie.showsItems()) { - openPie(); - } - } - - @Override - public boolean onSingleTapUp (MotionEvent e) { - // Tap to focus when pie is not open - if (mPie == null || !mPie.showsItems()) { - mTapListener.onSingleTapUp(null, (int) e.getX(), (int) e.getY()); - return true; - } - return false; - } - - @Override - public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (mMode == MODE_ZOOM) return false; - int deltaX = (int) (e1.getX() - e2.getX()); - int deltaY = (int) (e1.getY() - e2.getY()); - if (deltaY > 2 * deltaX && deltaY > -2 * deltaX) { - // Open pie on swipe up - if (mPie != null && !mPie.showsItems()) { - openPie(); - return true; - } - } - return false; - } - }; - - private Handler mHandler = new Handler() { - public void handleMessage(Message msg) { - if (msg.what == MSG_PIE) { - mMode = MODE_PIE; - openPie(); - } - } - }; - - public interface SingleTapListener { - public void onSingleTapUp(View v, int x, int y); - } - - public NewPreviewGestures(NewCameraActivity ctx, SingleTapListener tapListener, - ZoomRenderer zoom, PieRenderer pie) { - mActivity = ctx; - mTapListener = tapListener; - mPie = pie; - mZoom = zoom; - mMode = MODE_ALL; - mScale = new ScaleGestureDetector(ctx, this); - mSlop = (int) ctx.getResources().getDimension(R.dimen.pie_touch_slop); - mTapTimeout = ViewConfiguration.getTapTimeout(); - mEnabled = true; - mGestureDetector = new GestureDetector(mGestureListener); - } - - public void setRenderOverlay(RenderOverlay overlay) { - mOverlay = overlay; - } - - public void setOrientation(int orientation) { - mOrientation = orientation; - } - - public void setEnabled(boolean enabled) { - mEnabled = enabled; - } - - public void setZoomEnabled(boolean enable) { - mZoomEnabled = enable; - } - - public void setZoomOnly(boolean zoom) { - mZoomOnly = zoom; - } - - public boolean isEnabled() { - return mEnabled; - } - - public boolean dispatchTouch(MotionEvent m) { - if (!mEnabled) { - return false; - } - mCurrent = m; - if (MotionEvent.ACTION_DOWN == m.getActionMasked()) { - mMode = MODE_NONE; - mDown = MotionEvent.obtain(m); - } - - // If pie is open, redirects all the touch events to pie. - if (mPie != null && mPie.isOpen()) { - return sendToPie(m); - } - - // If pie is not open, send touch events to gesture detector and scale - // listener to recognize the gesture. - mGestureDetector.onTouchEvent(m); - if (mZoom != null) { - mScale.onTouchEvent(m); - if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) { - mMode = MODE_ZOOM; - if (mZoomEnabled) { - // Start showing zoom UI as soon as there is a second finger down - mZoom.onScaleBegin(mScale); - } - } else if (MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) { - mZoom.onScaleEnd(mScale); - } - } - return true; - } - - // left tests for finger moving right to left - private int getSwipeDirection(MotionEvent m) { - float dx = 0; - float dy = 0; - switch (mOrientation) { - case 0: - dx = m.getX() - mDown.getX(); - dy = m.getY() - mDown.getY(); - break; - case 90: - dx = - (m.getY() - mDown.getY()); - dy = m.getX() - mDown.getX(); - break; - case 180: - dx = -(m.getX() - mDown.getX()); - dy = m.getY() - mDown.getY(); - break; - case 270: - dx = m.getY() - mDown.getY(); - dy = m.getX() - mDown.getX(); - break; - } - if (dx < 0 && (Math.abs(dy) / -dx < 2)) return DIR_LEFT; - if (dx > 0 && (Math.abs(dy) / dx < 2)) return DIR_RIGHT; - if (dy > 0) return DIR_DOWN; - return DIR_UP; - } - - private MotionEvent makeCancelEvent(MotionEvent m) { - MotionEvent c = MotionEvent.obtain(m); - c.setAction(MotionEvent.ACTION_CANCEL); - return c; - } - - private void openPie() { - mGestureDetector.onTouchEvent(makeCancelEvent(mDown)); - mScale.onTouchEvent(makeCancelEvent(mDown)); - mOverlay.directDispatchTouch(mDown, mPie); - } - - private boolean sendToPie(MotionEvent m) { - return mOverlay.directDispatchTouch(m, mPie); - } - - // OnScaleGestureListener implementation - @Override - public boolean onScale(ScaleGestureDetector detector) { - return mZoom.onScale(detector); - } - - @Override - public boolean onScaleBegin(ScaleGestureDetector detector) { - if (mPie == null || !mPie.isOpen()) { - mMode = MODE_ZOOM; - mGestureDetector.onTouchEvent(makeCancelEvent(mCurrent)); - if (!mZoomEnabled) return false; - return mZoom.onScaleBegin(detector); - } - return false; - } - - @Override - public void onScaleEnd(ScaleGestureDetector detector) { - mZoom.onScaleEnd(detector); - } -} - diff --git a/src/com/android/camera/NewVideoMenu.java b/src/com/android/camera/NewVideoMenu.java deleted file mode 100644 index 70f73ec39..000000000 --- a/src/com/android/camera/NewVideoMenu.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.app.Activity; -import android.content.Context; -import android.view.LayoutInflater; - -import com.android.camera.ui.AbstractSettingPopup; -import com.android.camera.ui.ListPrefSettingPopup; -import com.android.camera.ui.MoreSettingPopup; -import com.android.camera.ui.PieItem; -import com.android.camera.ui.PieItem.OnClickListener; -import com.android.camera.ui.PieRenderer; -import com.android.camera.ui.TimeIntervalPopup; -import com.android.gallery3d.R; - -public class NewVideoMenu extends PieController - implements MoreSettingPopup.Listener, - ListPrefSettingPopup.Listener, - TimeIntervalPopup.Listener { - - private static String TAG = "CAM_VideoMenu"; - - private NewVideoUI mUI; - private String[] mOtherKeys; - private AbstractSettingPopup mPopup; - - private static final int POPUP_NONE = 0; - private static final int POPUP_FIRST_LEVEL = 1; - private static final int POPUP_SECOND_LEVEL = 2; - private int mPopupStatus; - private NewCameraActivity mActivity; - - public NewVideoMenu(NewCameraActivity activity, NewVideoUI ui, PieRenderer pie) { - super(activity, pie); - mUI = ui; - mActivity = activity; - } - - - public void initialize(PreferenceGroup group) { - super.initialize(group); - mPopup = null; - mPopupStatus = POPUP_NONE; - PieItem item = null; - // white balance - if (group.findPreference(CameraSettings.KEY_WHITE_BALANCE) != null) { - item = makeItem(CameraSettings.KEY_WHITE_BALANCE); - mRenderer.addItem(item); - } - // settings popup - mOtherKeys = new String[] { - CameraSettings.KEY_VIDEO_EFFECT, - CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL, - CameraSettings.KEY_VIDEO_QUALITY, - CameraSettings.KEY_RECORD_LOCATION - }; - item = makeItem(R.drawable.ic_settings_holo_light); - item.setLabel(mActivity.getResources().getString(R.string.camera_menu_settings_label)); - item.setOnClickListener(new OnClickListener() { - @Override - public void onClick(PieItem item) { - if (mPopup == null || mPopupStatus != POPUP_FIRST_LEVEL) { - initializePopup(); - mPopupStatus = POPUP_FIRST_LEVEL; - } - mUI.showPopup(mPopup); - } - }); - mRenderer.addItem(item); - // camera switcher - if (group.findPreference(CameraSettings.KEY_CAMERA_ID) != null) { - item = makeItem(R.drawable.ic_switch_back); - IconListPreference lpref = (IconListPreference) group.findPreference( - CameraSettings.KEY_CAMERA_ID); - item.setLabel(lpref.getLabel()); - item.setImageResource(mActivity, - ((IconListPreference) lpref).getIconIds() - [lpref.findIndexOfValue(lpref.getValue())]); - - final PieItem fitem = item; - item.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(PieItem item) { - // Find the index of next camera. - ListPreference pref = - mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); - if (pref != null) { - int index = pref.findIndexOfValue(pref.getValue()); - CharSequence[] values = pref.getEntryValues(); - index = (index + 1) % values.length; - int newCameraId = Integer.parseInt((String) values[index]); - fitem.setImageResource(mActivity, - ((IconListPreference) pref).getIconIds()[index]); - fitem.setLabel(pref.getLabel()); - mListener.onCameraPickerClicked(newCameraId); - } - } - }); - mRenderer.addItem(item); - } - // flash - if (group.findPreference(CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE) != null) { - item = makeItem(CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE); - mRenderer.addItem(item); - } - } - - @Override - public void reloadPreferences() { - super.reloadPreferences(); - if (mPopup != null) { - mPopup.reloadPreference(); - } - } - - @Override - public void overrideSettings(final String ... keyvalues) { - super.overrideSettings(keyvalues); - if (mPopup == null || mPopupStatus != POPUP_FIRST_LEVEL) { - mPopupStatus = POPUP_FIRST_LEVEL; - initializePopup(); - } - ((MoreSettingPopup) mPopup).overrideSettings(keyvalues); - } - - @Override - // Hit when an item in the second-level popup gets selected - public void onListPrefChanged(ListPreference pref) { - if (mPopup != null) { - if (mPopupStatus == POPUP_SECOND_LEVEL) { - mUI.dismissPopup(true); - } - } - super.onSettingChanged(pref); - } - - protected void initializePopup() { - LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - - MoreSettingPopup popup = (MoreSettingPopup) inflater.inflate( - R.layout.more_setting_popup, null, false); - popup.setSettingChangedListener(this); - popup.initialize(mPreferenceGroup, mOtherKeys); - if (mActivity.isSecureCamera()) { - // Prevent location preference from getting changed in secure camera mode - popup.setPreferenceEnabled(CameraSettings.KEY_RECORD_LOCATION, false); - } - mPopup = popup; - } - - public void popupDismissed(boolean topPopupOnly) { - // if the 2nd level popup gets dismissed - if (mPopupStatus == POPUP_SECOND_LEVEL) { - initializePopup(); - mPopupStatus = POPUP_FIRST_LEVEL; - if (topPopupOnly) mUI.showPopup(mPopup); - } - } - - @Override - // Hit when an item in the first-level popup gets selected, then bring up - // the second-level popup - public void onPreferenceClicked(ListPreference pref) { - if (mPopupStatus != POPUP_FIRST_LEVEL) return; - - LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - - if (CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL.equals(pref.getKey())) { - TimeIntervalPopup timeInterval = (TimeIntervalPopup) inflater.inflate( - R.layout.time_interval_popup, null, false); - timeInterval.initialize((IconListPreference) pref); - timeInterval.setSettingChangedListener(this); - mUI.dismissPopup(true); - mPopup = timeInterval; - } else { - ListPrefSettingPopup basic = (ListPrefSettingPopup) inflater.inflate( - R.layout.list_pref_setting_popup, null, false); - basic.initialize(pref); - basic.setSettingChangedListener(this); - mUI.dismissPopup(true); - mPopup = basic; - } - mUI.showPopup(mPopup); - mPopupStatus = POPUP_SECOND_LEVEL; - } -} diff --git a/src/com/android/camera/NewVideoModule.java b/src/com/android/camera/NewVideoModule.java deleted file mode 100644 index 9b6f59ba8..000000000 --- a/src/com/android/camera/NewVideoModule.java +++ /dev/null @@ -1,2261 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences.Editor; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.SurfaceTexture; -import android.hardware.Camera.CameraInfo; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.PictureCallback; -import android.hardware.Camera.Size; -import android.location.Location; -import android.media.CamcorderProfile; -import android.media.CameraProfile; -import android.media.MediaRecorder; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.ParcelFileDescriptor; -import android.os.SystemClock; -import android.provider.MediaStore; -import android.provider.MediaStore.MediaColumns; -import android.provider.MediaStore.Video; -import android.util.Log; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.OrientationEventListener; -import android.view.Surface; -import android.view.View; -import android.view.WindowManager; -import android.widget.Toast; - -import com.android.camera.CameraManager.CameraProxy; -import com.android.camera.ui.PopupManager; -import com.android.camera.ui.RotateTextToast; -import com.android.gallery3d.R; -import com.android.gallery3d.app.OrientationManager; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.exif.ExifInterface; -import com.android.gallery3d.util.AccessibilityUtils; -import com.android.gallery3d.util.UsageStatistics; - -import java.io.File; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -public class NewVideoModule implements NewCameraModule, - VideoController, - CameraPreference.OnPreferenceChangedListener, - ShutterButton.OnShutterButtonListener, - MediaRecorder.OnErrorListener, - MediaRecorder.OnInfoListener, - EffectsRecorder.EffectsListener { - - private static final String TAG = "CAM_VideoModule"; - - // We number the request code from 1000 to avoid collision with Gallery. - private static final int REQUEST_EFFECT_BACKDROPPER = 1000; - - private static final int CHECK_DISPLAY_ROTATION = 3; - private static final int CLEAR_SCREEN_DELAY = 4; - private static final int UPDATE_RECORD_TIME = 5; - private static final int ENABLE_SHUTTER_BUTTON = 6; - private static final int SHOW_TAP_TO_SNAPSHOT_TOAST = 7; - private static final int SWITCH_CAMERA = 8; - private static final int SWITCH_CAMERA_START_ANIMATION = 9; - private static final int HIDE_SURFACE_VIEW = 10; - private static final int CAPTURE_ANIMATION_DONE = 11; - - private static final int SCREEN_DELAY = 2 * 60 * 1000; - - private static final long SHUTTER_BUTTON_TIMEOUT = 500L; // 500ms - - /** - * An unpublished intent flag requesting to start recording straight away - * and return as soon as recording is stopped. - * TODO: consider publishing by moving into MediaStore. - */ - private static final String EXTRA_QUICK_CAPTURE = - "android.intent.extra.quickCapture"; - - private static final int MIN_THUMB_SIZE = 64; - // module fields - private NewCameraActivity mActivity; - private boolean mPaused; - private int mCameraId; - private Parameters mParameters; - - private Boolean mCameraOpened = false; - private boolean mIsInReviewMode; - private boolean mSnapshotInProgress = false; - - private static final String EFFECT_BG_FROM_GALLERY = "gallery"; - - private final CameraErrorCallback mErrorCallback = new CameraErrorCallback(); - - private ComboPreferences mPreferences; - private PreferenceGroup mPreferenceGroup; - - private boolean mIsVideoCaptureIntent; - private boolean mQuickCapture; - - private MediaRecorder mMediaRecorder; - private EffectsRecorder mEffectsRecorder; - private boolean mEffectsDisplayResult; - - private int mEffectType = EffectsRecorder.EFFECT_NONE; - private Object mEffectParameter = null; - private String mEffectUriFromGallery = null; - private String mPrefVideoEffectDefault; - private boolean mResetEffect = true; - - private boolean mSwitchingCamera; - private boolean mMediaRecorderRecording = false; - private long mRecordingStartTime; - private boolean mRecordingTimeCountsDown = false; - private long mOnResumeTime; - // The video file that the hardware camera is about to record into - // (or is recording into.) - private String mVideoFilename; - private ParcelFileDescriptor mVideoFileDescriptor; - - // The video file that has already been recorded, and that is being - // examined by the user. - private String mCurrentVideoFilename; - private Uri mCurrentVideoUri; - private ContentValues mCurrentVideoValues; - - private CamcorderProfile mProfile; - - // The video duration limit. 0 menas no limit. - private int mMaxVideoDurationInMs; - - // Time Lapse parameters. - private boolean mCaptureTimeLapse = false; - // Default 0. If it is larger than 0, the camcorder is in time lapse mode. - private int mTimeBetweenTimeLapseFrameCaptureMs = 0; - - boolean mPreviewing = false; // True if preview is started. - // The display rotation in degrees. This is only valid when mPreviewing is - // true. - private int mDisplayRotation; - private int mCameraDisplayOrientation; - - private int mDesiredPreviewWidth; - private int mDesiredPreviewHeight; - private ContentResolver mContentResolver; - - private LocationManager mLocationManager; - private OrientationManager mOrientationManager; - - private Surface mSurface; - private int mPendingSwitchCameraId; - private boolean mOpenCameraFail; - private boolean mCameraDisabled; - private final Handler mHandler = new MainHandler(); - private NewVideoUI mUI; - private CameraProxy mCameraDevice; - - // The degrees of the device rotated clockwise from its natural orientation. - private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; - - private int mZoomValue; // The current zoom value. - - private boolean mRestoreFlash; // This is used to check if we need to restore the flash - // status when going back from gallery. - - private final MediaSaveService.OnMediaSavedListener mOnVideoSavedListener = - new MediaSaveService.OnMediaSavedListener() { - @Override - public void onMediaSaved(Uri uri) { - if (uri != null) { - mActivity.sendBroadcast( - new Intent(Util.ACTION_NEW_VIDEO, uri)); - Util.broadcastNewPicture(mActivity, uri); - } - } - }; - - private final MediaSaveService.OnMediaSavedListener mOnPhotoSavedListener = - new MediaSaveService.OnMediaSavedListener() { - @Override - public void onMediaSaved(Uri uri) { - if (uri != null) { - Util.broadcastNewPicture(mActivity, uri); - } - } - }; - - - protected class CameraOpenThread extends Thread { - @Override - public void run() { - openCamera(); - } - } - - private void openCamera() { - try { - synchronized(mCameraOpened) { - if (!mCameraOpened) { - mCameraDevice = Util.openCamera(mActivity, mCameraId); - mCameraOpened = true; - } - } - mParameters = mCameraDevice.getParameters(); - } catch (CameraHardwareException e) { - mOpenCameraFail = true; - } catch (CameraDisabledException e) { - mCameraDisabled = true; - } - } - - // This Handler is used to post message back onto the main thread of the - // application - private class MainHandler extends Handler { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - - case ENABLE_SHUTTER_BUTTON: - mUI.enableShutter(true); - break; - - case CLEAR_SCREEN_DELAY: { - mActivity.getWindow().clearFlags( - WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - break; - } - - case UPDATE_RECORD_TIME: { - updateRecordingTime(); - break; - } - - case CHECK_DISPLAY_ROTATION: { - // Restart the preview if display rotation has changed. - // Sometimes this happens when the device is held upside - // down and camera app is opened. Rotation animation will - // take some time and the rotation value we have got may be - // wrong. Framework does not have a callback for this now. - if ((Util.getDisplayRotation(mActivity) != mDisplayRotation) - && !mMediaRecorderRecording && !mSwitchingCamera) { - startPreview(); - } - if (SystemClock.uptimeMillis() - mOnResumeTime < 5000) { - mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100); - } - break; - } - - case SHOW_TAP_TO_SNAPSHOT_TOAST: { - showTapToSnapshotToast(); - break; - } - - case SWITCH_CAMERA: { - switchCamera(); - break; - } - - case SWITCH_CAMERA_START_ANIMATION: { - //TODO: - //((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera(); - - // Enable all camera controls. - mSwitchingCamera = false; - break; - } - - case CAPTURE_ANIMATION_DONE: { - mUI.enablePreviewThumb(false); - break; - } - - default: - Log.v(TAG, "Unhandled message: " + msg.what); - break; - } - } - } - - private BroadcastReceiver mReceiver = null; - - private class MyBroadcastReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(Intent.ACTION_MEDIA_EJECT)) { - stopVideoRecording(); - } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) { - Toast.makeText(mActivity, - mActivity.getResources().getString(R.string.wait), Toast.LENGTH_LONG).show(); - } - } - } - - private String createName(long dateTaken) { - Date date = new Date(dateTaken); - SimpleDateFormat dateFormat = new SimpleDateFormat( - mActivity.getString(R.string.video_file_name_format)); - - return dateFormat.format(date); - } - - private int getPreferredCameraId(ComboPreferences preferences) { - int intentCameraId = Util.getCameraFacingIntentExtras(mActivity); - if (intentCameraId != -1) { - // Testing purpose. Launch a specific camera through the intent - // extras. - return intentCameraId; - } else { - return CameraSettings.readPreferredCameraId(preferences); - } - } - - private void initializeSurfaceView() { - if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { // API level < 16 - mUI.initializeSurfaceView(); - } - } - - @Override - public void init(NewCameraActivity activity, View root) { - mActivity = activity; - mUI = new NewVideoUI(activity, this, root); - mPreferences = new ComboPreferences(mActivity); - CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal()); - mCameraId = getPreferredCameraId(mPreferences); - - mPreferences.setLocalId(mActivity, mCameraId); - CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - - mPrefVideoEffectDefault = mActivity.getString(R.string.pref_video_effect_default); - resetEffect(); - mOrientationManager = new OrientationManager(mActivity); - - /* - * To reduce startup time, we start the preview in another thread. - * We make sure the preview is started at the end of onCreate. - */ - CameraOpenThread cameraOpenThread = new CameraOpenThread(); - cameraOpenThread.start(); - - mContentResolver = mActivity.getContentResolver(); - - // Surface texture is from camera screen nail and startPreview needs it. - // This must be done before startPreview. - mIsVideoCaptureIntent = isVideoCaptureIntent(); - initializeSurfaceView(); - - // Make sure camera device is opened. - try { - cameraOpenThread.join(); - if (mOpenCameraFail) { - Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); - return; - } else if (mCameraDisabled) { - Util.showErrorAndFinish(mActivity, R.string.camera_disabled); - return; - } - } catch (InterruptedException ex) { - // ignore - } - - readVideoPreferences(); - mUI.setPrefChangedListener(this); - new Thread(new Runnable() { - @Override - public void run() { - startPreview(); - } - }).start(); - - mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); - mLocationManager = new LocationManager(mActivity, null); - - mUI.setOrientationIndicator(0, false); - setDisplayOrientation(); - - mUI.showTimeLapseUI(mCaptureTimeLapse); - initializeVideoSnapshot(); - resizeForPreviewAspectRatio(); - - initializeVideoControl(); - mPendingSwitchCameraId = -1; - mUI.updateOnScreenIndicators(mParameters, mPreferences); - - // Disable the shutter button if effects are ON since it might take - // a little more time for the effects preview to be ready. We do not - // want to allow recording before that happens. The shutter button - // will be enabled when we get the message from effectsrecorder that - // the preview is running. This becomes critical when the camera is - // swapped. - if (effectsActive()) { - mUI.enableShutter(false); - } - } - - // SingleTapListener - // Preview area is touched. Take a picture. - @Override - public void onSingleTapUp(View view, int x, int y) { - if (mMediaRecorderRecording && effectsActive()) { - new RotateTextToast(mActivity, R.string.disable_video_snapshot_hint, - mOrientation).show(); - return; - } - - MediaSaveService s = mActivity.getMediaSaveService(); - if (mPaused || mSnapshotInProgress || effectsActive() || s == null || s.isQueueFull()) { - return; - } - - if (!mMediaRecorderRecording) { - // check for dismissing popup - mUI.dismissPopup(true); - return; - } - - // Set rotation and gps data. - int rotation = Util.getJpegRotation(mCameraId, mOrientation); - mParameters.setRotation(rotation); - Location loc = mLocationManager.getCurrentLocation(); - Util.setGpsParameters(mParameters, loc); - mCameraDevice.setParameters(mParameters); - - Log.v(TAG, "Video snapshot start"); - mCameraDevice.takePicture(null, null, null, new JpegPictureCallback(loc)); - showVideoSnapshotUI(true); - mSnapshotInProgress = true; - UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, - UsageStatistics.ACTION_CAPTURE_DONE, "VideoSnapshot"); - } - - @Override - public void onStop() {} - - private void loadCameraPreferences() { - CameraSettings settings = new CameraSettings(mActivity, mParameters, - mCameraId, CameraHolder.instance().getCameraInfo()); - // Remove the video quality preference setting when the quality is given in the intent. - mPreferenceGroup = filterPreferenceScreenByIntent( - settings.getPreferenceGroup(R.xml.video_preferences)); - } - - private void initializeVideoControl() { - loadCameraPreferences(); - mUI.initializePopup(mPreferenceGroup); - if (effectsActive()) { - mUI.overrideSettings( - CameraSettings.KEY_VIDEO_QUALITY, - Integer.toString(getLowVideoQuality())); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) - private static int getLowVideoQuality() { - if (ApiHelper.HAS_FINE_RESOLUTION_QUALITY_LEVELS) { - return CamcorderProfile.QUALITY_480P; - } else { - return CamcorderProfile.QUALITY_LOW; - } - } - - - @Override - public void onOrientationChanged(int orientation) { - // We keep the last known orientation. So if the user first orient - // the camera then point the camera to floor or sky, we still have - // the correct orientation. - if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) return; - int newOrientation = Util.roundOrientation(orientation, mOrientation); - - if (mOrientation != newOrientation) { - mOrientation = newOrientation; - // The input of effects recorder is affected by - // android.hardware.Camera.setDisplayOrientation. Its value only - // compensates the camera orientation (no Display.getRotation). - // So the orientation hint here should only consider sensor - // orientation. - if (effectsActive()) { - mEffectsRecorder.setOrientationHint(mOrientation); - } - } - - // Show the toast after getting the first orientation changed. - if (mHandler.hasMessages(SHOW_TAP_TO_SNAPSHOT_TOAST)) { - mHandler.removeMessages(SHOW_TAP_TO_SNAPSHOT_TOAST); - showTapToSnapshotToast(); - } - } - - private void startPlayVideoActivity() { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(mCurrentVideoUri, convertOutputFormatToMimeType(mProfile.fileFormat)); - try { - mActivity.startActivity(intent); - } catch (ActivityNotFoundException ex) { - Log.e(TAG, "Couldn't view video " + mCurrentVideoUri, ex); - } - } - - @OnClickAttr - public void onReviewPlayClicked(View v) { - startPlayVideoActivity(); - } - - @OnClickAttr - public void onReviewDoneClicked(View v) { - mIsInReviewMode = false; - doReturnToCaller(true); - } - - @OnClickAttr - public void onReviewCancelClicked(View v) { - mIsInReviewMode = false; - stopVideoRecording(); - doReturnToCaller(false); - } - - @Override - public boolean isInReviewMode() { - return mIsInReviewMode; - } - - private void onStopVideoRecording() { - mEffectsDisplayResult = true; - boolean recordFail = stopVideoRecording(); - if (mIsVideoCaptureIntent) { - if (!effectsActive()) { - if (mQuickCapture) { - doReturnToCaller(!recordFail); - } else if (!recordFail) { - showCaptureResult(); - } - } - } else if (!recordFail){ - // Start capture animation. - if (!mPaused && ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { - // The capture animation is disabled on ICS because we use SurfaceView - // for preview during recording. When the recording is done, we switch - // back to use SurfaceTexture for preview and we need to stop then start - // the preview. This will cause the preview flicker since the preview - // will not be continuous for a short period of time. - // TODO: need to get the capture animation to work - // ((CameraScreenNail) mActivity.mCameraScreenNail).animateCapture(mDisplayRotation); - - mUI.enablePreviewThumb(true); - - // Make sure to disable the thumbnail preview after the - // animation is done to disable the click target. - mHandler.removeMessages(CAPTURE_ANIMATION_DONE); - mHandler.sendEmptyMessageDelayed(CAPTURE_ANIMATION_DONE, - CaptureAnimManager.getAnimationDuration()); - } - } - } - - public void onProtectiveCurtainClick(View v) { - // Consume clicks - } - - @Override - public void onShutterButtonClick() { - if (mUI.collapseCameraControls() || mSwitchingCamera) return; - - boolean stop = mMediaRecorderRecording; - - if (stop) { - onStopVideoRecording(); - } else { - startVideoRecording(); - } - mUI.enableShutter(false); - - // Keep the shutter button disabled when in video capture intent - // mode and recording is stopped. It'll be re-enabled when - // re-take button is clicked. - if (!(mIsVideoCaptureIntent && stop)) { - mHandler.sendEmptyMessageDelayed( - ENABLE_SHUTTER_BUTTON, SHUTTER_BUTTON_TIMEOUT); - } - } - - @Override - public void onShutterButtonFocus(boolean pressed) { - mUI.setShutterPressed(pressed); - } - - private void readVideoPreferences() { - // The preference stores values from ListPreference and is thus string type for all values. - // We need to convert it to int manually. - String defaultQuality = CameraSettings.getDefaultVideoQuality(mCameraId, - mActivity.getResources().getString(R.string.pref_video_quality_default)); - String videoQuality = - mPreferences.getString(CameraSettings.KEY_VIDEO_QUALITY, - defaultQuality); - int quality = Integer.valueOf(videoQuality); - - // Set video quality. - Intent intent = mActivity.getIntent(); - if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) { - int extraVideoQuality = - intent.getIntExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); - if (extraVideoQuality > 0) { - quality = CamcorderProfile.QUALITY_HIGH; - } else { // 0 is mms. - quality = CamcorderProfile.QUALITY_LOW; - } - } - - // Set video duration limit. The limit is read from the preference, - // unless it is specified in the intent. - if (intent.hasExtra(MediaStore.EXTRA_DURATION_LIMIT)) { - int seconds = - intent.getIntExtra(MediaStore.EXTRA_DURATION_LIMIT, 0); - mMaxVideoDurationInMs = 1000 * seconds; - } else { - mMaxVideoDurationInMs = CameraSettings.getMaxVideoDuration(mActivity); - } - - // Set effect - mEffectType = CameraSettings.readEffectType(mPreferences); - if (mEffectType != EffectsRecorder.EFFECT_NONE) { - mEffectParameter = CameraSettings.readEffectParameter(mPreferences); - // Set quality to be no higher than 480p. - CamcorderProfile profile = CamcorderProfile.get(mCameraId, quality); - if (profile.videoFrameHeight > 480) { - quality = getLowVideoQuality(); - } - } else { - mEffectParameter = null; - } - // Read time lapse recording interval. - if (ApiHelper.HAS_TIME_LAPSE_RECORDING) { - String frameIntervalStr = mPreferences.getString( - CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL, - mActivity.getString(R.string.pref_video_time_lapse_frame_interval_default)); - mTimeBetweenTimeLapseFrameCaptureMs = Integer.parseInt(frameIntervalStr); - mCaptureTimeLapse = (mTimeBetweenTimeLapseFrameCaptureMs != 0); - } - // TODO: This should be checked instead directly +1000. - if (mCaptureTimeLapse) quality += 1000; - mProfile = CamcorderProfile.get(mCameraId, quality); - getDesiredPreviewSize(); - } - - private void writeDefaultEffectToPrefs() { - ComboPreferences.Editor editor = mPreferences.edit(); - editor.putString(CameraSettings.KEY_VIDEO_EFFECT, - mActivity.getString(R.string.pref_video_effect_default)); - editor.apply(); - } - - @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) - private void getDesiredPreviewSize() { - mParameters = mCameraDevice.getParameters(); - if (ApiHelper.HAS_GET_SUPPORTED_VIDEO_SIZE) { - if (mParameters.getSupportedVideoSizes() == null || effectsActive()) { - mDesiredPreviewWidth = mProfile.videoFrameWidth; - mDesiredPreviewHeight = mProfile.videoFrameHeight; - } else { // Driver supports separates outputs for preview and video. - List sizes = mParameters.getSupportedPreviewSizes(); - Size preferred = mParameters.getPreferredPreviewSizeForVideo(); - int product = preferred.width * preferred.height; - Iterator it = sizes.iterator(); - // Remove the preview sizes that are not preferred. - while (it.hasNext()) { - Size size = it.next(); - if (size.width * size.height > product) { - it.remove(); - } - } - Size optimalSize = Util.getOptimalPreviewSize(mActivity, sizes, - (double) mProfile.videoFrameWidth / mProfile.videoFrameHeight); - mDesiredPreviewWidth = optimalSize.width; - mDesiredPreviewHeight = optimalSize.height; - } - } else { - mDesiredPreviewWidth = mProfile.videoFrameWidth; - mDesiredPreviewHeight = mProfile.videoFrameHeight; - } - mUI.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight); - Log.v(TAG, "mDesiredPreviewWidth=" + mDesiredPreviewWidth + - ". mDesiredPreviewHeight=" + mDesiredPreviewHeight); - } - - private void resizeForPreviewAspectRatio() { - mUI.setAspectRatio( - (double) mProfile.videoFrameWidth / mProfile.videoFrameHeight); - } - - @Override - public void installIntentFilter() { - // install an intent filter to receive SD card related events. - IntentFilter intentFilter = - new IntentFilter(Intent.ACTION_MEDIA_EJECT); - intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED); - intentFilter.addDataScheme("file"); - mReceiver = new MyBroadcastReceiver(); - mActivity.registerReceiver(mReceiver, intentFilter); - } - - @Override - public void onResumeBeforeSuper() { - mPaused = false; - } - - @Override - public void onResumeAfterSuper() { - if (mOpenCameraFail || mCameraDisabled) - return; - mUI.enableShutter(false); - mZoomValue = 0; - - showVideoSnapshotUI(false); - - if (!mPreviewing) { - resetEffect(); - openCamera(); - if (mOpenCameraFail) { - Util.showErrorAndFinish(mActivity, - R.string.cannot_connect_camera); - return; - } else if (mCameraDisabled) { - Util.showErrorAndFinish(mActivity, R.string.camera_disabled); - return; - } - readVideoPreferences(); - resizeForPreviewAspectRatio(); - new Thread(new Runnable() { - @Override - public void run() { - startPreview(); - } - }).start(); - } else { - // preview already started - mUI.enableShutter(true); - } - - // Initializing it here after the preview is started. - mUI.initializeZoom(mParameters); - - keepScreenOnAwhile(); - - // Initialize location service. - boolean recordLocation = RecordLocationPreference.get(mPreferences, - mContentResolver); - mLocationManager.recordLocation(recordLocation); - - if (mPreviewing) { - mOnResumeTime = SystemClock.uptimeMillis(); - mHandler.sendEmptyMessageDelayed(CHECK_DISPLAY_ROTATION, 100); - } - // Dismiss open menu if exists. - PopupManager.getInstance(mActivity).notifyShowPopup(null); - - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_CAMERA, "VideoModule"); - } - - private void setDisplayOrientation() { - mDisplayRotation = Util.getDisplayRotation(mActivity); - mCameraDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId); - // Change the camera display orientation - if (mCameraDevice != null) { - mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); - } - } - - @Override - public void updateCameraOrientation() { - if (mMediaRecorderRecording) return; - if (mDisplayRotation != Util.getDisplayRotation(mActivity)) { - setDisplayOrientation(); - } - } - - @Override - public int onZoomChanged(int index) { - // Not useful to change zoom value when the activity is paused. - if (mPaused) return index; - mZoomValue = index; - if (mParameters == null || mCameraDevice == null) return index; - // Set zoom parameters asynchronously - mParameters.setZoom(mZoomValue); - mCameraDevice.setParameters(mParameters); - Parameters p = mCameraDevice.getParameters(); - if (p != null) return p.getZoom(); - return index; - } - private void startPreview() { - Log.v(TAG, "startPreview"); - - mCameraDevice.setErrorCallback(mErrorCallback); - if (mPreviewing == true) { - stopPreview(); - if (effectsActive() && mEffectsRecorder != null) { - mEffectsRecorder.release(); - mEffectsRecorder = null; - } - } - - setDisplayOrientation(); - mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); - setCameraParameters(); - - try { - if (!effectsActive()) { - SurfaceTexture surfaceTexture = mUI.getSurfaceTexture(); - if (surfaceTexture == null) { - return; // The texture has been destroyed (pause, etc) - } - mCameraDevice.setPreviewTextureAsync(surfaceTexture); - mCameraDevice.startPreviewAsync(); - mPreviewing = true; - onPreviewStarted(); - } else { - initializeEffectsPreview(); - mEffectsRecorder.startPreview(); - mPreviewing = true; - onPreviewStarted(); - } - } catch (Throwable ex) { - closeCamera(); - throw new RuntimeException("startPreview failed", ex); - } finally { - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - if (mOpenCameraFail) { - Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); - } else if (mCameraDisabled) { - Util.showErrorAndFinish(mActivity, R.string.camera_disabled); - } - } - }); - } - - } - - private void onPreviewStarted() { - mUI.enableShutter(true); - } - - @Override - public void stopPreview() { - if (!mPreviewing) return; - mCameraDevice.stopPreview(); - mPreviewing = false; - } - - // Closing the effects out. Will shut down the effects graph. - private void closeEffects() { - Log.v(TAG, "Closing effects"); - mEffectType = EffectsRecorder.EFFECT_NONE; - if (mEffectsRecorder == null) { - Log.d(TAG, "Effects are already closed. Nothing to do"); - return; - } - // This call can handle the case where the camera is already released - // after the recording has been stopped. - mEffectsRecorder.release(); - mEffectsRecorder = null; - } - - // By default, we want to close the effects as well with the camera. - private void closeCamera() { - closeCamera(true); - } - - // In certain cases, when the effects are active, we may want to shutdown - // only the camera related parts, and handle closing the effects in the - // effectsUpdate callback. - // For example, in onPause, we want to make the camera available to - // outside world immediately, however, want to wait till the effects - // callback to shut down the effects. In such a case, we just disconnect - // the effects from the camera by calling disconnectCamera. That way - // the effects can handle that when shutting down. - // - // @param closeEffectsAlso - indicates whether we want to close the - // effects also along with the camera. - private void closeCamera(boolean closeEffectsAlso) { - Log.v(TAG, "closeCamera"); - if (mCameraDevice == null) { - Log.d(TAG, "already stopped."); - return; - } - - if (mEffectsRecorder != null) { - // Disconnect the camera from effects so that camera is ready to - // be released to the outside world. - mEffectsRecorder.disconnectCamera(); - } - if (closeEffectsAlso) closeEffects(); - mCameraDevice.setZoomChangeListener(null); - mCameraDevice.setErrorCallback(null); - synchronized(mCameraOpened) { - if (mCameraOpened) { - CameraHolder.instance().release(); - } - mCameraOpened = false; - } - mCameraDevice = null; - mPreviewing = false; - mSnapshotInProgress = false; - } - - private void releasePreviewResources() { - if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { - mUI.hideSurfaceView(); - } - } - - @Override - public void onPauseBeforeSuper() { - mPaused = true; - - if (mMediaRecorderRecording) { - // Camera will be released in onStopVideoRecording. - onStopVideoRecording(); - } else { - closeCamera(); - if (!effectsActive()) releaseMediaRecorder(); - } - if (effectsActive()) { - // If the effects are active, make sure we tell the graph that the - // surfacetexture is not valid anymore. Disconnect the graph from - // the display. This should be done before releasing the surface - // texture. - mEffectsRecorder.disconnectDisplay(); - } else { - // Close the file descriptor and clear the video namer only if the - // effects are not active. If effects are active, we need to wait - // till we get the callback from the Effects that the graph is done - // recording. That also needs a change in the stopVideoRecording() - // call to not call closeCamera if the effects are active, because - // that will close down the effects are well, thus making this if - // condition invalid. - closeVideoFileDescriptor(); - } - - releasePreviewResources(); - - if (mReceiver != null) { - mActivity.unregisterReceiver(mReceiver); - mReceiver = null; - } - resetScreenOn(); - - if (mLocationManager != null) mLocationManager.recordLocation(false); - - mHandler.removeMessages(CHECK_DISPLAY_ROTATION); - mHandler.removeMessages(SWITCH_CAMERA); - mHandler.removeMessages(SWITCH_CAMERA_START_ANIMATION); - mPendingSwitchCameraId = -1; - mSwitchingCamera = false; - // Call onPause after stopping video recording. So the camera can be - // released as soon as possible. - } - - @Override - public void onPauseAfterSuper() { - } - - @Override - public void onUserInteraction() { - if (!mMediaRecorderRecording && !mActivity.isFinishing()) { - keepScreenOnAwhile(); - } - } - - @Override - public boolean onBackPressed() { - if (mPaused) return true; - if (mMediaRecorderRecording) { - onStopVideoRecording(); - return true; - } else if (mUI.hidePieRenderer()) { - return true; - } else { - return mUI.removeTopLevelPopup(); - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - // Do not handle any key if the activity is paused. - if (mPaused) { - return true; - } - - switch (keyCode) { - case KeyEvent.KEYCODE_CAMERA: - if (event.getRepeatCount() == 0) { - mUI.clickShutter(); - return true; - } - break; - case KeyEvent.KEYCODE_DPAD_CENTER: - if (event.getRepeatCount() == 0) { - mUI.clickShutter(); - return true; - } - break; - case KeyEvent.KEYCODE_MENU: - if (mMediaRecorderRecording) return true; - break; - } - return false; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_CAMERA: - mUI.pressShutter(false); - return true; - } - return false; - } - - @Override - public boolean isVideoCaptureIntent() { - String action = mActivity.getIntent().getAction(); - return (MediaStore.ACTION_VIDEO_CAPTURE.equals(action)); - } - - private void doReturnToCaller(boolean valid) { - Intent resultIntent = new Intent(); - int resultCode; - if (valid) { - resultCode = Activity.RESULT_OK; - resultIntent.setData(mCurrentVideoUri); - } else { - resultCode = Activity.RESULT_CANCELED; - } - mActivity.setResultEx(resultCode, resultIntent); - mActivity.finish(); - } - - private void cleanupEmptyFile() { - if (mVideoFilename != null) { - File f = new File(mVideoFilename); - if (f.length() == 0 && f.delete()) { - Log.v(TAG, "Empty video file deleted: " + mVideoFilename); - mVideoFilename = null; - } - } - } - - private void setupMediaRecorderPreviewDisplay() { - // Nothing to do here if using SurfaceTexture. - if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { - // We stop the preview here before unlocking the device because we - // need to change the SurfaceTexture to SurfaceView for preview. - stopPreview(); - mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder()); - // The orientation for SurfaceTexture is different from that for - // SurfaceView. For SurfaceTexture we don't need to consider the - // display rotation. Just consider the sensor's orientation and we - // will set the orientation correctly when showing the texture. - // Gallery will handle the orientation for the preview. For - // SurfaceView we will have to take everything into account so the - // display rotation is considered. - mCameraDevice.setDisplayOrientation( - Util.getDisplayOrientation(mDisplayRotation, mCameraId)); - mCameraDevice.startPreviewAsync(); - mPreviewing = true; - mMediaRecorder.setPreviewDisplay(mUI.getSurfaceHolder().getSurface()); - } - } - - // Prepares media recorder. - private void initializeRecorder() { - Log.v(TAG, "initializeRecorder"); - // If the mCameraDevice is null, then this activity is going to finish - if (mCameraDevice == null) return; - - if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { - // Set the SurfaceView to visible so the surface gets created. - // surfaceCreated() is called immediately when the visibility is - // changed to visible. Thus, mSurfaceViewReady should become true - // right after calling setVisibility(). - mUI.showSurfaceView(); - } - - Intent intent = mActivity.getIntent(); - Bundle myExtras = intent.getExtras(); - - long requestedSizeLimit = 0; - closeVideoFileDescriptor(); - if (mIsVideoCaptureIntent && myExtras != null) { - Uri saveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT); - if (saveUri != null) { - try { - mVideoFileDescriptor = - mContentResolver.openFileDescriptor(saveUri, "rw"); - mCurrentVideoUri = saveUri; - } catch (java.io.FileNotFoundException ex) { - // invalid uri - Log.e(TAG, ex.toString()); - } - } - requestedSizeLimit = myExtras.getLong(MediaStore.EXTRA_SIZE_LIMIT); - } - mMediaRecorder = new MediaRecorder(); - - setupMediaRecorderPreviewDisplay(); - // Unlock the camera object before passing it to media recorder. - mCameraDevice.unlock(); - mCameraDevice.waitDone(); - mMediaRecorder.setCamera(mCameraDevice.getCamera()); - if (!mCaptureTimeLapse) { - mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); - } - mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); - mMediaRecorder.setProfile(mProfile); - mMediaRecorder.setMaxDuration(mMaxVideoDurationInMs); - if (mCaptureTimeLapse) { - double fps = 1000 / (double) mTimeBetweenTimeLapseFrameCaptureMs; - setCaptureRate(mMediaRecorder, fps); - } - - setRecordLocation(); - - // Set output file. - // Try Uri in the intent first. If it doesn't exist, use our own - // instead. - if (mVideoFileDescriptor != null) { - mMediaRecorder.setOutputFile(mVideoFileDescriptor.getFileDescriptor()); - } else { - generateVideoFilename(mProfile.fileFormat); - mMediaRecorder.setOutputFile(mVideoFilename); - } - - // Set maximum file size. - long maxFileSize = mActivity.getStorageSpace() - Storage.LOW_STORAGE_THRESHOLD; - if (requestedSizeLimit > 0 && requestedSizeLimit < maxFileSize) { - maxFileSize = requestedSizeLimit; - } - - try { - mMediaRecorder.setMaxFileSize(maxFileSize); - } catch (RuntimeException exception) { - // We are going to ignore failure of setMaxFileSize here, as - // a) The composer selected may simply not support it, or - // b) The underlying media framework may not handle 64-bit range - // on the size restriction. - } - - // See android.hardware.Camera.Parameters.setRotation for - // documentation. - // Note that mOrientation here is the device orientation, which is the opposite of - // what activity.getWindowManager().getDefaultDisplay().getRotation() would return, - // which is the orientation the graphics need to rotate in order to render correctly. - int rotation = 0; - if (mOrientation != OrientationEventListener.ORIENTATION_UNKNOWN) { - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { - rotation = (info.orientation - mOrientation + 360) % 360; - } else { // back-facing camera - rotation = (info.orientation + mOrientation) % 360; - } - } - mMediaRecorder.setOrientationHint(rotation); - - try { - mMediaRecorder.prepare(); - } catch (IOException e) { - Log.e(TAG, "prepare failed for " + mVideoFilename, e); - releaseMediaRecorder(); - throw new RuntimeException(e); - } - - mMediaRecorder.setOnErrorListener(this); - mMediaRecorder.setOnInfoListener(this); - } - - @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) - private static void setCaptureRate(MediaRecorder recorder, double fps) { - recorder.setCaptureRate(fps); - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - private void setRecordLocation() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - Location loc = mLocationManager.getCurrentLocation(); - if (loc != null) { - mMediaRecorder.setLocation((float) loc.getLatitude(), - (float) loc.getLongitude()); - } - } - } - - private void initializeEffectsPreview() { - Log.v(TAG, "initializeEffectsPreview"); - // If the mCameraDevice is null, then this activity is going to finish - if (mCameraDevice == null) return; - - boolean inLandscape = (mActivity.getResources().getConfiguration().orientation - == Configuration.ORIENTATION_LANDSCAPE); - - CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId]; - - mEffectsDisplayResult = false; - mEffectsRecorder = new EffectsRecorder(mActivity); - - // TODO: Confirm none of the following need to go to initializeEffectsRecording() - // and none of these change even when the preview is not refreshed. - mEffectsRecorder.setCameraDisplayOrientation(mCameraDisplayOrientation); - mEffectsRecorder.setCamera(mCameraDevice); - mEffectsRecorder.setCameraFacing(info.facing); - mEffectsRecorder.setProfile(mProfile); - mEffectsRecorder.setEffectsListener(this); - mEffectsRecorder.setOnInfoListener(this); - mEffectsRecorder.setOnErrorListener(this); - - // The input of effects recorder is affected by - // android.hardware.Camera.setDisplayOrientation. Its value only - // compensates the camera orientation (no Display.getRotation). So the - // orientation hint here should only consider sensor orientation. - int orientation = 0; - if (mOrientation != OrientationEventListener.ORIENTATION_UNKNOWN) { - orientation = mOrientation; - } - mEffectsRecorder.setOrientationHint(orientation); - - mEffectsRecorder.setPreviewSurfaceTexture(mUI.getSurfaceTexture(), - mUI.getPreviewWidth(), mUI.getPreviewHeight()); - - if (mEffectType == EffectsRecorder.EFFECT_BACKDROPPER && - ((String) mEffectParameter).equals(EFFECT_BG_FROM_GALLERY)) { - mEffectsRecorder.setEffect(mEffectType, mEffectUriFromGallery); - } else { - mEffectsRecorder.setEffect(mEffectType, mEffectParameter); - } - } - - private void initializeEffectsRecording() { - Log.v(TAG, "initializeEffectsRecording"); - - Intent intent = mActivity.getIntent(); - Bundle myExtras = intent.getExtras(); - - long requestedSizeLimit = 0; - closeVideoFileDescriptor(); - if (mIsVideoCaptureIntent && myExtras != null) { - Uri saveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT); - if (saveUri != null) { - try { - mVideoFileDescriptor = - mContentResolver.openFileDescriptor(saveUri, "rw"); - mCurrentVideoUri = saveUri; - } catch (java.io.FileNotFoundException ex) { - // invalid uri - Log.e(TAG, ex.toString()); - } - } - requestedSizeLimit = myExtras.getLong(MediaStore.EXTRA_SIZE_LIMIT); - } - - mEffectsRecorder.setProfile(mProfile); - // important to set the capture rate to zero if not timelapsed, since the - // effectsrecorder object does not get created again for each recording - // session - if (mCaptureTimeLapse) { - mEffectsRecorder.setCaptureRate((1000 / (double) mTimeBetweenTimeLapseFrameCaptureMs)); - } else { - mEffectsRecorder.setCaptureRate(0); - } - - // Set output file - if (mVideoFileDescriptor != null) { - mEffectsRecorder.setOutputFile(mVideoFileDescriptor.getFileDescriptor()); - } else { - generateVideoFilename(mProfile.fileFormat); - mEffectsRecorder.setOutputFile(mVideoFilename); - } - - // Set maximum file size. - long maxFileSize = mActivity.getStorageSpace() - Storage.LOW_STORAGE_THRESHOLD; - if (requestedSizeLimit > 0 && requestedSizeLimit < maxFileSize) { - maxFileSize = requestedSizeLimit; - } - mEffectsRecorder.setMaxFileSize(maxFileSize); - mEffectsRecorder.setMaxDuration(mMaxVideoDurationInMs); - } - - - private void releaseMediaRecorder() { - Log.v(TAG, "Releasing media recorder."); - if (mMediaRecorder != null) { - cleanupEmptyFile(); - mMediaRecorder.reset(); - mMediaRecorder.release(); - mMediaRecorder = null; - } - mVideoFilename = null; - } - - private void releaseEffectsRecorder() { - Log.v(TAG, "Releasing effects recorder."); - if (mEffectsRecorder != null) { - cleanupEmptyFile(); - mEffectsRecorder.release(); - mEffectsRecorder = null; - } - mEffectType = EffectsRecorder.EFFECT_NONE; - mVideoFilename = null; - } - - private void generateVideoFilename(int outputFileFormat) { - long dateTaken = System.currentTimeMillis(); - String title = createName(dateTaken); - // Used when emailing. - String filename = title + convertOutputFormatToFileExt(outputFileFormat); - String mime = convertOutputFormatToMimeType(outputFileFormat); - String path = Storage.DIRECTORY + '/' + filename; - String tmpPath = path + ".tmp"; - mCurrentVideoValues = new ContentValues(9); - mCurrentVideoValues.put(Video.Media.TITLE, title); - mCurrentVideoValues.put(Video.Media.DISPLAY_NAME, filename); - mCurrentVideoValues.put(Video.Media.DATE_TAKEN, dateTaken); - mCurrentVideoValues.put(MediaColumns.DATE_MODIFIED, dateTaken / 1000); - mCurrentVideoValues.put(Video.Media.MIME_TYPE, mime); - mCurrentVideoValues.put(Video.Media.DATA, path); - mCurrentVideoValues.put(Video.Media.RESOLUTION, - Integer.toString(mProfile.videoFrameWidth) + "x" + - Integer.toString(mProfile.videoFrameHeight)); - Location loc = mLocationManager.getCurrentLocation(); - if (loc != null) { - mCurrentVideoValues.put(Video.Media.LATITUDE, loc.getLatitude()); - mCurrentVideoValues.put(Video.Media.LONGITUDE, loc.getLongitude()); - } - mVideoFilename = tmpPath; - Log.v(TAG, "New video filename: " + mVideoFilename); - } - - private void saveVideo() { - if (mVideoFileDescriptor == null) { - long duration = SystemClock.uptimeMillis() - mRecordingStartTime; - if (duration > 0) { - if (mCaptureTimeLapse) { - duration = getTimeLapseVideoLength(duration); - } - } else { - Log.w(TAG, "Video duration <= 0 : " + duration); - } - mActivity.getMediaSaveService().addVideo(mCurrentVideoFilename, - duration, mCurrentVideoValues, - mOnVideoSavedListener, mContentResolver); - } - mCurrentVideoValues = null; - } - - private void deleteVideoFile(String fileName) { - Log.v(TAG, "Deleting video " + fileName); - File f = new File(fileName); - if (!f.delete()) { - Log.v(TAG, "Could not delete " + fileName); - } - } - - private PreferenceGroup filterPreferenceScreenByIntent( - PreferenceGroup screen) { - Intent intent = mActivity.getIntent(); - if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) { - CameraSettings.removePreferenceFromScreen(screen, - CameraSettings.KEY_VIDEO_QUALITY); - } - - if (intent.hasExtra(MediaStore.EXTRA_DURATION_LIMIT)) { - CameraSettings.removePreferenceFromScreen(screen, - CameraSettings.KEY_VIDEO_QUALITY); - } - return screen; - } - - // from MediaRecorder.OnErrorListener - @Override - public void onError(MediaRecorder mr, int what, int extra) { - Log.e(TAG, "MediaRecorder error. what=" + what + ". extra=" + extra); - if (what == MediaRecorder.MEDIA_RECORDER_ERROR_UNKNOWN) { - // We may have run out of space on the sdcard. - stopVideoRecording(); - mActivity.updateStorageSpaceAndHint(); - } - } - - // from MediaRecorder.OnInfoListener - @Override - public void onInfo(MediaRecorder mr, int what, int extra) { - if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) { - if (mMediaRecorderRecording) onStopVideoRecording(); - } else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) { - if (mMediaRecorderRecording) onStopVideoRecording(); - - // Show the toast. - Toast.makeText(mActivity, R.string.video_reach_size_limit, - Toast.LENGTH_LONG).show(); - } - } - - /* - * Make sure we're not recording music playing in the background, ask the - * MediaPlaybackService to pause playback. - */ - private void pauseAudioPlayback() { - // Shamelessly copied from MediaPlaybackService.java, which - // should be public, but isn't. - Intent i = new Intent("com.android.music.musicservicecommand"); - i.putExtra("command", "pause"); - - mActivity.sendBroadcast(i); - } - - // For testing. - public boolean isRecording() { - return mMediaRecorderRecording; - } - - private void startVideoRecording() { - Log.v(TAG, "startVideoRecording"); - mUI.enablePreviewThumb(false); - mUI.setSwipingEnabled(false); - - mActivity.updateStorageSpaceAndHint(); - if (mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) { - Log.v(TAG, "Storage issue, ignore the start request"); - return; - } - - if (!mCameraDevice.waitDone()) return; - mCurrentVideoUri = null; - if (effectsActive()) { - initializeEffectsRecording(); - if (mEffectsRecorder == null) { - Log.e(TAG, "Fail to initialize effect recorder"); - return; - } - } else { - initializeRecorder(); - if (mMediaRecorder == null) { - Log.e(TAG, "Fail to initialize media recorder"); - return; - } - } - - pauseAudioPlayback(); - - if (effectsActive()) { - try { - mEffectsRecorder.startRecording(); - } catch (RuntimeException e) { - Log.e(TAG, "Could not start effects recorder. ", e); - releaseEffectsRecorder(); - return; - } - } else { - try { - mMediaRecorder.start(); // Recording is now started - } catch (RuntimeException e) { - Log.e(TAG, "Could not start media recorder. ", e); - releaseMediaRecorder(); - // If start fails, frameworks will not lock the camera for us. - mCameraDevice.lock(); - return; - } - } - - // Make sure the video recording has started before announcing - // this in accessibility. - AccessibilityUtils.makeAnnouncement(mUI.getShutterButton(), - mActivity.getString(R.string.video_recording_started)); - - // The parameters might have been altered by MediaRecorder already. - // We need to force mCameraDevice to refresh before getting it. - mCameraDevice.refreshParameters(); - // The parameters may have been changed by MediaRecorder upon starting - // recording. We need to alter the parameters if we support camcorder - // zoom. To reduce latency when setting the parameters during zoom, we - // update mParameters here once. - if (ApiHelper.HAS_ZOOM_WHEN_RECORDING) { - mParameters = mCameraDevice.getParameters(); - } - - mUI.enableCameraControls(false); - - mMediaRecorderRecording = true; - mOrientationManager.lockOrientation(); - mRecordingStartTime = SystemClock.uptimeMillis(); - mUI.showRecordingUI(true, mParameters.isZoomSupported()); - - updateRecordingTime(); - keepScreenOn(); - UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, - UsageStatistics.ACTION_CAPTURE_START, "Video"); - } - - private void showCaptureResult() { - mIsInReviewMode = true; - Bitmap bitmap = null; - if (mVideoFileDescriptor != null) { - bitmap = Thumbnail.createVideoThumbnailBitmap(mVideoFileDescriptor.getFileDescriptor(), - mDesiredPreviewWidth); - } else if (mCurrentVideoFilename != null) { - bitmap = Thumbnail.createVideoThumbnailBitmap(mCurrentVideoFilename, - mDesiredPreviewWidth); - } - if (bitmap != null) { - // MetadataRetriever already rotates the thumbnail. We should rotate - // it to match the UI orientation (and mirror if it is front-facing camera). - CameraInfo[] info = CameraHolder.instance().getCameraInfo(); - boolean mirror = (info[mCameraId].facing == CameraInfo.CAMERA_FACING_FRONT); - bitmap = Util.rotateAndMirror(bitmap, 0, mirror); - mUI.showReviewImage(bitmap); - } - - mUI.showReviewControls(); - mUI.enableCameraControls(false); - mUI.showTimeLapseUI(false); - } - - private void hideAlert() { - mUI.enableCameraControls(true); - mUI.hideReviewUI(); - if (mCaptureTimeLapse) { - mUI.showTimeLapseUI(true); - } - } - - private boolean stopVideoRecording() { - Log.v(TAG, "stopVideoRecording"); - mUI.setSwipingEnabled(true); - mUI.showSwitcher(); - - boolean fail = false; - if (mMediaRecorderRecording) { - boolean shouldAddToMediaStoreNow = false; - - try { - if (effectsActive()) { - // This is asynchronous, so we can't add to media store now because thumbnail - // may not be ready. In such case saveVideo() is called later - // through a callback from the MediaEncoderFilter to EffectsRecorder, - // and then to the VideoModule. - mEffectsRecorder.stopRecording(); - } else { - mMediaRecorder.setOnErrorListener(null); - mMediaRecorder.setOnInfoListener(null); - mMediaRecorder.stop(); - shouldAddToMediaStoreNow = true; - } - mCurrentVideoFilename = mVideoFilename; - Log.v(TAG, "stopVideoRecording: Setting current video filename: " - + mCurrentVideoFilename); - AccessibilityUtils.makeAnnouncement(mUI.getShutterButton(), - mActivity.getString(R.string.video_recording_stopped)); - } catch (RuntimeException e) { - Log.e(TAG, "stop fail", e); - if (mVideoFilename != null) deleteVideoFile(mVideoFilename); - fail = true; - } - mMediaRecorderRecording = false; - mOrientationManager.unlockOrientation(); - - // If the activity is paused, this means activity is interrupted - // during recording. Release the camera as soon as possible because - // face unlock or other applications may need to use the camera. - // However, if the effects are active, then we can only release the - // camera and cannot release the effects recorder since that will - // stop the graph. It is possible to separate out the Camera release - // part and the effects release part. However, the effects recorder - // does hold on to the camera, hence, it needs to be "disconnected" - // from the camera in the closeCamera call. - if (mPaused) { - // Closing only the camera part if effects active. Effects will - // be closed in the callback from effects. - boolean closeEffects = !effectsActive(); - closeCamera(closeEffects); - } - - mUI.showRecordingUI(false, mParameters.isZoomSupported()); - if (!mIsVideoCaptureIntent) { - mUI.enableCameraControls(true); - } - // The orientation was fixed during video recording. Now make it - // reflect the device orientation as video recording is stopped. - mUI.setOrientationIndicator(0, true); - keepScreenOnAwhile(); - if (shouldAddToMediaStoreNow) { - saveVideo(); - } - } - // always release media recorder if no effects running - if (!effectsActive()) { - releaseMediaRecorder(); - if (!mPaused) { - mCameraDevice.lock(); - mCameraDevice.waitDone(); - if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { - stopPreview(); - mUI.hideSurfaceView(); - // Switch back to use SurfaceTexture for preview. - startPreview(); - } - } - } - // Update the parameters here because the parameters might have been altered - // by MediaRecorder. - if (!mPaused) mParameters = mCameraDevice.getParameters(); - UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, - fail ? UsageStatistics.ACTION_CAPTURE_FAIL : - UsageStatistics.ACTION_CAPTURE_DONE, "Video", - SystemClock.uptimeMillis() - mRecordingStartTime); - return fail; - } - - private void resetScreenOn() { - mHandler.removeMessages(CLEAR_SCREEN_DELAY); - mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - private void keepScreenOnAwhile() { - mHandler.removeMessages(CLEAR_SCREEN_DELAY); - mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY); - } - - private void keepScreenOn() { - mHandler.removeMessages(CLEAR_SCREEN_DELAY); - mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - private static String millisecondToTimeString(long milliSeconds, boolean displayCentiSeconds) { - long seconds = milliSeconds / 1000; // round down to compute seconds - long minutes = seconds / 60; - long hours = minutes / 60; - long remainderMinutes = minutes - (hours * 60); - long remainderSeconds = seconds - (minutes * 60); - - StringBuilder timeStringBuilder = new StringBuilder(); - - // Hours - if (hours > 0) { - if (hours < 10) { - timeStringBuilder.append('0'); - } - timeStringBuilder.append(hours); - - timeStringBuilder.append(':'); - } - - // Minutes - if (remainderMinutes < 10) { - timeStringBuilder.append('0'); - } - timeStringBuilder.append(remainderMinutes); - timeStringBuilder.append(':'); - - // Seconds - if (remainderSeconds < 10) { - timeStringBuilder.append('0'); - } - timeStringBuilder.append(remainderSeconds); - - // Centi seconds - if (displayCentiSeconds) { - timeStringBuilder.append('.'); - long remainderCentiSeconds = (milliSeconds - seconds * 1000) / 10; - if (remainderCentiSeconds < 10) { - timeStringBuilder.append('0'); - } - timeStringBuilder.append(remainderCentiSeconds); - } - - return timeStringBuilder.toString(); - } - - private long getTimeLapseVideoLength(long deltaMs) { - // For better approximation calculate fractional number of frames captured. - // This will update the video time at a higher resolution. - double numberOfFrames = (double) deltaMs / mTimeBetweenTimeLapseFrameCaptureMs; - return (long) (numberOfFrames / mProfile.videoFrameRate * 1000); - } - - private void updateRecordingTime() { - if (!mMediaRecorderRecording) { - return; - } - long now = SystemClock.uptimeMillis(); - long delta = now - mRecordingStartTime; - - // Starting a minute before reaching the max duration - // limit, we'll countdown the remaining time instead. - boolean countdownRemainingTime = (mMaxVideoDurationInMs != 0 - && delta >= mMaxVideoDurationInMs - 60000); - - long deltaAdjusted = delta; - if (countdownRemainingTime) { - deltaAdjusted = Math.max(0, mMaxVideoDurationInMs - deltaAdjusted) + 999; - } - String text; - - long targetNextUpdateDelay; - if (!mCaptureTimeLapse) { - text = millisecondToTimeString(deltaAdjusted, false); - targetNextUpdateDelay = 1000; - } else { - // The length of time lapse video is different from the length - // of the actual wall clock time elapsed. Display the video length - // only in format hh:mm:ss.dd, where dd are the centi seconds. - text = millisecondToTimeString(getTimeLapseVideoLength(delta), true); - targetNextUpdateDelay = mTimeBetweenTimeLapseFrameCaptureMs; - } - - mUI.setRecordingTime(text); - - if (mRecordingTimeCountsDown != countdownRemainingTime) { - // Avoid setting the color on every update, do it only - // when it needs changing. - mRecordingTimeCountsDown = countdownRemainingTime; - - int color = mActivity.getResources().getColor(countdownRemainingTime - ? R.color.recording_time_remaining_text - : R.color.recording_time_elapsed_text); - - mUI.setRecordingTimeTextColor(color); - } - - long actualNextUpdateDelay = targetNextUpdateDelay - (delta % targetNextUpdateDelay); - mHandler.sendEmptyMessageDelayed( - UPDATE_RECORD_TIME, actualNextUpdateDelay); - } - - private static boolean isSupported(String value, List supported) { - return supported == null ? false : supported.indexOf(value) >= 0; - } - - @SuppressWarnings("deprecation") - private void setCameraParameters() { - mParameters.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight); - int[] fpsRange = Util.getMaxPreviewFpsRange(mParameters); - if (fpsRange.length > 0) { - mParameters.setPreviewFpsRange( - fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX], - fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]); - } else { - mParameters.setPreviewFrameRate(mProfile.videoFrameRate); - } - - // Set flash mode. - String flashMode; - if (mUI.isVisible()) { - flashMode = mPreferences.getString( - CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE, - mActivity.getString(R.string.pref_camera_video_flashmode_default)); - } else { - flashMode = Parameters.FLASH_MODE_OFF; - } - List supportedFlash = mParameters.getSupportedFlashModes(); - if (isSupported(flashMode, supportedFlash)) { - mParameters.setFlashMode(flashMode); - } else { - flashMode = mParameters.getFlashMode(); - if (flashMode == null) { - flashMode = mActivity.getString( - R.string.pref_camera_flashmode_no_flash); - } - } - - // Set white balance parameter. - String whiteBalance = mPreferences.getString( - CameraSettings.KEY_WHITE_BALANCE, - mActivity.getString(R.string.pref_camera_whitebalance_default)); - if (isSupported(whiteBalance, - mParameters.getSupportedWhiteBalance())) { - mParameters.setWhiteBalance(whiteBalance); - } else { - whiteBalance = mParameters.getWhiteBalance(); - if (whiteBalance == null) { - whiteBalance = Parameters.WHITE_BALANCE_AUTO; - } - } - - // Set zoom. - if (mParameters.isZoomSupported()) { - mParameters.setZoom(mZoomValue); - } - - // Set continuous autofocus. - List supportedFocus = mParameters.getSupportedFocusModes(); - if (isSupported(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO, supportedFocus)) { - mParameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); - } - - mParameters.set(Util.RECORDING_HINT, Util.TRUE); - - // Enable video stabilization. Convenience methods not available in API - // level <= 14 - String vstabSupported = mParameters.get("video-stabilization-supported"); - if ("true".equals(vstabSupported)) { - mParameters.set("video-stabilization", "true"); - } - - // Set picture size. - // The logic here is different from the logic in still-mode camera. - // There we determine the preview size based on the picture size, but - // here we determine the picture size based on the preview size. - List supported = mParameters.getSupportedPictureSizes(); - Size optimalSize = Util.getOptimalVideoSnapshotPictureSize(supported, - (double) mDesiredPreviewWidth / mDesiredPreviewHeight); - Size original = mParameters.getPictureSize(); - if (!original.equals(optimalSize)) { - mParameters.setPictureSize(optimalSize.width, optimalSize.height); - } - Log.v(TAG, "Video snapshot size is " + optimalSize.width + "x" + - optimalSize.height); - - // Set JPEG quality. - int jpegQuality = CameraProfile.getJpegEncodingQualityParameter(mCameraId, - CameraProfile.QUALITY_HIGH); - mParameters.setJpegQuality(jpegQuality); - - mCameraDevice.setParameters(mParameters); - // Keep preview size up to date. - mParameters = mCameraDevice.getParameters(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_EFFECT_BACKDROPPER: - if (resultCode == Activity.RESULT_OK) { - // onActivityResult() runs before onResume(), so this parameter will be - // seen by startPreview from onResume() - mEffectUriFromGallery = data.getData().toString(); - Log.v(TAG, "Received URI from gallery: " + mEffectUriFromGallery); - mResetEffect = false; - } else { - mEffectUriFromGallery = null; - Log.w(TAG, "No URI from gallery"); - mResetEffect = true; - } - break; - } - } - - @Override - public void onEffectsUpdate(int effectId, int effectMsg) { - Log.v(TAG, "onEffectsUpdate. Effect Message = " + effectMsg); - if (effectMsg == EffectsRecorder.EFFECT_MSG_EFFECTS_STOPPED) { - // Effects have shut down. Hide learning message if any, - // and restart regular preview. - checkQualityAndStartPreview(); - } else if (effectMsg == EffectsRecorder.EFFECT_MSG_RECORDING_DONE) { - // This follows the codepath from onStopVideoRecording. - if (mEffectsDisplayResult) { - saveVideo(); - if (mIsVideoCaptureIntent) { - if (mQuickCapture) { - doReturnToCaller(true); - } else { - showCaptureResult(); - } - } - } - mEffectsDisplayResult = false; - // In onPause, these were not called if the effects were active. We - // had to wait till the effects recording is complete to do this. - if (mPaused) { - closeVideoFileDescriptor(); - } - } else if (effectMsg == EffectsRecorder.EFFECT_MSG_PREVIEW_RUNNING) { - // Enable the shutter button once the preview is complete. - mUI.enableShutter(true); - } - // In onPause, this was not called if the effects were active. We had to - // wait till the effects completed to do this. - if (mPaused) { - Log.v(TAG, "OnEffectsUpdate: closing effects if activity paused"); - closeEffects(); - } - } - - public void onCancelBgTraining(View v) { - // Write default effect out to shared prefs - writeDefaultEffectToPrefs(); - // Tell VideoCamer to re-init based on new shared pref values. - onSharedPreferenceChanged(); - } - - @Override - public synchronized void onEffectsError(Exception exception, String fileName) { - // TODO: Eventually we may want to show the user an error dialog, and then restart the - // camera and encoder gracefully. For now, we just delete the file and bail out. - if (fileName != null && new File(fileName).exists()) { - deleteVideoFile(fileName); - } - try { - if (Class.forName("android.filterpacks.videosink.MediaRecorderStopException") - .isInstance(exception)) { - Log.w(TAG, "Problem recoding video file. Removing incomplete file."); - return; - } - } catch (ClassNotFoundException ex) { - Log.w(TAG, ex); - } - throw new RuntimeException("Error during recording!", exception); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - Log.v(TAG, "onConfigurationChanged"); - setDisplayOrientation(); - } - - @Override - public void onOverriddenPreferencesClicked() { - } - - @Override - // TODO: Delete this after old camera code is removed - public void onRestorePreferencesClicked() { - } - - private boolean effectsActive() { - return (mEffectType != EffectsRecorder.EFFECT_NONE); - } - - @Override - public void onSharedPreferenceChanged() { - // ignore the events after "onPause()" or preview has not started yet - if (mPaused) return; - synchronized (mPreferences) { - // If mCameraDevice is not ready then we can set the parameter in - // startPreview(). - if (mCameraDevice == null) return; - - boolean recordLocation = RecordLocationPreference.get( - mPreferences, mContentResolver); - mLocationManager.recordLocation(recordLocation); - - // Check if the current effects selection has changed - if (updateEffectSelection()) return; - - readVideoPreferences(); - mUI.showTimeLapseUI(mCaptureTimeLapse); - // We need to restart the preview if preview size is changed. - Size size = mParameters.getPreviewSize(); - if (size.width != mDesiredPreviewWidth - || size.height != mDesiredPreviewHeight) { - if (!effectsActive()) { - stopPreview(); - } else { - mEffectsRecorder.release(); - mEffectsRecorder = null; - } - resizeForPreviewAspectRatio(); - startPreview(); // Parameters will be set in startPreview(). - } else { - setCameraParameters(); - } - mUI.updateOnScreenIndicators(mParameters, mPreferences); - } - } - - protected void setCameraId(int cameraId) { - ListPreference pref = mPreferenceGroup.findPreference(CameraSettings.KEY_CAMERA_ID); - pref.setValue("" + cameraId); - } - - private void switchCamera() { - if (mPaused) return; - - Log.d(TAG, "Start to switch camera."); - mCameraId = mPendingSwitchCameraId; - mPendingSwitchCameraId = -1; - setCameraId(mCameraId); - - closeCamera(); - mUI.collapseCameraControls(); - // Restart the camera and initialize the UI. From onCreate. - mPreferences.setLocalId(mActivity, mCameraId); - CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - openCamera(); - readVideoPreferences(); - startPreview(); - initializeVideoSnapshot(); - resizeForPreviewAspectRatio(); - initializeVideoControl(); - - // From onResume - mZoomValue = 0; - mUI.initializeZoom(mParameters); - mUI.setOrientationIndicator(0, false); - - // Start switch camera animation. Post a message because - // onFrameAvailable from the old camera may already exist. - mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION); - mUI.updateOnScreenIndicators(mParameters, mPreferences); - } - - // Preview texture has been copied. Now camera can be released and the - // animation can be started. - @Override - public void onPreviewTextureCopied() { - mHandler.sendEmptyMessage(SWITCH_CAMERA); - } - - @Override - public void onCaptureTextureCopied() { - } - - private boolean updateEffectSelection() { - int previousEffectType = mEffectType; - Object previousEffectParameter = mEffectParameter; - mEffectType = CameraSettings.readEffectType(mPreferences); - mEffectParameter = CameraSettings.readEffectParameter(mPreferences); - - if (mEffectType == previousEffectType) { - if (mEffectType == EffectsRecorder.EFFECT_NONE) return false; - if (mEffectParameter.equals(previousEffectParameter)) return false; - } - Log.v(TAG, "New effect selection: " + mPreferences.getString( - CameraSettings.KEY_VIDEO_EFFECT, "none")); - - if (mEffectType == EffectsRecorder.EFFECT_NONE) { - // Stop effects and return to normal preview - mEffectsRecorder.stopPreview(); - mPreviewing = false; - return true; - } - if (mEffectType == EffectsRecorder.EFFECT_BACKDROPPER && - ((String) mEffectParameter).equals(EFFECT_BG_FROM_GALLERY)) { - // Request video from gallery to use for background - Intent i = new Intent(Intent.ACTION_PICK); - i.setDataAndType(Video.Media.EXTERNAL_CONTENT_URI, - "video/*"); - i.putExtra(Intent.EXTRA_LOCAL_ONLY, true); - mActivity.startActivityForResult(i, REQUEST_EFFECT_BACKDROPPER); - return true; - } - if (previousEffectType == EffectsRecorder.EFFECT_NONE) { - // Stop regular preview and start effects. - stopPreview(); - checkQualityAndStartPreview(); - } else { - // Switch currently running effect - mEffectsRecorder.setEffect(mEffectType, mEffectParameter); - } - return true; - } - - // Verifies that the current preview view size is correct before starting - // preview. If not, resets the surface texture and resizes the view. - private void checkQualityAndStartPreview() { - readVideoPreferences(); - mUI.showTimeLapseUI(mCaptureTimeLapse); - Size size = mParameters.getPreviewSize(); - if (size.width != mDesiredPreviewWidth - || size.height != mDesiredPreviewHeight) { - resizeForPreviewAspectRatio(); - } - // Start up preview again - startPreview(); - } - - private void initializeVideoSnapshot() { - if (mParameters == null) return; - if (Util.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) { - // Show the tap to focus toast if this is the first start. - if (mPreferences.getBoolean( - CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, true)) { - // Delay the toast for one second to wait for orientation. - mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_SNAPSHOT_TOAST, 1000); - } - } - } - - void showVideoSnapshotUI(boolean enabled) { - if (mParameters == null) return; - if (Util.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) { - if (enabled) { - // TODO: ((CameraScreenNail) mActivity.mCameraScreenNail).animateCapture(mDisplayRotation); - } else { - mUI.showPreviewBorder(enabled); - } - mUI.enableShutter(!enabled); - } - } - - @Override - public void updateCameraAppView() { - if (!mPreviewing || mParameters.getFlashMode() == null) return; - - // When going to and back from gallery, we need to turn off/on the flash. - if (!mUI.isVisible()) { - if (mParameters.getFlashMode().equals(Parameters.FLASH_MODE_OFF)) { - mRestoreFlash = false; - return; - } - mRestoreFlash = true; - setCameraParameters(); - } else if (mRestoreFlash) { - mRestoreFlash = false; - setCameraParameters(); - } - } - - @Override - public void onSwitchMode(boolean toCamera) { - mUI.onSwitchMode(toCamera); - } - - private final class JpegPictureCallback implements PictureCallback { - Location mLocation; - - public JpegPictureCallback(Location loc) { - mLocation = loc; - } - - @Override - public void onPictureTaken(byte [] jpegData, android.hardware.Camera camera) { - Log.v(TAG, "onPictureTaken"); - mSnapshotInProgress = false; - showVideoSnapshotUI(false); - storeImage(jpegData, mLocation); - } - } - - private void storeImage(final byte[] data, Location loc) { - long dateTaken = System.currentTimeMillis(); - String title = Util.createJpegName(dateTaken); - ExifInterface exif = Exif.getExif(data); - int orientation = Exif.getOrientation(exif); - Size s = mParameters.getPictureSize(); - mActivity.getMediaSaveService().addImage( - data, title, dateTaken, loc, s.width, s.height, orientation, - exif, mOnPhotoSavedListener, mContentResolver); - } - - private boolean resetEffect() { - if (mResetEffect) { - String value = mPreferences.getString(CameraSettings.KEY_VIDEO_EFFECT, - mPrefVideoEffectDefault); - if (!mPrefVideoEffectDefault.equals(value)) { - writeDefaultEffectToPrefs(); - return true; - } - } - mResetEffect = true; - return false; - } - - private String convertOutputFormatToMimeType(int outputFileFormat) { - if (outputFileFormat == MediaRecorder.OutputFormat.MPEG_4) { - return "video/mp4"; - } - return "video/3gpp"; - } - - private String convertOutputFormatToFileExt(int outputFileFormat) { - if (outputFileFormat == MediaRecorder.OutputFormat.MPEG_4) { - return ".mp4"; - } - return ".3gp"; - } - - private void closeVideoFileDescriptor() { - if (mVideoFileDescriptor != null) { - try { - mVideoFileDescriptor.close(); - } catch (IOException e) { - Log.e(TAG, "Fail to close fd", e); - } - mVideoFileDescriptor = null; - } - } - - private void showTapToSnapshotToast() { - new RotateTextToast(mActivity, R.string.video_snapshot_hint, 0) - .show(); - // Clear the preference. - Editor editor = mPreferences.edit(); - editor.putBoolean(CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, false); - editor.apply(); - } - - @Override - public boolean updateStorageHintOnResume() { - return true; - } - - // required by OnPreferenceChangedListener - @Override - public void onCameraPickerClicked(int cameraId) { - if (mPaused || mPendingSwitchCameraId != -1) return; - - mPendingSwitchCameraId = cameraId; - Log.d(TAG, "Start to copy texture."); - // We need to keep a preview frame for the animation before - // releasing the camera. This will trigger onPreviewTextureCopied. - // TODO: ((CameraScreenNail) mActivity.mCameraScreenNail).copyTexture(); - // Disable all camera controls. - mSwitchingCamera = true; - - } - - @Override - public boolean needsSwitcher() { - return !mIsVideoCaptureIntent; - } - - @Override - public boolean needsPieMenu() { - return true; - } - - @Override - public void onShowSwitcherPopup() { - mUI.onShowSwitcherPopup(); - } - - @Override - public void onMediaSaveServiceConnected(MediaSaveService s) { - // do nothing. - } -} diff --git a/src/com/android/camera/NewVideoUI.java b/src/com/android/camera/NewVideoUI.java deleted file mode 100644 index b0c9c507f..000000000 --- a/src/com/android/camera/NewVideoUI.java +++ /dev/null @@ -1,713 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.graphics.Bitmap; -import android.graphics.Matrix; -import android.graphics.SurfaceTexture; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.Size; -import android.os.Handler; -import android.os.Message; -import android.util.Log; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.TextureView; -import android.view.TextureView.SurfaceTextureListener; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnLayoutChangeListener; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.FrameLayout.LayoutParams; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.android.camera.CameraPreference.OnPreferenceChangedListener; -import com.android.camera.ui.AbstractSettingPopup; -import com.android.camera.ui.CameraControls; -import com.android.camera.ui.CameraSwitcher; -import com.android.camera.ui.NewCameraRootView; -import com.android.camera.ui.PieRenderer; -import com.android.camera.ui.RenderOverlay; -import com.android.camera.ui.RotateLayout; -import com.android.camera.ui.ZoomRenderer; -import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; - -import java.util.List; - -public class NewVideoUI implements PieRenderer.PieListener, - NewPreviewGestures.SingleTapListener, - NewCameraRootView.MyDisplayListener, - SurfaceTextureListener, SurfaceHolder.Callback { - private final static String TAG = "CAM_VideoUI"; - private static final int UPDATE_TRANSFORM_MATRIX = 1; - // module fields - private NewCameraActivity mActivity; - private View mRootView; - private TextureView mTextureView; - // An review image having same size as preview. It is displayed when - // recording is stopped in capture intent. - private ImageView mReviewImage; - private View mReviewCancelButton; - private View mReviewDoneButton; - private View mReviewPlayButton; - private ShutterButton mShutterButton; - private CameraSwitcher mSwitcher; - private TextView mRecordingTimeView; - private LinearLayout mLabelsLinearLayout; - private View mTimeLapseLabel; - private RenderOverlay mRenderOverlay; - private PieRenderer mPieRenderer; - private NewVideoMenu mVideoMenu; - private CameraControls mCameraControls; - private AbstractSettingPopup mPopup; - private ZoomRenderer mZoomRenderer; - private NewPreviewGestures mGestures; - private View mMenuButton; - private View mBlocker; - private OnScreenIndicators mOnScreenIndicators; - private RotateLayout mRecordingTimeRect; - private final Object mLock = new Object(); - private SurfaceTexture mSurfaceTexture; - private VideoController mController; - private int mZoomMax; - private List mZoomRatios; - private View mPreviewThumb; - - private SurfaceView mSurfaceView = null; - private int mPreviewWidth = 0; - private int mPreviewHeight = 0; - private float mSurfaceTextureUncroppedWidth; - private float mSurfaceTextureUncroppedHeight; - private float mAspectRatio = 4f / 3f; - private Matrix mMatrix = null; - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case UPDATE_TRANSFORM_MATRIX: - setTransformMatrix(mPreviewWidth, mPreviewHeight); - break; - default: - break; - } - } - }; - private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, - int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { - int width = right - left; - int height = bottom - top; - // Full-screen screennail - int w = width; - int h = height; - if (Util.getDisplayRotation(mActivity) % 180 != 0) { - w = height; - h = width; - } - if (mPreviewWidth != width || mPreviewHeight != height) { - mPreviewWidth = width; - mPreviewHeight = height; - onScreenSizeChanged(width, height, w, h); - } - } - }; - - public NewVideoUI(NewCameraActivity activity, VideoController controller, View parent) { - mActivity = activity; - mController = controller; - mRootView = parent; - mActivity.getLayoutInflater().inflate(R.layout.new_video_module, (ViewGroup) mRootView, true); - mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content); - mTextureView.setSurfaceTextureListener(this); - mRootView.addOnLayoutChangeListener(mLayoutListener); - ((NewCameraRootView) mRootView).setDisplayChangeListener(this); - mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button); - mSwitcher = (CameraSwitcher) mRootView.findViewById(R.id.camera_switcher); - mSwitcher.setCurrentIndex(1); - mSwitcher.setSwitchListener((CameraSwitchListener) mActivity); - initializeMiscControls(); - initializeControlByIntent(); - initializeOverlay(); - } - - - public void initializeSurfaceView() { - mSurfaceView = new SurfaceView(mActivity); - ((ViewGroup) mRootView).addView(mSurfaceView, 0); - mSurfaceView.getHolder().addCallback(this); - } - - private void initializeControlByIntent() { - mBlocker = mActivity.findViewById(R.id.blocker); - mMenuButton = mActivity.findViewById(R.id.menu); - mMenuButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mPieRenderer != null) { - mPieRenderer.showInCenter(); - } - } - }); - - mCameraControls = (CameraControls) mActivity.findViewById(R.id.camera_controls); - mOnScreenIndicators = new OnScreenIndicators(mActivity, - mActivity.findViewById(R.id.on_screen_indicators)); - mOnScreenIndicators.resetToDefault(); - if (mController.isVideoCaptureIntent()) { - hideSwitcher(); - mActivity.getLayoutInflater().inflate(R.layout.review_module_control, (ViewGroup) mCameraControls); - // Cannot use RotateImageView for "done" and "cancel" button because - // the tablet layout uses RotateLayout, which cannot be cast to - // RotateImageView. - mReviewDoneButton = mActivity.findViewById(R.id.btn_done); - mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel); - mReviewPlayButton = mActivity.findViewById(R.id.btn_play); - mReviewCancelButton.setVisibility(View.VISIBLE); - mReviewDoneButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mController.onReviewDoneClicked(v); - } - }); - mReviewCancelButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mController.onReviewCancelClicked(v); - } - }); - mReviewPlayButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mController.onReviewPlayClicked(v); - } - }); - } - } - - public void setPreviewSize(int width, int height) { - if (width == 0 || height == 0) { - Log.w(TAG, "Preview size should not be 0."); - return; - } - if (width > height) { - mAspectRatio = (float) width / height; - } else { - mAspectRatio = (float) height / width; - } - mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX); - } - - public int getPreviewWidth() { - return mPreviewWidth; - } - - public int getPreviewHeight() { - return mPreviewHeight; - } - - public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { - setTransformMatrix(width, height); - } - - private void setTransformMatrix(int width, int height) { - mMatrix = mTextureView.getTransform(mMatrix); - int orientation = Util.getDisplayRotation(mActivity); - float scaleX = 1f, scaleY = 1f; - float scaledTextureWidth, scaledTextureHeight; - if (width > height) { - scaledTextureWidth = Math.max(width, - (int) (height * mAspectRatio)); - scaledTextureHeight = Math.max(height, - (int)(width / mAspectRatio)); - } else { - scaledTextureWidth = Math.max(width, - (int) (height / mAspectRatio)); - scaledTextureHeight = Math.max(height, - (int) (width * mAspectRatio)); - } - - if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || - mSurfaceTextureUncroppedHeight != scaledTextureHeight) { - mSurfaceTextureUncroppedWidth = scaledTextureWidth; - mSurfaceTextureUncroppedHeight = scaledTextureHeight; - } - scaleX = scaledTextureWidth / width; - scaleY = scaledTextureHeight / height; - mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2); - mTextureView.setTransform(mMatrix); - - if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) { - LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams(); - lp.width = (int) mSurfaceTextureUncroppedWidth; - lp.height = (int) mSurfaceTextureUncroppedHeight; - lp.gravity = Gravity.CENTER; - mSurfaceView.requestLayout(); - } - } - - public void hideUI() { - mCameraControls.setVisibility(View.INVISIBLE); - mSwitcher.closePopup(); - } - - public void showUI() { - mCameraControls.setVisibility(View.VISIBLE); - } - - public void hideSwitcher() { - mSwitcher.closePopup(); - mSwitcher.setVisibility(View.INVISIBLE); - } - - public void showSwitcher() { - mSwitcher.setVisibility(View.VISIBLE); - } - - public boolean collapseCameraControls() { - boolean ret = false; - if (mPopup != null) { - dismissPopup(false); - ret = true; - } - return ret; - } - - public boolean removeTopLevelPopup() { - if (mPopup != null) { - dismissPopup(true); - return true; - } - return false; - } - - public void enableCameraControls(boolean enable) { - if (mGestures != null) { - mGestures.setZoomOnly(!enable); - } - if (mPieRenderer != null && mPieRenderer.showsItems()) { - mPieRenderer.hide(); - } - } - - public void overrideSettings(final String... keyvalues) { - mVideoMenu.overrideSettings(keyvalues); - } - - public void setOrientationIndicator(int orientation, boolean animation) { - if (mGestures != null) { - mGestures.setOrientation(orientation); - } - // We change the orientation of the linearlayout only for phone UI - // because when in portrait the width is not enough. - if (mLabelsLinearLayout != null) { - if (((orientation / 90) & 1) == 0) { - mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL); - } else { - mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL); - } - } - mRecordingTimeRect.setOrientation(0, animation); - } - - public SurfaceHolder getSurfaceHolder() { - return mSurfaceView.getHolder(); - } - - public void hideSurfaceView() { - mSurfaceView.setVisibility(View.GONE); - mTextureView.setVisibility(View.VISIBLE); - setTransformMatrix(mPreviewWidth, mPreviewHeight); - } - - public void showSurfaceView() { - mSurfaceView.setVisibility(View.VISIBLE); - mTextureView.setVisibility(View.GONE); - setTransformMatrix(mPreviewWidth, mPreviewHeight); - } - - private void initializeOverlay() { - mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay); - if (mPieRenderer == null) { - mPieRenderer = new PieRenderer(mActivity); - mVideoMenu = new NewVideoMenu(mActivity, this, mPieRenderer); - mPieRenderer.setPieListener(this); - } - mRenderOverlay.addRenderer(mPieRenderer); - if (mZoomRenderer == null) { - mZoomRenderer = new ZoomRenderer(mActivity); - } - mRenderOverlay.addRenderer(mZoomRenderer); - if (mGestures == null) { - mGestures = new NewPreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer); - mRenderOverlay.setGestures(mGestures); - } - mGestures.setRenderOverlay(mRenderOverlay); - - mPreviewThumb = mActivity.findViewById(R.id.preview_thumb); - mPreviewThumb.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - // TODO: Go to filmstrip view - } - }); - } - - public void setPrefChangedListener(OnPreferenceChangedListener listener) { - mVideoMenu.setListener(listener); - } - - private void initializeMiscControls() { - mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image); - mShutterButton.setImageResource(R.drawable.btn_new_shutter_video); - mShutterButton.setOnShutterButtonListener(mController); - mShutterButton.setVisibility(View.VISIBLE); - mShutterButton.requestFocus(); - mShutterButton.enableTouch(true); - mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time); - mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect); - mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label); - // The R.id.labels can only be found in phone layout. - // That is, mLabelsLinearLayout should be null in tablet layout. - mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels); - } - - public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) { - mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode()); - boolean location = RecordLocationPreference.get( - prefs, mActivity.getContentResolver()); - mOnScreenIndicators.updateLocationIndicator(location); - - } - - public void setAspectRatio(double ratio) { - // mPreviewFrameLayout.setAspectRatio(ratio); - } - - public void showTimeLapseUI(boolean enable) { - if (mTimeLapseLabel != null) { - mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE); - } - } - - private void openMenu() { - if (mPieRenderer != null) { - mPieRenderer.showInCenter(); - } - } - - public void showPopup(AbstractSettingPopup popup) { - hideUI(); - mBlocker.setVisibility(View.INVISIBLE); - setShowMenu(false); - mPopup = popup; - mPopup.setVisibility(View.VISIBLE); - FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, - LayoutParams.WRAP_CONTENT); - lp.gravity = Gravity.CENTER; - ((FrameLayout) mRootView).addView(mPopup, lp); - } - - public void dismissPopup(boolean topLevelOnly) { - dismissPopup(topLevelOnly, true); - } - - public void dismissPopup(boolean topLevelPopupOnly, boolean fullScreen) { - // In review mode, we do not want to bring up the camera UI - if (mController.isInReviewMode()) return; - - if (fullScreen) { - showUI(); - mBlocker.setVisibility(View.VISIBLE); - } - setShowMenu(fullScreen); - if (mPopup != null) { - ((FrameLayout) mRootView).removeView(mPopup); - mPopup = null; - } - mVideoMenu.popupDismissed(topLevelPopupOnly); - } - - public void onShowSwitcherPopup() { - hidePieRenderer(); - } - - public boolean hidePieRenderer() { - if (mPieRenderer != null && mPieRenderer.showsItems()) { - mPieRenderer.hide(); - return true; - } - return false; - } - - // disable preview gestures after shutter is pressed - public void setShutterPressed(boolean pressed) { - if (mGestures == null) return; - mGestures.setEnabled(!pressed); - } - - public void enableShutter(boolean enable) { - if (mShutterButton != null) { - mShutterButton.setEnabled(enable); - } - } - - // PieListener - @Override - public void onPieOpened(int centerX, int centerY) { - setSwipingEnabled(false); - dismissPopup(false, true); - } - - @Override - public void onPieClosed() { - setSwipingEnabled(true); - } - - public void setSwipingEnabled(boolean enable) { - mActivity.setSwipingEnabled(enable); - } - - public void showPreviewBorder(boolean enable) { - // TODO: mPreviewFrameLayout.showBorder(enable); - } - - // SingleTapListener - // Preview area is touched. Take a picture. - @Override - public void onSingleTapUp(View view, int x, int y) { - mController.onSingleTapUp(view, x, y); - } - - public void showRecordingUI(boolean recording, boolean zoomSupported) { - mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE); - mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE); - if (recording) { - mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording); - hideSwitcher(); - mRecordingTimeView.setText(""); - mRecordingTimeView.setVisibility(View.VISIBLE); - // The camera is not allowed to be accessed in older api levels during - // recording. It is therefore necessary to hide the zoom UI on older - // platforms. - // See the documentation of android.media.MediaRecorder.start() for - // further explanation. - if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) { - // TODO: disable zoom UI here. - } - } else { - mShutterButton.setImageResource(R.drawable.btn_new_shutter_video); - showSwitcher(); - mRecordingTimeView.setVisibility(View.GONE); - if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) { - // TODO: enable zoom UI here. - } - } - } - - public void showReviewImage(Bitmap bitmap) { - mReviewImage.setImageBitmap(bitmap); - mReviewImage.setVisibility(View.VISIBLE); - } - - public void showReviewControls() { - Util.fadeOut(mShutterButton); - Util.fadeIn(mReviewDoneButton); - Util.fadeIn(mReviewPlayButton); - mReviewImage.setVisibility(View.VISIBLE); - mMenuButton.setVisibility(View.GONE); - mOnScreenIndicators.setVisibility(View.GONE); - } - - public void hideReviewUI() { - mReviewImage.setVisibility(View.GONE); - mShutterButton.setEnabled(true); - mMenuButton.setVisibility(View.VISIBLE); - mOnScreenIndicators.setVisibility(View.VISIBLE); - Util.fadeOut(mReviewDoneButton); - Util.fadeOut(mReviewPlayButton); - Util.fadeIn(mShutterButton); - } - - private void setShowMenu(boolean show) { - if (mOnScreenIndicators != null) { - mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE); - } - if (mMenuButton != null) { - mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE); - } - } - - public void onSwitchMode(boolean toCamera) { - if (toCamera) { - showUI(); - } else { - hideUI(); - } - if (mGestures != null) { - mGestures.setEnabled(toCamera); - } - if (mPopup != null) { - dismissPopup(false, toCamera); - } - if (mRenderOverlay != null) { - // this can not happen in capture mode - mRenderOverlay.setVisibility(toCamera ? View.VISIBLE : View.GONE); - } - setShowMenu(toCamera); - } - - public void initializePopup(PreferenceGroup pref) { - mVideoMenu.initialize(pref); - } - - public void initializeZoom(Parameters param) { - if (param == null || !param.isZoomSupported()) { - mGestures.setZoomEnabled(false); - return; - } - mGestures.setZoomEnabled(true); - mZoomMax = param.getMaxZoom(); - mZoomRatios = param.getZoomRatios(); - // Currently we use immediate zoom for fast zooming to get better UX and - // there is no plan to take advantage of the smooth zoom. - mZoomRenderer.setZoomMax(mZoomMax); - mZoomRenderer.setZoom(param.getZoom()); - mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom())); - mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener()); - } - - public void clickShutter() { - mShutterButton.performClick(); - } - - public void pressShutter(boolean pressed) { - mShutterButton.setPressed(pressed); - } - - public View getShutterButton() { - return mShutterButton; - } - - public void setRecordingTime(String text) { - mRecordingTimeView.setText(text); - } - - public void setRecordingTimeTextColor(int color) { - mRecordingTimeView.setTextColor(color); - } - - public boolean isVisible() { - return mTextureView.getVisibility() == View.VISIBLE; - } - - public void onDisplayChanged() { - mCameraControls.checkLayoutFlip(); - mController.updateCameraOrientation(); - } - - /** - * Enable or disable the preview thumbnail for click events. - */ - public void enablePreviewThumb(boolean enabled) { - if (enabled) { - mPreviewThumb.setVisibility(View.VISIBLE); - } else { - mPreviewThumb.setVisibility(View.GONE); - } - } - - private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { - @Override - public void onZoomValueChanged(int index) { - int newZoom = mController.onZoomChanged(index); - if (mZoomRenderer != null) { - mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom)); - } - } - - @Override - public void onZoomStart() { - } - - @Override - public void onZoomEnd() { - } - } - - public SurfaceTexture getSurfaceTexture() { - synchronized (mLock) { - if (mSurfaceTexture == null) { - try { - mLock.wait(); - } catch (InterruptedException e) { - Log.w(TAG, "Unexpected interruption when waiting to get surface texture"); - } - } - } - return mSurfaceTexture; - } - - // SurfaceTexture callbacks - @Override - public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { - synchronized (mLock) { - mSurfaceTexture = surface; - mLock.notifyAll(); - } - } - - @Override - public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { - mSurfaceTexture = null; - mController.stopPreview(); - Log.d(TAG, "surfaceTexture is destroyed"); - return true; - } - - @Override - public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { - } - - @Override - public void onSurfaceTextureUpdated(SurfaceTexture surface) { - } - - // SurfaceHolder callbacks - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.v(TAG, "Surface changed. width=" + width + ". height=" + height); - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - Log.v(TAG, "Surface created"); - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - Log.v(TAG, "Surface destroyed"); - mController.stopPreview(); - } -} diff --git a/src/com/android/camera/PanoramaModule.java b/src/com/android/camera/PanoramaModule.java deleted file mode 100644 index 007ea7a4c..000000000 --- a/src/com/android/camera/PanoramaModule.java +++ /dev/null @@ -1,1304 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.annotation.TargetApi; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.ImageFormat; -import android.graphics.Matrix; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.SurfaceTexture; -import android.graphics.YuvImage; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.Size; -import android.location.Location; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.Message; -import android.os.PowerManager; -import android.util.Log; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.OrientationEventListener; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.android.camera.CameraManager.CameraProxy; -import com.android.camera.ui.LayoutChangeNotifier; -import com.android.camera.ui.LayoutNotifyView; -import com.android.camera.ui.PopupManager; -import com.android.camera.ui.Rotatable; -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.exif.ExifInterface; -import com.android.gallery3d.exif.ExifTag; -import com.android.gallery3d.ui.GLRootView; -import com.android.gallery3d.util.UsageStatistics; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.TimeZone; - -/** - * Activity to handle panorama capturing. - */ -@TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) // uses SurfaceTexture -public class PanoramaModule implements CameraModule, - SurfaceTexture.OnFrameAvailableListener, - ShutterButton.OnShutterButtonListener, - LayoutChangeNotifier.Listener { - - public static final int DEFAULT_SWEEP_ANGLE = 160; - public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL; - public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720; - - private static final int MSG_LOW_RES_FINAL_MOSAIC_READY = 1; - private static final int MSG_GENERATE_FINAL_MOSAIC_ERROR = 2; - private static final int MSG_END_DIALOG_RESET_TO_PREVIEW = 3; - private static final int MSG_CLEAR_SCREEN_DELAY = 4; - private static final int MSG_CONFIG_MOSAIC_PREVIEW = 5; - private static final int MSG_RESET_TO_PREVIEW = 6; - - private static final int SCREEN_DELAY = 2 * 60 * 1000; - - private static final String TAG = "CAM PanoModule"; - private static final int PREVIEW_STOPPED = 0; - private static final int PREVIEW_ACTIVE = 1; - private static final int CAPTURE_STATE_VIEWFINDER = 0; - private static final int CAPTURE_STATE_MOSAIC = 1; - // The unit of speed is degrees per frame. - private static final float PANNING_SPEED_THRESHOLD = 2.5f; - - private ContentResolver mContentResolver; - - private GLRootView mGLRootView; - private ViewGroup mPanoLayout; - private LinearLayout mCaptureLayout; - private View mReviewLayout; - private ImageView mReview; - private View mCaptureIndicator; - private PanoProgressBar mPanoProgressBar; - private PanoProgressBar mSavingProgressBar; - private Matrix mProgressDirectionMatrix = new Matrix(); - private float[] mProgressAngle = new float[2]; - private LayoutNotifyView mPreviewArea; - private View mLeftIndicator; - private View mRightIndicator; - private MosaicPreviewRenderer mMosaicPreviewRenderer; - private Object mRendererLock = new Object(); - private TextView mTooFastPrompt; - private ShutterButton mShutterButton; - private Object mWaitObject = new Object(); - - private String mPreparePreviewString; - private String mDialogTitle; - private String mDialogOkString; - private String mDialogPanoramaFailedString; - private String mDialogWaitingPreviousString; - - private int mIndicatorColor; - private int mIndicatorColorFast; - private int mReviewBackground; - - private boolean mUsingFrontCamera; - private int mPreviewWidth; - private int mPreviewHeight; - private int mCameraState; - private int mCaptureState; - private PowerManager.WakeLock mPartialWakeLock; - private MosaicFrameProcessor mMosaicFrameProcessor; - private boolean mMosaicFrameProcessorInitialized; - private AsyncTask mWaitProcessorTask; - private long mTimeTaken; - private Handler mMainHandler; - private SurfaceTexture mCameraTexture; - private boolean mThreadRunning; - private boolean mCancelComputation; - private float mHorizontalViewAngle; - private float mVerticalViewAngle; - - // Prefer FOCUS_MODE_INFINITY to FOCUS_MODE_CONTINUOUS_VIDEO because of - // getting a better image quality by the former. - private String mTargetFocusMode = Parameters.FOCUS_MODE_INFINITY; - - private PanoOrientationEventListener mOrientationEventListener; - // The value could be 0, 90, 180, 270 for the 4 different orientations measured in clockwise - // respectively. - private int mDeviceOrientation; - private int mDeviceOrientationAtCapture; - private int mCameraOrientation; - private int mOrientationCompensation; - - private RotateDialogController mRotateDialog; - - private SoundClips.Player mSoundPlayer; - - private Runnable mOnFrameAvailableRunnable; - - private CameraActivity mActivity; - private View mRootView; - private CameraProxy mCameraDevice; - private boolean mPaused; - private boolean mIsCreatingRenderer; - - private LocationManager mLocationManager; - private ComboPreferences mPreferences; - - private class MosaicJpeg { - public MosaicJpeg(byte[] data, int width, int height) { - this.data = data; - this.width = width; - this.height = height; - this.isValid = true; - } - - public MosaicJpeg() { - this.data = null; - this.width = 0; - this.height = 0; - this.isValid = false; - } - - public final byte[] data; - public final int width; - public final int height; - public final boolean isValid; - } - - private class PanoOrientationEventListener extends OrientationEventListener { - public PanoOrientationEventListener(Context context) { - super(context); - } - - @Override - public void onOrientationChanged(int orientation) { - // We keep the last known orientation. So if the user first orient - // the camera then point the camera to floor or sky, we still have - // the correct orientation. - if (orientation == ORIENTATION_UNKNOWN) return; - mDeviceOrientation = Util.roundOrientation(orientation, mDeviceOrientation); - // When the screen is unlocked, display rotation may change. Always - // calculate the up-to-date orientationCompensation. - int orientationCompensation = mDeviceOrientation - + Util.getDisplayRotation(mActivity) % 360; - if (mOrientationCompensation != orientationCompensation) { - mOrientationCompensation = orientationCompensation; - mActivity.getGLRoot().requestLayoutContentPane(); - } - } - } - - @Override - public void init(CameraActivity activity, View parent, boolean reuseScreenNail) { - mActivity = activity; - mRootView = parent; - - createContentView(); - - mContentResolver = mActivity.getContentResolver(); - if (reuseScreenNail) { - mActivity.reuseCameraScreenNail(true); - } else { - mActivity.createCameraScreenNail(true); - } - - // This runs in UI thread. - mOnFrameAvailableRunnable = new Runnable() { - @Override - public void run() { - // Frames might still be available after the activity is paused. - // If we call onFrameAvailable after pausing, the GL thread will crash. - if (mPaused) return; - - MosaicPreviewRenderer renderer = null; - synchronized (mRendererLock) { - if (mMosaicPreviewRenderer == null) { - return; - } - renderer = mMosaicPreviewRenderer; - } - if (mGLRootView.getVisibility() != View.VISIBLE) { - renderer.showPreviewFrameSync(); - mGLRootView.setVisibility(View.VISIBLE); - } else { - if (mCaptureState == CAPTURE_STATE_VIEWFINDER) { - renderer.showPreviewFrame(); - } else { - renderer.alignFrameSync(); - mMosaicFrameProcessor.processFrame(); - } - } - } - }; - - PowerManager pm = (PowerManager) mActivity.getSystemService(Context.POWER_SERVICE); - mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Panorama"); - - mOrientationEventListener = new PanoOrientationEventListener(mActivity); - - mMosaicFrameProcessor = MosaicFrameProcessor.getInstance(); - - Resources appRes = mActivity.getResources(); - mPreparePreviewString = appRes.getString(R.string.pano_dialog_prepare_preview); - mDialogTitle = appRes.getString(R.string.pano_dialog_title); - mDialogOkString = appRes.getString(R.string.dialog_ok); - mDialogPanoramaFailedString = appRes.getString(R.string.pano_dialog_panorama_failed); - mDialogWaitingPreviousString = appRes.getString(R.string.pano_dialog_waiting_previous); - - mGLRootView = (GLRootView) mActivity.getGLRoot(); - - mPreferences = new ComboPreferences(mActivity); - CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal()); - mLocationManager = new LocationManager(mActivity, null); - - mMainHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_LOW_RES_FINAL_MOSAIC_READY: - onBackgroundThreadFinished(); - showFinalMosaic((Bitmap) msg.obj); - saveHighResMosaic(); - break; - case MSG_GENERATE_FINAL_MOSAIC_ERROR: - onBackgroundThreadFinished(); - if (mPaused) { - resetToPreview(); - } else { - mRotateDialog.showAlertDialog( - mDialogTitle, mDialogPanoramaFailedString, - mDialogOkString, new Runnable() { - @Override - public void run() { - resetToPreview(); - }}, - null, null); - } - clearMosaicFrameProcessorIfNeeded(); - break; - case MSG_END_DIALOG_RESET_TO_PREVIEW: - onBackgroundThreadFinished(); - resetToPreview(); - clearMosaicFrameProcessorIfNeeded(); - break; - case MSG_CLEAR_SCREEN_DELAY: - mActivity.getWindow().clearFlags(WindowManager.LayoutParams. - FLAG_KEEP_SCREEN_ON); - break; - case MSG_CONFIG_MOSAIC_PREVIEW: - configMosaicPreview(msg.arg1, msg.arg2); - break; - case MSG_RESET_TO_PREVIEW: - resetToPreview(); - break; - } - } - }; - } - - @Override - public boolean dispatchTouchEvent(MotionEvent m) { - return mActivity.superDispatchTouchEvent(m); - } - - private void setupCamera() throws CameraHardwareException, CameraDisabledException { - openCamera(); - Parameters parameters = mCameraDevice.getParameters(); - setupCaptureParams(parameters); - configureCamera(parameters); - } - - private void releaseCamera() { - if (mCameraDevice != null) { - mCameraDevice.setPreviewCallbackWithBuffer(null); - CameraHolder.instance().release(); - mCameraDevice = null; - mCameraState = PREVIEW_STOPPED; - } - } - - private void openCamera() throws CameraHardwareException, CameraDisabledException { - int cameraId = CameraHolder.instance().getBackCameraId(); - // If there is no back camera, use the first camera. Camera id starts - // from 0. Currently if a camera is not back facing, it is front facing. - // This is also forward compatible if we have a new facing other than - // back or front in the future. - if (cameraId == -1) cameraId = 0; - mCameraDevice = Util.openCamera(mActivity, cameraId); - mCameraOrientation = Util.getCameraOrientation(cameraId); - if (cameraId == CameraHolder.instance().getFrontCameraId()) mUsingFrontCamera = true; - } - - private boolean findBestPreviewSize(List supportedSizes, boolean need4To3, - boolean needSmaller) { - int pixelsDiff = DEFAULT_CAPTURE_PIXELS; - boolean hasFound = false; - for (Size size : supportedSizes) { - int h = size.height; - int w = size.width; - // we only want 4:3 format. - int d = DEFAULT_CAPTURE_PIXELS - h * w; - if (needSmaller && d < 0) { // no bigger preview than 960x720. - continue; - } - if (need4To3 && (h * 4 != w * 3)) { - continue; - } - d = Math.abs(d); - if (d < pixelsDiff) { - mPreviewWidth = w; - mPreviewHeight = h; - pixelsDiff = d; - hasFound = true; - } - } - return hasFound; - } - - private void setupCaptureParams(Parameters parameters) { - List supportedSizes = parameters.getSupportedPreviewSizes(); - if (!findBestPreviewSize(supportedSizes, true, true)) { - Log.w(TAG, "No 4:3 ratio preview size supported."); - if (!findBestPreviewSize(supportedSizes, false, true)) { - Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); - findBestPreviewSize(supportedSizes, false, false); - } - } - Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth); - parameters.setPreviewSize(mPreviewWidth, mPreviewHeight); - - List frameRates = parameters.getSupportedPreviewFpsRange(); - int last = frameRates.size() - 1; - int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX]; - int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX]; - parameters.setPreviewFpsRange(minFps, maxFps); - Log.v(TAG, "preview fps: " + minFps + ", " + maxFps); - - List supportedFocusModes = parameters.getSupportedFocusModes(); - if (supportedFocusModes.indexOf(mTargetFocusMode) >= 0) { - parameters.setFocusMode(mTargetFocusMode); - } else { - // Use the default focus mode and log a message - Log.w(TAG, "Cannot set the focus mode to " + mTargetFocusMode + - " becuase the mode is not supported."); - } - - parameters.set(Util.RECORDING_HINT, Util.FALSE); - - mHorizontalViewAngle = parameters.getHorizontalViewAngle(); - mVerticalViewAngle = parameters.getVerticalViewAngle(); - } - - public int getPreviewBufSize() { - PixelFormat pixelInfo = new PixelFormat(); - PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo); - // TODO: remove this extra 32 byte after the driver bug is fixed. - return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32; - } - - private void configureCamera(Parameters parameters) { - mCameraDevice.setParameters(parameters); - } - - private void configMosaicPreview(final int w, final int h) { - synchronized (mRendererLock) { - if (mIsCreatingRenderer) { - mMainHandler.removeMessages(MSG_CONFIG_MOSAIC_PREVIEW); - mMainHandler.obtainMessage(MSG_CONFIG_MOSAIC_PREVIEW, w, h).sendToTarget(); - return; - } - mIsCreatingRenderer = true; - } - stopCameraPreview(); - CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; - screenNail.setSize(w, h); - synchronized (mRendererLock) { - if (mMosaicPreviewRenderer != null) { - mMosaicPreviewRenderer.release(); - } - mMosaicPreviewRenderer = null; - screenNail.releaseSurfaceTexture(); - screenNail.acquireSurfaceTexture(); - } - mActivity.notifyScreenNailChanged(); - final boolean isLandscape = (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); - new Thread(new Runnable() { - @Override - public void run() { - CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; - SurfaceTexture surfaceTexture = screenNail.getSurfaceTexture(); - if (surfaceTexture == null) { - synchronized (mRendererLock) { - mIsCreatingRenderer = false; - mRendererLock.notifyAll(); - return; - } - } - MosaicPreviewRenderer renderer = new MosaicPreviewRenderer( - screenNail.getSurfaceTexture(), w, h, isLandscape); - synchronized (mRendererLock) { - mMosaicPreviewRenderer = renderer; - mCameraTexture = mMosaicPreviewRenderer.getInputSurfaceTexture(); - - if (!mPaused && !mThreadRunning && mWaitProcessorTask == null) { - mMainHandler.sendEmptyMessage(MSG_RESET_TO_PREVIEW); - } - mIsCreatingRenderer = false; - mRendererLock.notifyAll(); - } - } - }).start(); - } - - // Receives the layout change event from the preview area. So we can set - // the camera preview screennail to the same size and initialize the mosaic - // preview renderer. - @Override - public void onLayoutChange(View v, int l, int t, int r, int b) { - Log.i(TAG, "layout change: "+(r - l) + "/" +(b - t)); - mActivity.onLayoutChange(v, l, t, r, b); - configMosaicPreview(r - l, b - t); - } - - @Override - public void onFrameAvailable(SurfaceTexture surface) { - /* This function may be called by some random thread, - * so let's be safe and jump back to ui thread. - * No OpenGL calls can be done here. */ - mActivity.runOnUiThread(mOnFrameAvailableRunnable); - } - - private void hideDirectionIndicators() { - mLeftIndicator.setVisibility(View.GONE); - mRightIndicator.setVisibility(View.GONE); - } - - private void showDirectionIndicators(int direction) { - switch (direction) { - case PanoProgressBar.DIRECTION_NONE: - mLeftIndicator.setVisibility(View.VISIBLE); - mRightIndicator.setVisibility(View.VISIBLE); - break; - case PanoProgressBar.DIRECTION_LEFT: - mLeftIndicator.setVisibility(View.VISIBLE); - mRightIndicator.setVisibility(View.GONE); - break; - case PanoProgressBar.DIRECTION_RIGHT: - mLeftIndicator.setVisibility(View.GONE); - mRightIndicator.setVisibility(View.VISIBLE); - break; - } - } - - public void startCapture() { - // Reset values so we can do this again. - mCancelComputation = false; - mTimeTaken = System.currentTimeMillis(); - mActivity.setSwipingEnabled(false); - mActivity.hideSwitcher(); - mShutterButton.setImageResource(R.drawable.btn_shutter_recording); - mCaptureState = CAPTURE_STATE_MOSAIC; - mCaptureIndicator.setVisibility(View.VISIBLE); - showDirectionIndicators(PanoProgressBar.DIRECTION_NONE); - - mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() { - @Override - public void onProgress(boolean isFinished, float panningRateX, float panningRateY, - float progressX, float progressY) { - float accumulatedHorizontalAngle = progressX * mHorizontalViewAngle; - float accumulatedVerticalAngle = progressY * mVerticalViewAngle; - if (isFinished - || (Math.abs(accumulatedHorizontalAngle) >= DEFAULT_SWEEP_ANGLE) - || (Math.abs(accumulatedVerticalAngle) >= DEFAULT_SWEEP_ANGLE)) { - stopCapture(false); - } else { - float panningRateXInDegree = panningRateX * mHorizontalViewAngle; - float panningRateYInDegree = panningRateY * mVerticalViewAngle; - updateProgress(panningRateXInDegree, panningRateYInDegree, - accumulatedHorizontalAngle, accumulatedVerticalAngle); - } - } - }); - - mPanoProgressBar.reset(); - // TODO: calculate the indicator width according to different devices to reflect the actual - // angle of view of the camera device. - mPanoProgressBar.setIndicatorWidth(20); - mPanoProgressBar.setMaxProgress(DEFAULT_SWEEP_ANGLE); - mPanoProgressBar.setVisibility(View.VISIBLE); - mDeviceOrientationAtCapture = mDeviceOrientation; - keepScreenOn(); - mActivity.getOrientationManager().lockOrientation(); - setupProgressDirectionMatrix(); - } - - void setupProgressDirectionMatrix() { - int degrees = Util.getDisplayRotation(mActivity); - int cameraId = CameraHolder.instance().getBackCameraId(); - int orientation = Util.getDisplayOrientation(degrees, cameraId); - mProgressDirectionMatrix.reset(); - mProgressDirectionMatrix.postRotate(orientation); - } - - private void stopCapture(boolean aborted) { - mCaptureState = CAPTURE_STATE_VIEWFINDER; - mCaptureIndicator.setVisibility(View.GONE); - hideTooFastIndication(); - hideDirectionIndicators(); - - mMosaicFrameProcessor.setProgressListener(null); - stopCameraPreview(); - - mCameraTexture.setOnFrameAvailableListener(null); - - if (!aborted && !mThreadRunning) { - mRotateDialog.showWaitingDialog(mPreparePreviewString); - // Hide shutter button, shutter icon, etc when waiting for - // panorama to stitch - mActivity.hideUI(); - runBackgroundThread(new Thread() { - @Override - public void run() { - MosaicJpeg jpeg = generateFinalMosaic(false); - - if (jpeg != null && jpeg.isValid) { - Bitmap bitmap = null; - bitmap = BitmapFactory.decodeByteArray(jpeg.data, 0, jpeg.data.length); - mMainHandler.sendMessage(mMainHandler.obtainMessage( - MSG_LOW_RES_FINAL_MOSAIC_READY, bitmap)); - } else { - mMainHandler.sendMessage(mMainHandler.obtainMessage( - MSG_END_DIALOG_RESET_TO_PREVIEW)); - } - } - }); - } - keepScreenOnAwhile(); - } - - private void showTooFastIndication() { - mTooFastPrompt.setVisibility(View.VISIBLE); - // The PreviewArea also contains the border for "too fast" indication. - mPreviewArea.setVisibility(View.VISIBLE); - mPanoProgressBar.setIndicatorColor(mIndicatorColorFast); - mLeftIndicator.setEnabled(true); - mRightIndicator.setEnabled(true); - } - - private void hideTooFastIndication() { - mTooFastPrompt.setVisibility(View.GONE); - // We set "INVISIBLE" instead of "GONE" here because we need mPreviewArea to have layout - // information so we can know the size and position for mCameraScreenNail. - mPreviewArea.setVisibility(View.INVISIBLE); - mPanoProgressBar.setIndicatorColor(mIndicatorColor); - mLeftIndicator.setEnabled(false); - mRightIndicator.setEnabled(false); - } - - private void updateProgress(float panningRateXInDegree, float panningRateYInDegree, - float progressHorizontalAngle, float progressVerticalAngle) { - mGLRootView.requestRender(); - - if ((Math.abs(panningRateXInDegree) > PANNING_SPEED_THRESHOLD) - || (Math.abs(panningRateYInDegree) > PANNING_SPEED_THRESHOLD)) { - showTooFastIndication(); - } else { - hideTooFastIndication(); - } - - // progressHorizontalAngle and progressVerticalAngle are relative to the - // camera. Convert them to UI direction. - mProgressAngle[0] = progressHorizontalAngle; - mProgressAngle[1] = progressVerticalAngle; - mProgressDirectionMatrix.mapPoints(mProgressAngle); - - int angleInMajorDirection = - (Math.abs(mProgressAngle[0]) > Math.abs(mProgressAngle[1])) - ? (int) mProgressAngle[0] - : (int) mProgressAngle[1]; - mPanoProgressBar.setProgress((angleInMajorDirection)); - } - - private void setViews(Resources appRes) { - mCaptureState = CAPTURE_STATE_VIEWFINDER; - mPanoProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_pan_progress_bar); - mPanoProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); - mPanoProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_done)); - mPanoProgressBar.setIndicatorColor(mIndicatorColor); - mPanoProgressBar.setOnDirectionChangeListener( - new PanoProgressBar.OnDirectionChangeListener () { - @Override - public void onDirectionChange(int direction) { - if (mCaptureState == CAPTURE_STATE_MOSAIC) { - showDirectionIndicators(direction); - } - } - }); - - mLeftIndicator = mRootView.findViewById(R.id.pano_pan_left_indicator); - mRightIndicator = mRootView.findViewById(R.id.pano_pan_right_indicator); - mLeftIndicator.setEnabled(false); - mRightIndicator.setEnabled(false); - mTooFastPrompt = (TextView) mRootView.findViewById(R.id.pano_capture_too_fast_textview); - // This mPreviewArea also shows the border for visual "too fast" indication. - mPreviewArea = (LayoutNotifyView) mRootView.findViewById(R.id.pano_preview_area); - mPreviewArea.setOnLayoutChangeListener(this); - - mSavingProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_saving_progress_bar); - mSavingProgressBar.setIndicatorWidth(0); - mSavingProgressBar.setMaxProgress(100); - mSavingProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); - mSavingProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_indication)); - - mCaptureIndicator = mRootView.findViewById(R.id.pano_capture_indicator); - - mReviewLayout = mRootView.findViewById(R.id.pano_review_layout); - mReview = (ImageView) mRootView.findViewById(R.id.pano_reviewarea); - mReview.setBackgroundColor(mReviewBackground); - View cancelButton = mRootView.findViewById(R.id.pano_review_cancel_button); - cancelButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View arg0) { - if (mPaused || mCameraTexture == null) return; - cancelHighResComputation(); - } - }); - - mShutterButton = mActivity.getShutterButton(); - mShutterButton.setImageResource(R.drawable.btn_new_shutter); - mShutterButton.setOnShutterButtonListener(this); - - if (mActivity.getResources().getConfiguration().orientation - == Configuration.ORIENTATION_PORTRAIT) { - Rotatable view = (Rotatable) mRootView.findViewById(R.id.pano_rotate_reviewarea); - view.setOrientation(270, false); - } - } - - private void createContentView() { - mActivity.getLayoutInflater().inflate(R.layout.panorama_module, (ViewGroup) mRootView, true); - Resources appRes = mActivity.getResources(); - mCaptureLayout = (LinearLayout) mRootView.findViewById(R.id.camera_app); - mIndicatorColor = appRes.getColor(R.color.pano_progress_indication); - mReviewBackground = appRes.getColor(R.color.review_background); - mIndicatorColorFast = appRes.getColor(R.color.pano_progress_indication_fast); - mPanoLayout = (ViewGroup) mRootView.findViewById(R.id.camera_app_root); - mRotateDialog = new RotateDialogController(mActivity, R.layout.rotate_dialog); - setViews(appRes); - } - - @Override - public void onShutterButtonClick() { - // If mCameraTexture == null then GL setup is not finished yet. - // No buttons can be pressed. - if (mPaused || mThreadRunning || mCameraTexture == null) return; - // Since this button will stay on the screen when capturing, we need to check the state - // right now. - switch (mCaptureState) { - case CAPTURE_STATE_VIEWFINDER: - if(mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) return; - mSoundPlayer.play(SoundClips.START_VIDEO_RECORDING); - startCapture(); - break; - case CAPTURE_STATE_MOSAIC: - mSoundPlayer.play(SoundClips.STOP_VIDEO_RECORDING); - stopCapture(false); - } - } - - @Override - public void onShutterButtonFocus(boolean pressed) { - } - - public void reportProgress() { - mSavingProgressBar.reset(); - mSavingProgressBar.setRightIncreasing(true); - Thread t = new Thread() { - @Override - public void run() { - while (mThreadRunning) { - final int progress = mMosaicFrameProcessor.reportProgress( - true, mCancelComputation); - - try { - synchronized (mWaitObject) { - mWaitObject.wait(50); - } - } catch (InterruptedException e) { - throw new RuntimeException("Panorama reportProgress failed", e); - } - // Update the progress bar - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mSavingProgressBar.setProgress(progress); - } - }); - } - } - }; - t.start(); - } - - private int getCaptureOrientation() { - // The panorama image returned from the library is oriented based on the - // natural orientation of a camera. We need to set an orientation for the image - // in its EXIF header, so the image can be displayed correctly. - // The orientation is calculated from compensating the - // device orientation at capture and the camera orientation respective to - // the natural orientation of the device. - int orientation; - if (mUsingFrontCamera) { - // mCameraOrientation is negative with respect to the front facing camera. - // See document of android.hardware.Camera.Parameters.setRotation. - orientation = (mDeviceOrientationAtCapture - mCameraOrientation + 360) % 360; - } else { - orientation = (mDeviceOrientationAtCapture + mCameraOrientation) % 360; - } - return orientation; - } - - public void saveHighResMosaic() { - runBackgroundThread(new Thread() { - @Override - public void run() { - mPartialWakeLock.acquire(); - MosaicJpeg jpeg; - try { - jpeg = generateFinalMosaic(true); - } finally { - mPartialWakeLock.release(); - } - - if (jpeg == null) { // Cancelled by user. - mMainHandler.sendEmptyMessage(MSG_END_DIALOG_RESET_TO_PREVIEW); - } else if (!jpeg.isValid) { // Error when generating mosaic. - mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR); - } else { - int orientation = getCaptureOrientation(); - Uri uri = savePanorama(jpeg.data, jpeg.width, jpeg.height, orientation); - if (uri != null) { - mActivity.addSecureAlbumItemIfNeeded(false, uri); - Util.broadcastNewPicture(mActivity, uri); - } - mMainHandler.sendMessage( - mMainHandler.obtainMessage(MSG_END_DIALOG_RESET_TO_PREVIEW)); - } - } - }); - reportProgress(); - } - - private void runBackgroundThread(Thread thread) { - mThreadRunning = true; - thread.start(); - } - - private void onBackgroundThreadFinished() { - mThreadRunning = false; - mRotateDialog.dismissDialog(); - } - - private void cancelHighResComputation() { - mCancelComputation = true; - synchronized (mWaitObject) { - mWaitObject.notify(); - } - } - - // This function will be called upon the first camera frame is available. - private void reset() { - mCaptureState = CAPTURE_STATE_VIEWFINDER; - - mActivity.getOrientationManager().unlockOrientation(); - // We should set mGLRootView visible too. However, since there might be no - // frame available yet, setting mGLRootView visible should be done right after - // the first camera frame is available and therefore it is done by - // mOnFirstFrameAvailableRunnable. - mActivity.setSwipingEnabled(true); - mShutterButton.setImageResource(R.drawable.btn_new_shutter); - mReviewLayout.setVisibility(View.GONE); - mPanoProgressBar.setVisibility(View.GONE); - mGLRootView.setVisibility(View.VISIBLE); - // Orientation change will trigger onLayoutChange->configMosaicPreview-> - // resetToPreview. Do not show the capture UI in film strip. - if (mActivity.mShowCameraAppView) { - mCaptureLayout.setVisibility(View.VISIBLE); - mActivity.showUI(); - } - mMosaicFrameProcessor.reset(); - } - - private void resetToPreview() { - reset(); - if (!mPaused) startCameraPreview(); - } - - private static class FlipBitmapDrawable extends BitmapDrawable { - - public FlipBitmapDrawable(Resources res, Bitmap bitmap) { - super(res, bitmap); - } - - @Override - public void draw(Canvas canvas) { - Rect bounds = getBounds(); - int cx = bounds.centerX(); - int cy = bounds.centerY(); - canvas.save(Canvas.MATRIX_SAVE_FLAG); - canvas.rotate(180, cx, cy); - super.draw(canvas); - canvas.restore(); - } - } - - private void showFinalMosaic(Bitmap bitmap) { - if (bitmap != null) { - int orientation = getCaptureOrientation(); - if (orientation >= 180) { - // We need to flip the drawable to compensate - mReview.setImageDrawable(new FlipBitmapDrawable( - mActivity.getResources(), bitmap)); - } else { - mReview.setImageBitmap(bitmap); - } - } - - mCaptureLayout.setVisibility(View.GONE); - mReviewLayout.setVisibility(View.VISIBLE); - } - - private Uri savePanorama(byte[] jpegData, int width, int height, int orientation) { - if (jpegData != null) { - String filename = PanoUtil.createName( - mActivity.getResources().getString(R.string.pano_file_name_format), mTimeTaken); - String filepath = Storage.generateFilepath(filename); - - Location loc = mLocationManager.getCurrentLocation(); - ExifInterface exif = new ExifInterface(); - try { - exif.readExif(jpegData); - exif.addGpsDateTimeStampTag(mTimeTaken); - exif.addDateTimeStampTag(ExifInterface.TAG_DATE_TIME, mTimeTaken, - TimeZone.getDefault()); - exif.setTag(exif.buildTag(ExifInterface.TAG_ORIENTATION, - ExifInterface.getOrientationValueForRotation(orientation))); - writeLocation(loc, exif); - exif.writeExif(jpegData, filepath); - } catch (IOException e) { - Log.e(TAG, "Cannot set exif for " + filepath, e); - Storage.writeFile(filepath, jpegData); - } - int jpegLength = (int) (new File(filepath).length()); - return Storage.addImage(mContentResolver, filename, mTimeTaken, - loc, orientation, jpegLength, filepath, width, height); - } - return null; - } - - private static void writeLocation(Location location, ExifInterface exif) { - if (location == null) { - return; - } - exif.addGpsTags(location.getLatitude(), location.getLongitude()); - exif.setTag(exif.buildTag(ExifInterface.TAG_GPS_PROCESSING_METHOD, location.getProvider())); - } - - private void clearMosaicFrameProcessorIfNeeded() { - if (!mPaused || mThreadRunning) return; - // Only clear the processor if it is initialized by this activity - // instance. Other activity instances may be using it. - if (mMosaicFrameProcessorInitialized) { - mMosaicFrameProcessor.clear(); - mMosaicFrameProcessorInitialized = false; - } - } - - private void initMosaicFrameProcessorIfNeeded() { - if (mPaused || mThreadRunning) return; - mMosaicFrameProcessor.initialize( - mPreviewWidth, mPreviewHeight, getPreviewBufSize()); - mMosaicFrameProcessorInitialized = true; - } - - @Override - public void onPauseBeforeSuper() { - mPaused = true; - if (mLocationManager != null) mLocationManager.recordLocation(false); - } - - @Override - public void onPauseAfterSuper() { - mOrientationEventListener.disable(); - if (mCameraDevice == null) { - // Camera open failed. Nothing should be done here. - return; - } - // Stop the capturing first. - if (mCaptureState == CAPTURE_STATE_MOSAIC) { - stopCapture(true); - reset(); - } - - releaseCamera(); - synchronized (mRendererLock) { - mCameraTexture = null; - - // The preview renderer might not have a chance to be initialized - // before onPause(). - if (mMosaicPreviewRenderer != null) { - mMosaicPreviewRenderer.release(); - mMosaicPreviewRenderer = null; - } - } - - clearMosaicFrameProcessorIfNeeded(); - if (mWaitProcessorTask != null) { - mWaitProcessorTask.cancel(true); - mWaitProcessorTask = null; - } - resetScreenOn(); - if (mSoundPlayer != null) { - mSoundPlayer.release(); - mSoundPlayer = null; - } - CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; - screenNail.releaseSurfaceTexture(); - System.gc(); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - Drawable lowResReview = null; - if (mThreadRunning) lowResReview = mReview.getDrawable(); - - // Change layout in response to configuration change - mCaptureLayout.setOrientation( - newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE - ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); - mCaptureLayout.removeAllViews(); - LayoutInflater inflater = mActivity.getLayoutInflater(); - inflater.inflate(R.layout.preview_frame_pano, mCaptureLayout); - - mPanoLayout.removeView(mReviewLayout); - inflater.inflate(R.layout.pano_review, mPanoLayout); - - setViews(mActivity.getResources()); - if (mThreadRunning) { - mReview.setImageDrawable(lowResReview); - mCaptureLayout.setVisibility(View.GONE); - mReviewLayout.setVisibility(View.VISIBLE); - } - } - - @Override - public void onOrientationChanged(int orientation) { - } - - @Override - public void onResumeBeforeSuper() { - mPaused = false; - } - - @Override - public void onResumeAfterSuper() { - mOrientationEventListener.enable(); - - mCaptureState = CAPTURE_STATE_VIEWFINDER; - - try { - setupCamera(); - } catch (CameraHardwareException e) { - Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); - return; - } catch (CameraDisabledException e) { - Util.showErrorAndFinish(mActivity, R.string.camera_disabled); - return; - } - - // Set up sound playback for shutter button - mSoundPlayer = SoundClips.getPlayer(mActivity); - - // Check if another panorama instance is using the mosaic frame processor. - mRotateDialog.dismissDialog(); - if (!mThreadRunning && mMosaicFrameProcessor.isMosaicMemoryAllocated()) { - mGLRootView.setVisibility(View.GONE); - mRotateDialog.showWaitingDialog(mDialogWaitingPreviousString); - // If stitching is still going on, make sure switcher and shutter button - // are not showing - mActivity.hideUI(); - mWaitProcessorTask = new WaitProcessorTask().execute(); - } else { - mGLRootView.setVisibility(View.VISIBLE); - // Camera must be initialized before MosaicFrameProcessor is - // initialized. The preview size has to be decided by camera device. - initMosaicFrameProcessorIfNeeded(); - int w = mPreviewArea.getWidth(); - int h = mPreviewArea.getHeight(); - if (w != 0 && h != 0) { // The layout has been calculated. - configMosaicPreview(w, h); - } - } - keepScreenOnAwhile(); - - // Initialize location service. - boolean recordLocation = RecordLocationPreference.get(mPreferences, - mContentResolver); - mLocationManager.recordLocation(recordLocation); - - // Dismiss open menu if exists. - PopupManager.getInstance(mActivity).notifyShowPopup(null); - mRootView.requestLayout(); - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_CAMERA, "PanoramaModule"); - } - - /** - * Generate the final mosaic image. - * - * @param highRes flag to indicate whether we want to get a high-res version. - * @return a MosaicJpeg with its isValid flag set to true if successful; null if the generation - * process is cancelled; and a MosaicJpeg with its isValid flag set to false if there - * is an error in generating the final mosaic. - */ - public MosaicJpeg generateFinalMosaic(boolean highRes) { - int mosaicReturnCode = mMosaicFrameProcessor.createMosaic(highRes); - if (mosaicReturnCode == Mosaic.MOSAIC_RET_CANCELLED) { - return null; - } else if (mosaicReturnCode == Mosaic.MOSAIC_RET_ERROR) { - return new MosaicJpeg(); - } - - byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21(); - if (imageData == null) { - Log.e(TAG, "getFinalMosaicNV21() returned null."); - return new MosaicJpeg(); - } - - int len = imageData.length - 8; - int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16) - + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF); - int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16) - + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF); - Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height); - - if (width <= 0 || height <= 0) { - // TODO: pop up an error message indicating that the final result is not generated. - Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " + - height); - return new MosaicJpeg(); - } - - YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out); - try { - out.close(); - } catch (Exception e) { - Log.e(TAG, "Exception in storing final mosaic", e); - return new MosaicJpeg(); - } - return new MosaicJpeg(out.toByteArray(), width, height); - } - - private void startCameraPreview() { - if (mCameraDevice == null) { - // Camera open failed. Return. - return; - } - - // This works around a driver issue. startPreview may fail if - // stopPreview/setPreviewTexture/startPreview are called several times - // in a row. mCameraTexture can be null after pressing home during - // mosaic generation and coming back. Preview will be started later in - // onLayoutChange->configMosaicPreview. This also reduces the latency. - synchronized (mRendererLock) { - if (mCameraTexture == null) return; - - // If we're previewing already, stop the preview first (this will - // blank the screen). - if (mCameraState != PREVIEW_STOPPED) stopCameraPreview(); - - // Set the display orientation to 0, so that the underlying mosaic - // library can always get undistorted mPreviewWidth x mPreviewHeight - // image data from SurfaceTexture. - mCameraDevice.setDisplayOrientation(0); - - mCameraTexture.setOnFrameAvailableListener(this); - mCameraDevice.setPreviewTextureAsync(mCameraTexture); - } - mCameraDevice.startPreviewAsync(); - mCameraState = PREVIEW_ACTIVE; - } - - private void stopCameraPreview() { - if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { - Log.v(TAG, "stopPreview"); - mCameraDevice.stopPreview(); - } - mCameraState = PREVIEW_STOPPED; - } - - @Override - public void onUserInteraction() { - if (mCaptureState != CAPTURE_STATE_MOSAIC) keepScreenOnAwhile(); - } - - @Override - public boolean onBackPressed() { - // If panorama is generating low res or high res mosaic, ignore back - // key. So the activity will not be destroyed. - if (mThreadRunning) return true; - return false; - } - - private void resetScreenOn() { - mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY); - mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - private void keepScreenOnAwhile() { - mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY); - mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - mMainHandler.sendEmptyMessageDelayed(MSG_CLEAR_SCREEN_DELAY, SCREEN_DELAY); - } - - private void keepScreenOn() { - mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY); - mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - private class WaitProcessorTask extends AsyncTask { - @Override - protected Void doInBackground(Void... params) { - synchronized (mMosaicFrameProcessor) { - while (!isCancelled() && mMosaicFrameProcessor.isMosaicMemoryAllocated()) { - try { - mMosaicFrameProcessor.wait(); - } catch (Exception e) { - // ignore - } - } - } - return null; - } - - @Override - protected void onPostExecute(Void result) { - mWaitProcessorTask = null; - mRotateDialog.dismissDialog(); - mGLRootView.setVisibility(View.VISIBLE); - initMosaicFrameProcessorIfNeeded(); - int w = mPreviewArea.getWidth(); - int h = mPreviewArea.getHeight(); - if (w != 0 && h != 0) { // The layout has been calculated. - configMosaicPreview(w, h); - } - resetToPreview(); - } - } - - @Override - public void onFullScreenChanged(boolean full) { - } - - - @Override - public void onStop() { - } - - @Override - public void installIntentFilter() { - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - } - - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return false; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - return false; - } - - @Override - public void onSingleTapUp(View view, int x, int y) { - } - - @Override - public void onPreviewTextureCopied() { - } - - @Override - public void onCaptureTextureCopied() { - } - - @Override - public boolean updateStorageHintOnResume() { - return false; - } - - @Override - public void updateCameraAppView() { - } - - @Override - public boolean needsSwitcher() { - return true; - } - - @Override - public boolean needsPieMenu() { - return false; - } - - @Override - public void onShowSwitcherPopup() { - } - - @Override - public void onMediaSaveServiceConnected(MediaSaveService s) { - // do nothing. - } -} diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java index d0f21ed68..6c1e2d085 100644 --- a/src/com/android/camera/PhotoMenu.java +++ b/src/com/android/camera/PhotoMenu.java @@ -168,7 +168,6 @@ public class PhotoMenu extends PieController } public void popupDismissed() { - // the popup gets dismissed if (mPopup != null) { mPopup = null; } @@ -198,5 +197,4 @@ public class PhotoMenu extends PieController } super.onSettingChanged(pref); } - } diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index ecda6c6e3..49b209d34 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -64,7 +64,6 @@ import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.exif.ExifTag; import com.android.gallery3d.exif.Rational; -import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.crop.CropActivity; import com.android.gallery3d.filtershow.crop.CropExtras; import com.android.gallery3d.util.UsageStatistics; @@ -127,8 +126,6 @@ public class PhotoModule private PhotoUI mUI; - // these are only used by Camera - // The activity is going to switch to the specified camera id. This is // needed because texture copy is done in GL thread. -1 means camera is not // switching. @@ -252,23 +249,21 @@ public class PhotoModule private PreferenceGroup mPreferenceGroup; private boolean mQuickCapture; - - CameraStartUpThread mCameraStartUpThread; - ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable(); - private SensorManager mSensorManager; private float[] mGData = new float[3]; private float[] mMData = new float[3]; private float[] mR = new float[16]; private int mHeading = -1; + CameraStartUpThread mCameraStartUpThread; + ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable(); + private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = new MediaSaveService.OnMediaSavedListener() { @Override public void onMediaSaved(Uri uri) { if (uri != null) { - mActivity.addSecureAlbumItemIfNeeded(false, uri); - Util.broadcastNewPicture(mActivity, uri); + mActivity.notifyNewMedia(uri); } } }; @@ -371,7 +366,8 @@ public class PhotoModule } case SWITCH_CAMERA_START_ANIMATION: { - ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera(); + // TODO: Need to revisit + // ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera(); break; } @@ -409,7 +405,7 @@ public class PhotoModule } @Override - public void init(CameraActivity activity, View parent, boolean reuseNail) { + public void init(CameraActivity activity, View parent) { mActivity = activity; mUI = new PhotoUI(activity, this, parent); mPreferences = new ComboPreferences(mActivity); @@ -423,15 +419,9 @@ public class PhotoModule mCameraStartUpThread = new CameraStartUpThread(); mCameraStartUpThread.start(); - // Surface texture is from camera screen nail and startPreview needs it. // This must be done before startPreview. mIsImageCaptureIntent = isImageCaptureIntent(); - if (reuseNail) { - mActivity.reuseCameraScreenNail(!mIsImageCaptureIntent); - } else { - mActivity.createCameraScreenNail(!mIsImageCaptureIntent); - } mPreferences.setLocalId(mActivity, mCameraId); CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); @@ -445,7 +435,6 @@ public class PhotoModule mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); mLocationManager = new LocationManager(mActivity, mUI); mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE)); - } private void initializeControlByIntent() { @@ -458,10 +447,6 @@ public class PhotoModule private void onPreviewStarted() { mCameraStartUpThread = null; setCameraState(IDLE); - if (!ApiHelper.HAS_SURFACE_TEXTURE) { - // This may happen if surfaceCreated has arrived. - mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder()); - } startFaceDetection(); locationFirstRun(); } @@ -520,16 +505,7 @@ public class PhotoModule int width = root.getWidth(); int height = root.getHeight(); mFocusManager.setPreviewSize(width, height); - // Full-screen screennail - if (Util.getDisplayRotation(mActivity) % 180 == 0) { - ((CameraScreenNail) mActivity.mCameraScreenNail).setPreviewFrameLayoutSize(width, height); - } else { - ((CameraScreenNail) mActivity.mCameraScreenNail).setPreviewFrameLayoutSize(height, width); - } - // Set touch focus listener. - mActivity.setSingleTapUpListener(root); openCameraCommon(); - onFullScreenChanged(mActivity.isInCameraApp()); } private void switchCamera() { @@ -566,6 +542,8 @@ public class PhotoModule mFocusManager.setParameters(mInitialParams); setupPreview(); + // reset zoom value index + mZoomValue = 0; openCameraCommon(); if (ApiHelper.HAS_SURFACE_TEXTURE) { @@ -592,11 +570,7 @@ public class PhotoModule } public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { - Log.d(TAG, "Preview size changed."); if (mFocusManager != null) mFocusManager.setPreviewSize(width, height); - ((CameraScreenNail) mActivity.mCameraScreenNail).setPreviewFrameLayoutSize( - previewWidth, previewHeight); - mActivity.notifyScreenNailChanged(); } private void resetExposureCompensation() { @@ -726,12 +700,6 @@ public class PhotoModule } } - @Override - public boolean dispatchTouchEvent(MotionEvent m) { - if (mCameraState == SWITCHING_CAMERA) return true; - return mUI.dispatchTouchEvent(m); - } - private final class ShutterCallback implements android.hardware.Camera.ShutterCallback { @@ -786,9 +754,13 @@ public class PhotoModule if (mPaused) { return; } + //TODO: We should show the picture taken rather than frozen preview here + if (mIsImageCaptureIntent) { + stopPreview(); + } if (mSceneMode == Util.SCENE_MODE_HDR) { - mActivity.showSwitcher(); - mActivity.setSwipingEnabled(true); + mUI.showSwitcher(); + mUI.setSwipingEnabled(true); } mJpegPictureCallbackTime = System.currentTimeMillis(); @@ -809,6 +781,7 @@ public class PhotoModule Log.v(TAG, "mPictureDisplayedToJpegCallbackTime = " + mPictureDisplayedToJpegCallbackTime + "ms"); + /*TODO: // Only animate when in full screen capture mode // i.e. If monkey/a user swipes to the gallery during picture taking, // don't show animation @@ -819,7 +792,7 @@ public class PhotoModule ((CameraScreenNail) mActivity.mCameraScreenNail).animateSlide(); mHandler.sendEmptyMessageDelayed(CAPTURE_ANIMATION_DONE, CaptureAnimManager.getAnimationDuration()); - } + } */ mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden. if (!mIsImageCaptureIntent) { if (ApiHelper.CAN_START_PREVIEW_IN_JPEG_CALLBACK) { @@ -957,19 +930,17 @@ public class PhotoModule switch (state) { case PhotoController.PREVIEW_STOPPED: case PhotoController.SNAPSHOT_IN_PROGRESS: - case PhotoController.FOCUSING: case PhotoController.SWITCHING_CAMERA: mUI.enableGestures(false); break; case PhotoController.IDLE: - if (mActivity.isInCameraApp()) { - mUI.enableGestures(true); - } + mUI.enableGestures(true); break; } } private void animateFlash() { + /* //TODO: // Only animate when in full screen capture mode // i.e. If monkey/a user swipes to the gallery during picture taking, // don't show animation @@ -980,7 +951,7 @@ public class PhotoModule mUI.enablePreviewThumb(true); mHandler.sendEmptyMessageDelayed(CAPTURE_ANIMATION_DONE, CaptureAnimManager.getAnimationDuration()); - } + } */ } @Override @@ -1047,17 +1018,6 @@ public class PhotoModule } } - @Override - public void onFullScreenChanged(boolean full) { - mUI.onFullScreenChanged(full); - if (ApiHelper.HAS_SURFACE_TEXTURE) { - if (mActivity.mCameraScreenNail != null) { - ((CameraScreenNail) mActivity.mCameraScreenNail).setFullScreen(full); - } - return; - } - } - private void updateSceneMode() { // If scene mode is set, we cannot set flash mode, white balance, and // focus mode, instead, we read it from driver @@ -1236,8 +1196,8 @@ public class PhotoModule Log.v(TAG, "onShutterButtonClick: mCameraState=" + mCameraState); if (mSceneMode == Util.SCENE_MODE_HDR) { - mActivity.hideSwitcher(); - mActivity.setSwipingEnabled(false); + mUI.hideSwitcher(); + mUI.setSwipingEnabled(false); } // If the user wants to do a snapshot while the previous one is still // in progress, remember the fact and do it after we finish the previous @@ -1295,7 +1255,6 @@ public class PhotoModule mJpegPictureCallbackTime = 0; mZoomValue = 0; - // Start the preview if it is not started. if (mCameraState == PREVIEW_STOPPED && mCameraStartUpThread == null) { resetExposureCompensation(); @@ -1375,8 +1334,6 @@ public class PhotoModule mCameraDevice.cancelAutoFocus(); } stopPreview(); - // Release surface texture. - ((CameraScreenNail) mActivity.mCameraScreenNail).releaseSurfaceTexture(); mNamedImages = null; @@ -1437,6 +1394,13 @@ public class PhotoModule setDisplayOrientation(); } + @Override + public void updateCameraOrientation() { + if (mDisplayRotation != Util.getDisplayRotation(mActivity)) { + setDisplayOrientation(); + } + } + @Override public void onActivityResult( int requestCode, int resultCode, Intent data) { @@ -1507,7 +1471,7 @@ public class PhotoModule case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_FOCUS: - if (mActivity.isInCameraApp() && mFirstTimeInitialized) { + if (/*TODO: mActivity.isInCameraApp() &&*/ mFirstTimeInitialized) { if (event.getRepeatCount() == 0) { onShutterButtonFocus(true); } @@ -1540,7 +1504,7 @@ public class PhotoModule switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: - if (mActivity.isInCameraApp() && mFirstTimeInitialized) { + if (/*mActivity.isInCameraApp() && */ mFirstTimeInitialized) { onShutterButtonClick(); return true; } @@ -1573,13 +1537,15 @@ public class PhotoModule private void setDisplayOrientation() { mDisplayRotation = Util.getDisplayRotation(mActivity); mDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId); - mCameraDisplayOrientation = Util.getDisplayOrientation(0, mCameraId); + mCameraDisplayOrientation = mDisplayOrientation; mUI.setDisplayOrientation(mDisplayOrientation); if (mFocusManager != null) { mFocusManager.setDisplayOrientation(mDisplayOrientation); } - // GLRoot also uses the DisplayRotation, and needs to be told to layout to update - mActivity.getGLRoot().requestLayoutContentPane(); + // Change the camera display orientation + if (mCameraDevice != null) { + mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); + } } // Only called by UI thread. @@ -1611,40 +1577,15 @@ public class PhotoModule mFocusManager.setAeAwbLock(false); // Unlock AE and AWB. } setCameraParameters(UPDATE_PARAM_ALL); - - if (ApiHelper.HAS_SURFACE_TEXTURE) { - CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; - if (mUI.getSurfaceTexture() == null) { - Size size = mParameters.getPreviewSize(); - if (mCameraDisplayOrientation % 180 == 0) { - screenNail.setSize(size.width, size.height); - } else { - screenNail.setSize(size.height, size.width); - } - screenNail.enableAspectRatioClamping(); - mActivity.notifyScreenNailChanged(); - screenNail.acquireSurfaceTexture(); - CameraStartUpThread t = mCameraStartUpThread; - if (t != null && t.isCanceled()) { - return; // Exiting, so no need to get the surface texture. - } - mUI.setSurfaceTexture(screenNail.getSurfaceTexture()); - } else { - updatePreviewSize(screenNail); - } - mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); - Object st = mUI.getSurfaceTexture(); - if (st != null) { - mCameraDevice.setPreviewTextureAsync((SurfaceTexture) st); - } - } else { - mCameraDevice.setDisplayOrientation(mDisplayOrientation); - mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder()); + // Let UI set its expected aspect ratio + mUI.setPreviewSize(mParameters.getPreviewSize()); + Object st = mUI.getSurfaceTexture(); + if (st != null) { + mCameraDevice.setPreviewTextureAsync((SurfaceTexture) st); } Log.v(TAG, "startPreview"); mCameraDevice.startPreviewAsync(); - mFocusManager.onPreviewStarted(); if (mSnapshotOnIdle) { @@ -1652,21 +1593,6 @@ public class PhotoModule } } - private void updatePreviewSize(CameraScreenNail snail) { - Size size = mParameters.getPreviewSize(); - int w = size.width; - int h = size.height; - if (mCameraDisplayOrientation % 180 != 0) { - w = size.height; - h = size.width; - } - if (snail.getWidth() != w || snail.getHeight() != h) { - snail.setSize(w, h); - } - snail.enableAspectRatioClamping(); - mActivity.notifyScreenNailChanged(); - } - @Override public void stopPreview() { if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { @@ -1682,10 +1608,11 @@ public class PhotoModule private void updateCameraParametersInitialize() { // Reset preview frame rate to the maximum because it may be lowered by // video camera application. - List frameRates = mParameters.getSupportedPreviewFrameRates(); - if (frameRates != null) { - Integer max = Collections.max(frameRates); - mParameters.setPreviewFrameRate(max); + int[] fpsRange = Util.getMaxPreviewFpsRange(mParameters); + if (fpsRange.length > 0) { + mParameters.setPreviewFpsRange( + fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX], + fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]); } mParameters.set(Util.RECORDING_HINT, Util.FALSE); @@ -1760,6 +1687,7 @@ public class PhotoModule Size original = mParameters.getPreviewSize(); if (!original.equals(optimalSize)) { mParameters.setPreviewSize(optimalSize.width, optimalSize.height); + // Zoom related settings will be changed for different preview // sizes, so set and read the parameters to get latest values if (mHandler.getLooper() == Looper.myLooper()) { @@ -1950,16 +1878,12 @@ public class PhotoModule if (mPaused || mPendingSwitchCameraId != -1) return; mPendingSwitchCameraId = cameraId; - if (ApiHelper.HAS_SURFACE_TEXTURE) { - Log.v(TAG, "Start to copy texture. cameraId=" + cameraId); - // We need to keep a preview frame for the animation before - // releasing the camera. This will trigger onPreviewTextureCopied. - ((CameraScreenNail) mActivity.mCameraScreenNail).copyTexture(); - // Disable all camera controls. - setCameraState(SWITCHING_CAMERA); - } else { - switchCamera(); - } + + Log.v(TAG, "Start to switch camera. cameraId=" + cameraId); + // We need to keep a preview frame for the animation before + // releasing the camera. This will trigger onPreviewTextureCopied. + //TODO: Need to animate the camera switch + switchCamera(); } // Preview texture has been copied. Now camera can be released and the @@ -1975,7 +1899,7 @@ public class PhotoModule @Override public void onUserInteraction() { - if (!mActivity.isFinishing()) keepScreenOnAwhile(); + if (!mActivity.isFinishing()) keepScreenOnAwhile(); } private void resetScreenOn() { @@ -1989,11 +1913,6 @@ public class PhotoModule mHandler.sendEmptyMessageDelayed(CLEAR_SCREEN_DELAY, SCREEN_DELAY); } - // TODO: Delete this function after old camera code is removed - @Override - public void onRestorePreferencesClicked() { - } - @Override public void onOverriddenPreferencesClicked() { if (mPaused) return; @@ -2026,16 +1945,6 @@ public class PhotoModule mFocusManager.onShutterUp(); } - @Override - public boolean needsSwitcher() { - return !mIsImageCaptureIntent; - } - - @Override - public boolean needsPieMenu() { - return true; - } - @Override public void onShowSwitcherPopup() { mUI.onShowSwitcherPopup(); @@ -2101,5 +2010,18 @@ public class PhotoModule mHeading += 360; } } - public void updateCameraOrientation() {} + + @Override + public void onSwitchMode(boolean toCamera) { + mUI.onSwitchMode(toCamera); + } + +/* Below is no longer needed, except to get rid of compile error + * TODO: Remove these + */ + + // TODO: Delete this function after old camera code is removed + @Override + public void onRestorePreferencesClicked() {} + } diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java index a364d797e..1468a3ce4 100644 --- a/src/com/android/camera/PhotoUI.java +++ b/src/com/android/camera/PhotoUI.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,13 +17,19 @@ package com.android.camera; +import android.graphics.Matrix; +import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.hardware.Camera.Face; import android.hardware.Camera.FaceDetectionListener; +import android.hardware.Camera.Parameters; +import android.hardware.Camera.Size; +import android.os.Handler; +import android.os.Message; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; -import android.view.SurfaceHolder; +import android.view.TextureView; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLayoutChangeListener; @@ -31,15 +37,20 @@ import android.view.ViewGroup; import android.view.ViewStub; import android.widget.FrameLayout; import android.widget.FrameLayout.LayoutParams; +import android.widget.ImageView; import android.widget.Toast; import com.android.camera.CameraPreference.OnPreferenceChangedListener; import com.android.camera.FocusOverlayManager.FocusUI; import com.android.camera.ui.AbstractSettingPopup; +import com.android.camera.ui.CameraControls; +import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; import com.android.camera.ui.CountDownView; import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; +import com.android.camera.ui.CameraSwitcher; import com.android.camera.ui.FaceView; import com.android.camera.ui.FocusIndicator; +import com.android.camera.ui.CameraRootView; import com.android.camera.ui.PieRenderer; import com.android.camera.ui.PieRenderer.PieListener; import com.android.camera.ui.RenderOverlay; @@ -47,25 +58,23 @@ import com.android.camera.ui.ZoomRenderer; import com.android.gallery3d.R; import com.android.gallery3d.common.ApiHelper; +import java.io.IOException; import java.util.List; public class PhotoUI implements PieListener, - SurfaceHolder.Callback, PreviewGestures.SingleTapListener, - FocusUI, - LocationManager.Listener, - FaceDetectionListener, - PreviewGestures.SwipeListener { + FocusUI, TextureView.SurfaceTextureListener, + LocationManager.Listener, CameraRootView.MyDisplayListener, + FaceDetectionListener { private static final String TAG = "CAM_UI"; - + private static final int UPDATE_TRANSFORM_MATRIX = 1; private CameraActivity mActivity; private PhotoController mController; private PreviewGestures mGestures; private View mRootView; private Object mSurfaceTexture; - private volatile SurfaceHolder mSurfaceHolder; private AbstractSettingPopup mPopup; private ShutterButton mShutterButton; @@ -80,7 +89,10 @@ public class PhotoUI implements PieListener, private View mMenuButton; private View mBlocker; private PhotoMenu mMenu; + private CameraSwitcher mSwitcher; + private CameraControls mCameraControls; + // Small indicators which show the camera settings in the viewfinder. private OnScreenIndicators mOnScreenIndicators; private PieRenderer mPieRenderer; @@ -92,8 +104,33 @@ public class PhotoUI implements PieListener, private int mPreviewWidth = 0; private int mPreviewHeight = 0; + private float mSurfaceTextureUncroppedWidth; + private float mSurfaceTextureUncroppedHeight; + private View mPreviewThumb; + private SurfaceTextureSizeChangedListener mSurfaceTextureSizeListener; + private TextureView mTextureView; + private Matrix mMatrix = null; + private float mAspectRatio = 4f / 3f; + private final Object mLock = new Object(); + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case UPDATE_TRANSFORM_MATRIX: + setTransformMatrix(mPreviewWidth, mPreviewHeight); + break; + default: + break; + } + } + }; + + public interface SurfaceTextureSizeChangedListener { + public void onSurfaceTextureSizeChanged(int uncroppedWidth, int uncroppedHeight); + } + private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, @@ -107,9 +144,10 @@ public class PhotoUI implements PieListener, w = height; h = width; } - if (mPreviewWidth != w || mPreviewHeight != h) { - mPreviewWidth = w; - mPreviewHeight = h; + if (mPreviewWidth != width || mPreviewHeight != height) { + mPreviewWidth = width; + mPreviewHeight = height; + onScreenSizeChanged(width, height, w, h); mController.onScreenSizeChanged(width, height, w, h); } } @@ -123,20 +161,106 @@ public class PhotoUI implements PieListener, mActivity.getLayoutInflater().inflate(R.layout.photo_module, (ViewGroup) mRootView, true); mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay); - + // display the view + mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content); + mTextureView.setSurfaceTextureListener(this); + mTextureView.addOnLayoutChangeListener(mLayoutListener); initIndicators(); - mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture)); - mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController); + mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button); + mSwitcher = (CameraSwitcher) mRootView.findViewById(R.id.camera_switcher); + mSwitcher.setCurrentIndex(0); + mSwitcher.setSwitchListener((CameraSwitchListener) mActivity); + mMenuButton = mRootView.findViewById(R.id.menu); if (ApiHelper.HAS_FACE_DETECTION) { ViewStub faceViewStub = (ViewStub) mRootView .findViewById(R.id.face_view_stub); if (faceViewStub != null) { faceViewStub.inflate(); mFaceView = (FaceView) mRootView.findViewById(R.id.face_view); + setSurfaceTextureSizeChangedListener( + (SurfaceTextureSizeChangedListener) mFaceView); + } + } + mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls); + ((CameraRootView) mRootView).setDisplayChangeListener(this); + } + + public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { + setTransformMatrix(width, height); + } + + public void setSurfaceTextureSizeChangedListener(SurfaceTextureSizeChangedListener listener) { + mSurfaceTextureSizeListener = listener; + } + + public void setPreviewSize(Size size) { + int width = size.width; + int height = size.height; + if (width == 0 || height == 0) { + Log.w(TAG, "Preview size should not be 0."); + return; + } + if (width > height) { + mAspectRatio = (float) width / height; + } else { + mAspectRatio = (float) height / width; + } + mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX); + } + + private void setTransformMatrix(int width, int height) { + mMatrix = mTextureView.getTransform(mMatrix); + int orientation = Util.getDisplayRotation(mActivity); + float scaleX = 1f, scaleY = 1f; + float scaledTextureWidth, scaledTextureHeight; + if (width > height) { + scaledTextureWidth = Math.max(width, + (int) (height * mAspectRatio)); + scaledTextureHeight = Math.max(height, + (int)(width / mAspectRatio)); + } else { + scaledTextureWidth = Math.max(width, + (int) (height / mAspectRatio)); + scaledTextureHeight = Math.max(height, + (int) (width * mAspectRatio)); + } + + if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || + mSurfaceTextureUncroppedHeight != scaledTextureHeight) { + mSurfaceTextureUncroppedWidth = scaledTextureWidth; + mSurfaceTextureUncroppedHeight = scaledTextureHeight; + if (mSurfaceTextureSizeListener != null) { + mSurfaceTextureSizeListener.onSurfaceTextureSizeChanged( + (int) mSurfaceTextureUncroppedWidth, (int) mSurfaceTextureUncroppedHeight); } } + scaleX = scaledTextureWidth / width; + scaleY = scaledTextureHeight / height; + mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2); + mTextureView.setTransform(mMatrix); + } + + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { + synchronized (mLock) { + mSurfaceTexture = surface; + mLock.notifyAll(); + } + } + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + // Ignored, Camera does all the work for us + } + + public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { + mSurfaceTexture = null; + mController.stopPreview(); + Log.w(TAG, "surfaceTexture is destroyed"); + return true; + } + + public void onSurfaceTextureUpdated(SurfaceTexture surface) { + // Invoked every time there's a new Camera preview frame } public View getRootView() { @@ -145,7 +269,7 @@ public class PhotoUI implements PieListener, private void initIndicators() { mOnScreenIndicators = new OnScreenIndicators(mActivity, - mActivity.findViewById(R.id.on_screen_indicators)); + mRootView.findViewById(R.id.on_screen_indicators)); } public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs, @@ -155,6 +279,7 @@ public class PhotoUI implements PieListener, mPieRenderer.setPieListener(this); mRenderOverlay.addRenderer(mPieRenderer); } + if (mMenu == null) { mMenu = new PhotoMenu(mActivity, this, mPieRenderer); mMenu.setListener(listener); @@ -165,25 +290,14 @@ public class PhotoUI implements PieListener, mZoomRenderer = new ZoomRenderer(mActivity); mRenderOverlay.addRenderer(mZoomRenderer); } + if (mGestures == null) { // this will handle gesture disambiguation and dispatching - mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer, - this); + mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer); + mRenderOverlay.setGestures(mGestures); } - mGestures.reset(); + mGestures.setZoomEnabled(params.isZoomSupported()); mGestures.setRenderOverlay(mRenderOverlay); - mGestures.addTouchReceiver(mMenuButton); - mGestures.addUnclickableArea(mBlocker); - enablePreviewThumb(false); - // make sure to add touch targets for image capture - if (mController.isImageCaptureIntent()) { - if (mReviewCancelButton != null) { - mGestures.addTouchReceiver(mReviewCancelButton); - } - if (mReviewDoneButton != null) { - mGestures.addTouchReceiver(mReviewDoneButton); - } - } mRenderOverlay.requestLayout(); initializeZoom(params); @@ -202,15 +316,16 @@ public class PhotoUI implements PieListener, } public void initializeControlByIntent() { - mBlocker = mActivity.findViewById(R.id.blocker); + mBlocker = mRootView.findViewById(R.id.blocker); mPreviewThumb = mActivity.findViewById(R.id.preview_thumb); mPreviewThumb.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - mActivity.gotoGallery(); + // TODO: go to filmstrip + // mActivity.gotoGallery(); } }); - mMenuButton = mActivity.findViewById(R.id.menu); + mMenuButton = mRootView.findViewById(R.id.menu); mMenuButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -218,13 +333,13 @@ public class PhotoUI implements PieListener, } }); if (mController.isImageCaptureIntent()) { - mActivity.hideSwitcher(); - ViewGroup cameraControls = (ViewGroup) mActivity.findViewById(R.id.camera_controls); + hideSwitcher(); + ViewGroup cameraControls = (ViewGroup) mRootView.findViewById(R.id.camera_controls); mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls); - mReviewDoneButton = mActivity.findViewById(R.id.btn_done); - mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel); - mReviewRetakeButton = mActivity.findViewById(R.id.btn_retake); + mReviewDoneButton = mRootView.findViewById(R.id.btn_done); + mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel); + mReviewRetakeButton = mRootView.findViewById(R.id.btn_retake); mReviewCancelButton.setVisibility(View.VISIBLE); mReviewDoneButton.setOnClickListener(new OnClickListener() { @@ -249,14 +364,29 @@ public class PhotoUI implements PieListener, } } + public void hideUI() { + mCameraControls.setVisibility(View.INVISIBLE); + mSwitcher.closePopup(); + } + + public void showUI() { + mCameraControls.setVisibility(View.VISIBLE); + } + + public void hideSwitcher() { + mSwitcher.closePopup(); + mSwitcher.setVisibility(View.INVISIBLE); + } + + public void showSwitcher() { + mSwitcher.setVisibility(View.VISIBLE); + } // called from onResume but only the first time public void initializeFirstTime() { // Initialize shutter button. - mShutterButton = mActivity.getShutterButton(); mShutterButton.setImageResource(R.drawable.btn_new_shutter); mShutterButton.setOnShutterButtonListener(mController); mShutterButton.setVisibility(View.VISIBLE); - mRootView.addOnLayoutChangeListener(mLayoutListener); } // called from onResume every other time @@ -268,7 +398,6 @@ public class PhotoUI implements PieListener, if (mMenu != null) { mMenu.reloadPreferences(); } - mRootView.addOnLayoutChangeListener(mLayoutListener); } public void initializeZoom(Camera.Parameters params) { @@ -286,16 +415,8 @@ public class PhotoUI implements PieListener, } } - public void enableGestures(boolean enable) { - if (mGestures != null) { - mGestures.setEnabled(enable); - } - } - - @Override public void showGpsOnScreenIndicator(boolean hasSignal) { } - @Override public void hideGpsOnScreenIndicator() { } public void overrideSettings(final String ... keyvalues) { @@ -323,11 +444,16 @@ public class PhotoUI implements PieListener, public void setCameraState(int state) { } - public boolean dispatchTouchEvent(MotionEvent m) { - if (mGestures != null && mRenderOverlay != null) { - return mGestures.dispatchTouch(m); + public void enableGestures(boolean enable) { + if (mGestures != null) { + mGestures.setEnabled(enable); } - return false; + } + + // forward from preview gestures to controller + @Override + public void onSingleTapUp(View view, int x, int y) { + mController.onSingleTapUp(view, x, y); } public boolean onBackPressed() { @@ -352,36 +478,36 @@ public class PhotoUI implements PieListener, } } - public void onFullScreenChanged(boolean full) { + public void onSwitchMode(boolean toCamera) { + if (toCamera) { + showUI(); + } else { + hideUI(); + } if (mFaceView != null) { - mFaceView.setBlockDraw(!full); + mFaceView.setBlockDraw(!toCamera); } if (mPopup != null) { - dismissPopup(full); + dismissPopup(toCamera); } if (mGestures != null) { - mGestures.setEnabled(full); + mGestures.setEnabled(toCamera); } if (mRenderOverlay != null) { // this can not happen in capture mode - mRenderOverlay.setVisibility(full ? View.VISIBLE : View.GONE); + mRenderOverlay.setVisibility(toCamera ? View.VISIBLE : View.GONE); } if (mPieRenderer != null) { - mPieRenderer.setBlockFocus(!full); + mPieRenderer.setBlockFocus(!toCamera); } - setShowMenu(full); - if (mBlocker != null) { - mBlocker.setVisibility(full ? View.VISIBLE : View.GONE); - } - if (!full && mCountDownView != null) mCountDownView.cancelCountDown(); + setShowMenu(toCamera); + if (!toCamera && mCountDownView != null) mCountDownView.cancelCountDown(); } public void enablePreviewThumb(boolean enabled) { if (enabled) { - mGestures.addTouchReceiver(mPreviewThumb); mPreviewThumb.setVisibility(View.VISIBLE); } else { - mGestures.removeTouchReceiver(mPreviewThumb); mPreviewThumb.setVisibility(View.GONE); } } @@ -396,7 +522,7 @@ public class PhotoUI implements PieListener, } public void showPopup(AbstractSettingPopup popup) { - mActivity.hideUI(); + hideUI(); mBlocker.setVisibility(View.INVISIBLE); setShowMenu(false); mPopup = popup; @@ -405,7 +531,6 @@ public class PhotoUI implements PieListener, LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.CENTER; ((FrameLayout) mRootView).addView(mPopup, lp); - mGestures.addTouchReceiver(mPopup); } public void dismissPopup() { @@ -414,12 +539,11 @@ public class PhotoUI implements PieListener, private void dismissPopup(boolean fullScreen) { if (fullScreen) { - mActivity.showUI(); + showUI(); mBlocker.setVisibility(View.VISIBLE); } setShowMenu(fullScreen); if (mPopup != null) { - mGestures.removeTouchReceiver(mPopup); ((FrameLayout) mRootView).removeView(mPopup); mPopup = null; } @@ -482,8 +606,20 @@ public class PhotoUI implements PieListener, return mShutterButton.isPressed(); } - // focus handling + public void enableShutter(boolean enabled) { + if (mShutterButton != null) { + mShutterButton.setEnabled(enabled); + } + } + public void pressShutterButton() { + if (mShutterButton.isInTouchMode()) { + mShutterButton.requestFocusFromTouch(); + } else { + mShutterButton.requestFocus(); + } + mShutterButton.setPressed(true); + } private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { @Override @@ -511,9 +647,8 @@ public class PhotoUI implements PieListener, @Override public void onPieOpened(int centerX, int centerY) { + setSwipingEnabled(false); dismissPopup(); - mActivity.cancelActivityTouchHandling(); - mActivity.setSwipingEnabled(false); if (mFaceView != null) { mFaceView.setBlockDraw(true); } @@ -521,55 +656,49 @@ public class PhotoUI implements PieListener, @Override public void onPieClosed() { - mActivity.setSwipingEnabled(true); + setSwipingEnabled(true); if (mFaceView != null) { mFaceView.setBlockDraw(false); } } - // Surface Listener - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.v(TAG, "surfaceChanged:" + holder + " width=" + width + ". height=" - + height); - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - Log.v(TAG, "surfaceCreated: " + holder); - mSurfaceHolder = holder; - mController.onSurfaceCreated(holder); - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - Log.v(TAG, "surfaceDestroyed: " + holder); - mSurfaceHolder = null; - mController.stopPreview(); + public void setSwipingEnabled(boolean enable) { + mActivity.setSwipingEnabled(enable); } public Object getSurfaceTexture() { + synchronized (mLock) { + if (mSurfaceTexture == null) { + try { + mLock.wait(); + } catch (InterruptedException e) { + Log.w(TAG, "Unexpected interruption when waiting to get surface texture"); + } + } + } return mSurfaceTexture; } - public void setSurfaceTexture(Object st) { - mSurfaceTexture = st; - } + // Countdown timer - public SurfaceHolder getSurfaceHolder() { - return mSurfaceHolder; + private void initializeCountDown() { + mActivity.getLayoutInflater().inflate(R.layout.count_down_to_capture, + (ViewGroup) mRootView, true); + mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture)); + mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController); } public boolean isCountingDown() { - return mCountDownView.isCountingDown(); + return mCountDownView != null && mCountDownView.isCountingDown(); } public void cancelCountDown() { + if (mCountDownView == null) return; mCountDownView.cancelCountDown(); } public void startCountDown(int sec, boolean playSound) { + if (mCountDownView == null) initializeCountDown(); mCountDownView.startCountDown(sec, playSound); } @@ -582,41 +711,16 @@ public class PhotoUI implements PieListener, } public void onPause() { - mCountDownView.cancelCountDown(); - // Close the camera now because other activities may need to use it. - mSurfaceTexture = null; + cancelCountDown(); // Clear UI. collapseCameraControls(); if (mFaceView != null) mFaceView.clear(); - - mRootView.removeOnLayoutChangeListener(mLayoutListener); mPreviewWidth = 0; mPreviewHeight = 0; } - public void enableShutter(boolean enabled) { - if (mShutterButton != null) { - mShutterButton.setEnabled(enabled); - } - } - - public void pressShutterButton() { - if (mShutterButton.isInTouchMode()) { - mShutterButton.requestFocusFromTouch(); - } else { - mShutterButton.requestFocus(); - } - mShutterButton.setPressed(true); - } - - // forward from preview gestures to controller - @Override - public void onSingleTapUp(View view, int x, int y) { - mController.onSingleTapUp(view, x, y); - } - // focus UI implementation private FocusIndicator getFocusIndicator() { @@ -681,11 +785,9 @@ public class PhotoUI implements PieListener, mFaceView.setFaces(faces); } - @Override - public void onSwipe(int direction) { - if (direction == PreviewGestures.DIR_UP) { - openMenu(); - } + public void onDisplayChanged() { + mCameraControls.checkLayoutFlip(); + mController.updateCameraOrientation(); } } diff --git a/src/com/android/camera/PreviewGestures.java b/src/com/android/camera/PreviewGestures.java index 0b80ff688..925607e80 100644 --- a/src/com/android/camera/PreviewGestures.java +++ b/src/com/android/camera/PreviewGestures.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package com.android.camera; import android.os.Handler; import android.os.Message; +import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; @@ -28,9 +29,10 @@ import com.android.camera.ui.RenderOverlay; import com.android.camera.ui.ZoomRenderer; import com.android.gallery3d.R; -import java.util.ArrayList; -import java.util.List; - +/* PreviewGestures disambiguates touch events received on RenderOverlay + * and dispatch them to the proper recipient (i.e. zoom renderer or pie renderer). + * Touch events on CameraControls will be handled by framework. + * */ public class PreviewGestures implements ScaleGestureDetector.OnScaleGestureListener { @@ -58,23 +60,55 @@ public class PreviewGestures private MotionEvent mDown; private MotionEvent mCurrent; private ScaleGestureDetector mScale; - private List mReceivers; - private List mUnclickableAreas; private int mMode; private int mSlop; private int mTapTimeout; + private boolean mZoomEnabled; private boolean mEnabled; private boolean mZoomOnly; private int mOrientation; - private int[] mLocation; - private SwipeListener mSwipeListener; + private GestureDetector mGestureDetector; + + private GestureDetector.SimpleOnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() { + @Override + public void onLongPress (MotionEvent e) { + // Open pie + if (mPie != null && !mPie.showsItems()) { + openPie(); + } + } + + @Override + public boolean onSingleTapUp (MotionEvent e) { + // Tap to focus when pie is not open + if (mPie == null || !mPie.showsItems()) { + mTapListener.onSingleTapUp(null, (int) e.getX(), (int) e.getY()); + return true; + } + return false; + } + + @Override + public boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (mMode == MODE_ZOOM) return false; + int deltaX = (int) (e1.getX() - e2.getX()); + int deltaY = (int) (e1.getY() - e2.getY()); + if (deltaY > 2 * deltaX && deltaY > -2 * deltaX) { + // Open pie on swipe up + if (mPie != null && !mPie.showsItems()) { + openPie(); + return true; + } + } + return false; + } + }; private Handler mHandler = new Handler() { public void handleMessage(Message msg) { if (msg.what == MSG_PIE) { mMode = MODE_PIE; openPie(); - cancelActivityTouchHandling(mDown); } } }; @@ -83,12 +117,8 @@ public class PreviewGestures public void onSingleTapUp(View v, int x, int y); } - interface SwipeListener { - public void onSwipe(int direction); - } - public PreviewGestures(CameraActivity ctx, SingleTapListener tapListener, - ZoomRenderer zoom, PieRenderer pie, SwipeListener swipe) { + ZoomRenderer zoom, PieRenderer pie) { mActivity = ctx; mTapListener = tapListener; mPie = pie; @@ -98,8 +128,7 @@ public class PreviewGestures mSlop = (int) ctx.getResources().getDimension(R.dimen.pie_touch_slop); mTapTimeout = ViewConfiguration.getTapTimeout(); mEnabled = true; - mLocation = new int[2]; - mSwipeListener = swipe; + mGestureDetector = new GestureDetector(mGestureListener); } public void setRenderOverlay(RenderOverlay overlay) { @@ -112,184 +141,51 @@ public class PreviewGestures public void setEnabled(boolean enabled) { mEnabled = enabled; - if (!enabled) { - cancelPie(); - } - } - - public void setZoomOnly(boolean zoom) { - mZoomOnly = zoom; - } - - public void addTouchReceiver(View v) { - if (mReceivers == null) { - mReceivers = new ArrayList(); - } - mReceivers.add(v); - } - - public void removeTouchReceiver(View v) { - if (mReceivers == null || v == null) return; - mReceivers.remove(v); - } - - public void addUnclickableArea(View v) { - if (mUnclickableAreas == null) { - mUnclickableAreas = new ArrayList(); - } - mUnclickableAreas.add(v); - } - - public void clearTouchReceivers() { - if (mReceivers != null) { - mReceivers.clear(); - } } - public void clearUnclickableAreas() { - if (mUnclickableAreas != null) { - mUnclickableAreas.clear(); - } + public void setZoomEnabled(boolean enable) { + mZoomEnabled = enable; } - private boolean checkClickable(MotionEvent m) { - if (mUnclickableAreas != null) { - for (View v : mUnclickableAreas) { - if (isInside(m, v)) { - return false; - } - } - } - return true; + public void setZoomOnly(boolean zoom) { + mZoomOnly = zoom; } - public void reset() { - clearTouchReceivers(); - clearUnclickableAreas(); + public boolean isEnabled() { + return mEnabled; } public boolean dispatchTouch(MotionEvent m) { if (!mEnabled) { - return mActivity.superDispatchTouchEvent(m); + return false; } mCurrent = m; if (MotionEvent.ACTION_DOWN == m.getActionMasked()) { - if (checkReceivers(m)) { - mMode = MODE_MODULE; - return mActivity.superDispatchTouchEvent(m); - } else { - mMode = MODE_ALL; - mDown = MotionEvent.obtain(m); - if (mPie != null && mPie.showsItems()) { - mMode = MODE_PIE; - return sendToPie(m); - } - if (mPie != null && !mZoomOnly && checkClickable(m)) { - mHandler.sendEmptyMessageDelayed(MSG_PIE, TIMEOUT_PIE); - } - if (mZoom != null) { - mScale.onTouchEvent(m); - } - // make sure this is ok - return mActivity.superDispatchTouchEvent(m); - } - } else if (mMode == MODE_NONE) { - return false; - } else if (mMode == MODE_SWIPE) { - if (MotionEvent.ACTION_UP == m.getActionMasked()) { - mSwipeListener.onSwipe(getSwipeDirection(m)); - } - return true; - } else if (mMode == MODE_PIE) { - if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) { - sendToPie(makeCancelEvent(m)); - if (mZoom != null) { - onScaleBegin(mScale); - } - } else { - return sendToPie(m); - } - return true; - } else if (mMode == MODE_ZOOM) { - mScale.onTouchEvent(m); - if (!mScale.isInProgress() && MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) { - mMode = MODE_NONE; - onScaleEnd(mScale); - } - return true; - } else if (mMode == MODE_MODULE) { - return mActivity.superDispatchTouchEvent(m); - } else { - // didn't receive down event previously; - // assume module wasn't initialzed and ignore this event. - if (mDown == null) { - return true; - } - if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) { - if (!mZoomOnly) { - cancelPie(); - sendToPie(makeCancelEvent(m)); - } - if (mZoom != null) { - mScale.onTouchEvent(m); - onScaleBegin(mScale); - } - } else if ((mMode == MODE_ZOOM) && !mScale.isInProgress() - && MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) { - // user initiated and stopped zoom gesture without zooming - mScale.onTouchEvent(m); - onScaleEnd(mScale); - } - // not zoom or pie mode and no timeout yet - if (mZoom != null) { - boolean res = mScale.onTouchEvent(m); - if (mScale.isInProgress()) { - cancelPie(); - cancelActivityTouchHandling(m); - return res; - } - } - if (MotionEvent.ACTION_UP == m.getActionMasked()) { - cancelPie(); - // must have been tap - if (m.getEventTime() - mDown.getEventTime() < mTapTimeout - && checkClickable(m)) { - cancelActivityTouchHandling(m); - mTapListener.onSingleTapUp(null, - (int) mDown.getX() - mOverlay.getWindowPositionX(), - (int) mDown.getY() - mOverlay.getWindowPositionY()); - return true; - } else { - return mActivity.superDispatchTouchEvent(m); - } - } else if (MotionEvent.ACTION_MOVE == m.getActionMasked()) { - if ((Math.abs(m.getX() - mDown.getX()) > mSlop) - || Math.abs(m.getY() - mDown.getY()) > mSlop) { - // moved too far and no timeout yet, no focus or pie - cancelPie(); - int dir = getSwipeDirection(m); - if (dir == DIR_LEFT) { - mMode = MODE_MODULE; - return mActivity.superDispatchTouchEvent(m); - } else { - cancelActivityTouchHandling(m); - mMode = MODE_NONE; - } - } - } - return false; + mMode = MODE_NONE; + mDown = MotionEvent.obtain(m); } - } - private boolean checkReceivers(MotionEvent m) { - if (mReceivers != null) { - for (View receiver : mReceivers) { - if (isInside(m, receiver)) { - return true; + // If pie is open, redirects all the touch events to pie. + if (mPie != null && mPie.isOpen()) { + return sendToPie(m); + } + + // If pie is not open, send touch events to gesture detector and scale + // listener to recognize the gesture. + mGestureDetector.onTouchEvent(m); + if (mZoom != null) { + mScale.onTouchEvent(m); + if (MotionEvent.ACTION_POINTER_DOWN == m.getActionMasked()) { + mMode = MODE_ZOOM; + if (mZoomEnabled) { + // Start showing zoom UI as soon as there is a second finger down + mZoom.onScaleBegin(mScale); } + } else if (MotionEvent.ACTION_POINTER_UP == m.getActionMasked()) { + mZoom.onScaleEnd(mScale); } } - return false; + return true; } // left tests for finger moving right to left @@ -320,25 +216,6 @@ public class PreviewGestures return DIR_UP; } - private boolean isInside(MotionEvent evt, View v) { - v.getLocationInWindow(mLocation); - // when view is flipped horizontally - if ((int) v.getRotationY() == 180) { - mLocation[0] -= v.getWidth(); - } - // when view is flipped vertically - if ((int) v.getRotationX() == 180) { - mLocation[1] -= v.getHeight(); - } - return (v.getVisibility() == View.VISIBLE - && evt.getX() >= mLocation[0] && evt.getX() < mLocation[0] + v.getWidth() - && evt.getY() >= mLocation[1] && evt.getY() < mLocation[1] + v.getHeight()); - } - - public void cancelActivityTouchHandling(MotionEvent m) { - mActivity.superDispatchTouchEvent(makeCancelEvent(m)); - } - private MotionEvent makeCancelEvent(MotionEvent m) { MotionEvent c = MotionEvent.obtain(m); c.setAction(MotionEvent.ACTION_CANCEL); @@ -346,21 +223,16 @@ public class PreviewGestures } private void openPie() { - mDown.offsetLocation(-mOverlay.getWindowPositionX(), - -mOverlay.getWindowPositionY()); + mGestureDetector.onTouchEvent(makeCancelEvent(mDown)); + mScale.onTouchEvent(makeCancelEvent(mDown)); mOverlay.directDispatchTouch(mDown, mPie); } - private void cancelPie() { - mHandler.removeMessages(MSG_PIE); - } - private boolean sendToPie(MotionEvent m) { - m.offsetLocation(-mOverlay.getWindowPositionX(), - -mOverlay.getWindowPositionY()); return mOverlay.directDispatchTouch(m, mPie); } + // OnScaleGestureListener implementation @Override public boolean onScale(ScaleGestureDetector detector) { return mZoom.onScale(detector); @@ -368,21 +240,18 @@ public class PreviewGestures @Override public boolean onScaleBegin(ScaleGestureDetector detector) { - if (mMode != MODE_ZOOM) { + if (mPie == null || !mPie.isOpen()) { mMode = MODE_ZOOM; - cancelActivityTouchHandling(mCurrent); - } - if (mCurrent.getActionMasked() != MotionEvent.ACTION_MOVE) { + mGestureDetector.onTouchEvent(makeCancelEvent(mCurrent)); + if (!mZoomEnabled) return false; return mZoom.onScaleBegin(detector); - } else { - return true; } + return false; } @Override public void onScaleEnd(ScaleGestureDetector detector) { - if (mCurrent.getActionMasked() != MotionEvent.ACTION_MOVE) { - mZoom.onScaleEnd(detector); - } + mZoom.onScaleEnd(detector); } } + diff --git a/src/com/android/camera/VideoMenu.java b/src/com/android/camera/VideoMenu.java index 9bfcdea5d..da0bde10e 100644 --- a/src/com/android/camera/VideoMenu.java +++ b/src/com/android/camera/VideoMenu.java @@ -16,6 +16,7 @@ package com.android.camera; +import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; @@ -51,6 +52,7 @@ public class VideoMenu extends PieController mActivity = activity; } + public void initialize(PreferenceGroup group) { super.initialize(group); mPopup = null; @@ -200,5 +202,4 @@ public class VideoMenu extends PieController mUI.showPopup(mPopup); mPopupStatus = POPUP_SECOND_LEVEL; } - } diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 977986d1f..839037fc0 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -51,13 +51,16 @@ import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.OrientationEventListener; +import android.view.Surface; import android.view.View; import android.view.WindowManager; import android.widget.Toast; +import com.android.camera.CameraManager.CameraProxy; import com.android.camera.ui.PopupManager; import com.android.camera.ui.RotateTextToast; import com.android.gallery3d.R; +import com.android.gallery3d.app.OrientationManager; import com.android.gallery3d.common.ApiHelper; import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.util.AccessibilityUtils; @@ -113,7 +116,7 @@ public class VideoModule implements CameraModule, private Parameters mParameters; private Boolean mCameraOpened = false; - + private boolean mIsInReviewMode; private boolean mSnapshotInProgress = false; private static final String EFFECT_BG_FROM_GALLERY = "gallery"; @@ -123,11 +126,8 @@ public class VideoModule implements CameraModule, private ComboPreferences mPreferences; private PreferenceGroup mPreferenceGroup; - private CameraScreenNail.OnFrameDrawnListener mFrameDrawnListener; - private boolean mIsVideoCaptureIntent; private boolean mQuickCapture; - private boolean mIsInReviewMode = false; private MediaRecorder mMediaRecorder; private EffectsRecorder mEffectsRecorder; @@ -176,11 +176,16 @@ public class VideoModule implements CameraModule, private ContentResolver mContentResolver; private LocationManager mLocationManager; + private OrientationManager mOrientationManager; + private Surface mSurface; private int mPendingSwitchCameraId; - + private boolean mOpenCameraFail; + private boolean mCameraDisabled; private final Handler mHandler = new MainHandler(); private VideoUI mUI; + private CameraProxy mCameraDevice; + // The degrees of the device rotated clockwise from its natural orientation. private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; @@ -194,7 +199,6 @@ public class VideoModule implements CameraModule, @Override public void onMediaSaved(Uri uri) { if (uri != null) { - mActivity.addSecureAlbumItemIfNeeded(true, uri); mActivity.sendBroadcast( new Intent(Util.ACTION_NEW_VIDEO, uri)); Util.broadcastNewPicture(mActivity, uri); @@ -224,15 +228,15 @@ public class VideoModule implements CameraModule, try { synchronized(mCameraOpened) { if (!mCameraOpened) { - mActivity.mCameraDevice = Util.openCamera(mActivity, mCameraId); + mCameraDevice = Util.openCamera(mActivity, mCameraId); mCameraOpened = true; } } - mParameters = mActivity.mCameraDevice.getParameters(); + mParameters = mCameraDevice.getParameters(); } catch (CameraHardwareException e) { - mActivity.mOpenCameraFail = true; + mOpenCameraFail = true; } catch (CameraDisabledException e) { - mActivity.mCameraDisabled = true; + mCameraDisabled = true; } } @@ -285,18 +289,14 @@ public class VideoModule implements CameraModule, } case SWITCH_CAMERA_START_ANIMATION: { - ((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera(); + //TODO: + //((CameraScreenNail) mActivity.mCameraScreenNail).animateSwitchCamera(); // Enable all camera controls. mSwitchingCamera = false; break; } - case HIDE_SURFACE_VIEW: { - mUI.hideSurfaceView(); - break; - } - case CAPTURE_ANIMATION_DONE: { mUI.enablePreviewThumb(false); break; @@ -345,18 +345,12 @@ public class VideoModule implements CameraModule, private void initializeSurfaceView() { if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { // API level < 16 - mFrameDrawnListener = new CameraScreenNail.OnFrameDrawnListener() { - @Override - public void onFrameDrawn(CameraScreenNail c) { - mHandler.sendEmptyMessage(HIDE_SURFACE_VIEW); - } - }; - mUI.getSurfaceHolder().addCallback(mUI); + mUI.initializeSurfaceView(); } } @Override - public void init(CameraActivity activity, View root, boolean reuseScreenNail) { + public void init(CameraActivity activity, View root) { mActivity = activity; mUI = new VideoUI(activity, this, root); mPreferences = new ComboPreferences(mActivity); @@ -366,9 +360,9 @@ public class VideoModule implements CameraModule, mPreferences.setLocalId(mActivity, mCameraId); CameraSettings.upgradeLocalPreferences(mPreferences.getLocal()); - mActivity.mNumberOfCameras = CameraHolder.instance().getNumberOfCameras(); mPrefVideoEffectDefault = mActivity.getString(R.string.pref_video_effect_default); resetEffect(); + mOrientationManager = new OrientationManager(mActivity); /* * To reduce startup time, we start the preview in another thread. @@ -382,20 +376,15 @@ public class VideoModule implements CameraModule, // Surface texture is from camera screen nail and startPreview needs it. // This must be done before startPreview. mIsVideoCaptureIntent = isVideoCaptureIntent(); - if (reuseScreenNail) { - mActivity.reuseCameraScreenNail(!mIsVideoCaptureIntent); - } else { - mActivity.createCameraScreenNail(!mIsVideoCaptureIntent); - } initializeSurfaceView(); // Make sure camera device is opened. try { cameraOpenThread.join(); - if (mActivity.mOpenCameraFail) { + if (mOpenCameraFail) { Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); return; - } else if (mActivity.mCameraDisabled) { + } else if (mCameraDisabled) { Util.showErrorAndFinish(mActivity, R.string.camera_disabled); return; } @@ -463,10 +452,10 @@ public class VideoModule implements CameraModule, mParameters.setRotation(rotation); Location loc = mLocationManager.getCurrentLocation(); Util.setGpsParameters(mParameters, loc); - mActivity.mCameraDevice.setParameters(mParameters); + mCameraDevice.setParameters(mParameters); Log.v(TAG, "Video snapshot start"); - mActivity.mCameraDevice.takePicture(null, null, null, new JpegPictureCallback(loc)); + mCameraDevice.takePicture(null, null, null, new JpegPictureCallback(loc)); showVideoSnapshotUI(true); mSnapshotInProgress = true; UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, @@ -583,7 +572,8 @@ public class VideoModule implements CameraModule, // back to use SurfaceTexture for preview and we need to stop then start // the preview. This will cause the preview flicker since the preview // will not be continuous for a short period of time. - ((CameraScreenNail) mActivity.mCameraScreenNail).animateCapture(mDisplayRotation); + // TODO: need to get the capture animation to work + // ((CameraScreenNail) mActivity.mCameraScreenNail).animateCapture(mDisplayRotation); mUI.enablePreviewThumb(true); @@ -694,7 +684,7 @@ public class VideoModule implements CameraModule, @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) private void getDesiredPreviewSize() { - mParameters = mActivity.mCameraDevice.getParameters(); + mParameters = mCameraDevice.getParameters(); if (ApiHelper.HAS_GET_SUPPORTED_VIDEO_SIZE) { if (mParameters.getSupportedVideoSizes() == null || effectsActive()) { mDesiredPreviewWidth = mProfile.videoFrameWidth; @@ -720,6 +710,7 @@ public class VideoModule implements CameraModule, mDesiredPreviewWidth = mProfile.videoFrameWidth; mDesiredPreviewHeight = mProfile.videoFrameHeight; } + mUI.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight); Log.v(TAG, "mDesiredPreviewWidth=" + mDesiredPreviewWidth + ". mDesiredPreviewHeight=" + mDesiredPreviewHeight); } @@ -747,7 +738,7 @@ public class VideoModule implements CameraModule, @Override public void onResumeAfterSuper() { - if (mActivity.mOpenCameraFail || mActivity.mCameraDisabled) + if (mOpenCameraFail || mCameraDisabled) return; mUI.enableShutter(false); mZoomValue = 0; @@ -757,11 +748,11 @@ public class VideoModule implements CameraModule, if (!mPreviewing) { resetEffect(); openCamera(); - if (mActivity.mOpenCameraFail) { + if (mOpenCameraFail) { Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); return; - } else if (mActivity.mCameraDisabled) { + } else if (mCameraDisabled) { Util.showErrorAndFinish(mActivity, R.string.camera_disabled); return; } @@ -801,15 +792,19 @@ public class VideoModule implements CameraModule, private void setDisplayOrientation() { mDisplayRotation = Util.getDisplayRotation(mActivity); - if (ApiHelper.HAS_SURFACE_TEXTURE) { - // The display rotation is handled by gallery. - mCameraDisplayOrientation = Util.getDisplayOrientation(0, mCameraId); - } else { - // We need to consider display rotation ourselves. - mCameraDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId); + mCameraDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, mCameraId); + // Change the camera display orientation + if (mCameraDevice != null) { + mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); + } + } + + @Override + public void updateCameraOrientation() { + if (mMediaRecorderRecording) return; + if (mDisplayRotation != Util.getDisplayRotation(mActivity)) { + setDisplayOrientation(); } - // GLRoot also uses the DisplayRotation, and needs to be told to layout to update - mActivity.getGLRoot().requestLayoutContentPane(); } @Override @@ -817,18 +812,18 @@ public class VideoModule implements CameraModule, // Not useful to change zoom value when the activity is paused. if (mPaused) return index; mZoomValue = index; - if (mParameters == null || mActivity.mCameraDevice == null) return index; + if (mParameters == null || mCameraDevice == null) return index; // Set zoom parameters asynchronously mParameters.setZoom(mZoomValue); - mActivity.mCameraDevice.setParameters(mParameters); - Parameters p = mActivity.mCameraDevice.getParameters(); + mCameraDevice.setParameters(mParameters); + Parameters p = mCameraDevice.getParameters(); if (p != null) return p.getZoom(); return index; } private void startPreview() { Log.v(TAG, "startPreview"); - mActivity.mCameraDevice.setErrorCallback(mErrorCallback); + mCameraDevice.setErrorCallback(mErrorCallback); if (mPreviewing == true) { stopPreview(); if (effectsActive() && mEffectsRecorder != null) { @@ -838,22 +833,17 @@ public class VideoModule implements CameraModule, } setDisplayOrientation(); - mActivity.mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); + mCameraDevice.setDisplayOrientation(mCameraDisplayOrientation); setCameraParameters(); try { if (!effectsActive()) { - if (ApiHelper.HAS_SURFACE_TEXTURE) { - SurfaceTexture surfaceTexture = ((CameraScreenNail) mActivity.mCameraScreenNail) - .getSurfaceTexture(); - if (surfaceTexture == null) { - return; // The texture has been destroyed (pause, etc) - } - mActivity.mCameraDevice.setPreviewTextureAsync(surfaceTexture); - } else { - mActivity.mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder()); + SurfaceTexture surfaceTexture = mUI.getSurfaceTexture(); + if (surfaceTexture == null) { + return; // The texture has been destroyed (pause, etc) } - mActivity.mCameraDevice.startPreviewAsync(); + mCameraDevice.setPreviewTextureAsync(surfaceTexture); + mCameraDevice.startPreviewAsync(); mPreviewing = true; onPreviewStarted(); } else { @@ -869,9 +859,9 @@ public class VideoModule implements CameraModule, mActivity.runOnUiThread(new Runnable() { @Override public void run() { - if (mActivity.mOpenCameraFail) { + if (mOpenCameraFail) { Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); - } else if (mActivity.mCameraDisabled) { + } else if (mCameraDisabled) { Util.showErrorAndFinish(mActivity, R.string.camera_disabled); } } @@ -886,7 +876,8 @@ public class VideoModule implements CameraModule, @Override public void stopPreview() { - mActivity.mCameraDevice.stopPreview(); + if (!mPreviewing) return; + mCameraDevice.stopPreview(); mPreviewing = false; } @@ -922,7 +913,7 @@ public class VideoModule implements CameraModule, // effects also along with the camera. private void closeCamera(boolean closeEffectsAlso) { Log.v(TAG, "closeCamera"); - if (mActivity.mCameraDevice == null) { + if (mCameraDevice == null) { Log.d(TAG, "already stopped."); return; } @@ -933,27 +924,22 @@ public class VideoModule implements CameraModule, mEffectsRecorder.disconnectCamera(); } if (closeEffectsAlso) closeEffects(); - mActivity.mCameraDevice.setZoomChangeListener(null); - mActivity.mCameraDevice.setErrorCallback(null); + mCameraDevice.setZoomChangeListener(null); + mCameraDevice.setErrorCallback(null); synchronized(mCameraOpened) { if (mCameraOpened) { CameraHolder.instance().release(); } mCameraOpened = false; } - mActivity.mCameraDevice = null; + mCameraDevice = null; mPreviewing = false; mSnapshotInProgress = false; } private void releasePreviewResources() { - if (ApiHelper.HAS_SURFACE_TEXTURE) { - CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; - screenNail.releaseSurfaceTexture(); - if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { - mHandler.removeMessages(HIDE_SURFACE_VIEW); - mUI.hideSurfaceView(); - } + if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { + mUI.hideSurfaceView(); } } @@ -1096,13 +1082,11 @@ public class VideoModule implements CameraModule, private void setupMediaRecorderPreviewDisplay() { // Nothing to do here if using SurfaceTexture. - if (!ApiHelper.HAS_SURFACE_TEXTURE) { - mMediaRecorder.setPreviewDisplay(mUI.getSurfaceHolder().getSurface()); - } else if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { + if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { // We stop the preview here before unlocking the device because we // need to change the SurfaceTexture to SurfaceView for preview. stopPreview(); - mActivity.mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder()); + mCameraDevice.setPreviewDisplayAsync(mUI.getSurfaceHolder()); // The orientation for SurfaceTexture is different from that for // SurfaceView. For SurfaceTexture we don't need to consider the // display rotation. Just consider the sensor's orientation and we @@ -1110,9 +1094,9 @@ public class VideoModule implements CameraModule, // Gallery will handle the orientation for the preview. For // SurfaceView we will have to take everything into account so the // display rotation is considered. - mActivity.mCameraDevice.setDisplayOrientation( + mCameraDevice.setDisplayOrientation( Util.getDisplayOrientation(mDisplayRotation, mCameraId)); - mActivity.mCameraDevice.startPreviewAsync(); + mCameraDevice.startPreviewAsync(); mPreviewing = true; mMediaRecorder.setPreviewDisplay(mUI.getSurfaceHolder().getSurface()); } @@ -1122,15 +1106,14 @@ public class VideoModule implements CameraModule, private void initializeRecorder() { Log.v(TAG, "initializeRecorder"); // If the mCameraDevice is null, then this activity is going to finish - if (mActivity.mCameraDevice == null) return; + if (mCameraDevice == null) return; - if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING && ApiHelper.HAS_SURFACE_TEXTURE) { + if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { // Set the SurfaceView to visible so the surface gets created. // surfaceCreated() is called immediately when the visibility is // changed to visible. Thus, mSurfaceViewReady should become true // right after calling setVisibility(). mUI.showSurfaceView(); - if (!mUI.isSurfaceViewReady()) return; } Intent intent = mActivity.getIntent(); @@ -1156,9 +1139,9 @@ public class VideoModule implements CameraModule, setupMediaRecorderPreviewDisplay(); // Unlock the camera object before passing it to media recorder. - mActivity.mCameraDevice.unlock(); - mActivity.mCameraDevice.waitDone(); - mMediaRecorder.setCamera(mActivity.mCameraDevice.getCamera()); + mCameraDevice.unlock(); + mCameraDevice.waitDone(); + mMediaRecorder.setCamera(mCameraDevice.getCamera()); if (!mCaptureTimeLapse) { mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); } @@ -1244,7 +1227,7 @@ public class VideoModule implements CameraModule, private void initializeEffectsPreview() { Log.v(TAG, "initializeEffectsPreview"); // If the mCameraDevice is null, then this activity is going to finish - if (mActivity.mCameraDevice == null) return; + if (mCameraDevice == null) return; boolean inLandscape = (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); @@ -1257,7 +1240,7 @@ public class VideoModule implements CameraModule, // TODO: Confirm none of the following need to go to initializeEffectsRecording() // and none of these change even when the preview is not refreshed. mEffectsRecorder.setCameraDisplayOrientation(mCameraDisplayOrientation); - mEffectsRecorder.setCamera(mActivity.mCameraDevice); + mEffectsRecorder.setCamera(mCameraDevice); mEffectsRecorder.setCameraFacing(info.facing); mEffectsRecorder.setProfile(mProfile); mEffectsRecorder.setEffectsListener(this); @@ -1274,9 +1257,8 @@ public class VideoModule implements CameraModule, } mEffectsRecorder.setOrientationHint(orientation); - CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; - mEffectsRecorder.setPreviewSurfaceTexture(screenNail.getSurfaceTexture(), - screenNail.getWidth(), screenNail.getHeight()); + mEffectsRecorder.setPreviewSurfaceTexture(mUI.getSurfaceTexture(), + mUI.getPreviewWidth(), mUI.getPreviewHeight()); if (mEffectType == EffectsRecorder.EFFECT_BACKDROPPER && ((String) mEffectParameter).equals(EFFECT_BG_FROM_GALLERY)) { @@ -1472,7 +1454,7 @@ public class VideoModule implements CameraModule, private void startVideoRecording() { Log.v(TAG, "startVideoRecording"); mUI.enablePreviewThumb(false); - mActivity.setSwipingEnabled(false); + mUI.setSwipingEnabled(false); mActivity.updateStorageSpaceAndHint(); if (mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) { @@ -1480,7 +1462,7 @@ public class VideoModule implements CameraModule, return; } - if (!mActivity.mCameraDevice.waitDone()) return; + if (!mCameraDevice.waitDone()) return; mCurrentVideoUri = null; if (effectsActive()) { initializeEffectsRecording(); @@ -1513,31 +1495,31 @@ public class VideoModule implements CameraModule, Log.e(TAG, "Could not start media recorder. ", e); releaseMediaRecorder(); // If start fails, frameworks will not lock the camera for us. - mActivity.mCameraDevice.lock(); + mCameraDevice.lock(); return; } } // Make sure the video recording has started before announcing // this in accessibility. - AccessibilityUtils.makeAnnouncement(mActivity.getShutterButton(), + AccessibilityUtils.makeAnnouncement(mUI.getShutterButton(), mActivity.getString(R.string.video_recording_started)); // The parameters might have been altered by MediaRecorder already. // We need to force mCameraDevice to refresh before getting it. - mActivity.mCameraDevice.refreshParameters(); + mCameraDevice.refreshParameters(); // The parameters may have been changed by MediaRecorder upon starting // recording. We need to alter the parameters if we support camcorder // zoom. To reduce latency when setting the parameters during zoom, we // update mParameters here once. if (ApiHelper.HAS_ZOOM_WHEN_RECORDING) { - mParameters = mActivity.mCameraDevice.getParameters(); + mParameters = mCameraDevice.getParameters(); } mUI.enableCameraControls(false); mMediaRecorderRecording = true; - mActivity.getOrientationManager().lockOrientation(); + mOrientationManager.lockOrientation(); mRecordingStartTime = SystemClock.uptimeMillis(); mUI.showRecordingUI(true, mParameters.isZoomSupported()); @@ -1581,8 +1563,8 @@ public class VideoModule implements CameraModule, private boolean stopVideoRecording() { Log.v(TAG, "stopVideoRecording"); - mActivity.setSwipingEnabled(true); - mActivity.showSwitcher(); + mUI.setSwipingEnabled(true); + mUI.showSwitcher(); boolean fail = false; if (mMediaRecorderRecording) { @@ -1604,7 +1586,7 @@ public class VideoModule implements CameraModule, mCurrentVideoFilename = mVideoFilename; Log.v(TAG, "stopVideoRecording: Setting current video filename: " + mCurrentVideoFilename); - AccessibilityUtils.makeAnnouncement(mActivity.getShutterButton(), + AccessibilityUtils.makeAnnouncement(mUI.getShutterButton(), mActivity.getString(R.string.video_recording_stopped)); } catch (RuntimeException e) { Log.e(TAG, "stop fail", e); @@ -1612,7 +1594,7 @@ public class VideoModule implements CameraModule, fail = true; } mMediaRecorderRecording = false; - mActivity.getOrientationManager().unlockOrientation(); + mOrientationManager.unlockOrientation(); // If the activity is paused, this means activity is interrupted // during recording. Release the camera as soon as possible because @@ -1646,21 +1628,19 @@ public class VideoModule implements CameraModule, if (!effectsActive()) { releaseMediaRecorder(); if (!mPaused) { - mActivity.mCameraDevice.lock(); - mActivity.mCameraDevice.waitDone(); - if (ApiHelper.HAS_SURFACE_TEXTURE && - !ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { + mCameraDevice.lock(); + mCameraDevice.waitDone(); + if (!ApiHelper.HAS_SURFACE_TEXTURE_RECORDING) { stopPreview(); + mUI.hideSurfaceView(); // Switch back to use SurfaceTexture for preview. - ((CameraScreenNail) mActivity.mCameraScreenNail).setOneTimeOnFrameDrawnListener( - mFrameDrawnListener); startPreview(); } } } // Update the parameters here because the parameters might have been altered // by MediaRecorder. - if (!mPaused) mParameters = mActivity.mCameraDevice.getParameters(); + if (!mPaused) mParameters = mCameraDevice.getParameters(); UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, fail ? UsageStatistics.ACTION_CAPTURE_FAIL : UsageStatistics.ACTION_CAPTURE_DONE, "Video", @@ -1792,11 +1772,18 @@ public class VideoModule implements CameraModule, @SuppressWarnings("deprecation") private void setCameraParameters() { mParameters.setPreviewSize(mDesiredPreviewWidth, mDesiredPreviewHeight); - mParameters.setPreviewFrameRate(mProfile.videoFrameRate); + int[] fpsRange = Util.getMaxPreviewFpsRange(mParameters); + if (fpsRange.length > 0) { + mParameters.setPreviewFpsRange( + fpsRange[Parameters.PREVIEW_FPS_MIN_INDEX], + fpsRange[Parameters.PREVIEW_FPS_MAX_INDEX]); + } else { + mParameters.setPreviewFrameRate(mProfile.videoFrameRate); + } // Set flash mode. String flashMode; - if (mActivity.mShowCameraAppView) { + if (mUI.isVisible()) { flashMode = mPreferences.getString( CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE, mActivity.getString(R.string.pref_camera_video_flashmode_default)); @@ -1867,35 +1854,9 @@ public class VideoModule implements CameraModule, CameraProfile.QUALITY_HIGH); mParameters.setJpegQuality(jpegQuality); - mActivity.mCameraDevice.setParameters(mParameters); + mCameraDevice.setParameters(mParameters); // Keep preview size up to date. - mParameters = mActivity.mCameraDevice.getParameters(); - - updateCameraScreenNailSize(mDesiredPreviewWidth, mDesiredPreviewHeight); - } - - private void updateCameraScreenNailSize(int width, int height) { - if (!ApiHelper.HAS_SURFACE_TEXTURE) return; - - if (mCameraDisplayOrientation % 180 != 0) { - int tmp = width; - width = height; - height = tmp; - } - - CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; - int oldWidth = screenNail.getWidth(); - int oldHeight = screenNail.getHeight(); - - if (oldWidth != width || oldHeight != height) { - screenNail.setSize(width, height); - screenNail.enableAspectRatioClamping(); - mActivity.notifyScreenNailChanged(); - } - - if (screenNail.getSurfaceTexture() == null) { - screenNail.acquireSurfaceTexture(); - } + mParameters = mCameraDevice.getParameters(); } @Override @@ -2006,7 +1967,7 @@ public class VideoModule implements CameraModule, synchronized (mPreferences) { // If mCameraDevice is not ready then we can set the parameter in // startPreview(). - if (mActivity.mCameraDevice == null) return; + if (mCameraDevice == null) return; boolean recordLocation = RecordLocationPreference.get( mPreferences, mContentResolver); @@ -2062,14 +2023,13 @@ public class VideoModule implements CameraModule, initializeVideoControl(); // From onResume + mZoomValue = 0; mUI.initializeZoom(mParameters); mUI.setOrientationIndicator(0, false); - if (ApiHelper.HAS_SURFACE_TEXTURE) { - // Start switch camera animation. Post a message because - // onFrameAvailable from the old camera may already exist. - mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION); - } + // Start switch camera animation. Post a message because + // onFrameAvailable from the old camera may already exist. + mHandler.sendEmptyMessage(SWITCH_CAMERA_START_ANIMATION); mUI.updateOnScreenIndicators(mParameters, mPreferences); } @@ -2138,32 +2098,23 @@ public class VideoModule implements CameraModule, startPreview(); } - @Override - public boolean dispatchTouchEvent(MotionEvent m) { - if (mSwitchingCamera) return true; - return mUI.dispatchTouchEvent(m); - } - private void initializeVideoSnapshot() { if (mParameters == null) return; if (Util.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) { - mActivity.setSingleTapUpListener(mUI.getPreview()); // Show the tap to focus toast if this is the first start. if (mPreferences.getBoolean( CameraSettings.KEY_VIDEO_FIRST_USE_HINT_SHOWN, true)) { // Delay the toast for one second to wait for orientation. mHandler.sendEmptyMessageDelayed(SHOW_TAP_TO_SNAPSHOT_TOAST, 1000); } - } else { - mActivity.setSingleTapUpListener(null); } } void showVideoSnapshotUI(boolean enabled) { if (mParameters == null) return; if (Util.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) { - if (ApiHelper.HAS_SURFACE_TEXTURE && enabled) { - ((CameraScreenNail) mActivity.mCameraScreenNail).animateCapture(mDisplayRotation); + if (enabled) { + // TODO: ((CameraScreenNail) mActivity.mCameraScreenNail).animateCapture(mDisplayRotation); } else { mUI.showPreviewBorder(enabled); } @@ -2176,7 +2127,7 @@ public class VideoModule implements CameraModule, if (!mPreviewing || mParameters.getFlashMode() == null) return; // When going to and back from gallery, we need to turn off/on the flash. - if (!mActivity.mShowCameraAppView) { + if (!mUI.isVisible()) { if (mParameters.getFlashMode().equals(Parameters.FLASH_MODE_OFF)) { mRestoreFlash = false; return; @@ -2190,14 +2141,8 @@ public class VideoModule implements CameraModule, } @Override - public void onFullScreenChanged(boolean full) { - mUI.onFullScreenChanged(full); - if (ApiHelper.HAS_SURFACE_TEXTURE) { - if (mActivity.mCameraScreenNail != null) { - ((CameraScreenNail) mActivity.mCameraScreenNail).setFullScreen(full); - } - return; - } + public void onSwitchMode(boolean toCamera) { + mUI.onSwitchMode(toCamera); } private final class JpegPictureCallback implements PictureCallback { @@ -2285,26 +2230,13 @@ public class VideoModule implements CameraModule, if (mPaused || mPendingSwitchCameraId != -1) return; mPendingSwitchCameraId = cameraId; - if (ApiHelper.HAS_SURFACE_TEXTURE) { - Log.d(TAG, "Start to copy texture."); - // We need to keep a preview frame for the animation before - // releasing the camera. This will trigger onPreviewTextureCopied. - ((CameraScreenNail) mActivity.mCameraScreenNail).copyTexture(); - // Disable all camera controls. - mSwitchingCamera = true; - } else { - switchCamera(); - } - } + Log.d(TAG, "Start to copy texture."); + // We need to keep a preview frame for the animation before + // releasing the camera. This will trigger onPreviewTextureCopied. + // TODO: ((CameraScreenNail) mActivity.mCameraScreenNail).copyTexture(); + // Disable all camera controls. + mSwitchingCamera = true; - @Override - public boolean needsSwitcher() { - return !mIsVideoCaptureIntent; - } - - @Override - public boolean needsPieMenu() { - return true; } @Override @@ -2316,7 +2248,4 @@ public class VideoModule implements CameraModule, public void onMediaSaveServiceConnected(MediaSaveService s) { // do nothing. } - - @Override - public void updateCameraOrientation() {} } diff --git a/src/com/android/camera/VideoUI.java b/src/com/android/camera/VideoUI.java index 9fc05769f..c446b9778 100644 --- a/src/com/android/camera/VideoUI.java +++ b/src/com/android/camera/VideoUI.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,13 +17,20 @@ package com.android.camera; import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.graphics.SurfaceTexture; import android.hardware.Camera.Parameters; +import android.os.Handler; +import android.os.Message; import android.util.Log; import android.view.Gravity; -import android.view.MotionEvent; import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.TextureView; +import android.view.TextureView.SurfaceTextureListener; import android.view.View; import android.view.View.OnClickListener; +import android.view.View.OnLayoutChangeListener; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.FrameLayout.LayoutParams; @@ -33,8 +40,11 @@ import android.widget.TextView; import com.android.camera.CameraPreference.OnPreferenceChangedListener; import com.android.camera.ui.AbstractSettingPopup; +import com.android.camera.ui.CameraControls; +import com.android.camera.ui.CameraRootView; +import com.android.camera.ui.CameraSwitcher; +import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; import com.android.camera.ui.PieRenderer; -import com.android.camera.ui.PreviewSurfaceView; import com.android.camera.ui.RenderOverlay; import com.android.camera.ui.RotateLayout; import com.android.camera.ui.ZoomRenderer; @@ -43,16 +53,16 @@ import com.android.gallery3d.common.ApiHelper; import java.util.List; -public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, +public class VideoUI implements PieRenderer.PieListener, PreviewGestures.SingleTapListener, - PreviewGestures.SwipeListener { + CameraRootView.MyDisplayListener, + SurfaceTextureListener, SurfaceHolder.Callback { private final static String TAG = "CAM_VideoUI"; + private static final int UPDATE_TRANSFORM_MATRIX = 1; // module fields private CameraActivity mActivity; private View mRootView; - private PreviewFrameLayout mPreviewFrameLayout; - private boolean mSurfaceViewReady; - private PreviewSurfaceView mPreviewSurfaceView; + private TextureView mTextureView; // An review image having same size as preview. It is displayed when // recording is stopped in capture intent. private ImageView mReviewImage; @@ -60,40 +70,97 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, private View mReviewDoneButton; private View mReviewPlayButton; private ShutterButton mShutterButton; + private CameraSwitcher mSwitcher; private TextView mRecordingTimeView; private LinearLayout mLabelsLinearLayout; private View mTimeLapseLabel; private RenderOverlay mRenderOverlay; private PieRenderer mPieRenderer; private VideoMenu mVideoMenu; + private CameraControls mCameraControls; private AbstractSettingPopup mPopup; private ZoomRenderer mZoomRenderer; private PreviewGestures mGestures; - private View mMenu; + private View mMenuButton; private View mBlocker; private OnScreenIndicators mOnScreenIndicators; private RotateLayout mRecordingTimeRect; + private final Object mLock = new Object(); + private SurfaceTexture mSurfaceTexture; private VideoController mController; private int mZoomMax; private List mZoomRatios; private View mPreviewThumb; + private SurfaceView mSurfaceView = null; + private int mPreviewWidth = 0; + private int mPreviewHeight = 0; + private float mSurfaceTextureUncroppedWidth; + private float mSurfaceTextureUncroppedHeight; + private float mAspectRatio = 4f / 3f; + private Matrix mMatrix = null; + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case UPDATE_TRANSFORM_MATRIX: + setTransformMatrix(mPreviewWidth, mPreviewHeight); + break; + default: + break; + } + } + }; + private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, + int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + int width = right - left; + int height = bottom - top; + // Full-screen screennail + int w = width; + int h = height; + if (Util.getDisplayRotation(mActivity) % 180 != 0) { + w = height; + h = width; + } + if (mPreviewWidth != width || mPreviewHeight != height) { + mPreviewWidth = width; + mPreviewHeight = height; + onScreenSizeChanged(width, height, w, h); + } + } + }; + public VideoUI(CameraActivity activity, VideoController controller, View parent) { mActivity = activity; mController = controller; mRootView = parent; mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true); - mPreviewSurfaceView = (PreviewSurfaceView) mRootView - .findViewById(R.id.preview_surface_view); + mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content); + mTextureView.setSurfaceTextureListener(this); + mRootView.addOnLayoutChangeListener(mLayoutListener); + ((CameraRootView) mRootView).setDisplayChangeListener(this); + mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button); + mSwitcher = (CameraSwitcher) mRootView.findViewById(R.id.camera_switcher); + mSwitcher.setCurrentIndex(1); + mSwitcher.setSwitchListener((CameraSwitchListener) mActivity); initializeMiscControls(); initializeControlByIntent(); initializeOverlay(); } + + public void initializeSurfaceView() { + mSurfaceView = new SurfaceView(mActivity); + ((ViewGroup) mRootView).addView(mSurfaceView, 0); + mSurfaceView.getHolder().addCallback(this); + } + private void initializeControlByIntent() { mBlocker = mActivity.findViewById(R.id.blocker); - mMenu = mActivity.findViewById(R.id.menu); - mMenu.setOnClickListener(new OnClickListener() { + mMenuButton = mActivity.findViewById(R.id.menu); + mMenuButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mPieRenderer != null) { @@ -101,13 +168,15 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } } }); + + mCameraControls = (CameraControls) mActivity.findViewById(R.id.camera_controls); mOnScreenIndicators = new OnScreenIndicators(mActivity, mActivity.findViewById(R.id.on_screen_indicators)); mOnScreenIndicators.resetToDefault(); if (mController.isVideoCaptureIntent()) { - mActivity.hideSwitcher(); - ViewGroup cameraControls = (ViewGroup) mActivity.findViewById(R.id.camera_controls); - mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls); + hideSwitcher(); + mActivity.getLayoutInflater().inflate(R.layout.review_module_control, + (ViewGroup) mCameraControls); // Cannot use RotateImageView for "done" and "cancel" button because // the tablet layout uses RotateLayout, which cannot be cast to // RotateImageView. @@ -136,6 +205,85 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } } + public void setPreviewSize(int width, int height) { + if (width == 0 || height == 0) { + Log.w(TAG, "Preview size should not be 0."); + return; + } + if (width > height) { + mAspectRatio = (float) width / height; + } else { + mAspectRatio = (float) height / width; + } + mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX); + } + + public int getPreviewWidth() { + return mPreviewWidth; + } + + public int getPreviewHeight() { + return mPreviewHeight; + } + + public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) { + setTransformMatrix(width, height); + } + + private void setTransformMatrix(int width, int height) { + mMatrix = mTextureView.getTransform(mMatrix); + int orientation = Util.getDisplayRotation(mActivity); + float scaleX = 1f, scaleY = 1f; + float scaledTextureWidth, scaledTextureHeight; + if (width > height) { + scaledTextureWidth = Math.max(width, + (int) (height * mAspectRatio)); + scaledTextureHeight = Math.max(height, + (int)(width / mAspectRatio)); + } else { + scaledTextureWidth = Math.max(width, + (int) (height / mAspectRatio)); + scaledTextureHeight = Math.max(height, + (int) (width * mAspectRatio)); + } + + if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || + mSurfaceTextureUncroppedHeight != scaledTextureHeight) { + mSurfaceTextureUncroppedWidth = scaledTextureWidth; + mSurfaceTextureUncroppedHeight = scaledTextureHeight; + } + scaleX = scaledTextureWidth / width; + scaleY = scaledTextureHeight / height; + mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2); + mTextureView.setTransform(mMatrix); + + if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) { + LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams(); + lp.width = (int) mSurfaceTextureUncroppedWidth; + lp.height = (int) mSurfaceTextureUncroppedHeight; + lp.gravity = Gravity.CENTER; + mSurfaceView.requestLayout(); + } + } + + public void hideUI() { + mCameraControls.setVisibility(View.INVISIBLE); + mSwitcher.closePopup(); + } + + public void showUI() { + mCameraControls.setVisibility(View.VISIBLE); + } + + public void hideSwitcher() { + mSwitcher.closePopup(); + mSwitcher.setVisibility(View.INVISIBLE); + } + + public void showSwitcher() { + mSwitcher.setVisibility(View.VISIBLE); + } + public boolean collapseCameraControls() { boolean ret = false; if (mPopup != null) { @@ -166,10 +314,6 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, mVideoMenu.overrideSettings(keyvalues); } - public View getPreview() { - return mPreviewFrameLayout; - } - public void setOrientationIndicator(int orientation, boolean animation) { if (mGestures != null) { mGestures.setOrientation(orientation); @@ -187,15 +331,19 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } public SurfaceHolder getSurfaceHolder() { - return mPreviewSurfaceView.getHolder(); + return mSurfaceView.getHolder(); } public void hideSurfaceView() { - mPreviewSurfaceView.setVisibility(View.GONE); + mSurfaceView.setVisibility(View.GONE); + mTextureView.setVisibility(View.VISIBLE); + setTransformMatrix(mPreviewWidth, mPreviewHeight); } public void showSurfaceView() { - mPreviewSurfaceView.setVisibility(View.VISIBLE); + mSurfaceView.setVisibility(View.VISIBLE); + mTextureView.setVisibility(View.GONE); + setTransformMatrix(mPreviewWidth, mPreviewHeight); } private void initializeOverlay() { @@ -211,29 +359,16 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } mRenderOverlay.addRenderer(mZoomRenderer); if (mGestures == null) { - mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer, this); + mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer); + mRenderOverlay.setGestures(mGestures); } mGestures.setRenderOverlay(mRenderOverlay); - mGestures.reset(); - mGestures.addTouchReceiver(mMenu); - mGestures.addUnclickableArea(mBlocker); - if (mController.isVideoCaptureIntent()) { - if (mReviewCancelButton != null) { - mGestures.addTouchReceiver(mReviewCancelButton); - } - if (mReviewDoneButton != null) { - mGestures.addTouchReceiver(mReviewDoneButton); - } - if (mReviewPlayButton != null) { - mGestures.addTouchReceiver(mReviewPlayButton); - } - } mPreviewThumb = mActivity.findViewById(R.id.preview_thumb); mPreviewThumb.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - mActivity.gotoGallery(); + // TODO: Go to filmstrip view } }); } @@ -243,10 +378,7 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } private void initializeMiscControls() { - mPreviewFrameLayout = (PreviewFrameLayout) mRootView.findViewById(R.id.frame); - mPreviewFrameLayout.setOnLayoutChangeListener(mActivity); mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image); - mShutterButton = mActivity.getShutterButton(); mShutterButton.setImageResource(R.drawable.btn_new_shutter_video); mShutterButton.setOnShutterButtonListener(mController); mShutterButton.setVisibility(View.VISIBLE); @@ -269,7 +401,7 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } public void setAspectRatio(double ratio) { - mPreviewFrameLayout.setAspectRatio(ratio); + // mPreviewFrameLayout.setAspectRatio(ratio); } public void showTimeLapseUI(boolean enable) { @@ -285,7 +417,7 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } public void showPopup(AbstractSettingPopup popup) { - mActivity.hideUI(); + hideUI(); mBlocker.setVisibility(View.INVISIBLE); setShowMenu(false); mPopup = popup; @@ -294,7 +426,6 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.CENTER; ((FrameLayout) mRootView).addView(mPopup, lp); - mGestures.addTouchReceiver(mPopup); } public void dismissPopup(boolean topLevelOnly) { @@ -306,12 +437,11 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, if (mController.isInReviewMode()) return; if (fullScreen) { - mActivity.showUI(); + showUI(); mBlocker.setVisibility(View.VISIBLE); } setShowMenu(fullScreen); if (mPopup != null) { - mGestures.removeTouchReceiver(mPopup); ((FrameLayout) mRootView).removeView(mPopup); mPopup = null; } @@ -345,18 +475,21 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, // PieListener @Override public void onPieOpened(int centerX, int centerY) { + setSwipingEnabled(false); dismissPopup(false, true); - mActivity.cancelActivityTouchHandling(); - mActivity.setSwipingEnabled(false); } @Override public void onPieClosed() { - mActivity.setSwipingEnabled(true); + setSwipingEnabled(true); + } + + public void setSwipingEnabled(boolean enable) { + mActivity.setSwipingEnabled(enable); } public void showPreviewBorder(boolean enable) { - mPreviewFrameLayout.showBorder(enable); + // TODO: mPreviewFrameLayout.showBorder(enable); } // SingleTapListener @@ -366,35 +499,12 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, mController.onSingleTapUp(view, x, y); } - // SurfaceView callback - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.v(TAG, "Surface changed. width=" + width + ". height=" + height); - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - Log.v(TAG, "Surface created"); - mSurfaceViewReady = true; - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - Log.v(TAG, "Surface destroyed"); - mSurfaceViewReady = false; - mController.stopPreview(); - } - - public boolean isSurfaceViewReady() { - return mSurfaceViewReady; - } - public void showRecordingUI(boolean recording, boolean zoomSupported) { - mMenu.setVisibility(recording ? View.GONE : View.VISIBLE); + mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE); mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE); if (recording) { mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording); - mActivity.hideSwitcher(); + hideSwitcher(); mRecordingTimeView.setText(""); mRecordingTimeView.setVisibility(View.VISIBLE); // The camera is not allowed to be accessed in older api levels during @@ -407,7 +517,7 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } } else { mShutterButton.setImageResource(R.drawable.btn_new_shutter_video); - mActivity.showSwitcher(); + showSwitcher(); mRecordingTimeView.setVisibility(View.GONE); if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) { // TODO: enable zoom UI here. @@ -425,14 +535,14 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, Util.fadeIn(mReviewDoneButton); Util.fadeIn(mReviewPlayButton); mReviewImage.setVisibility(View.VISIBLE); - mMenu.setVisibility(View.GONE); + mMenuButton.setVisibility(View.GONE); mOnScreenIndicators.setVisibility(View.GONE); } public void hideReviewUI() { mReviewImage.setVisibility(View.GONE); mShutterButton.setEnabled(true); - mMenu.setVisibility(View.VISIBLE); + mMenuButton.setVisibility(View.VISIBLE); mOnScreenIndicators.setVisibility(View.VISIBLE); Util.fadeOut(mReviewDoneButton); Util.fadeOut(mReviewPlayButton); @@ -443,27 +553,28 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, if (mOnScreenIndicators != null) { mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE); } - if (mMenu != null) { - mMenu.setVisibility(show ? View.VISIBLE : View.GONE); + if (mMenuButton != null) { + mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE); } } - public void onFullScreenChanged(boolean full) { + public void onSwitchMode(boolean toCamera) { + if (toCamera) { + showUI(); + } else { + hideUI(); + } if (mGestures != null) { - mGestures.setEnabled(full); + mGestures.setEnabled(toCamera); } if (mPopup != null) { - dismissPopup(false, full); + dismissPopup(false, toCamera); } if (mRenderOverlay != null) { // this can not happen in capture mode - mRenderOverlay.setVisibility(full ? View.VISIBLE : View.GONE); - } - setShowMenu(full); - if (mBlocker != null) { - // this can not happen in capture mode - mBlocker.setVisibility(full ? View.VISIBLE : View.GONE); + mRenderOverlay.setVisibility(toCamera ? View.VISIBLE : View.GONE); } + setShowMenu(toCamera); } public void initializePopup(PreferenceGroup pref) { @@ -471,7 +582,11 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } public void initializeZoom(Parameters param) { - if (param == null || !param.isZoomSupported()) return; + if (param == null || !param.isZoomSupported()) { + mGestures.setZoomEnabled(false); + return; + } + mGestures.setZoomEnabled(true); mZoomMax = param.getMaxZoom(); mZoomRatios = param.getZoomRatios(); // Currently we use immediate zoom for fast zooming to get better UX and @@ -490,11 +605,8 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, mShutterButton.setPressed(pressed); } - public boolean dispatchTouchEvent(MotionEvent m) { - if (mGestures != null && mRenderOverlay != null) { - return mGestures.dispatchTouch(m); - } - return false; + public View getShutterButton() { + return mShutterButton; } public void setRecordingTime(String text) { @@ -505,6 +617,26 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, mRecordingTimeView.setTextColor(color); } + public boolean isVisible() { + return mTextureView.getVisibility() == View.VISIBLE; + } + + public void onDisplayChanged() { + mCameraControls.checkLayoutFlip(); + mController.updateCameraOrientation(); + } + + /** + * Enable or disable the preview thumbnail for click events. + */ + public void enablePreviewThumb(boolean enabled) { + if (enabled) { + mPreviewThumb.setVisibility(View.VISIBLE); + } else { + mPreviewThumb.setVisibility(View.GONE); + } + } + private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { @Override public void onZoomValueChanged(int index) { @@ -523,23 +655,58 @@ public class VideoUI implements SurfaceHolder.Callback, PieRenderer.PieListener, } } - @Override - public void onSwipe(int direction) { - if (direction == PreviewGestures.DIR_UP) { - openMenu(); + public SurfaceTexture getSurfaceTexture() { + synchronized (mLock) { + if (mSurfaceTexture == null) { + try { + mLock.wait(); + } catch (InterruptedException e) { + Log.w(TAG, "Unexpected interruption when waiting to get surface texture"); + } + } } + return mSurfaceTexture; } - /** - * Enable or disable the preview thumbnail for click events. - */ - public void enablePreviewThumb(boolean enabled) { - if (enabled) { - mGestures.addTouchReceiver(mPreviewThumb); - mPreviewThumb.setVisibility(View.VISIBLE); - } else { - mGestures.removeTouchReceiver(mPreviewThumb); - mPreviewThumb.setVisibility(View.GONE); + // SurfaceTexture callbacks + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { + synchronized (mLock) { + mSurfaceTexture = surface; + mLock.notifyAll(); } } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { + mSurfaceTexture = null; + mController.stopPreview(); + Log.d(TAG, "surfaceTexture is destroyed"); + return true; + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surface) { + } + + // SurfaceHolder callbacks + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + Log.v(TAG, "Surface changed. width=" + width + ". height=" + height); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + Log.v(TAG, "Surface created"); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + Log.v(TAG, "Surface destroyed"); + mController.stopPreview(); + } } diff --git a/src/com/android/camera/ui/CameraRootView.java b/src/com/android/camera/ui/CameraRootView.java index 76fea2cfa..adda70697 100644 --- a/src/com/android/camera/ui/CameraRootView.java +++ b/src/com/android/camera/ui/CameraRootView.java @@ -20,28 +20,34 @@ import android.app.Activity; import android.content.Context; import android.content.res.Configuration; import android.graphics.Rect; +import android.hardware.display.DisplayManager; +import android.hardware.display.DisplayManager.DisplayListener; import android.util.AttributeSet; -import android.view.Gravity; import android.view.View; import android.widget.FrameLayout; -import android.widget.RelativeLayout; import com.android.camera.Util; -import com.android.gallery3d.R; +import com.android.gallery3d.common.ApiHelper; -public class CameraRootView extends RelativeLayout { +public class CameraRootView extends FrameLayout { private int mTopMargin = 0; private int mBottomMargin = 0; private int mLeftMargin = 0; private int mRightMargin = 0; - private int mOffset = 0; private Rect mCurrentInsets; + private int mOffset = 0; + private Object mDisplayListener; + private MyDisplayListener mListener; + public interface MyDisplayListener { + public void onDisplayChanged(); + } + public CameraRootView(Context context, AttributeSet attrs) { super(context, attrs); - // Layout the window as if we did not need navigation bar - setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); + initDisplayListener(); + setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } @Override @@ -60,6 +66,46 @@ public class CameraRootView extends RelativeLayout { return true; } + public void initDisplayListener() { + if (ApiHelper.HAS_DISPLAY_LISTENER) { + mDisplayListener = new DisplayListener() { + + @Override + public void onDisplayAdded(int arg0) {} + + @Override + public void onDisplayChanged(int arg0) { + mListener.onDisplayChanged(); + } + + @Override + public void onDisplayRemoved(int arg0) {} + }; + } + } + + public void setDisplayChangeListener(MyDisplayListener listener) { + mListener = listener; + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + if (ApiHelper.HAS_DISPLAY_LISTENER) { + ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE)) + .registerDisplayListener((DisplayListener) mDisplayListener, null); + } + } + + @Override + public void onDetachedFromWindow () { + super.onDetachedFromWindow(); + if (ApiHelper.HAS_DISPLAY_LISTENER) { + ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE)) + .unregisterDisplayListener((DisplayListener) mDisplayListener); + } + } + @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int rotation = Util.getDisplayRotation((Activity) getContext()); @@ -102,12 +148,15 @@ public class CameraRootView extends RelativeLayout { // make sure all the children are resized super.onMeasure(widthMeasureSpec - mLeftMargin - mRightMargin, heightMeasureSpec - mTopMargin - mBottomMargin); - setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); } @Override public void onLayout(boolean changed, int l, int t, int r, int b) { + r -= l; + b -= t; + l = 0; + t = 0; int orientation = getResources().getConfiguration().orientation; // Lay out children for (int i = 0; i < getChildCount(); i++) { diff --git a/src/com/android/camera/ui/FaceView.java b/src/com/android/camera/ui/FaceView.java index 24150497c..7d66dc079 100644 --- a/src/com/android/camera/ui/FaceView.java +++ b/src/com/android/camera/ui/FaceView.java @@ -31,9 +31,7 @@ import android.util.AttributeSet; import android.util.Log; import android.view.View; -import com.android.camera.CameraActivity; -import com.android.camera.CameraScreenNail; -import com.android.camera.NewPhotoUI; +import com.android.camera.PhotoUI; import com.android.camera.Util; import com.android.gallery3d.R; import com.android.gallery3d.common.ApiHelper; @@ -41,7 +39,7 @@ import com.android.gallery3d.common.ApiHelper; @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) public class FaceView extends View implements FocusIndicator, Rotatable, - NewPhotoUI.SurfaceTextureSizeChangedListener { + PhotoUI.SurfaceTextureSizeChangedListener { private static final String TAG = "CAM FaceView"; private final boolean LOGV = false; // The value for android.hardware.Camera.setDisplayOrientation. @@ -190,16 +188,8 @@ public class FaceView extends View protected void onDraw(Canvas canvas) { if (!mBlocked && (mFaces != null) && (mFaces.length > 0)) { int rw, rh; - if (mUncroppedWidth == 0) { - // TODO: This check is temporary. It needs to be removed after the - // refactoring is fully functioning. - final CameraScreenNail sn = ((CameraActivity) getContext()).getCameraScreenNail(); - rw = sn.getUncroppedRenderWidth(); - rh = sn.getUncroppedRenderHeight(); - } else { - rw = mUncroppedWidth; - rh = mUncroppedHeight; - } + rw = mUncroppedWidth; + rh = mUncroppedHeight; // Prepare the matrix. if (((rh > rw) && ((mDisplayOrientation == 0) || (mDisplayOrientation == 180))) || ((rw > rh) && ((mDisplayOrientation == 90) || (mDisplayOrientation == 270)))) { diff --git a/src/com/android/camera/ui/NewCameraRootView.java b/src/com/android/camera/ui/NewCameraRootView.java deleted file mode 100644 index 07b6ec623..000000000 --- a/src/com/android/camera/ui/NewCameraRootView.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera.ui; - -import android.app.Activity; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Rect; -import android.hardware.display.DisplayManager; -import android.hardware.display.DisplayManager.DisplayListener; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.widget.FrameLayout; - -import com.android.camera.Util; -import com.android.gallery3d.R; -import com.android.gallery3d.common.ApiHelper; - -public class NewCameraRootView extends FrameLayout { - - private int mTopMargin = 0; - private int mBottomMargin = 0; - private int mLeftMargin = 0; - private int mRightMargin = 0; - private Rect mCurrentInsets; - private int mOffset = 0; - private Object mDisplayListener; - private MyDisplayListener mListener; - public interface MyDisplayListener { - public void onDisplayChanged(); - } - - public NewCameraRootView(Context context, AttributeSet attrs) { - super(context, attrs); - initDisplayListener(); - setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); - } - - @Override - protected boolean fitSystemWindows(Rect insets) { - super.fitSystemWindows(insets); - mCurrentInsets = insets; - // insets include status bar, navigation bar, etc - // In this case, we are only concerned with the size of nav bar - if (mOffset > 0) return true; - - if (insets.bottom > 0) { - mOffset = insets.bottom; - } else if (insets.right > 0) { - mOffset = insets.right; - } - return true; - } - - public void initDisplayListener() { - if (ApiHelper.HAS_DISPLAY_LISTENER) { - mDisplayListener = new DisplayListener() { - - @Override - public void onDisplayAdded(int arg0) {} - - @Override - public void onDisplayChanged(int arg0) { - mListener.onDisplayChanged(); - } - - @Override - public void onDisplayRemoved(int arg0) {} - }; - } - } - - public void setDisplayChangeListener(MyDisplayListener listener) { - mListener = listener; - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - if (ApiHelper.HAS_DISPLAY_LISTENER) { - ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE)) - .registerDisplayListener((DisplayListener) mDisplayListener, null); - } - } - - @Override - public void onDetachedFromWindow () { - super.onDetachedFromWindow(); - if (ApiHelper.HAS_DISPLAY_LISTENER) { - ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE)) - .unregisterDisplayListener((DisplayListener) mDisplayListener); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int rotation = Util.getDisplayRotation((Activity) getContext()); - // all the layout code assumes camera device orientation to be portrait - // adjust rotation for landscape - int orientation = getResources().getConfiguration().orientation; - int camOrientation = (rotation % 180 == 0) ? Configuration.ORIENTATION_PORTRAIT - : Configuration.ORIENTATION_LANDSCAPE; - if (camOrientation != orientation) { - rotation = (rotation + 90) % 360; - } - // calculate margins - mLeftMargin = 0; - mRightMargin = 0; - mBottomMargin = 0; - mTopMargin = 0; - switch (rotation) { - case 0: - mBottomMargin += mOffset; - break; - case 90: - mRightMargin += mOffset; - break; - case 180: - mTopMargin += mOffset; - break; - case 270: - mLeftMargin += mOffset; - break; - } - if (mCurrentInsets != null) { - if (mCurrentInsets.right > 0) { - // navigation bar on the right - mRightMargin = mRightMargin > 0 ? mRightMargin : mCurrentInsets.right; - } else { - // navigation bar on the bottom - mBottomMargin = mBottomMargin > 0 ? mBottomMargin : mCurrentInsets.bottom; - } - } - // make sure all the children are resized - super.onMeasure(widthMeasureSpec - mLeftMargin - mRightMargin, - heightMeasureSpec - mTopMargin - mBottomMargin); - setMeasuredDimension(widthMeasureSpec, heightMeasureSpec); - } - - @Override - public void onLayout(boolean changed, int l, int t, int r, int b) { - r -= l; - b -= t; - l = 0; - t = 0; - int orientation = getResources().getConfiguration().orientation; - // Lay out children - for (int i = 0; i < getChildCount(); i++) { - View v = getChildAt(i); - if (v instanceof CameraControls) { - // Lay out camera controls to center on the short side of the screen - // so that they stay in place during rotation - int width = v.getMeasuredWidth(); - int height = v.getMeasuredHeight(); - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - int left = (l + r - width) / 2; - v.layout(left, t + mTopMargin, left + width, b - mBottomMargin); - } else { - int top = (t + b - height) / 2; - v.layout(l + mLeftMargin, top, r - mRightMargin, top + height); - } - } else { - v.layout(l + mLeftMargin, t + mTopMargin, r - mRightMargin, b - mBottomMargin); - } - } - } -} diff --git a/src/com/android/camera/ui/RenderOverlay.java b/src/com/android/camera/ui/RenderOverlay.java index c61103018..d82ce18b6 100644 --- a/src/com/android/camera/ui/RenderOverlay.java +++ b/src/com/android/camera/ui/RenderOverlay.java @@ -23,7 +23,7 @@ import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; -import com.android.camera.NewPreviewGestures; +import com.android.camera.PreviewGestures; import java.util.ArrayList; import java.util.List; @@ -44,7 +44,7 @@ public class RenderOverlay extends FrameLayout { private RenderView mRenderView; private List mClients; - private NewPreviewGestures mGestures; + private PreviewGestures mGestures; // reverse list of touch clients private List mTouchClients; private int[] mPosition = new int[2]; @@ -59,7 +59,7 @@ public class RenderOverlay extends FrameLayout { setWillNotDraw(false); } - public void setGestures(NewPreviewGestures gestures) { + public void setGestures(PreviewGestures gestures) { mGestures = gestures; } diff --git a/src/com/android/gallery3d/app/StateManager.java b/src/com/android/gallery3d/app/StateManager.java index c0c84c950..53c3fc228 100644 --- a/src/com/android/gallery3d/app/StateManager.java +++ b/src/com/android/gallery3d/app/StateManager.java @@ -64,14 +64,10 @@ public class StateManager { StateTransitionAnimation.Transition.Incoming); if (mIsResumed) top.onPause(); } - // Ignore the filmstrip used for the root of the camera app - boolean ignoreHit = (mActivity instanceof CameraActivity) - && mStack.isEmpty(); - if (!ignoreHit) { - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_GALLERY, - klass.getSimpleName()); - } + + UsageStatistics.onContentViewChanged( + UsageStatistics.COMPONENT_GALLERY, + klass.getSimpleName()); state.initialize(mActivity, data); mStack.push(new StateEntry(data, state)); -- cgit v1.2.3