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