CameraActivity.java revision a3dc2c0dd75f4659146fcd257ce32acc3800ae5f
1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.camera; 18 19import android.animation.Animator; 20import android.animation.AnimatorListenerAdapter; 21import android.animation.ObjectAnimator; 22import android.content.Context; 23import android.content.ComponentName; 24import android.content.Intent; 25import android.content.ServiceConnection; 26import android.content.res.Configuration; 27import android.graphics.drawable.Drawable; 28import android.os.Bundle; 29import android.os.IBinder; 30import android.provider.MediaStore; 31import android.view.KeyEvent; 32import android.view.LayoutInflater; 33import android.view.MotionEvent; 34import android.view.OrientationEventListener; 35import android.view.View; 36import android.view.ViewGroup; 37import android.widget.FrameLayout; 38 39import com.android.camera.ui.CameraSwitcher; 40import com.android.gallery3d.R; 41import com.android.gallery3d.app.PhotoPage; 42import com.android.gallery3d.common.ApiHelper; 43import com.android.gallery3d.util.LightCycleHelper; 44 45public class CameraActivity extends ActivityBase 46 implements CameraSwitcher.CameraSwitchListener { 47 public static final int PHOTO_MODULE_INDEX = 0; 48 public static final int VIDEO_MODULE_INDEX = 1; 49 public static final int PANORAMA_MODULE_INDEX = 2; 50 public static final int LIGHTCYCLE_MODULE_INDEX = 3; 51 52 CameraModule mCurrentModule; 53 private FrameLayout mFrame; 54 private ShutterButton mShutter; 55 private CameraSwitcher mSwitcher; 56 private View mShutterSwitcher; 57 private View mControlsBackground; 58 private Drawable[] mDrawables; 59 private int mCurrentModuleIndex; 60 private MotionEvent mDown; 61 62 private MyOrientationEventListener mOrientationListener; 63 // The degrees of the device rotated clockwise from its natural orientation. 64 private int mLastRawOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; 65 66 private MediaSaveService mMediaSaveService; 67 private ServiceConnection mConnection = new ServiceConnection() { 68 @Override 69 public void onServiceConnected(ComponentName className, IBinder b) { 70 mMediaSaveService = ((MediaSaveService.LocalBinder) b).getService(); 71 mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); 72 } 73 @Override 74 public void onServiceDisconnected(ComponentName className) { 75 mMediaSaveService = null; 76 }}; 77 78 private static final String TAG = "CAM_activity"; 79 80 private static final int[] DRAW_IDS = { 81 R.drawable.ic_switch_camera, 82 R.drawable.ic_switch_video, 83 R.drawable.ic_switch_pan, 84 R.drawable.ic_switch_photosphere 85 }; 86 87 @Override 88 public void onCreate(Bundle state) { 89 super.onCreate(state); 90 setContentView(R.layout.camera_main); 91 mFrame = (FrameLayout) findViewById(R.id.main_content); 92 mDrawables = new Drawable[DRAW_IDS.length]; 93 for (int i = 0; i < DRAW_IDS.length; i++) { 94 mDrawables[i] = getResources().getDrawable(DRAW_IDS[i]); 95 } 96 init(); 97 if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction()) 98 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) { 99 mCurrentModule = new VideoModule(); 100 mCurrentModuleIndex = VIDEO_MODULE_INDEX; 101 } else { 102 mCurrentModule = new PhotoModule(); 103 mCurrentModuleIndex = PHOTO_MODULE_INDEX; 104 } 105 mCurrentModule.init(this, mFrame, true); 106 mSwitcher.setCurrentIndex(mCurrentModuleIndex); 107 mOrientationListener = new MyOrientationEventListener(this); 108 bindMediaSaveService(); 109 } 110 111 public void init() { 112 mControlsBackground = findViewById(R.id.controls); 113 mShutterSwitcher = findViewById(R.id.camera_shutter_switcher); 114 mShutter = (ShutterButton) findViewById(R.id.shutter_button); 115 mSwitcher = (CameraSwitcher) findViewById(R.id.camera_switcher); 116 int totaldrawid = (LightCycleHelper.hasLightCycleCapture(this) 117 ? DRAW_IDS.length : DRAW_IDS.length - 1); 118 if (!ApiHelper.HAS_OLD_PANORAMA) totaldrawid--; 119 120 int[] drawids = new int[totaldrawid]; 121 int[] moduleids = new int[totaldrawid]; 122 int ix = 0; 123 for (int i = 0; i < mDrawables.length; i++) { 124 if (i == PANORAMA_MODULE_INDEX && !ApiHelper.HAS_OLD_PANORAMA) { 125 continue; // not enabled, so don't add to UI 126 } 127 if (i == LIGHTCYCLE_MODULE_INDEX && !LightCycleHelper.hasLightCycleCapture(this)) { 128 continue; // not enabled, so don't add to UI 129 } 130 moduleids[ix] = i; 131 drawids[ix++] = DRAW_IDS[i]; 132 } 133 mSwitcher.setIds(moduleids, drawids); 134 mSwitcher.setSwitchListener(this); 135 mSwitcher.setCurrentIndex(mCurrentModuleIndex); 136 } 137 138 @Override 139 public void onDestroy() { 140 unbindMediaSaveService(); 141 super.onDestroy(); 142 } 143 144 private class MyOrientationEventListener 145 extends OrientationEventListener { 146 public MyOrientationEventListener(Context context) { 147 super(context); 148 } 149 150 @Override 151 public void onOrientationChanged(int orientation) { 152 // We keep the last known orientation. So if the user first orient 153 // the camera then point the camera to floor or sky, we still have 154 // the correct orientation. 155 if (orientation == ORIENTATION_UNKNOWN) return; 156 mLastRawOrientation = orientation; 157 mCurrentModule.onOrientationChanged(orientation); 158 } 159 } 160 161 private ObjectAnimator mCameraSwitchAnimator; 162 163 @Override 164 public void onCameraSelected(final int i) { 165 if (mPaused) return; 166 if (i != mCurrentModuleIndex) { 167 mPaused = true; 168 CameraScreenNail screenNail = getCameraScreenNail(); 169 if (screenNail != null) { 170 if (mCameraSwitchAnimator != null && mCameraSwitchAnimator.isRunning()) { 171 mCameraSwitchAnimator.cancel(); 172 } 173 mCameraSwitchAnimator = ObjectAnimator.ofFloat( 174 screenNail, "alpha", screenNail.getAlpha(), 0f); 175 mCameraSwitchAnimator.addListener(new AnimatorListenerAdapter() { 176 @Override 177 public void onAnimationEnd(Animator animation) { 178 super.onAnimationEnd(animation); 179 doChangeCamera(i); 180 } 181 }); 182 mCameraSwitchAnimator.start(); 183 } else { 184 doChangeCamera(i); 185 } 186 } 187 } 188 189 private void doChangeCamera(int i) { 190 boolean canReuse = canReuseScreenNail(); 191 CameraHolder.instance().keep(); 192 closeModule(mCurrentModule); 193 mCurrentModuleIndex = i; 194 switch (i) { 195 case VIDEO_MODULE_INDEX: 196 mCurrentModule = new VideoModule(); 197 break; 198 case PHOTO_MODULE_INDEX: 199 mCurrentModule = new PhotoModule(); 200 break; 201 case PANORAMA_MODULE_INDEX: 202 mCurrentModule = new PanoramaModule(); 203 break; 204 case LIGHTCYCLE_MODULE_INDEX: 205 mCurrentModule = LightCycleHelper.createPanoramaModule(); 206 break; 207 } 208 openModule(mCurrentModule, canReuse); 209 mCurrentModule.onOrientationChanged(mLastRawOrientation); 210 if (mMediaSaveService != null) { 211 mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); 212 } 213 getCameraScreenNail().setAlpha(0f); 214 getCameraScreenNail().setOnFrameDrawnOneShot(mOnFrameDrawn); 215 } 216 217 private Runnable mOnFrameDrawn = new Runnable() { 218 219 @Override 220 public void run() { 221 runOnUiThread(mFadeInCameraScreenNail); 222 } 223 }; 224 225 private Runnable mFadeInCameraScreenNail = new Runnable() { 226 227 @Override 228 public void run() { 229 mCameraSwitchAnimator = ObjectAnimator.ofFloat( 230 getCameraScreenNail(), "alpha", 0f, 1f); 231 mCameraSwitchAnimator.setStartDelay(50); 232 mCameraSwitchAnimator.start(); 233 } 234 }; 235 236 @Override 237 public void onShowSwitcherPopup() { 238 mCurrentModule.onShowSwitcherPopup(); 239 } 240 241 private void openModule(CameraModule module, boolean canReuse) { 242 module.init(this, mFrame, canReuse && canReuseScreenNail()); 243 mPaused = false; 244 module.onResumeBeforeSuper(); 245 module.onResumeAfterSuper(); 246 } 247 248 private void closeModule(CameraModule module) { 249 module.onPauseBeforeSuper(); 250 module.onPauseAfterSuper(); 251 mFrame.removeAllViews(); 252 } 253 254 public ShutterButton getShutterButton() { 255 return mShutter; 256 } 257 258 public void hideUI() { 259 mControlsBackground.setVisibility(View.INVISIBLE); 260 hideSwitcher(); 261 mShutter.setVisibility(View.GONE); 262 } 263 264 public void showUI() { 265 mControlsBackground.setVisibility(View.VISIBLE); 266 showSwitcher(); 267 mShutter.setVisibility(View.VISIBLE); 268 // Force a layout change to show shutter button 269 mShutter.requestLayout(); 270 } 271 272 public void hideSwitcher() { 273 mSwitcher.closePopup(); 274 mSwitcher.setVisibility(View.INVISIBLE); 275 } 276 277 public void showSwitcher() { 278 if (mCurrentModule.needsSwitcher()) { 279 mSwitcher.setVisibility(View.VISIBLE); 280 } 281 } 282 283 public boolean isInCameraApp() { 284 return mShowCameraAppView; 285 } 286 287 @Override 288 public void onConfigurationChanged(Configuration config) { 289 super.onConfigurationChanged(config); 290 291 ViewGroup appRoot = (ViewGroup) findViewById(R.id.content); 292 // remove old switcher, shutter and shutter icon 293 View cameraControlsView = findViewById(R.id.camera_shutter_switcher); 294 appRoot.removeView(cameraControlsView); 295 296 // create new layout with the current orientation 297 LayoutInflater inflater = getLayoutInflater(); 298 inflater.inflate(R.layout.camera_shutter_switcher, appRoot); 299 init(); 300 301 if (mShowCameraAppView) { 302 showUI(); 303 } else { 304 hideUI(); 305 } 306 mCurrentModule.onConfigurationChanged(config); 307 } 308 309 @Override 310 public void onPause() { 311 mPaused = true; 312 mOrientationListener.disable(); 313 mCurrentModule.onPauseBeforeSuper(); 314 super.onPause(); 315 mCurrentModule.onPauseAfterSuper(); 316 } 317 318 @Override 319 public void onResume() { 320 mPaused = false; 321 mOrientationListener.enable(); 322 mCurrentModule.onResumeBeforeSuper(); 323 super.onResume(); 324 mCurrentModule.onResumeAfterSuper(); 325 } 326 327 private void bindMediaSaveService() { 328 Intent intent = new Intent(this, MediaSaveService.class); 329 startService(intent); // start service before binding it so the 330 // service won't be killed if we unbind it. 331 bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 332 } 333 334 private void unbindMediaSaveService() { 335 mMediaSaveService.setListener(null); 336 unbindService(mConnection); 337 } 338 339 @Override 340 protected void onFullScreenChanged(boolean full) { 341 if (full) { 342 showUI(); 343 } else { 344 hideUI(); 345 } 346 super.onFullScreenChanged(full); 347 mCurrentModule.onFullScreenChanged(full); 348 } 349 350 @Override 351 protected void onStop() { 352 super.onStop(); 353 mCurrentModule.onStop(); 354 getStateManager().clearTasks(); 355 } 356 357 @Override 358 protected void onNewIntent(Intent intent) { 359 super.onNewIntent(intent); 360 getStateManager().clearActivityResult(); 361 } 362 363 @Override 364 protected void installIntentFilter() { 365 super.installIntentFilter(); 366 mCurrentModule.installIntentFilter(); 367 } 368 369 @Override 370 protected void onActivityResult( 371 int requestCode, int resultCode, Intent data) { 372 // Only PhotoPage understands ProxyLauncher.RESULT_USER_CANCELED 373 if (resultCode == ProxyLauncher.RESULT_USER_CANCELED 374 && !(getStateManager().getTopState() instanceof PhotoPage)) { 375 resultCode = RESULT_CANCELED; 376 } 377 super.onActivityResult(requestCode, resultCode, data); 378 // Unmap cancel vs. reset 379 if (resultCode == ProxyLauncher.RESULT_USER_CANCELED) { 380 resultCode = RESULT_CANCELED; 381 } 382 mCurrentModule.onActivityResult(requestCode, resultCode, data); 383 } 384 385 // Preview area is touched. Handle touch focus. 386 @Override 387 protected void onSingleTapUp(View view, int x, int y) { 388 mCurrentModule.onSingleTapUp(view, x, y); 389 } 390 391 @Override 392 public void onBackPressed() { 393 if (!mCurrentModule.onBackPressed()) { 394 super.onBackPressed(); 395 } 396 } 397 398 @Override 399 public boolean onKeyDown(int keyCode, KeyEvent event) { 400 return mCurrentModule.onKeyDown(keyCode, event) 401 || super.onKeyDown(keyCode, event); 402 } 403 404 @Override 405 public boolean onKeyUp(int keyCode, KeyEvent event) { 406 return mCurrentModule.onKeyUp(keyCode, event) 407 || super.onKeyUp(keyCode, event); 408 } 409 410 public void cancelActivityTouchHandling() { 411 if (mDown != null) { 412 MotionEvent cancel = MotionEvent.obtain(mDown); 413 cancel.setAction(MotionEvent.ACTION_CANCEL); 414 super.dispatchTouchEvent(cancel); 415 } 416 } 417 418 @Override 419 public boolean dispatchTouchEvent(MotionEvent m) { 420 if (m.getActionMasked() == MotionEvent.ACTION_DOWN) { 421 mDown = m; 422 } 423 if ((mSwitcher != null) && mSwitcher.showsPopup() && !mSwitcher.isInsidePopup(m)) { 424 return mSwitcher.onTouch(null, m); 425 } else { 426 return mShutterSwitcher.dispatchTouchEvent(m) 427 || mCurrentModule.dispatchTouchEvent(m); 428 } 429 } 430 431 @Override 432 public void startActivityForResult(Intent intent, int requestCode) { 433 Intent proxyIntent = new Intent(this, ProxyLauncher.class); 434 proxyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 435 proxyIntent.putExtra(Intent.EXTRA_INTENT, intent); 436 super.startActivityForResult(proxyIntent, requestCode); 437 } 438 439 public boolean superDispatchTouchEvent(MotionEvent m) { 440 return super.dispatchTouchEvent(m); 441 } 442 443 // Preview texture has been copied. Now camera can be released and the 444 // animation can be started. 445 @Override 446 public void onPreviewTextureCopied() { 447 mCurrentModule.onPreviewTextureCopied(); 448 } 449 450 @Override 451 public void onCaptureTextureCopied() { 452 mCurrentModule.onCaptureTextureCopied(); 453 } 454 455 @Override 456 public void onUserInteraction() { 457 super.onUserInteraction(); 458 mCurrentModule.onUserInteraction(); 459 } 460 461 @Override 462 protected boolean updateStorageHintOnResume() { 463 return mCurrentModule.updateStorageHintOnResume(); 464 } 465 466 @Override 467 public void updateCameraAppView() { 468 super.updateCameraAppView(); 469 mCurrentModule.updateCameraAppView(); 470 } 471 472 private boolean canReuseScreenNail() { 473 return mCurrentModuleIndex == PHOTO_MODULE_INDEX 474 || mCurrentModuleIndex == VIDEO_MODULE_INDEX 475 || mCurrentModuleIndex == LIGHTCYCLE_MODULE_INDEX; 476 } 477 478 @Override 479 public boolean isPanoramaActivity() { 480 return (mCurrentModuleIndex == PANORAMA_MODULE_INDEX); 481 } 482 483 // Accessor methods for getting latency times used in performance testing 484 public long getAutoFocusTime() { 485 return (mCurrentModule instanceof PhotoModule) ? 486 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1; 487 } 488 489 public long getShutterLag() { 490 return (mCurrentModule instanceof PhotoModule) ? 491 ((PhotoModule) mCurrentModule).mShutterLag : -1; 492 } 493 494 public long getShutterToPictureDisplayedTime() { 495 return (mCurrentModule instanceof PhotoModule) ? 496 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1; 497 } 498 499 public long getPictureDisplayedToJpegCallbackTime() { 500 return (mCurrentModule instanceof PhotoModule) ? 501 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1; 502 } 503 504 public long getJpegCallbackFinishTime() { 505 return (mCurrentModule instanceof PhotoModule) ? 506 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1; 507 } 508 509 public long getCaptureStartTime() { 510 return (mCurrentModule instanceof PhotoModule) ? 511 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1; 512 } 513 514 public boolean isRecording() { 515 return (mCurrentModule instanceof VideoModule) ? 516 ((VideoModule) mCurrentModule).isRecording() : false; 517 } 518 519 public CameraScreenNail getCameraScreenNail() { 520 return (CameraScreenNail) mCameraScreenNail; 521 } 522 523 public MediaSaveService getMediaSaveService() { 524 return mMediaSaveService; 525 } 526} 527