CameraActivity.java revision 50df47071c776703a36dbc4cb90ec8d1df3c0f6e
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.ActionBar; 20import android.app.Activity; 21import android.content.BroadcastReceiver; 22import android.content.ComponentName; 23import android.content.ContentResolver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.content.ServiceConnection; 28import android.content.pm.ActivityInfo; 29import android.content.res.Configuration; 30import android.graphics.drawable.ColorDrawable; 31import android.net.Uri; 32import android.os.Bundle; 33import android.os.Handler; 34import android.os.IBinder; 35import android.provider.MediaStore; 36import android.provider.Settings; 37import android.util.Log; 38import android.view.KeyEvent; 39import android.view.LayoutInflater; 40import android.view.Menu; 41import android.view.MenuInflater; 42import android.view.MenuItem; 43import android.view.OrientationEventListener; 44import android.view.View; 45import android.view.ViewGroup; 46import android.view.Window; 47import android.view.WindowManager; 48import android.widget.ImageView; 49import android.widget.ProgressBar; 50 51import com.android.camera.data.CameraDataAdapter; 52import com.android.camera.data.CameraPreviewData; 53import com.android.camera.data.FixedFirstDataAdapter; 54import com.android.camera.data.FixedLastDataAdapter; 55import com.android.camera.data.LocalData; 56import com.android.camera.data.LocalDataAdapter; 57import com.android.camera.data.SimpleViewData; 58import com.android.camera.util.ApiHelper; 59import com.android.camera.ui.CameraSwitcher; 60import com.android.camera.ui.CameraSwitcher.CameraSwitchListener; 61import com.android.camera.ui.FilmStripView; 62import com.android.camera.util.CameraUtil; 63import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper; 64import com.android.camera.util.PhotoSphereHelper; 65import com.android.camera2.R; 66 67public class CameraActivity extends Activity 68 implements CameraSwitchListener { 69 70 private static final String TAG = "CAM_Activity"; 71 72 private static final String INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE = 73 "android.media.action.STILL_IMAGE_CAMERA_SECURE"; 74 public static final String ACTION_IMAGE_CAPTURE_SECURE = 75 "android.media.action.IMAGE_CAPTURE_SECURE"; 76 77 // The intent extra for camera from secure lock screen. True if the gallery 78 // should only show newly captured pictures. sSecureAlbumId does not 79 // increment. This is used when switching between camera, camcorder, and 80 // panorama. If the extra is not set, it is in the normal camera mode. 81 public static final String SECURE_CAMERA_EXTRA = "secure_camera"; 82 83 // Supported operations at FilmStripView. Different data has different 84 // set of supported operations. 85 private static final int SUPPORT_DELETE = 1 << 0; 86 private static final int SUPPORT_ROTATE = 1 << 1; 87 private static final int SUPPORT_INFO = 1 << 2; 88 private static final int SUPPORT_CROP = 1 << 3; 89 private static final int SUPPORT_SETAS = 1 << 4; 90 private static final int SUPPORT_EDIT = 1 << 5; 91 private static final int SUPPORT_TRIM = 1 << 6; 92 private static final int SUPPORT_MUTE = 1 << 7; 93 private static final int SUPPORT_SHOW_ON_MAP = 1 << 8; 94 private static final int SUPPORT_ALL = 0xffffffff; 95 96 /** This data adapter is used by FilmStirpView. */ 97 private LocalDataAdapter mDataAdapter; 98 /** This data adapter represents the real local camera data. */ 99 private LocalDataAdapter mWrappedDataAdapter; 100 101 private PanoramaStitchingManager mPanoramaManager; 102 private int mCurrentModuleIndex; 103 private CameraModule mCurrentModule; 104 private View mRootView; 105 private FilmStripView mFilmStripView; 106 private ProgressBar mBottomProgress; 107 private View mPanoStitchingPanel; 108 private int mResultCodeForTesting; 109 private Intent mResultDataForTesting; 110 private OnScreenHint mStorageHint; 111 private long mStorageSpace = Storage.LOW_STORAGE_THRESHOLD; 112 private boolean mAutoRotateScreen; 113 private boolean mSecureCamera; 114 // This is a hack to speed up the start of SecureCamera. 115 private static boolean sFirstStartAfterScreenOn = true; 116 private boolean mShowCameraPreview; 117 private int mLastRawOrientation; 118 private MyOrientationEventListener mOrientationListener; 119 private Handler mMainHandler; 120 private PanoramaViewHelper mPanoramaViewHelper; 121 private CameraPreviewData mCameraPreviewData; 122 private ActionBar mActionBar; 123 private Menu mActionBarMenu; 124 125 private class MyOrientationEventListener 126 extends OrientationEventListener { 127 public MyOrientationEventListener(Context context) { 128 super(context); 129 } 130 131 @Override 132 public void onOrientationChanged(int orientation) { 133 // We keep the last known orientation. So if the user first orient 134 // the camera then point the camera to floor or sky, we still have 135 // the correct orientation. 136 if (orientation == ORIENTATION_UNKNOWN) return; 137 mLastRawOrientation = orientation; 138 mCurrentModule.onOrientationChanged(orientation); 139 } 140 } 141 142 private MediaSaveService mMediaSaveService; 143 private ServiceConnection mConnection = new ServiceConnection() { 144 @Override 145 public void onServiceConnected(ComponentName className, IBinder b) { 146 mMediaSaveService = ((MediaSaveService.LocalBinder) b).getService(); 147 mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); 148 } 149 @Override 150 public void onServiceDisconnected(ComponentName className) { 151 mMediaSaveService = null; 152 }}; 153 154 // close activity when screen turns off 155 private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { 156 @Override 157 public void onReceive(Context context, Intent intent) { 158 finish(); 159 } 160 }; 161 162 private static BroadcastReceiver sScreenOffReceiver; 163 private static class ScreenOffReceiver extends BroadcastReceiver { 164 @Override 165 public void onReceive(Context context, Intent intent) { 166 sFirstStartAfterScreenOn = true; 167 } 168 } 169 170 public static boolean isFirstStartAfterScreenOn() { 171 return sFirstStartAfterScreenOn; 172 } 173 174 public static void resetFirstStartAfterScreenOn() { 175 sFirstStartAfterScreenOn = false; 176 } 177 178 private FilmStripView.Listener mFilmStripListener = 179 new FilmStripView.Listener() { 180 @Override 181 public void onDataPromoted(int dataID) { 182 removeData(dataID); 183 } 184 185 @Override 186 public void onDataDemoted(int dataID) { 187 removeData(dataID); 188 } 189 190 @Override 191 public void onDataFullScreenChange(int dataID, boolean full) { 192 } 193 194 @Override 195 public void onSwitchMode(boolean toCamera) { 196 mCurrentModule.onSwitchMode(toCamera); 197 if (toCamera) { 198 mActionBar.hide(); 199 } else { 200 mActionBar.show(); 201 } 202 } 203 204 @Override 205 public void onCurrentDataChanged(int dataID, boolean current) { 206 if (!current) { 207 hidePanoStitchingProgress(); 208 } else { 209 LocalData currentData = mDataAdapter.getLocalData(dataID); 210 if (currentData == null) { 211 Log.w(TAG, "Current data ID not found."); 212 hidePanoStitchingProgress(); 213 return; 214 } 215 int type = currentData.getLocalDataType(dataID); 216 updateActionBarMenu(type); 217 218 Uri contentUri = currentData.getContentUri(); 219 if (contentUri == null) { 220 hidePanoStitchingProgress(); 221 return; 222 } 223 int panoStitchingProgress = mPanoramaManager.getTaskProgress(contentUri); 224 if (panoStitchingProgress < 0) { 225 hidePanoStitchingProgress(); 226 return; 227 } 228 showPanoStitchingProgress(); 229 updateStitchingProgress(panoStitchingProgress); 230 } 231 } 232 }; 233 234 private void hidePanoStitchingProgress() { 235 mPanoStitchingPanel.setVisibility(View.GONE); 236 } 237 238 private void showPanoStitchingProgress() { 239 mPanoStitchingPanel.setVisibility(View.VISIBLE); 240 } 241 242 private void updateStitchingProgress(int progress) { 243 mBottomProgress.setProgress(progress); 244 } 245 246 /** 247 * According to the data type, make the menu items for supported operations 248 * visible. 249 * @param type : the data type for the current local data. 250 */ 251 private void updateActionBarMenu(int type) { 252 if (mActionBarMenu == null) { 253 return; 254 } 255 256 int supported = 0; 257 switch (type) { 258 case LocalData.LOCAL_IMAGE: 259 supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO 260 | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT 261 | SUPPORT_SHOW_ON_MAP; 262 break; 263 case LocalData.LOCAL_VIDEO: 264 supported |= SUPPORT_DELETE | SUPPORT_INFO | SUPPORT_TRIM 265 | SUPPORT_MUTE; 266 break; 267 case LocalData.LOCAL_PHOTO_SPHERE: 268 supported |= SUPPORT_DELETE | SUPPORT_ROTATE | SUPPORT_INFO 269 | SUPPORT_CROP | SUPPORT_SETAS | SUPPORT_EDIT 270 | SUPPORT_SHOW_ON_MAP; 271 break; 272 default: 273 break; 274 } 275 276 setMenuItemVisible(mActionBarMenu, R.id.action_delete, 277 (supported & SUPPORT_DELETE) != 0); 278 setMenuItemVisible(mActionBarMenu, R.id.action_rotate_ccw, 279 (supported & SUPPORT_ROTATE) != 0); 280 setMenuItemVisible(mActionBarMenu, R.id.action_rotate_cw, 281 (supported & SUPPORT_ROTATE) != 0); 282 setMenuItemVisible(mActionBarMenu, R.id.action_crop, 283 (supported & SUPPORT_CROP) != 0); 284 setMenuItemVisible(mActionBarMenu, R.id.action_trim, 285 (supported & SUPPORT_TRIM) != 0); 286 setMenuItemVisible(mActionBarMenu, R.id.action_mute, 287 (supported & SUPPORT_MUTE) != 0); 288 setMenuItemVisible(mActionBarMenu, R.id.action_setas, 289 (supported & SUPPORT_SETAS) != 0); 290 setMenuItemVisible(mActionBarMenu, R.id.action_show_on_map, 291 (supported & SUPPORT_SHOW_ON_MAP) != 0); 292 setMenuItemVisible(mActionBarMenu, R.id.action_edit, 293 (supported & SUPPORT_EDIT) != 0); 294 setMenuItemVisible(mActionBarMenu, R.id.action_details, 295 (supported & SUPPORT_INFO) != 0); 296 } 297 298 private void setMenuItemVisible(Menu menu, int itemId, boolean visible) { 299 MenuItem item = menu.findItem(itemId); 300 if (item != null) 301 item.setVisible(visible); 302 } 303 304 private Runnable mDeletionRunnable = new Runnable() { 305 @Override 306 public void run() { 307 mDataAdapter.executeDeletion(CameraActivity.this); 308 } 309 }; 310 311 private ImageTaskManager.TaskListener mStitchingListener = 312 new ImageTaskManager.TaskListener() { 313 @Override 314 public void onTaskQueued(String filePath, final Uri imageUri) { 315 mMainHandler.post(new Runnable() { 316 @Override 317 public void run() { 318 notifyNewMedia(imageUri); 319 } 320 }); 321 } 322 323 @Override 324 public void onTaskDone(String filePath, final Uri imageUri) { 325 Log.v(TAG, "onTaskDone:" + filePath); 326 mMainHandler.post(new Runnable() { 327 @Override 328 public void run() { 329 int doneID = mDataAdapter.findDataByContentUri(imageUri); 330 int currentDataId = mFilmStripView.getCurrentId(); 331 332 if (currentDataId == doneID) { 333 hidePanoStitchingProgress(); 334 updateStitchingProgress(0); 335 } 336 337 mDataAdapter.refresh(getContentResolver(), imageUri); 338 } 339 }); 340 } 341 342 @Override 343 public void onTaskProgress( 344 String filePath, final Uri imageUri, final int progress) { 345 mMainHandler.post(new Runnable() { 346 @Override 347 public void run() { 348 int currentDataId = mFilmStripView.getCurrentId(); 349 if (currentDataId == -1) { 350 return; 351 } 352 if (imageUri.equals( 353 mDataAdapter.getLocalData(currentDataId).getContentUri())) { 354 updateStitchingProgress(progress); 355 } 356 } 357 }); 358 } 359 }; 360 361 public MediaSaveService getMediaSaveService() { 362 return mMediaSaveService; 363 } 364 365 public void notifyNewMedia(Uri uri) { 366 ContentResolver cr = getContentResolver(); 367 String mimeType = cr.getType(uri); 368 if (mimeType.startsWith("video/")) { 369 sendBroadcast(new Intent(CameraUtil.ACTION_NEW_VIDEO, uri)); 370 mDataAdapter.addNewVideo(cr, uri); 371 } else if (mimeType.startsWith("image/")) { 372 CameraUtil.broadcastNewPicture(this, uri); 373 mDataAdapter.addNewPhoto(cr, uri); 374 } else if (mimeType.startsWith("application/stitching-preview")) { 375 mDataAdapter.addNewPhoto(cr, uri); 376 } else { 377 android.util.Log.w(TAG, "Unknown new media with MIME type:" 378 + mimeType + ", uri:" + uri); 379 } 380 } 381 382 private void removeData(int dataID) { 383 mDataAdapter.removeData(CameraActivity.this, dataID); 384 mMainHandler.removeCallbacks(mDeletionRunnable); 385 mMainHandler.postDelayed(mDeletionRunnable, 3000); 386 } 387 388 private void bindMediaSaveService() { 389 Intent intent = new Intent(this, MediaSaveService.class); 390 startService(intent); // start service before binding it so the 391 // service won't be killed if we unbind it. 392 bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 393 } 394 395 private void unbindMediaSaveService() { 396 if (mMediaSaveService != null) { 397 mMediaSaveService.setListener(null); 398 } 399 if (mConnection != null) { 400 unbindService(mConnection); 401 } 402 } 403 404 @Override 405 public boolean onCreateOptionsMenu(Menu menu) { 406 // Inflate the menu items for use in the action bar 407 MenuInflater inflater = getMenuInflater(); 408 inflater.inflate(R.menu.operations, menu); 409 mActionBarMenu = menu; 410 return super.onCreateOptionsMenu(menu); 411 } 412 413 @Override 414 public boolean onOptionsItemSelected(MenuItem item) { 415 // Handle presses on the action bar items 416 switch (item.getItemId()) { 417 case R.id.action_delete: 418 // TODO: add the functionality. 419 return true; 420 case R.id.action_edit: 421 // TODO: add the functionality. 422 return true; 423 case R.id.action_trim: 424 // TODO: add the functionality. 425 return true; 426 case R.id.action_mute: 427 // TODO: add the functionality. 428 return true; 429 case R.id.action_rotate_ccw: 430 // TODO: add the functionality. 431 return true; 432 case R.id.action_rotate_cw: 433 // TODO: add the functionality. 434 return true; 435 case R.id.action_crop: 436 // TODO: add the functionality. 437 return true; 438 case R.id.action_setas: 439 // TODO: add the functionality. 440 return true; 441 case R.id.action_details: 442 // TODO: add the functionality. 443 return true; 444 case R.id.action_show_on_map: 445 // TODO: add the functionality. 446 return true; 447 default: 448 return super.onOptionsItemSelected(item); 449 } 450 } 451 452 @Override 453 public void onCreate(Bundle state) { 454 super.onCreate(state); 455 getWindow().requestFeature(Window.FEATURE_ACTION_BAR); 456 setContentView(R.layout.camera_filmstrip); 457 mActionBar = getActionBar(); 458 // Hide action bar first since we are in full screen mode first. 459 mActionBar.hide(); 460 461 if (ApiHelper.HAS_ROTATION_ANIMATION) { 462 setRotationAnimation(); 463 } 464 // Check if this is in the secure camera mode. 465 Intent intent = getIntent(); 466 String action = intent.getAction(); 467 if (INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action) 468 || ACTION_IMAGE_CAPTURE_SECURE.equals(action)) { 469 mSecureCamera = true; 470 } else { 471 mSecureCamera = intent.getBooleanExtra(SECURE_CAMERA_EXTRA, false); 472 } 473 474 if (mSecureCamera) { 475 // Change the window flags so that secure camera can show when locked 476 Window win = getWindow(); 477 WindowManager.LayoutParams params = win.getAttributes(); 478 params.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 479 win.setAttributes(params); 480 481 // Filter for screen off so that we can finish secure camera activity 482 // when screen is off. 483 IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); 484 registerReceiver(mScreenOffReceiver, filter); 485 // TODO: This static screen off event receiver is a workaround to the 486 // double onResume() invocation (onResume->onPause->onResume). We should 487 // find a better solution to this. 488 if (sScreenOffReceiver == null) { 489 sScreenOffReceiver = new ScreenOffReceiver(); 490 registerReceiver(sScreenOffReceiver, filter); 491 } 492 } 493 mPanoramaManager = new PanoramaStitchingManager(CameraActivity.this); 494 mPanoramaManager.addTaskListener(mStitchingListener); 495 LayoutInflater inflater = getLayoutInflater(); 496 View rootLayout = inflater.inflate(R.layout.camera, null, false); 497 mRootView = rootLayout.findViewById(R.id.camera_app_root); 498 mPanoStitchingPanel = findViewById(R.id.pano_stitching_progress_panel); 499 mBottomProgress = (ProgressBar) findViewById(R.id.pano_stitching_progress_bar); 500 mCameraPreviewData = new CameraPreviewData(rootLayout, 501 FilmStripView.ImageData.SIZE_FULL, 502 FilmStripView.ImageData.SIZE_FULL); 503 // Put a CameraPreviewData at the first position. 504 mWrappedDataAdapter = new FixedFirstDataAdapter( 505 new CameraDataAdapter(new ColorDrawable( 506 getResources().getColor(R.color.photo_placeholder))), 507 mCameraPreviewData); 508 mFilmStripView = (FilmStripView) findViewById(R.id.filmstrip_view); 509 mFilmStripView.setViewGap( 510 getResources().getDimensionPixelSize(R.dimen.camera_film_strip_gap)); 511 mPanoramaViewHelper = new PanoramaViewHelper(this); 512 mPanoramaViewHelper.onCreate(); 513 mFilmStripView.setPanoramaViewHelper(mPanoramaViewHelper); 514 // Set up the camera preview first so the preview shows up ASAP. 515 mFilmStripView.setListener(mFilmStripListener); 516 if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction()) 517 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) { 518 mCurrentModule = new VideoModule(); 519 mCurrentModuleIndex = CameraSwitcher.VIDEO_MODULE_INDEX; 520 } else { 521 mCurrentModule = new PhotoModule(); 522 } 523 mCurrentModule.init(this, mRootView); 524 mOrientationListener = new MyOrientationEventListener(this); 525 mMainHandler = new Handler(getMainLooper()); 526 bindMediaSaveService(); 527 528 if (!mSecureCamera) { 529 mDataAdapter = mWrappedDataAdapter; 530 mDataAdapter.requestLoad(getContentResolver()); 531 } else { 532 // Put a lock placeholder as the last image by setting its date to 0. 533 ImageView v = (ImageView) getLayoutInflater().inflate( 534 R.layout.secure_album_placeholder, null); 535 mDataAdapter = new FixedLastDataAdapter( 536 mWrappedDataAdapter, 537 new SimpleViewData( 538 v, 539 v.getDrawable().getIntrinsicWidth(), 540 v.getDrawable().getIntrinsicHeight(), 541 0, 0)); 542 // Flush out all the original data. 543 mDataAdapter.flush(); 544 } 545 mFilmStripView.setDataAdapter(mDataAdapter); 546 } 547 548 private void setRotationAnimation() { 549 int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; 550 rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; 551 Window win = getWindow(); 552 WindowManager.LayoutParams winParams = win.getAttributes(); 553 winParams.rotationAnimation = rotationAnimation; 554 win.setAttributes(winParams); 555 } 556 557 @Override 558 public void onUserInteraction() { 559 super.onUserInteraction(); 560 mCurrentModule.onUserInteraction(); 561 } 562 563 @Override 564 public void onPause() { 565 mOrientationListener.disable(); 566 mCurrentModule.onPauseBeforeSuper(); 567 super.onPause(); 568 mCurrentModule.onPauseAfterSuper(); 569 } 570 571 @Override 572 public void onResume() { 573 if (Settings.System.getInt(getContentResolver(), 574 Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {// auto-rotate off 575 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 576 mAutoRotateScreen = false; 577 } else { 578 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); 579 mAutoRotateScreen = true; 580 } 581 mOrientationListener.enable(); 582 mCurrentModule.onResumeBeforeSuper(); 583 super.onResume(); 584 mCurrentModule.onResumeAfterSuper(); 585 586 setSwipingEnabled(true); 587 } 588 589 @Override 590 public void onStart() { 591 super.onStart(); 592 593 mPanoramaViewHelper.onStart(); 594 } 595 596 @Override 597 protected void onStop() { 598 super.onStop(); 599 mPanoramaViewHelper.onStop(); 600 } 601 602 @Override 603 public void onDestroy() { 604 unbindMediaSaveService(); 605 if (mSecureCamera) unregisterReceiver(mScreenOffReceiver); 606 super.onDestroy(); 607 } 608 609 @Override 610 public void onConfigurationChanged(Configuration config) { 611 super.onConfigurationChanged(config); 612 mCurrentModule.onConfigurationChanged(config); 613 } 614 615 @Override 616 public boolean onKeyDown(int keyCode, KeyEvent event) { 617 if (mCurrentModule.onKeyDown(keyCode, event)) return true; 618 // Prevent software keyboard or voice search from showing up. 619 if (keyCode == KeyEvent.KEYCODE_SEARCH 620 || keyCode == KeyEvent.KEYCODE_MENU) { 621 if (event.isLongPress()) return true; 622 } 623 if (keyCode == KeyEvent.KEYCODE_MENU && mShowCameraPreview) { 624 return true; 625 } 626 627 return super.onKeyDown(keyCode, event); 628 } 629 630 @Override 631 public boolean onKeyUp(int keyCode, KeyEvent event) { 632 if (mCurrentModule.onKeyUp(keyCode, event)) return true; 633 if (keyCode == KeyEvent.KEYCODE_MENU && mShowCameraPreview) { 634 return true; 635 } 636 return super.onKeyUp(keyCode, event); 637 } 638 639 public boolean isAutoRotateScreen() { 640 return mAutoRotateScreen; 641 } 642 643 protected void updateStorageSpace() { 644 mStorageSpace = Storage.getAvailableSpace(); 645 } 646 647 protected long getStorageSpace() { 648 return mStorageSpace; 649 } 650 651 protected void updateStorageSpaceAndHint() { 652 updateStorageSpace(); 653 updateStorageHint(mStorageSpace); 654 } 655 656 protected void updateStorageHint() { 657 updateStorageHint(mStorageSpace); 658 } 659 660 protected boolean updateStorageHintOnResume() { 661 return true; 662 } 663 664 protected void updateStorageHint(long storageSpace) { 665 String message = null; 666 if (storageSpace == Storage.UNAVAILABLE) { 667 message = getString(R.string.no_storage); 668 } else if (storageSpace == Storage.PREPARING) { 669 message = getString(R.string.preparing_sd); 670 } else if (storageSpace == Storage.UNKNOWN_SIZE) { 671 message = getString(R.string.access_sd_fail); 672 } else if (storageSpace <= Storage.LOW_STORAGE_THRESHOLD) { 673 message = getString(R.string.spaceIsLow_content); 674 } 675 676 if (message != null) { 677 if (mStorageHint == null) { 678 mStorageHint = OnScreenHint.makeText(this, message); 679 } else { 680 mStorageHint.setText(message); 681 } 682 mStorageHint.show(); 683 } else if (mStorageHint != null) { 684 mStorageHint.cancel(); 685 mStorageHint = null; 686 } 687 } 688 689 protected void setResultEx(int resultCode) { 690 mResultCodeForTesting = resultCode; 691 setResult(resultCode); 692 } 693 694 protected void setResultEx(int resultCode, Intent data) { 695 mResultCodeForTesting = resultCode; 696 mResultDataForTesting = data; 697 setResult(resultCode, data); 698 } 699 700 public int getResultCode() { 701 return mResultCodeForTesting; 702 } 703 704 public Intent getResultData() { 705 return mResultDataForTesting; 706 } 707 708 public boolean isSecureCamera() { 709 return mSecureCamera; 710 } 711 712 @Override 713 public void onCameraSelected(int i) { 714 if (mCurrentModuleIndex == i) return; 715 716 CameraHolder.instance().keep(); 717 closeModule(mCurrentModule); 718 mCurrentModuleIndex = i; 719 switch (i) { 720 case CameraSwitcher.VIDEO_MODULE_INDEX: 721 mCurrentModule = new VideoModule(); 722 break; 723 case CameraSwitcher.PHOTO_MODULE_INDEX: 724 mCurrentModule = new PhotoModule(); 725 break; 726 case CameraSwitcher.LIGHTCYCLE_MODULE_INDEX: 727 mCurrentModule = PhotoSphereHelper.createPanoramaModule(); 728 break; 729 default: 730 break; 731 } 732 733 openModule(mCurrentModule); 734 mCurrentModule.onOrientationChanged(mLastRawOrientation); 735 if (mMediaSaveService != null) { 736 mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService); 737 } 738 } 739 740 private void openModule(CameraModule module) { 741 module.init(this, mRootView); 742 module.onResumeBeforeSuper(); 743 module.onResumeAfterSuper(); 744 } 745 746 private void closeModule(CameraModule module) { 747 module.onPauseBeforeSuper(); 748 module.onPauseAfterSuper(); 749 ((ViewGroup) mRootView).removeAllViews(); 750 } 751 752 @Override 753 public void onShowSwitcherPopup() { 754 } 755 756 public void setSwipingEnabled(boolean enable) { 757 mCameraPreviewData.lockPreview(!enable); 758 } 759 760 // Accessor methods for getting latency times used in performance testing 761 public long getAutoFocusTime() { 762 return (mCurrentModule instanceof PhotoModule) ? 763 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1; 764 } 765 766 public long getShutterLag() { 767 return (mCurrentModule instanceof PhotoModule) ? 768 ((PhotoModule) mCurrentModule).mShutterLag : -1; 769 } 770 771 public long getShutterToPictureDisplayedTime() { 772 return (mCurrentModule instanceof PhotoModule) ? 773 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1; 774 } 775 776 public long getPictureDisplayedToJpegCallbackTime() { 777 return (mCurrentModule instanceof PhotoModule) ? 778 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1; 779 } 780 781 public long getJpegCallbackFinishTime() { 782 return (mCurrentModule instanceof PhotoModule) ? 783 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1; 784 } 785 786 public long getCaptureStartTime() { 787 return (mCurrentModule instanceof PhotoModule) ? 788 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1; 789 } 790 791 public boolean isRecording() { 792 return (mCurrentModule instanceof VideoModule) ? 793 ((VideoModule) mCurrentModule).isRecording() : false; 794 } 795} 796