CameraActivity.java revision 54424d9c722b6d40be2eb50ae24e6d8dd17ddcab
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.content.Context; 20import android.content.Intent; 21import android.content.res.Configuration; 22import android.graphics.drawable.Drawable; 23import android.os.Bundle; 24import android.provider.MediaStore; 25import android.view.KeyEvent; 26import android.view.LayoutInflater; 27import android.view.MotionEvent; 28import android.view.OrientationEventListener; 29import android.view.View; 30import android.view.ViewGroup; 31import android.widget.FrameLayout; 32 33import com.android.camera.ui.CameraSwitcher; 34import com.android.gallery3d.app.PhotoPage; 35import com.android.gallery3d.util.LightCycleHelper; 36import com.android.gallery3d.common.ApiHelper; 37 38public class CameraActivity extends ActivityBase 39 implements CameraSwitcher.CameraSwitchListener { 40 public static final int PHOTO_MODULE_INDEX = 0; 41 public static final int VIDEO_MODULE_INDEX = 1; 42 public static final int PANORAMA_MODULE_INDEX = 2; 43 public static final int LIGHTCYCLE_MODULE_INDEX = 3; 44 45 CameraModule mCurrentModule; 46 private FrameLayout mFrame; 47 private ShutterButton mShutter; 48 private CameraSwitcher mSwitcher; 49 private View mShutterSwitcher; 50 private View mControlsBackground; 51 private Drawable[] mDrawables; 52 private int mCurrentModuleIndex; 53 private MotionEvent mDown; 54 55 private MyOrientationEventListener mOrientationListener; 56 // The degrees of the device rotated clockwise from its natural orientation. 57 private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; 58 // The orientation compensation for icons. Eg: if the value 59 // is 90, the UI components should be rotated 90 degrees counter-clockwise. 60 private int mOrientationCompensation = 0; 61 62 private static final String TAG = "CAM_activity"; 63 64 private static final int[] DRAW_IDS = { 65 R.drawable.ic_switch_camera, 66 R.drawable.ic_switch_video, 67 R.drawable.ic_switch_pan, 68 R.drawable.ic_switch_photosphere 69 }; 70 71 @Override 72 public void onCreate(Bundle state) { 73 super.onCreate(state); 74 setContentView(R.layout.camera_main); 75 mFrame = (FrameLayout) findViewById(R.id.main_content); 76 mDrawables = new Drawable[DRAW_IDS.length]; 77 for (int i = 0; i < DRAW_IDS.length; i++) { 78 mDrawables[i] = getResources().getDrawable(DRAW_IDS[i]); 79 } 80 init(); 81 if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction()) 82 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) { 83 mCurrentModule = new VideoModule(); 84 mCurrentModuleIndex = VIDEO_MODULE_INDEX; 85 } else { 86 mCurrentModule = new PhotoModule(); 87 mCurrentModuleIndex = PHOTO_MODULE_INDEX; 88 } 89 mCurrentModule.init(this, mFrame, true); 90 mSwitcher.setCurrentIndex(mCurrentModuleIndex); 91 mOrientationListener = new MyOrientationEventListener(this); 92 } 93 94 public void init() { 95 mControlsBackground = findViewById(R.id.controls); 96 mShutterSwitcher = findViewById(R.id.camera_shutter_switcher); 97 mShutter = (ShutterButton) findViewById(R.id.shutter_button); 98 mSwitcher = (CameraSwitcher) findViewById(R.id.camera_switcher); 99 int totaldrawid = (LightCycleHelper.hasLightCycleCapture(this) 100 ? DRAW_IDS.length : DRAW_IDS.length - 1); 101 if (!ApiHelper.HAS_OLD_PANORAMA) totaldrawid--; 102 103 int[] drawids = new int[totaldrawid]; 104 int[] moduleids = new int[totaldrawid]; 105 int ix = 0; 106 for (int i = 0; i < mDrawables.length; i++) { 107 if (i == PANORAMA_MODULE_INDEX && !ApiHelper.HAS_OLD_PANORAMA) { 108 continue; // not enabled, so don't add to UI 109 } 110 if (i == LIGHTCYCLE_MODULE_INDEX && !LightCycleHelper.hasLightCycleCapture(this)) { 111 continue; // not enabled, so don't add to UI 112 } 113 moduleids[ix] = i; 114 drawids[ix++] = DRAW_IDS[i]; 115 } 116 mSwitcher.setIds(moduleids, drawids); 117 mSwitcher.setSwitchListener(this); 118 mSwitcher.setCurrentIndex(mCurrentModuleIndex); 119 } 120 121 private class MyOrientationEventListener 122 extends OrientationEventListener { 123 public MyOrientationEventListener(Context context) { 124 super(context); 125 } 126 127 @Override 128 public void onOrientationChanged(int orientation) { 129 // We keep the last known orientation. So if the user first orient 130 // the camera then point the camera to floor or sky, we still have 131 // the correct orientation. 132 if (orientation == ORIENTATION_UNKNOWN) return; 133 mOrientation = Util.roundOrientation(orientation, mOrientation); 134 // When the screen is unlocked, display rotation may change. Always 135 // calculate the up-to-date orientationCompensation. 136 int orientationCompensation = 137 (mOrientation + Util.getDisplayRotation(CameraActivity.this)) % 360; 138 // Rotate camera mode icons in the switcher 139 if (mOrientationCompensation != orientationCompensation) { 140 mOrientationCompensation = orientationCompensation; 141 } 142 mCurrentModule.onOrientationChanged(orientation); 143 } 144 } 145 146 @Override 147 public void onCameraSelected(int i) { 148 if (mPaused) return; 149 if (i != mCurrentModuleIndex) { 150 mPaused = true; 151 boolean canReuse = canReuseScreenNail(); 152 CameraHolder.instance().keep(); 153 closeModule(mCurrentModule); 154 mCurrentModuleIndex = i; 155 switch (i) { 156 case VIDEO_MODULE_INDEX: 157 mCurrentModule = new VideoModule(); 158 break; 159 case PHOTO_MODULE_INDEX: 160 mCurrentModule = new PhotoModule(); 161 break; 162 case PANORAMA_MODULE_INDEX: 163 mCurrentModule = new PanoramaModule(); 164 break; 165 case LIGHTCYCLE_MODULE_INDEX: 166 mCurrentModule = LightCycleHelper.createPanoramaModule(); 167 break; 168 } 169 openModule(mCurrentModule, canReuse); 170 mCurrentModule.onOrientationChanged(mOrientation); 171 } 172 } 173 174 @Override 175 public void onShowSwitcherPopup() { 176 mCurrentModule.onShowSwitcherPopup(); 177 } 178 179 private void openModule(CameraModule module, boolean canReuse) { 180 module.init(this, mFrame, canReuse && canReuseScreenNail()); 181 mPaused = false; 182 module.onResumeBeforeSuper(); 183 module.onResumeAfterSuper(); 184 } 185 186 private void closeModule(CameraModule module) { 187 module.onPauseBeforeSuper(); 188 module.onPauseAfterSuper(); 189 mFrame.removeAllViews(); 190 } 191 192 public ShutterButton getShutterButton() { 193 return mShutter; 194 } 195 196 public void hideUI() { 197 mControlsBackground.setVisibility(View.INVISIBLE); 198 hideSwitcher(); 199 mShutter.setVisibility(View.GONE); 200 } 201 202 public void showUI() { 203 mControlsBackground.setVisibility(View.VISIBLE); 204 showSwitcher(); 205 mShutter.setVisibility(View.VISIBLE); 206 } 207 208 public void hideSwitcher() { 209 mSwitcher.closePopup(); 210 mSwitcher.setVisibility(View.INVISIBLE); 211 } 212 213 public void showSwitcher() { 214 if (mCurrentModule.needsSwitcher()) { 215 mSwitcher.setVisibility(View.VISIBLE); 216 } 217 } 218 219 public boolean isInCameraApp() { 220 return mShowCameraAppView; 221 } 222 223 @Override 224 public void onConfigurationChanged(Configuration config) { 225 super.onConfigurationChanged(config); 226 227 ViewGroup appRoot = (ViewGroup) findViewById(R.id.content); 228 // remove old switcher, shutter and shutter icon 229 View cameraControlsView = findViewById(R.id.camera_shutter_switcher); 230 appRoot.removeView(cameraControlsView); 231 232 // create new layout with the current orientation 233 LayoutInflater inflater = getLayoutInflater(); 234 inflater.inflate(R.layout.camera_shutter_switcher, appRoot); 235 init(); 236 237 if (mShowCameraAppView) { 238 showUI(); 239 } else { 240 hideUI(); 241 } 242 mCurrentModule.onConfigurationChanged(config); 243 } 244 245 @Override 246 public void onPause() { 247 mPaused = true; 248 mOrientationListener.disable(); 249 mCurrentModule.onPauseBeforeSuper(); 250 super.onPause(); 251 mCurrentModule.onPauseAfterSuper(); 252 } 253 254 @Override 255 public void onResume() { 256 mPaused = false; 257 mOrientationListener.enable(); 258 mCurrentModule.onResumeBeforeSuper(); 259 super.onResume(); 260 mCurrentModule.onResumeAfterSuper(); 261 } 262 263 @Override 264 protected void onFullScreenChanged(boolean full) { 265 if (full) { 266 showUI(); 267 } else { 268 hideUI(); 269 } 270 super.onFullScreenChanged(full); 271 mCurrentModule.onFullScreenChanged(full); 272 } 273 274 @Override 275 protected void onStop() { 276 super.onStop(); 277 mCurrentModule.onStop(); 278 getStateManager().clearTasks(); 279 } 280 281 @Override 282 protected void onNewIntent(Intent intent) { 283 super.onNewIntent(intent); 284 getStateManager().clearActivityResult(); 285 } 286 287 @Override 288 protected void installIntentFilter() { 289 super.installIntentFilter(); 290 mCurrentModule.installIntentFilter(); 291 } 292 293 @Override 294 protected void onActivityResult( 295 int requestCode, int resultCode, Intent data) { 296 // Only PhotoPage understands ProxyLauncher.RESULT_USER_CANCELED 297 if (resultCode == ProxyLauncher.RESULT_USER_CANCELED 298 && !(getStateManager().getTopState() instanceof PhotoPage)) { 299 resultCode = RESULT_CANCELED; 300 } 301 super.onActivityResult(requestCode, resultCode, data); 302 // Unmap cancel vs. reset 303 if (resultCode == ProxyLauncher.RESULT_USER_CANCELED) { 304 resultCode = RESULT_CANCELED; 305 } 306 mCurrentModule.onActivityResult(requestCode, resultCode, data); 307 } 308 309 // Preview area is touched. Handle touch focus. 310 @Override 311 protected void onSingleTapUp(View view, int x, int y) { 312 mCurrentModule.onSingleTapUp(view, x, y); 313 } 314 315 @Override 316 public void onBackPressed() { 317 if (!mCurrentModule.onBackPressed()) { 318 super.onBackPressed(); 319 } 320 } 321 322 @Override 323 public boolean onKeyDown(int keyCode, KeyEvent event) { 324 return mCurrentModule.onKeyDown(keyCode, event) 325 || super.onKeyDown(keyCode, event); 326 } 327 328 @Override 329 public boolean onKeyUp(int keyCode, KeyEvent event) { 330 return mCurrentModule.onKeyUp(keyCode, event) 331 || super.onKeyUp(keyCode, event); 332 } 333 334 public void cancelActivityTouchHandling() { 335 if (mDown != null) { 336 MotionEvent cancel = MotionEvent.obtain(mDown); 337 cancel.setAction(MotionEvent.ACTION_CANCEL); 338 super.dispatchTouchEvent(cancel); 339 } 340 } 341 342 @Override 343 public boolean dispatchTouchEvent(MotionEvent m) { 344 if (m.getActionMasked() == MotionEvent.ACTION_DOWN) { 345 mDown = m; 346 } 347 if ((mSwitcher != null) && mSwitcher.showsPopup() && !mSwitcher.isInsidePopup(m)) { 348 return mSwitcher.onTouch(null, m); 349 } else { 350 return mShutterSwitcher.dispatchTouchEvent(m) 351 || mCurrentModule.dispatchTouchEvent(m); 352 } 353 } 354 355 @Override 356 public void startActivityForResult(Intent intent, int requestCode) { 357 Intent proxyIntent = new Intent(this, ProxyLauncher.class); 358 proxyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 359 proxyIntent.putExtra(Intent.EXTRA_INTENT, intent); 360 super.startActivityForResult(proxyIntent, requestCode); 361 } 362 363 public boolean superDispatchTouchEvent(MotionEvent m) { 364 return super.dispatchTouchEvent(m); 365 } 366 367 // Preview texture has been copied. Now camera can be released and the 368 // animation can be started. 369 @Override 370 public void onPreviewTextureCopied() { 371 mCurrentModule.onPreviewTextureCopied(); 372 } 373 374 @Override 375 public void onCaptureTextureCopied() { 376 mCurrentModule.onCaptureTextureCopied(); 377 } 378 379 @Override 380 public void onUserInteraction() { 381 super.onUserInteraction(); 382 mCurrentModule.onUserInteraction(); 383 } 384 385 @Override 386 protected boolean updateStorageHintOnResume() { 387 return mCurrentModule.updateStorageHintOnResume(); 388 } 389 390 @Override 391 public void updateCameraAppView() { 392 super.updateCameraAppView(); 393 mCurrentModule.updateCameraAppView(); 394 } 395 396 private boolean canReuseScreenNail() { 397 return mCurrentModuleIndex == PHOTO_MODULE_INDEX 398 || mCurrentModuleIndex == VIDEO_MODULE_INDEX; 399 } 400 401 @Override 402 public boolean isPanoramaActivity() { 403 return (mCurrentModuleIndex == PANORAMA_MODULE_INDEX); 404 } 405 406 // Accessor methods for getting latency times used in performance testing 407 public long getAutoFocusTime() { 408 return (mCurrentModule instanceof PhotoModule) ? 409 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1; 410 } 411 412 public long getShutterLag() { 413 return (mCurrentModule instanceof PhotoModule) ? 414 ((PhotoModule) mCurrentModule).mShutterLag : -1; 415 } 416 417 public long getShutterToPictureDisplayedTime() { 418 return (mCurrentModule instanceof PhotoModule) ? 419 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1; 420 } 421 422 public long getPictureDisplayedToJpegCallbackTime() { 423 return (mCurrentModule instanceof PhotoModule) ? 424 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1; 425 } 426 427 public long getJpegCallbackFinishTime() { 428 return (mCurrentModule instanceof PhotoModule) ? 429 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1; 430 } 431 432 public long getCaptureStartTime() { 433 return (mCurrentModule instanceof PhotoModule) ? 434 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1; 435 } 436 437 public boolean isRecording() { 438 return (mCurrentModule instanceof VideoModule) ? 439 ((VideoModule) mCurrentModule).isRecording() : false; 440 } 441 442 public CameraScreenNail getCameraScreenNail() { 443 return (CameraScreenNail) mCameraScreenNail; 444 } 445} 446