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