PhotoUI.java revision 3044d8c577432d6e9721fc8b26ac2afbbaf21266
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 17 18package com.android.camera; 19 20import android.app.AlertDialog; 21import android.content.DialogInterface; 22import android.graphics.Bitmap; 23import android.graphics.Color; 24import android.graphics.Matrix; 25import android.graphics.SurfaceTexture; 26import android.graphics.drawable.ColorDrawable; 27import android.hardware.Camera; 28import android.hardware.Camera.Face; 29import android.os.AsyncTask; 30import android.util.Log; 31import android.view.Gravity; 32import android.view.TextureView; 33import android.view.View; 34import android.view.View.OnClickListener; 35import android.view.View.OnLayoutChangeListener; 36import android.view.ViewGroup; 37import android.view.ViewStub; 38import android.widget.FrameLayout.LayoutParams; 39import android.widget.ImageView; 40import android.widget.PopupWindow; 41import android.widget.Toast; 42 43import com.android.camera.CameraPreference.OnPreferenceChangedListener; 44import com.android.camera.FocusOverlayManager.FocusUI; 45import com.android.camera.ui.AbstractSettingPopup; 46import com.android.camera.ui.CameraControls; 47import com.android.camera.ui.CameraRootView; 48import com.android.camera.ui.CountDownView; 49import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; 50import com.android.camera.ui.FaceView; 51import com.android.camera.ui.FocusIndicator; 52import com.android.camera.ui.ModuleSwitcher; 53import com.android.camera.ui.PieRenderer; 54import com.android.camera.ui.PieRenderer.PieListener; 55import com.android.camera.ui.RenderOverlay; 56import com.android.camera.ui.ZoomRenderer; 57import com.android.camera.util.CameraUtil; 58import com.android.camera2.R; 59 60import java.util.List; 61 62public class PhotoUI implements PieListener, 63 PreviewGestures.SingleTapListener, 64 FocusUI, TextureView.SurfaceTextureListener, 65 LocationManager.Listener, CameraRootView.MyDisplayListener, 66 CameraManager.CameraFaceDetectionCallback { 67 68 private static final String TAG = "CAM_UI"; 69 private static final int DOWN_SAMPLE_FACTOR = 4; 70 private final AnimationManager mAnimationManager; 71 private CameraActivity mActivity; 72 private PhotoController mController; 73 private PreviewGestures mGestures; 74 75 private View mRootView; 76 private SurfaceTexture mSurfaceTexture; 77 78 private PopupWindow mPopup; 79 private ShutterButton mShutterButton; 80 private CountDownView mCountDownView; 81 82 private FaceView mFaceView; 83 private RenderOverlay mRenderOverlay; 84 private View mReviewCancelButton; 85 private View mReviewDoneButton; 86 private View mReviewRetakeButton; 87 private ImageView mReviewImage; 88 private DecodeImageForReview mDecodeTaskForReview = null; 89 90 private View mMenuButton; 91 private PhotoMenu mMenu; 92 private ModuleSwitcher mSwitcher; 93 private CameraControls mCameraControls; 94 private AlertDialog mLocationDialog; 95 96 // Small indicators which show the camera settings in the viewfinder. 97 private OnScreenIndicators mOnScreenIndicators; 98 99 private PieRenderer mPieRenderer; 100 private ZoomRenderer mZoomRenderer; 101 private Toast mNotSelectableToast; 102 103 private int mZoomMax; 104 private List<Integer> mZoomRatios; 105 106 private int mPreviewWidth = 0; 107 private int mPreviewHeight = 0; 108 private float mSurfaceTextureUncroppedWidth; 109 private float mSurfaceTextureUncroppedHeight; 110 111 private ImageView mPreviewThumb; 112 private View mFlashOverlay; 113 114 private SurfaceTextureSizeChangedListener mSurfaceTextureSizeListener; 115 private TextureView mTextureView; 116 private Matrix mMatrix = null; 117 private float mAspectRatio = 4f / 3f; 118 119 public interface SurfaceTextureSizeChangedListener { 120 public void onSurfaceTextureSizeChanged(int uncroppedWidth, int uncroppedHeight); 121 } 122 123 private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { 124 @Override 125 public void onLayoutChange(View v, int left, int top, int right, 126 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 127 int width = right - left; 128 int height = bottom - top; 129 if (mPreviewWidth != width || mPreviewHeight != height) { 130 mPreviewWidth = width; 131 mPreviewHeight = height; 132 setTransformMatrix(width, height); 133 mController.onScreenSizeChanged((int) mSurfaceTextureUncroppedWidth, 134 (int) mSurfaceTextureUncroppedHeight); 135 } 136 } 137 }; 138 139 private class DecodeTask extends AsyncTask<Void, Void, Bitmap> { 140 private final byte [] mData; 141 private int mOrientation; 142 private boolean mMirror; 143 144 public DecodeTask(byte[] data, int orientation, boolean mirror) { 145 mData = data; 146 mOrientation = orientation; 147 mMirror = mirror; 148 } 149 150 @Override 151 protected Bitmap doInBackground(Void... params) { 152 // Decode image in background. 153 Bitmap bitmap = CameraUtil.downSample(mData, DOWN_SAMPLE_FACTOR); 154 if (mOrientation != 0 || mMirror) { 155 Matrix m = new Matrix(); 156 m.preRotate(mOrientation); 157 if (mMirror) { 158 // Flip horizontally 159 m.setScale(-1f, 1f); 160 } 161 return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, 162 false); 163 } 164 return bitmap; 165 } 166 167 @Override 168 protected void onPostExecute(Bitmap bitmap) { 169 mPreviewThumb.setImageBitmap(bitmap); 170 mAnimationManager.startCaptureAnimation(mPreviewThumb); 171 } 172 } 173 174 private class DecodeImageForReview extends DecodeTask { 175 public DecodeImageForReview(byte[] data, int orientation, boolean mirror) { 176 super(data, orientation, mirror); 177 } 178 179 @Override 180 protected void onPostExecute(Bitmap bitmap) { 181 if (isCancelled()) { 182 return; 183 } 184 mReviewImage.setImageBitmap(bitmap); 185 mReviewImage.setVisibility(View.VISIBLE); 186 mDecodeTaskForReview = null; 187 } 188 } 189 190 public PhotoUI(CameraActivity activity, PhotoController controller, View parent) { 191 mActivity = activity; 192 mController = controller; 193 mRootView = parent; 194 195 mActivity.getLayoutInflater().inflate(R.layout.photo_module, 196 (ViewGroup) mRootView, true); 197 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay); 198 mFlashOverlay = mRootView.findViewById(R.id.flash_overlay); 199 // display the view 200 mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content); 201 mTextureView.setSurfaceTextureListener(this); 202 mTextureView.addOnLayoutChangeListener(mLayoutListener); 203 initIndicators(); 204 205 mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button); 206 mSwitcher = (ModuleSwitcher) mRootView.findViewById(R.id.camera_switcher); 207 mSwitcher.setCurrentIndex(ModuleSwitcher.PHOTO_MODULE_INDEX); 208 mSwitcher.setSwitchListener(mActivity); 209 mMenuButton = mRootView.findViewById(R.id.menu); 210 ViewStub faceViewStub = (ViewStub) mRootView 211 .findViewById(R.id.face_view_stub); 212 if (faceViewStub != null) { 213 faceViewStub.inflate(); 214 mFaceView = (FaceView) mRootView.findViewById(R.id.face_view); 215 setSurfaceTextureSizeChangedListener(mFaceView); 216 } 217 mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls); 218 mAnimationManager = new AnimationManager(); 219 } 220 221 public void setSurfaceTextureSizeChangedListener(SurfaceTextureSizeChangedListener listener) { 222 mSurfaceTextureSizeListener = listener; 223 } 224 225 private void setTransformMatrix(int width, int height) { 226 mMatrix = mTextureView.getTransform(mMatrix); 227 float scaleX = 1f, scaleY = 1f; 228 float scaledTextureWidth, scaledTextureHeight; 229 if (width > height) { 230 scaledTextureWidth = Math.max(width, 231 (int) (height * mAspectRatio)); 232 scaledTextureHeight = Math.max(height, 233 (int)(width / mAspectRatio)); 234 } else { 235 scaledTextureWidth = Math.max(width, 236 (int) (height / mAspectRatio)); 237 scaledTextureHeight = Math.max(height, 238 (int) (width * mAspectRatio)); 239 } 240 241 if (mSurfaceTextureUncroppedWidth != scaledTextureWidth || 242 mSurfaceTextureUncroppedHeight != scaledTextureHeight) { 243 mSurfaceTextureUncroppedWidth = scaledTextureWidth; 244 mSurfaceTextureUncroppedHeight = scaledTextureHeight; 245 if (mSurfaceTextureSizeListener != null) { 246 mSurfaceTextureSizeListener.onSurfaceTextureSizeChanged( 247 (int) mSurfaceTextureUncroppedWidth, (int) mSurfaceTextureUncroppedHeight); 248 } 249 } 250 scaleX = scaledTextureWidth / width; 251 scaleY = scaledTextureHeight / height; 252 mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2); 253 mTextureView.setTransform(mMatrix); 254 } 255 256 @Override 257 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 258 Log.v(TAG, "SurfaceTexture ready."); 259 mSurfaceTexture = surface; 260 mController.onPreviewUIReady(); 261 // Workaround for b/11168275, see b/10981460 for more details 262 if (mPreviewWidth != 0 && mPreviewHeight != 0) { 263 // Re-apply transform matrix for new surface texture 264 setTransformMatrix(mPreviewWidth, mPreviewHeight); 265 } 266 } 267 268 @Override 269 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 270 // Ignored, Camera does all the work for us 271 } 272 273 @Override 274 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 275 mSurfaceTexture = null; 276 mController.onPreviewUIDestroyed(); 277 Log.w(TAG, "SurfaceTexture destroyed"); 278 return true; 279 } 280 281 @Override 282 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 283 // Do nothing. 284 } 285 286 public View getRootView() { 287 return mRootView; 288 } 289 290 private void initIndicators() { 291 mOnScreenIndicators = new OnScreenIndicators(mActivity, 292 mRootView.findViewById(R.id.on_screen_indicators)); 293 } 294 295 public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs, 296 Camera.Parameters params, OnPreferenceChangedListener listener) { 297 if (mPieRenderer == null) { 298 mPieRenderer = new PieRenderer(mActivity); 299 mPieRenderer.setPieListener(this); 300 mRenderOverlay.addRenderer(mPieRenderer); 301 } 302 303 if (mMenu == null) { 304 mMenu = new PhotoMenu(mActivity, this, mPieRenderer); 305 mMenu.setListener(listener); 306 } 307 mMenu.initialize(prefGroup); 308 309 if (mZoomRenderer == null) { 310 mZoomRenderer = new ZoomRenderer(mActivity); 311 mRenderOverlay.addRenderer(mZoomRenderer); 312 } 313 314 if (mGestures == null) { 315 // this will handle gesture disambiguation and dispatching 316 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer); 317 mRenderOverlay.setGestures(mGestures); 318 } 319 mGestures.setZoomEnabled(params.isZoomSupported()); 320 mGestures.setRenderOverlay(mRenderOverlay); 321 mRenderOverlay.requestLayout(); 322 323 initializeZoom(params); 324 updateOnScreenIndicators(params, prefGroup, prefs); 325 } 326 327 public void animateCapture(final byte[] jpegData, int orientation, boolean mirror) { 328 // Decode jpeg byte array and then animate the jpeg 329 DecodeTask task = new DecodeTask(jpegData, orientation, mirror); 330 task.execute(); 331 } 332 333 private void openMenu() { 334 if (mPieRenderer != null) { 335 // If autofocus is not finished, cancel autofocus so that the 336 // subsequent touch can be handled by PreviewGestures 337 if (mController.getCameraState() == PhotoController.FOCUSING) { 338 mController.cancelAutoFocus(); 339 } 340 mPieRenderer.showInCenter(); 341 } 342 } 343 344 public void initializeControlByIntent() { 345 mPreviewThumb = (ImageView) mRootView.findViewById(R.id.preview_thumb); 346 mPreviewThumb.setOnClickListener(new OnClickListener() { 347 @Override 348 public void onClick(View v) { 349 mActivity.gotoGallery(); 350 } 351 }); 352 mMenuButton = mRootView.findViewById(R.id.menu); 353 mMenuButton.setOnClickListener(new OnClickListener() { 354 @Override 355 public void onClick(View v) { 356 openMenu(); 357 } 358 }); 359 if (mController.isImageCaptureIntent()) { 360 hideSwitcher(); 361 ViewGroup cameraControls = (ViewGroup) mRootView.findViewById(R.id.camera_controls); 362 mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls); 363 364 mReviewDoneButton = mRootView.findViewById(R.id.btn_done); 365 mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel); 366 mReviewRetakeButton = mRootView.findViewById(R.id.btn_retake); 367 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image); 368 mReviewCancelButton.setVisibility(View.VISIBLE); 369 370 mReviewDoneButton.setOnClickListener(new OnClickListener() { 371 @Override 372 public void onClick(View v) { 373 mController.onCaptureDone(); 374 } 375 }); 376 mReviewCancelButton.setOnClickListener(new OnClickListener() { 377 @Override 378 public void onClick(View v) { 379 mController.onCaptureCancelled(); 380 } 381 }); 382 383 mReviewRetakeButton.setOnClickListener(new OnClickListener() { 384 @Override 385 public void onClick(View v) { 386 mController.onCaptureRetake(); 387 } 388 }); 389 } 390 } 391 392 public void hideUI() { 393 mCameraControls.setVisibility(View.INVISIBLE); 394 mSwitcher.closePopup(); 395 } 396 397 public void showUI() { 398 mCameraControls.setVisibility(View.VISIBLE); 399 } 400 401 public boolean arePreviewControlsVisible() { 402 return (mCameraControls.getVisibility() == View.VISIBLE); 403 } 404 405 public void hideSwitcher() { 406 mSwitcher.closePopup(); 407 mSwitcher.setVisibility(View.INVISIBLE); 408 } 409 410 public void showSwitcher() { 411 mSwitcher.setVisibility(View.VISIBLE); 412 } 413 // called from onResume but only the first time 414 public void initializeFirstTime() { 415 // Initialize shutter button. 416 mShutterButton.setImageResource(R.drawable.btn_new_shutter); 417 mShutterButton.setOnShutterButtonListener(mController); 418 mShutterButton.setVisibility(View.VISIBLE); 419 } 420 421 // called from onResume every other time 422 public void initializeSecondTime(Camera.Parameters params) { 423 initializeZoom(params); 424 if (mController.isImageCaptureIntent()) { 425 hidePostCaptureAlert(); 426 } 427 if (mMenu != null) { 428 mMenu.reloadPreferences(); 429 } 430 } 431 432 public void showLocationDialog() { 433 mLocationDialog = new AlertDialog.Builder(mActivity) 434 .setTitle(R.string.remember_location_title) 435 .setMessage(R.string.remember_location_prompt) 436 .setPositiveButton(R.string.remember_location_yes, 437 new DialogInterface.OnClickListener() { 438 @Override 439 public void onClick(DialogInterface dialog, int arg1) { 440 mController.enableRecordingLocation(true); 441 mLocationDialog = null; 442 } 443 }) 444 .setNegativeButton(R.string.remember_location_no, 445 new DialogInterface.OnClickListener() { 446 @Override 447 public void onClick(DialogInterface dialog, int arg1) { 448 dialog.cancel(); 449 } 450 }) 451 .setOnCancelListener(new DialogInterface.OnCancelListener() { 452 @Override 453 public void onCancel(DialogInterface dialog) { 454 mController.enableRecordingLocation(false); 455 mLocationDialog = null; 456 } 457 }) 458 .show(); 459 } 460 461 public void initializeZoom(Camera.Parameters params) { 462 if ((params == null) || !params.isZoomSupported() 463 || (mZoomRenderer == null)) return; 464 mZoomMax = params.getMaxZoom(); 465 mZoomRatios = params.getZoomRatios(); 466 // Currently we use immediate zoom for fast zooming to get better UX and 467 // there is no plan to take advantage of the smooth zoom. 468 if (mZoomRenderer != null) { 469 mZoomRenderer.setZoomMax(mZoomMax); 470 mZoomRenderer.setZoom(params.getZoom()); 471 mZoomRenderer.setZoomValue(mZoomRatios.get(params.getZoom())); 472 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener()); 473 } 474 } 475 476 @Override 477 public void showGpsOnScreenIndicator(boolean hasSignal) { } 478 479 @Override 480 public void hideGpsOnScreenIndicator() { } 481 482 public void overrideSettings(final String ... keyvalues) { 483 mMenu.overrideSettings(keyvalues); 484 } 485 486 public void updateOnScreenIndicators(Camera.Parameters params, 487 PreferenceGroup group, ComboPreferences prefs) { 488 if (params == null) return; 489 mOnScreenIndicators.updateSceneOnScreenIndicator(params.getSceneMode()); 490 mOnScreenIndicators.updateExposureOnScreenIndicator(params, 491 CameraSettings.readExposure(prefs)); 492 mOnScreenIndicators.updateFlashOnScreenIndicator(params.getFlashMode()); 493 int wbIndex = 2; 494 ListPreference pref = group.findPreference(CameraSettings.KEY_WHITE_BALANCE); 495 if (pref != null) { 496 wbIndex = pref.getCurrentIndex(); 497 } 498 mOnScreenIndicators.updateWBIndicator(wbIndex); 499 boolean location = RecordLocationPreference.get( 500 prefs, mActivity.getContentResolver()); 501 mOnScreenIndicators.updateLocationIndicator(location); 502 } 503 504 public void setCameraState(int state) { 505 } 506 507 public void animateFlash() { 508 mAnimationManager.startFlashAnimation(mFlashOverlay); 509 } 510 511 public void enableGestures(boolean enable) { 512 if (mGestures != null) { 513 mGestures.setEnabled(enable); 514 } 515 } 516 517 // forward from preview gestures to controller 518 @Override 519 public void onSingleTapUp(View view, int x, int y) { 520 mController.onSingleTapUp(view, x, y); 521 } 522 523 public boolean onBackPressed() { 524 if (mPieRenderer != null && mPieRenderer.showsItems()) { 525 mPieRenderer.hide(); 526 return true; 527 } 528 // In image capture mode, back button should: 529 // 1) if there is any popup, dismiss them, 2) otherwise, get out of 530 // image capture 531 if (mController.isImageCaptureIntent()) { 532 mController.onCaptureCancelled(); 533 return true; 534 } else if (!mController.isCameraIdle()) { 535 // ignore backs while we're taking a picture 536 return true; 537 } else { 538 return false; 539 } 540 } 541 542 public void onPreviewFocusChanged(boolean previewFocused) { 543 if (previewFocused) { 544 showUI(); 545 } else { 546 hideUI(); 547 } 548 if (mFaceView != null) { 549 mFaceView.setBlockDraw(!previewFocused); 550 } 551 if (mGestures != null) { 552 mGestures.setEnabled(previewFocused); 553 } 554 if (mRenderOverlay != null) { 555 // this can not happen in capture mode 556 mRenderOverlay.setVisibility(previewFocused ? View.VISIBLE : View.GONE); 557 } 558 if (mPieRenderer != null) { 559 mPieRenderer.setBlockFocus(!previewFocused); 560 } 561 setShowMenu(previewFocused); 562 if (!previewFocused && mCountDownView != null) mCountDownView.cancelCountDown(); 563 } 564 565 public void showPopup(AbstractSettingPopup popup) { 566 hideUI(); 567 568 if (mPopup == null) { 569 mPopup = new PopupWindow(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 570 mPopup.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 571 mPopup.setOutsideTouchable(true); 572 mPopup.setFocusable(true); 573 mPopup.setOnDismissListener(new PopupWindow.OnDismissListener() { 574 @Override 575 public void onDismiss() { 576 mPopup = null; 577 mMenu.popupDismissed(); 578 showUI(); 579 580 // Switch back into fullscreen/lights-out mode after popup 581 // is dimissed. 582 mActivity.setSystemBarsVisibility(false); 583 } 584 }); 585 } 586 popup.setVisibility(View.VISIBLE); 587 mPopup.setContentView(popup); 588 mPopup.showAtLocation(mRootView, Gravity.CENTER, 0, 0); 589 } 590 591 public void dismissPopup() { 592 if (mPopup != null && mPopup.isShowing()) { 593 mPopup.dismiss(); 594 } 595 } 596 597 public void onShowSwitcherPopup() { 598 if (mPieRenderer != null && mPieRenderer.showsItems()) { 599 mPieRenderer.hide(); 600 } 601 } 602 603 private void setShowMenu(boolean show) { 604 if (mOnScreenIndicators != null) { 605 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE); 606 } 607 if (mMenuButton != null) { 608 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE); 609 } 610 } 611 612 public boolean collapseCameraControls() { 613 // Remove all the popups/dialog boxes 614 boolean ret = false; 615 if (mPopup != null) { 616 dismissPopup(); 617 ret = true; 618 } 619 onShowSwitcherPopup(); 620 return ret; 621 } 622 623 protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) { 624 mDecodeTaskForReview = new DecodeImageForReview(jpegData, orientation, mirror); 625 mDecodeTaskForReview.execute(); 626 mOnScreenIndicators.setVisibility(View.GONE); 627 mMenuButton.setVisibility(View.GONE); 628 CameraUtil.fadeIn(mReviewDoneButton); 629 mShutterButton.setVisibility(View.INVISIBLE); 630 CameraUtil.fadeIn(mReviewRetakeButton); 631 pauseFaceDetection(); 632 } 633 634 protected void hidePostCaptureAlert() { 635 if (mDecodeTaskForReview != null) { 636 mDecodeTaskForReview.cancel(true); 637 } 638 mReviewImage.setVisibility(View.GONE); 639 mOnScreenIndicators.setVisibility(View.VISIBLE); 640 mMenuButton.setVisibility(View.VISIBLE); 641 CameraUtil.fadeOut(mReviewDoneButton); 642 mShutterButton.setVisibility(View.VISIBLE); 643 CameraUtil.fadeOut(mReviewRetakeButton); 644 resumeFaceDetection(); 645 } 646 647 public void setDisplayOrientation(int orientation) { 648 if (mFaceView != null) { 649 mFaceView.setDisplayOrientation(orientation); 650 } 651 } 652 653 // shutter button handling 654 655 public boolean isShutterPressed() { 656 return mShutterButton.isPressed(); 657 } 658 659 /** 660 * Enables or disables the shutter button. 661 */ 662 public void enableShutter(boolean enabled) { 663 if (mShutterButton != null) { 664 mShutterButton.setEnabled(enabled); 665 } 666 } 667 668 public void pressShutterButton() { 669 if (mShutterButton.isInTouchMode()) { 670 mShutterButton.requestFocusFromTouch(); 671 } else { 672 mShutterButton.requestFocus(); 673 } 674 mShutterButton.setPressed(true); 675 } 676 677 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { 678 @Override 679 public void onZoomValueChanged(int index) { 680 int newZoom = mController.onZoomChanged(index); 681 if (mZoomRenderer != null) { 682 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom)); 683 } 684 } 685 686 @Override 687 public void onZoomStart() { 688 if (mPieRenderer != null) { 689 mPieRenderer.setBlockFocus(true); 690 } 691 } 692 693 @Override 694 public void onZoomEnd() { 695 if (mPieRenderer != null) { 696 mPieRenderer.setBlockFocus(false); 697 } 698 } 699 } 700 701 @Override 702 public void onPieOpened(int centerX, int centerY) { 703 setSwipingEnabled(false); 704 if (mFaceView != null) { 705 mFaceView.setBlockDraw(true); 706 } 707 } 708 709 @Override 710 public void onPieClosed() { 711 setSwipingEnabled(true); 712 if (mFaceView != null) { 713 mFaceView.setBlockDraw(false); 714 } 715 } 716 717 public void setSwipingEnabled(boolean enable) { 718 mActivity.setSwipingEnabled(enable); 719 } 720 721 public SurfaceTexture getSurfaceTexture() { 722 return mSurfaceTexture; 723 } 724 725 // Countdown timer 726 727 private void initializeCountDown() { 728 mActivity.getLayoutInflater().inflate(R.layout.count_down_to_capture, 729 (ViewGroup) mRootView, true); 730 mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture)); 731 mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController); 732 } 733 734 public boolean isCountingDown() { 735 return mCountDownView != null && mCountDownView.isCountingDown(); 736 } 737 738 public void cancelCountDown() { 739 if (mCountDownView == null) return; 740 mCountDownView.cancelCountDown(); 741 } 742 743 public void startCountDown(int sec, boolean playSound) { 744 if (mCountDownView == null) initializeCountDown(); 745 mCountDownView.startCountDown(sec, playSound); 746 } 747 748 public void showPreferencesToast() { 749 if (mNotSelectableToast == null) { 750 String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode); 751 mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT); 752 } 753 mNotSelectableToast.show(); 754 } 755 756 public void onPause() { 757 cancelCountDown(); 758 759 // Clear UI. 760 collapseCameraControls(); 761 if (mFaceView != null) mFaceView.clear(); 762 763 if (mLocationDialog != null && mLocationDialog.isShowing()) { 764 mLocationDialog.dismiss(); 765 } 766 mLocationDialog = null; 767 mPreviewWidth = 0; 768 mPreviewHeight = 0; 769 } 770 771 public void initDisplayChangeListener() { 772 ((CameraRootView) mRootView).setDisplayChangeListener(this); 773 } 774 775 public void removeDisplayChangeListener() { 776 ((CameraRootView) mRootView).removeDisplayChangeListener(); 777 } 778 779 // focus UI implementation 780 781 private FocusIndicator getFocusIndicator() { 782 return (mFaceView != null && mFaceView.faceExists()) ? mFaceView : mPieRenderer; 783 } 784 785 @Override 786 public boolean hasFaces() { 787 return (mFaceView != null && mFaceView.faceExists()); 788 } 789 790 public void clearFaces() { 791 if (mFaceView != null) mFaceView.clear(); 792 } 793 794 @Override 795 public void clearFocus() { 796 FocusIndicator indicator = getFocusIndicator(); 797 if (indicator != null) indicator.clear(); 798 } 799 800 @Override 801 public void setFocusPosition(int x, int y) { 802 mPieRenderer.setFocus(x, y); 803 } 804 805 @Override 806 public void onFocusStarted() { 807 getFocusIndicator().showStart(); 808 } 809 810 @Override 811 public void onFocusSucceeded(boolean timeout) { 812 getFocusIndicator().showSuccess(timeout); 813 } 814 815 @Override 816 public void onFocusFailed(boolean timeout) { 817 getFocusIndicator().showFail(timeout); 818 } 819 820 @Override 821 public void pauseFaceDetection() { 822 if (mFaceView != null) mFaceView.pause(); 823 } 824 825 @Override 826 public void resumeFaceDetection() { 827 if (mFaceView != null) mFaceView.resume(); 828 } 829 830 public void onStartFaceDetection(int orientation, boolean mirror) { 831 mFaceView.clear(); 832 mFaceView.setVisibility(View.VISIBLE); 833 mFaceView.setDisplayOrientation(orientation); 834 mFaceView.setMirror(mirror); 835 mFaceView.resume(); 836 } 837 838 @Override 839 public void onFaceDetection(Face[] faces, CameraManager.CameraProxy camera) { 840 mFaceView.setFaces(faces); 841 } 842 843 @Override 844 public void onDisplayChanged() { 845 mCameraControls.checkLayoutFlip(); 846 mController.updateCameraOrientation(); 847 } 848 849} 850