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