| /* |
| * 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. |
| * 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.animation.Animator; |
| import android.animation.AnimatorListenerAdapter; |
| import android.animation.ObjectAnimator; |
| import android.content.Context; |
| import android.content.ComponentName; |
| 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.os.Bundle; |
| import android.os.IBinder; |
| import android.provider.MediaStore; |
| import android.provider.Settings; |
| 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.ViewGroup; |
| import android.widget.FrameLayout; |
| |
| import com.android.camera.ui.CameraSwitcher; |
| 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 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 mShutterSwitcher; |
| private View mControlsBackground; |
| private Drawable[] mDrawables; |
| private int mCurrentModuleIndex; |
| private MotionEvent mDown; |
| private boolean mAutoRotateScreen; |
| |
| 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.main_content); |
| 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() { |
| mControlsBackground = findViewById(R.id.controls); |
| mShutterSwitcher = findViewById(R.id.camera_shutter_switcher); |
| mShutter = (ShutterButton) findViewById(R.id.shutter_button); |
| mSwitcher = (CameraSwitcher) findViewById(R.id.camera_switcher); |
| 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 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 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 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; |
| } |
| openModule(mCurrentModule, canReuse); |
| mCurrentModule.onOrientationChanged(mLastRawOrientation); |
| if (mMediaSaveService != null) { |
| mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); |
| } |
| getCameraScreenNail().setAlpha(0f); |
| getCameraScreenNail().setOnFrameDrawnOneShot(mOnFrameDrawn); |
| } |
| |
| private Runnable mOnFrameDrawn = new Runnable() { |
| |
| @Override |
| public void run() { |
| runOnUiThread(mFadeInCameraScreenNail); |
| } |
| }; |
| |
| private Runnable mFadeInCameraScreenNail = new Runnable() { |
| |
| @Override |
| public void run() { |
| mCameraSwitchAnimator = ObjectAnimator.ofFloat( |
| getCameraScreenNail(), "alpha", 0f, 1f); |
| mCameraSwitchAnimator.setStartDelay(50); |
| mCameraSwitchAnimator.start(); |
| } |
| }; |
| |
| @Override |
| public void onShowSwitcherPopup() { |
| mCurrentModule.onShowSwitcherPopup(); |
| } |
| |
| private void openModule(CameraModule module, boolean canReuse) { |
| module.init(this, mFrame, canReuse && canReuseScreenNail()); |
| mPaused = false; |
| module.onResumeBeforeSuper(); |
| module.onResumeAfterSuper(); |
| } |
| |
| private void closeModule(CameraModule module) { |
| module.onPauseBeforeSuper(); |
| module.onPauseAfterSuper(); |
| mFrame.removeAllViews(); |
| } |
| |
| public ShutterButton getShutterButton() { |
| return mShutter; |
| } |
| |
| public void hideUI() { |
| mControlsBackground.setVisibility(View.INVISIBLE); |
| hideSwitcher(); |
| mShutter.setVisibility(View.GONE); |
| } |
| |
| public void showUI() { |
| mControlsBackground.setVisibility(View.VISIBLE); |
| showSwitcher(); |
| mShutter.setVisibility(View.VISIBLE); |
| // Force a layout change to show shutter button |
| mShutter.requestLayout(); |
| } |
| |
| public void hideSwitcher() { |
| mSwitcher.closePopup(); |
| mSwitcher.setVisibility(View.INVISIBLE); |
| } |
| |
| public void showSwitcher() { |
| if (mCurrentModule.needsSwitcher()) { |
| mSwitcher.setVisibility(View.VISIBLE); |
| } |
| } |
| |
| public boolean isInCameraApp() { |
| return mShowCameraAppView; |
| } |
| |
| @Override |
| public void onConfigurationChanged(Configuration config) { |
| super.onConfigurationChanged(config); |
| |
| ViewGroup appRoot = (ViewGroup) findViewById(R.id.content); |
| // remove old switcher, shutter and shutter icon |
| View cameraControlsView = findViewById(R.id.camera_shutter_switcher); |
| appRoot.removeView(cameraControlsView); |
| |
| // create new layout with the current orientation |
| LayoutInflater inflater = getLayoutInflater(); |
| inflater.inflate(R.layout.camera_shutter_switcher, appRoot); |
| init(); |
| |
| if (mShowCameraAppView) { |
| showUI(); |
| } else { |
| hideUI(); |
| } |
| mCurrentModule.onConfigurationChanged(config); |
| } |
| |
| @Override |
| public void onPause() { |
| mPaused = true; |
| mOrientationListener.disable(); |
| mCurrentModule.onPauseBeforeSuper(); |
| super.onPause(); |
| mCurrentModule.onPauseAfterSuper(); |
| } |
| |
| @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); |
| mAutoRotateScreen = false; |
| } else { |
| setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); |
| mAutoRotateScreen = true; |
| } |
| mOrientationListener.enable(); |
| mCurrentModule.onResumeBeforeSuper(); |
| super.onResume(); |
| mCurrentModule.onResumeAfterSuper(); |
| } |
| |
| 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() { |
| mMediaSaveService.setListener(null); |
| unbindService(mConnection); |
| } |
| |
| @Override |
| protected void onFullScreenChanged(boolean full) { |
| if (full) { |
| showUI(); |
| } else { |
| hideUI(); |
| } |
| super.onFullScreenChanged(full); |
| mCurrentModule.onFullScreenChanged(full); |
| } |
| |
| @Override |
| protected void onStop() { |
| super.onStop(); |
| mCurrentModule.onStop(); |
| getStateManager().clearTasks(); |
| } |
| |
| @Override |
| protected void onNewIntent(Intent intent) { |
| super.onNewIntent(intent); |
| getStateManager().clearActivityResult(); |
| } |
| |
| @Override |
| protected void installIntentFilter() { |
| super.installIntentFilter(); |
| mCurrentModule.installIntentFilter(); |
| } |
| |
| @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; |
| } |
| mCurrentModule.onActivityResult(requestCode, resultCode, data); |
| } |
| |
| // Preview area is touched. Handle touch focus. |
| @Override |
| protected void onSingleTapUp(View view, int x, int y) { |
| mCurrentModule.onSingleTapUp(view, x, y); |
| } |
| |
| @Override |
| public void onBackPressed() { |
| if (!mCurrentModule.onBackPressed()) { |
| super.onBackPressed(); |
| } |
| } |
| |
| @Override |
| public boolean onKeyDown(int keyCode, KeyEvent event) { |
| return mCurrentModule.onKeyDown(keyCode, event) |
| || super.onKeyDown(keyCode, event); |
| } |
| |
| @Override |
| public boolean onKeyUp(int keyCode, KeyEvent event) { |
| return mCurrentModule.onKeyUp(keyCode, event) |
| || super.onKeyUp(keyCode, event); |
| } |
| |
| public void cancelActivityTouchHandling() { |
| if (mDown != null) { |
| MotionEvent cancel = MotionEvent.obtain(mDown); |
| cancel.setAction(MotionEvent.ACTION_CANCEL); |
| super.dispatchTouchEvent(cancel); |
| } |
| } |
| |
| @Override |
| public boolean dispatchTouchEvent(MotionEvent m) { |
| if (m.getActionMasked() == MotionEvent.ACTION_DOWN) { |
| mDown = m; |
| } |
| if ((mSwitcher != null) && mSwitcher.showsPopup() && !mSwitcher.isInsidePopup(m)) { |
| return mSwitcher.onTouch(null, m); |
| } else { |
| return mShutterSwitcher.dispatchTouchEvent(m) |
| || mCurrentModule.dispatchTouchEvent(m); |
| } |
| } |
| |
| @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); |
| } |
| |
| public boolean superDispatchTouchEvent(MotionEvent m) { |
| return super.dispatchTouchEvent(m); |
| } |
| |
| // Preview texture has been copied. Now camera can be released and the |
| // animation can be started. |
| @Override |
| public void onPreviewTextureCopied() { |
| mCurrentModule.onPreviewTextureCopied(); |
| } |
| |
| @Override |
| public void onCaptureTextureCopied() { |
| mCurrentModule.onCaptureTextureCopied(); |
| } |
| |
| @Override |
| public void onUserInteraction() { |
| super.onUserInteraction(); |
| mCurrentModule.onUserInteraction(); |
| } |
| |
| @Override |
| protected boolean updateStorageHintOnResume() { |
| return mCurrentModule.updateStorageHintOnResume(); |
| } |
| |
| @Override |
| public void updateCameraAppView() { |
| super.updateCameraAppView(); |
| mCurrentModule.updateCameraAppView(); |
| } |
| |
| private boolean canReuseScreenNail() { |
| return mCurrentModuleIndex == PHOTO_MODULE_INDEX |
| || mCurrentModuleIndex == VIDEO_MODULE_INDEX |
| || mCurrentModuleIndex == LIGHTCYCLE_MODULE_INDEX; |
| } |
| |
| @Override |
| public boolean isPanoramaActivity() { |
| return (mCurrentModuleIndex == PANORAMA_MODULE_INDEX); |
| } |
| |
| // 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; |
| } |
| |
| public CameraScreenNail getCameraScreenNail() { |
| return (CameraScreenNail) mCameraScreenNail; |
| } |
| |
| public MediaSaveService getMediaSaveService() { |
| return mMediaSaveService; |
| } |
| } |