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