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