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