CameraActivity.java revision 43d796d5c098be9f92c89db5501b986daf52763e
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.app.Activity; 20import android.content.ComponentName; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.ServiceConnection; 25import android.content.pm.ActivityInfo; 26import android.content.res.Configuration; 27import android.graphics.drawable.ColorDrawable; 28import android.net.Uri; 29import android.os.Bundle; 30import android.os.Handler; 31import android.os.IBinder; 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.ImageView; 42 43import com.android.camera.data.CameraDataAdapter; 44import com.android.camera.data.LocalData; 45import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; 46import com.android.camera.ui.FilmStripView; 47import com.android.gallery3d.R; 48import com.android.gallery3d.common.ApiHelper; 49import com.android.gallery3d.util.LightCycleHelper; 50 51public class CameraActivity extends Activity 52 implements CameraSwitchListener { 53 54 private static final String TAG = "CAM_Activity"; 55 56 public static final int PHOTO_MODULE_INDEX = 0; 57 public static final int VIDEO_MODULE_INDEX = 1; 58 public static final int PANORAMA_MODULE_INDEX = 2; 59 public static final int LIGHTCYCLE_MODULE_INDEX = 3; 60 61 private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE = 62 "android.media.action.STILL_IMAGE_CAMERA_SECURE"; 63 public static final String ACTION_IMAGE_CAPTURE_SECURE = 64 "android.media.action.IMAGE_CAPTURE_SECURE"; 65 66 // The intent extra for camera from secure lock screen. True if the gallery 67 // should only show newly captured pictures. sSecureAlbumId does not 68 // increment. This is used when switching between camera, camcorder, and 69 // panorama. If the extra is not set, it is in the normal camera mode. 70 public static final String SECURE_CAMERA_EXTRA = "secure_camera"; 71 72 private CameraDataAdapter mDataAdapter; 73 private int mCurrentModuleIndex; 74 private CameraModule mCurrentModule; 75 private View mRootView; 76 private FilmStripView mFilmStripView; 77 private int mResultCodeForTesting; 78 private Intent mResultDataForTesting; 79 private OnScreenHint mStorageHint; 80 private long mStorageSpace = Storage.LOW_STORAGE_THRESHOLD; 81 private PhotoModule mController; 82 private boolean mAutoRotateScreen; 83 private boolean mSecureCamera; 84 private boolean mShowCameraPreview; 85 private int mLastRawOrientation; 86 private MyOrientationEventListener mOrientationListener; 87 private Handler mMainHandler; 88 89 private class MyOrientationEventListener 90 extends OrientationEventListener { 91 public MyOrientationEventListener(Context context) { 92 super(context); 93 } 94 95 @Override 96 public void onOrientationChanged(int orientation) { 97 // We keep the last known orientation. So if the user first orient 98 // the camera then point the camera to floor or sky, we still have 99 // the correct orientation. 100 if (orientation == ORIENTATION_UNKNOWN) return; 101 mLastRawOrientation = orientation; 102 mCurrentModule.onOrientationChanged(orientation); 103 } 104 } 105 106 private MediaSaveService mMediaSaveService; 107 private ServiceConnection mConnection = new ServiceConnection() { 108 @Override 109 public void onServiceConnected(ComponentName className, IBinder b) { 110 mMediaSaveService = ((MediaSaveService.LocalBinder) b).getService(); 111 mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); 112 } 113 @Override 114 public void onServiceDisconnected(ComponentName className) { 115 mMediaSaveService = null; 116 }}; 117 118 private FilmStripView.Listener mFilmStripListener = new FilmStripView.Listener() { 119 @Override 120 public void onDataPromoted(int dataID) { 121 removeData(dataID); 122 } 123 124 @Override 125 public void onDataDemoted(int dataID) { 126 removeData(dataID); 127 } 128 129 @Override 130 public void onDataFullScreenChange(int dataID, boolean full) { 131 } 132 133 @Override 134 public void onSwitchMode(boolean toCamera) { 135 mCurrentModule.onSwitchMode(toCamera); 136 } 137 }; 138 139 private Runnable mDeletionRunnable = new Runnable() { 140 @Override 141 public void run() { 142 mDataAdapter.executeDeletion(CameraActivity.this); 143 } 144 }; 145 146 public MediaSaveService getMediaSaveService() { 147 return mMediaSaveService; 148 } 149 150 public void notifyNewMedia(Uri uri) { 151 ContentResolver cr = getContentResolver(); 152 String mimeType = cr.getType(uri); 153 if (mimeType.startsWith("video/")) { 154 sendBroadcast(new Intent(Util.ACTION_NEW_VIDEO, uri)); 155 mDataAdapter.addNewVideo(cr, uri); 156 } else if (mimeType.startsWith("image/")) { 157 Util.broadcastNewPicture(this, uri); 158 mDataAdapter.addNewPhoto(cr, uri); 159 } else { 160 android.util.Log.w(TAG, "Unknown new media with MIME type:" 161 + mimeType + ", uri:" + uri); 162 } 163 } 164 165 private void removeData(int dataID) { 166 mDataAdapter.removeData(CameraActivity.this, dataID); 167 mMainHandler.removeCallbacks(mDeletionRunnable); 168 mMainHandler.postDelayed(mDeletionRunnable, 3000); 169 } 170 171 private void bindMediaSaveService() { 172 Intent intent = new Intent(this, MediaSaveService.class); 173 startService(intent); // start service before binding it so the 174 // service won't be killed if we unbind it. 175 bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 176 } 177 178 private void unbindMediaSaveService() { 179 if (mMediaSaveService != null) { 180 mMediaSaveService.setListener(null); 181 } 182 if (mConnection != null) { 183 unbindService(mConnection); 184 } 185 } 186 187 @Override 188 public void onCreate(Bundle state) { 189 super.onCreate(state); 190 setContentView(R.layout.camera_filmstrip); 191 if (ApiHelper.HAS_ROTATION_ANIMATION) { 192 setRotationAnimation(); 193 } 194 // Check if this is in the secure camera mode. 195 Intent intent = getIntent(); 196 String action = intent.getAction(); 197 if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) { 198 mSecureCamera = true; 199 } else if (ACTION_IMAGE_CAPTURE_SECURE.equals(action)) { 200 mSecureCamera = true; 201 } else { 202 mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false); 203 } 204 /*TODO: if (mSecureCamera) { 205 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); 206 registerReceiver(mScreenOffReceiver, filter); 207 if (sScreenOffReceiver == null) { 208 sScreenOffReceiver = new ScreenOffReceiver(); 209 getApplicationContext().registerReceiver(sScreenOffReceiver, filter); 210 } 211 }*/ 212 LayoutInflater inflater = getLayoutInflater(); 213 View rootLayout = inflater.inflate(R.layout.camera, null, false); 214 mRootView = rootLayout.findViewById(R.id.camera_app_root); 215 mDataAdapter = new CameraDataAdapter( 216 new ColorDrawable(getResources().getColor(R.color.photo_placeholder))); 217 mFilmStripView = (FilmStripView) findViewById(R.id.filmstrip_view); 218 mFilmStripView.setViewGap( 219 getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap)); 220 // Set up the camera preview first so the preview shows up ASAP. 221 mDataAdapter.setCameraPreviewInfo(rootLayout, 222 FilmStripView.ImageData.SIZE_FULL, FilmStripView.ImageData.SIZE_FULL); 223 mFilmStripView.setDataAdapter(mDataAdapter); 224 mFilmStripView.setListener(mFilmStripListener); 225 mCurrentModule = new PhotoModule(); 226 mCurrentModule.init(this, mRootView); 227 mOrientationListener = new MyOrientationEventListener(this); 228 mMainHandler = new Handler(getMainLooper()); 229 bindMediaSaveService(); 230 } 231 232 private void setRotationAnimation() { 233 int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; 234 rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; 235 Window win = getWindow(); 236 WindowManager.LayoutParams winParams = win.getAttributes(); 237 winParams.rotationAnimation = rotationAnimation; 238 win.setAttributes(winParams); 239 } 240 241 @Override 242 public void onUserInteraction() { 243 super.onUserInteraction(); 244 mCurrentModule.onUserInteraction(); 245 } 246 247 @Override 248 public void onPause() { 249 mOrientationListener.disable(); 250 mCurrentModule.onPauseBeforeSuper(); 251 super.onPause(); 252 mCurrentModule.onPauseAfterSuper(); 253 } 254 255 @Override 256 public void onResume() { 257 if (Settings.System.getInt(getContentResolver(), 258 Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {// auto-rotate off 259 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 260 mAutoRotateScreen = false; 261 } else { 262 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); 263 mAutoRotateScreen = true; 264 } 265 mOrientationListener.enable(); 266 mCurrentModule.onResumeBeforeSuper(); 267 super.onResume(); 268 mCurrentModule.onResumeAfterSuper(); 269 270 // The loading is done in background and will update the filmstrip later. 271 if (!mSecureCamera) { 272 mDataAdapter.requestLoad(getContentResolver()); 273 } else { 274 // Flush out all the original data first. 275 mDataAdapter.flush(); 276 ImageView v = (ImageView) getLayoutInflater().inflate( 277 R.layout.secure_album_placeholder, null); 278 // Put a lock placeholder as the last image by setting its date to 0. 279 mDataAdapter.addLocalData( 280 new LocalData.LocalViewData( 281 v, 282 v.getDrawable().getIntrinsicWidth(), 283 v.getDrawable().getIntrinsicHeight(), 284 0, 0)); 285 } 286 setSwipingEnabled(true); 287 } 288 289 @Override 290 public void onDestroy() { 291 unbindMediaSaveService(); 292 super.onDestroy(); 293 } 294 295 @Override 296 public void onConfigurationChanged(Configuration config) { 297 super.onConfigurationChanged(config); 298 mCurrentModule.onConfigurationChanged(config); 299 } 300 301 @Override 302 public boolean onKeyDown(int keyCode, KeyEvent event) { 303 if (mCurrentModule.onKeyDown(keyCode, event)) return true; 304 // Prevent software keyboard or voice search from showing up. 305 if (keyCode == KeyEvent.KEYCODE_SEARCH 306 || keyCode == KeyEvent.KEYCODE_MENU) { 307 if (event.isLongPress()) return true; 308 } 309 if (keyCode == KeyEvent.KEYCODE_MENU && mShowCameraPreview) { 310 return true; 311 } 312 313 return super.onKeyDown(keyCode, event); 314 } 315 316 @Override 317 public boolean onKeyUp(int keyCode, KeyEvent event) { 318 if (mCurrentModule.onKeyUp(keyCode, event)) return true; 319 if (keyCode == KeyEvent.KEYCODE_MENU && mShowCameraPreview) { 320 return true; 321 } 322 return super.onKeyUp(keyCode, event); 323 } 324 325 @Override 326 public boolean dispatchTouchEvent(MotionEvent m) { 327 return mFilmStripView.dispatchTouchEvent(m); 328 } 329 public boolean isAutoRotateScreen() { 330 return mAutoRotateScreen; 331 } 332 333 protected void updateStorageSpace() { 334 mStorageSpace = Storage.getAvailableSpace(); 335 } 336 337 protected long getStorageSpace() { 338 return mStorageSpace; 339 } 340 341 protected void updateStorageSpaceAndHint() { 342 updateStorageSpace(); 343 updateStorageHint(mStorageSpace); 344 } 345 346 protected void updateStorageHint() { 347 updateStorageHint(mStorageSpace); 348 } 349 350 protected boolean updateStorageHintOnResume() { 351 return true; 352 } 353 354 protected void updateStorageHint(long storageSpace) { 355 String message = null; 356 if (storageSpace == Storage.UNAVAILABLE) { 357 message = getString(R.string.no_storage); 358 } else if (storageSpace == Storage.PREPARING) { 359 message = getString(R.string.preparing_sd); 360 } else if (storageSpace == Storage.UNKNOWN_SIZE) { 361 message = getString(R.string.access_sd_fail); 362 } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD) { 363 message = getString(R.string.spaceIsLow_content); 364 } 365 366 if (message != null) { 367 if (mStorageHint == null) { 368 mStorageHint = OnScreenHint.makeText(this, message); 369 } else { 370 mStorageHint.setText(message); 371 } 372 mStorageHint.show(); 373 } else if (mStorageHint != null) { 374 mStorageHint.cancel(); 375 mStorageHint = null; 376 } 377 } 378 379 protected void setResultEx(int resultCode) { 380 mResultCodeForTesting = resultCode; 381 setResult(resultCode); 382 } 383 384 protected void setResultEx(int resultCode, Intent data) { 385 mResultCodeForTesting = resultCode; 386 mResultDataForTesting = data; 387 setResult(resultCode, data); 388 } 389 390 public int getResultCode() { 391 return mResultCodeForTesting; 392 } 393 394 public Intent getResultData() { 395 return mResultDataForTesting; 396 } 397 398 public boolean isSecureCamera() { 399 return mSecureCamera; 400 } 401 402 @Override 403 public void onCameraSelected(int i) { 404 if (mCurrentModuleIndex == i) return; 405 406 CameraHolder.instance().keep(); 407 closeModule(mCurrentModule); 408 mCurrentModuleIndex = i; 409 switch (i) { 410 case VIDEO_MODULE_INDEX: 411 mCurrentModule = new VideoModule(); 412 break; 413 case PHOTO_MODULE_INDEX: 414 mCurrentModule = new PhotoModule(); 415 break; 416 case LIGHTCYCLE_MODULE_INDEX: 417 mCurrentModule = LightCycleHelper.createPanoramaModule(); 418 break; 419 default: 420 break; 421 } 422 423 openModule(mCurrentModule); 424 mCurrentModule.onOrientationChanged(mLastRawOrientation); 425 if (mMediaSaveService != null) { 426 mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); 427 } 428 } 429 430 private void openModule(CameraModule module) { 431 module.init(this, mRootView); 432 module.onResumeBeforeSuper(); 433 module.onResumeAfterSuper(); 434 } 435 436 private void closeModule(CameraModule module) { 437 module.onPauseBeforeSuper(); 438 module.onPauseAfterSuper(); 439 ((ViewGroup) mRootView).removeAllViews(); 440 } 441 442 @Override 443 public void onShowSwitcherPopup() { 444 } 445 446 public void setSwipingEnabled(boolean enable) { 447 mDataAdapter.setCameraPreviewLock(!enable); 448 } 449 450 // Accessor methods for getting latency times used in performance testing 451 public long getAutoFocusTime() { 452 return (mCurrentModule instanceof PhotoModule) ? 453 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1; 454 } 455 456 public long getShutterLag() { 457 return (mCurrentModule instanceof PhotoModule) ? 458 ((PhotoModule) mCurrentModule).mShutterLag : -1; 459 } 460 461 public long getShutterToPictureDisplayedTime() { 462 return (mCurrentModule instanceof PhotoModule) ? 463 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1; 464 } 465 466 public long getPictureDisplayedToJpegCallbackTime() { 467 return (mCurrentModule instanceof PhotoModule) ? 468 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1; 469 } 470 471 public long getJpegCallbackFinishTime() { 472 return (mCurrentModule instanceof PhotoModule) ? 473 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1; 474 } 475 476 public long getCaptureStartTime() { 477 return (mCurrentModule instanceof PhotoModule) ? 478 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1; 479 } 480 481 public boolean isRecording() { 482 return (mCurrentModule instanceof VideoModule) ? 483 ((VideoModule) mCurrentModule).isRecording() : false; 484 } 485} 486