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