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 18 package com.android.camera; 19 20 import android.app.AlertDialog; 21 import android.content.DialogInterface; 22 import android.graphics.Bitmap; 23 import android.graphics.Color; 24 import android.graphics.Matrix; 25 import android.graphics.SurfaceTexture; 26 import android.graphics.drawable.ColorDrawable; 27 import android.hardware.Camera; 28 import android.hardware.Camera.Face; 29 import android.os.AsyncTask; 30 import android.util.Log; 31 import android.view.Gravity; 32 import android.view.TextureView; 33 import android.view.View; 34 import android.view.View.OnClickListener; 35 import android.view.View.OnLayoutChangeListener; 36 import android.view.ViewGroup; 37 import android.view.ViewStub; 38 import android.widget.FrameLayout.LayoutParams; 39 import android.widget.ImageView; 40 import android.widget.PopupWindow; 41 import android.widget.Toast; 42 43 import com.android.camera.CameraPreference.OnPreferenceChangedListener; 44 import com.android.camera.FocusOverlayManager.FocusUI; 45 import com.android.camera.ui.AbstractSettingPopup; 46 import com.android.camera.ui.CameraControls; 47 import com.android.camera.ui.CameraRootView; 48 import com.android.camera.ui.CountDownView; 49 import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; 50 import com.android.camera.ui.FaceView; 51 import com.android.camera.ui.FocusIndicator; 52 import com.android.camera.ui.ModuleSwitcher; 53 import com.android.camera.ui.PieRenderer; 54 import com.android.camera.ui.PieRenderer.PieListener; 55 import com.android.camera.ui.RenderOverlay; 56 import com.android.camera.ui.ZoomRenderer; 57 import com.android.camera.util.CameraUtil; 58 import com.android.camera2.R; 59 60 import java.util.List; 61 62 public 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 // TODO: Mode switcher should behave like a popup and should hide itself when there 614 // is a touch outside of it. 615 mSwitcher.closePopup(); 616 // Remove all the popups/dialog boxes 617 boolean ret = false; 618 if (mPopup != null) { 619 dismissPopup(); 620 ret = true; 621 } 622 onShowSwitcherPopup(); 623 return ret; 624 } 625 626 protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) { 627 mDecodeTaskForReview = new DecodeImageForReview(jpegData, orientation, mirror); 628 mDecodeTaskForReview.execute(); 629 mOnScreenIndicators.setVisibility(View.GONE); 630 mMenuButton.setVisibility(View.GONE); 631 CameraUtil.fadeIn(mReviewDoneButton); 632 mShutterButton.setVisibility(View.INVISIBLE); 633 CameraUtil.fadeIn(mReviewRetakeButton); 634 pauseFaceDetection(); 635 } 636 637 protected void hidePostCaptureAlert() { 638 if (mDecodeTaskForReview != null) { 639 mDecodeTaskForReview.cancel(true); 640 } 641 mReviewImage.setVisibility(View.GONE); 642 mOnScreenIndicators.setVisibility(View.VISIBLE); 643 mMenuButton.setVisibility(View.VISIBLE); 644 CameraUtil.fadeOut(mReviewDoneButton); 645 mShutterButton.setVisibility(View.VISIBLE); 646 CameraUtil.fadeOut(mReviewRetakeButton); 647 resumeFaceDetection(); 648 } 649 650 public void setDisplayOrientation(int orientation) { 651 if (mFaceView != null) { 652 mFaceView.setDisplayOrientation(orientation); 653 } 654 } 655 656 // shutter button handling 657 658 public boolean isShutterPressed() { 659 return mShutterButton.isPressed(); 660 } 661 662 /** 663 * Enables or disables the shutter button. 664 */ 665 public void enableShutter(boolean enabled) { 666 if (mShutterButton != null) { 667 mShutterButton.setEnabled(enabled); 668 } 669 } 670 671 public void pressShutterButton() { 672 if (mShutterButton.isInTouchMode()) { 673 mShutterButton.requestFocusFromTouch(); 674 } else { 675 mShutterButton.requestFocus(); 676 } 677 mShutterButton.setPressed(true); 678 } 679 680 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { 681 @Override 682 public void onZoomValueChanged(int index) { 683 int newZoom = mController.onZoomChanged(index); 684 if (mZoomRenderer != null) { 685 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom)); 686 } 687 } 688 689 @Override 690 public void onZoomStart() { 691 if (mPieRenderer != null) { 692 mPieRenderer.setBlockFocus(true); 693 } 694 } 695 696 @Override 697 public void onZoomEnd() { 698 if (mPieRenderer != null) { 699 mPieRenderer.setBlockFocus(false); 700 } 701 } 702 } 703 704 @Override 705 public void onPieOpened(int centerX, int centerY) { 706 setSwipingEnabled(false); 707 if (mFaceView != null) { 708 mFaceView.setBlockDraw(true); 709 } 710 } 711 712 @Override 713 public void onPieClosed() { 714 setSwipingEnabled(true); 715 if (mFaceView != null) { 716 mFaceView.setBlockDraw(false); 717 } 718 } 719 720 public void setSwipingEnabled(boolean enable) { 721 mActivity.setSwipingEnabled(enable); 722 } 723 724 public SurfaceTexture getSurfaceTexture() { 725 return mSurfaceTexture; 726 } 727 728 // Countdown timer 729 730 private void initializeCountDown() { 731 mActivity.getLayoutInflater().inflate(R.layout.count_down_to_capture, 732 (ViewGroup) mRootView, true); 733 mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture)); 734 mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController); 735 } 736 737 public boolean isCountingDown() { 738 return mCountDownView != null && mCountDownView.isCountingDown(); 739 } 740 741 public void cancelCountDown() { 742 if (mCountDownView == null) return; 743 mCountDownView.cancelCountDown(); 744 } 745 746 public void startCountDown(int sec, boolean playSound) { 747 if (mCountDownView == null) initializeCountDown(); 748 mCountDownView.startCountDown(sec, playSound); 749 } 750 751 public void showPreferencesToast() { 752 if (mNotSelectableToast == null) { 753 String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode); 754 mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT); 755 } 756 mNotSelectableToast.show(); 757 } 758 759 public void onPause() { 760 cancelCountDown(); 761 762 // Clear UI. 763 collapseCameraControls(); 764 if (mFaceView != null) mFaceView.clear(); 765 766 if (mLocationDialog != null && mLocationDialog.isShowing()) { 767 mLocationDialog.dismiss(); 768 } 769 mLocationDialog = null; 770 } 771 772 public void initDisplayChangeListener() { 773 ((CameraRootView) mRootView).setDisplayChangeListener(this); 774 } 775 776 public void removeDisplayChangeListener() { 777 ((CameraRootView) mRootView).removeDisplayChangeListener(); 778 } 779 780 // focus UI implementation 781 782 private FocusIndicator getFocusIndicator() { 783 return (mFaceView != null && mFaceView.faceExists()) ? mFaceView : mPieRenderer; 784 } 785 786 @Override 787 public boolean hasFaces() { 788 return (mFaceView != null && mFaceView.faceExists()); 789 } 790 791 public void clearFaces() { 792 if (mFaceView != null) mFaceView.clear(); 793 } 794 795 @Override 796 public void clearFocus() { 797 FocusIndicator indicator = getFocusIndicator(); 798 if (indicator != null) indicator.clear(); 799 } 800 801 @Override 802 public void setFocusPosition(int x, int y) { 803 mPieRenderer.setFocus(x, y); 804 } 805 806 @Override 807 public void onFocusStarted() { 808 getFocusIndicator().showStart(); 809 } 810 811 @Override 812 public void onFocusSucceeded(boolean timeout) { 813 getFocusIndicator().showSuccess(timeout); 814 } 815 816 @Override 817 public void onFocusFailed(boolean timeout) { 818 getFocusIndicator().showFail(timeout); 819 } 820 821 @Override 822 public void pauseFaceDetection() { 823 if (mFaceView != null) mFaceView.pause(); 824 } 825 826 @Override 827 public void resumeFaceDetection() { 828 if (mFaceView != null) mFaceView.resume(); 829 } 830 831 public void onStartFaceDetection(int orientation, boolean mirror) { 832 mFaceView.clear(); 833 mFaceView.setVisibility(View.VISIBLE); 834 mFaceView.setDisplayOrientation(orientation); 835 mFaceView.setMirror(mirror); 836 mFaceView.resume(); 837 } 838 839 @Override 840 public void onFaceDetection(Face[] faces, CameraManager.CameraProxy camera) { 841 mFaceView.setFaces(faces); 842 } 843 844 @Override 845 public void onDisplayChanged() { 846 Log.d(TAG, "Device flip detected."); 847 mCameraControls.checkLayoutFlip(); 848 mController.updateCameraOrientation(); 849 } 850 851 } 852