1 /* 2 * Copyright (C) 2013 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.hardware.Camera; 21 import android.hardware.Camera.Face; 22 import android.hardware.Camera.FaceDetectionListener; 23 import android.util.Log; 24 import android.view.Gravity; 25 import android.view.MotionEvent; 26 import android.view.SurfaceHolder; 27 import android.view.View; 28 import android.view.View.OnClickListener; 29 import android.view.View.OnLayoutChangeListener; 30 import android.view.ViewGroup; 31 import android.view.ViewStub; 32 import android.widget.FrameLayout; 33 import android.widget.FrameLayout.LayoutParams; 34 import android.widget.Toast; 35 36 import com.android.camera.CameraPreference.OnPreferenceChangedListener; 37 import com.android.camera.FocusOverlayManager.FocusUI; 38 import com.android.camera.ui.AbstractSettingPopup; 39 import com.android.camera.ui.CountDownView; 40 import com.android.camera.ui.CountDownView.OnCountDownFinishedListener; 41 import com.android.camera.ui.FaceView; 42 import com.android.camera.ui.FocusIndicator; 43 import com.android.camera.ui.PieRenderer; 44 import com.android.camera.ui.PieRenderer.PieListener; 45 import com.android.camera.ui.RenderOverlay; 46 import com.android.camera.ui.ZoomRenderer; 47 import com.android.gallery3d.R; 48 import com.android.gallery3d.common.ApiHelper; 49 50 import java.util.List; 51 52 public class PhotoUI implements PieListener, 53 SurfaceHolder.Callback, 54 PreviewGestures.SingleTapListener, 55 FocusUI, 56 LocationManager.Listener, 57 FaceDetectionListener, 58 PreviewGestures.SwipeListener { 59 60 private static final String TAG = "CAM_UI"; 61 62 private CameraActivity mActivity; 63 private PhotoController mController; 64 private PreviewGestures mGestures; 65 66 private View mRootView; 67 private Object mSurfaceTexture; 68 private volatile SurfaceHolder mSurfaceHolder; 69 70 private AbstractSettingPopup mPopup; 71 private ShutterButton mShutterButton; 72 private CountDownView mCountDownView; 73 74 private FaceView mFaceView; 75 private RenderOverlay mRenderOverlay; 76 private View mReviewCancelButton; 77 private View mReviewDoneButton; 78 private View mReviewRetakeButton; 79 80 private View mMenuButton; 81 private View mBlocker; 82 private PhotoMenu mMenu; 83 84 private OnScreenIndicators mOnScreenIndicators; 85 86 private PieRenderer mPieRenderer; 87 private ZoomRenderer mZoomRenderer; 88 private Toast mNotSelectableToast; 89 90 private int mZoomMax; 91 private List<Integer> mZoomRatios; 92 93 private int mPreviewWidth = 0; 94 private int mPreviewHeight = 0; 95 private View mPreviewThumb; 96 97 private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() { 98 @Override 99 public void onLayoutChange(View v, int left, int top, int right, 100 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 101 int width = right - left; 102 int height = bottom - top; 103 // Full-screen screennail 104 int w = width; 105 int h = height; 106 if (Util.getDisplayRotation(mActivity) % 180 != 0) { 107 w = height; 108 h = width; 109 } 110 if (mPreviewWidth != width || mPreviewHeight != height) { 111 mPreviewWidth = width; 112 mPreviewHeight = height; 113 mController.onScreenSizeChanged(width, height, w, h); 114 } 115 } 116 }; 117 PhotoUI(CameraActivity activity, PhotoController controller, View parent)118 public PhotoUI(CameraActivity activity, PhotoController controller, View parent) { 119 mActivity = activity; 120 mController = controller; 121 mRootView = parent; 122 123 mActivity.getLayoutInflater().inflate(R.layout.photo_module, 124 (ViewGroup) mRootView, true); 125 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay); 126 127 initIndicators(); 128 mCountDownView = (CountDownView) (mRootView.findViewById(R.id.count_down_to_capture)); 129 mCountDownView.setCountDownFinishedListener((OnCountDownFinishedListener) mController); 130 131 if (ApiHelper.HAS_FACE_DETECTION) { 132 ViewStub faceViewStub = (ViewStub) mRootView 133 .findViewById(R.id.face_view_stub); 134 if (faceViewStub != null) { 135 faceViewStub.inflate(); 136 mFaceView = (FaceView) mRootView.findViewById(R.id.face_view); 137 } 138 } 139 140 } 141 getRootView()142 public View getRootView() { 143 return mRootView; 144 } 145 initIndicators()146 private void initIndicators() { 147 mOnScreenIndicators = new OnScreenIndicators(mActivity, 148 mActivity.findViewById(R.id.on_screen_indicators)); 149 } 150 onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs, Camera.Parameters params, OnPreferenceChangedListener listener)151 public void onCameraOpened(PreferenceGroup prefGroup, ComboPreferences prefs, 152 Camera.Parameters params, OnPreferenceChangedListener listener) { 153 if (mPieRenderer == null) { 154 mPieRenderer = new PieRenderer(mActivity); 155 mPieRenderer.setPieListener(this); 156 mRenderOverlay.addRenderer(mPieRenderer); 157 } 158 if (mMenu == null) { 159 mMenu = new PhotoMenu(mActivity, this, mPieRenderer); 160 mMenu.setListener(listener); 161 } 162 mMenu.initialize(prefGroup); 163 164 if (mZoomRenderer == null) { 165 mZoomRenderer = new ZoomRenderer(mActivity); 166 mRenderOverlay.addRenderer(mZoomRenderer); 167 } 168 if (mGestures == null) { 169 // this will handle gesture disambiguation and dispatching 170 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer, 171 this); 172 } 173 mGestures.reset(); 174 mGestures.setRenderOverlay(mRenderOverlay); 175 mGestures.addTouchReceiver(mMenuButton); 176 mGestures.addUnclickableArea(mBlocker); 177 enablePreviewThumb(false); 178 // make sure to add touch targets for image capture 179 if (mController.isImageCaptureIntent()) { 180 if (mReviewCancelButton != null) { 181 mGestures.addTouchReceiver(mReviewCancelButton); 182 } 183 if (mReviewDoneButton != null) { 184 mGestures.addTouchReceiver(mReviewDoneButton); 185 } 186 } 187 mRenderOverlay.requestLayout(); 188 189 initializeZoom(params); 190 updateOnScreenIndicators(params, prefGroup, prefs); 191 } 192 openMenu()193 private void openMenu() { 194 if (mPieRenderer != null) { 195 // If autofocus is not finished, cancel autofocus so that the 196 // subsequent touch can be handled by PreviewGestures 197 if (mController.getCameraState() == PhotoController.FOCUSING) { 198 mController.cancelAutoFocus(); 199 } 200 mPieRenderer.showInCenter(); 201 } 202 } 203 initializeControlByIntent()204 public void initializeControlByIntent() { 205 mBlocker = mActivity.findViewById(R.id.blocker); 206 mPreviewThumb = mActivity.findViewById(R.id.preview_thumb); 207 mPreviewThumb.setOnClickListener(new OnClickListener() { 208 @Override 209 public void onClick(View v) { 210 mActivity.gotoGallery(); 211 } 212 }); 213 mMenuButton = mActivity.findViewById(R.id.menu); 214 mMenuButton.setOnClickListener(new OnClickListener() { 215 @Override 216 public void onClick(View v) { 217 openMenu(); 218 } 219 }); 220 if (mController.isImageCaptureIntent()) { 221 mActivity.hideSwitcher(); 222 ViewGroup cameraControls = (ViewGroup) mActivity.findViewById(R.id.camera_controls); 223 mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls); 224 225 mReviewDoneButton = mActivity.findViewById(R.id.btn_done); 226 mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel); 227 mReviewRetakeButton = mActivity.findViewById(R.id.btn_retake); 228 mReviewCancelButton.setVisibility(View.VISIBLE); 229 230 mReviewDoneButton.setOnClickListener(new OnClickListener() { 231 @Override 232 public void onClick(View v) { 233 mController.onCaptureDone(); 234 } 235 }); 236 mReviewCancelButton.setOnClickListener(new OnClickListener() { 237 @Override 238 public void onClick(View v) { 239 mController.onCaptureCancelled(); 240 } 241 }); 242 243 mReviewRetakeButton.setOnClickListener(new OnClickListener() { 244 @Override 245 public void onClick(View v) { 246 mController.onCaptureRetake(); 247 } 248 }); 249 } 250 } 251 252 // called from onResume but only the first time initializeFirstTime()253 public void initializeFirstTime() { 254 // Initialize shutter button. 255 mShutterButton = mActivity.getShutterButton(); 256 mShutterButton.setImageResource(R.drawable.btn_new_shutter); 257 mShutterButton.setOnShutterButtonListener(mController); 258 mShutterButton.setVisibility(View.VISIBLE); 259 mRootView.addOnLayoutChangeListener(mLayoutListener); 260 } 261 262 // called from onResume every other time initializeSecondTime(Camera.Parameters params)263 public void initializeSecondTime(Camera.Parameters params) { 264 initializeZoom(params); 265 if (mController.isImageCaptureIntent()) { 266 hidePostCaptureAlert(); 267 } 268 if (mMenu != null) { 269 mMenu.reloadPreferences(); 270 } 271 mRootView.addOnLayoutChangeListener(mLayoutListener); 272 } 273 initializeZoom(Camera.Parameters params)274 public void initializeZoom(Camera.Parameters params) { 275 if ((params == null) || !params.isZoomSupported() 276 || (mZoomRenderer == null)) return; 277 mZoomMax = params.getMaxZoom(); 278 mZoomRatios = params.getZoomRatios(); 279 // Currently we use immediate zoom for fast zooming to get better UX and 280 // there is no plan to take advantage of the smooth zoom. 281 if (mZoomRenderer != null) { 282 mZoomRenderer.setZoomMax(mZoomMax); 283 mZoomRenderer.setZoom(params.getZoom()); 284 mZoomRenderer.setZoomValue(mZoomRatios.get(params.getZoom())); 285 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener()); 286 } 287 } 288 enableGestures(boolean enable)289 public void enableGestures(boolean enable) { 290 if (mGestures != null) { 291 mGestures.setEnabled(enable); 292 } 293 } 294 295 @Override showGpsOnScreenIndicator(boolean hasSignal)296 public void showGpsOnScreenIndicator(boolean hasSignal) { } 297 298 @Override hideGpsOnScreenIndicator()299 public void hideGpsOnScreenIndicator() { } 300 overrideSettings(final String ... keyvalues)301 public void overrideSettings(final String ... keyvalues) { 302 mMenu.overrideSettings(keyvalues); 303 } 304 updateOnScreenIndicators(Camera.Parameters params, PreferenceGroup group, ComboPreferences prefs)305 public void updateOnScreenIndicators(Camera.Parameters params, 306 PreferenceGroup group, ComboPreferences prefs) { 307 if (params == null) return; 308 mOnScreenIndicators.updateSceneOnScreenIndicator(params.getSceneMode()); 309 mOnScreenIndicators.updateExposureOnScreenIndicator(params, 310 CameraSettings.readExposure(prefs)); 311 mOnScreenIndicators.updateFlashOnScreenIndicator(params.getFlashMode()); 312 int wbIndex = 2; 313 ListPreference pref = group.findPreference(CameraSettings.KEY_WHITE_BALANCE); 314 if (pref != null) { 315 wbIndex = pref.getCurrentIndex(); 316 } 317 mOnScreenIndicators.updateWBIndicator(wbIndex); 318 boolean location = RecordLocationPreference.get( 319 prefs, mActivity.getContentResolver()); 320 mOnScreenIndicators.updateLocationIndicator(location); 321 } 322 setCameraState(int state)323 public void setCameraState(int state) { 324 } 325 dispatchTouchEvent(MotionEvent m)326 public boolean dispatchTouchEvent(MotionEvent m) { 327 if (mGestures != null && mRenderOverlay != null) { 328 return mGestures.dispatchTouch(m); 329 } 330 return false; 331 } 332 onBackPressed()333 public boolean onBackPressed() { 334 if (mPieRenderer != null && mPieRenderer.showsItems()) { 335 mPieRenderer.hide(); 336 return true; 337 } 338 // In image capture mode, back button should: 339 // 1) if there is any popup, dismiss them, 2) otherwise, get out of 340 // image capture 341 if (mController.isImageCaptureIntent()) { 342 if (!removeTopLevelPopup()) { 343 // no popup to dismiss, cancel image capture 344 mController.onCaptureCancelled(); 345 } 346 return true; 347 } else if (!mController.isCameraIdle()) { 348 // ignore backs while we're taking a picture 349 return true; 350 } else { 351 return removeTopLevelPopup(); 352 } 353 } 354 onFullScreenChanged(boolean full)355 public void onFullScreenChanged(boolean full) { 356 if (mFaceView != null) { 357 mFaceView.setBlockDraw(!full); 358 } 359 if (mPopup != null) { 360 dismissPopup(full); 361 } 362 if (mGestures != null) { 363 mGestures.setEnabled(full); 364 } 365 if (mRenderOverlay != null) { 366 // this can not happen in capture mode 367 mRenderOverlay.setVisibility(full ? View.VISIBLE : View.GONE); 368 } 369 if (mPieRenderer != null) { 370 mPieRenderer.setBlockFocus(!full); 371 } 372 setShowMenu(full); 373 if (mBlocker != null) { 374 mBlocker.setVisibility(full ? View.VISIBLE : View.GONE); 375 } 376 if (!full && mCountDownView != null) mCountDownView.cancelCountDown(); 377 } 378 enablePreviewThumb(boolean enabled)379 public void enablePreviewThumb(boolean enabled) { 380 if (enabled) { 381 mGestures.addTouchReceiver(mPreviewThumb); 382 mPreviewThumb.setVisibility(View.VISIBLE); 383 } else { 384 mGestures.removeTouchReceiver(mPreviewThumb); 385 mPreviewThumb.setVisibility(View.GONE); 386 } 387 } 388 removeTopLevelPopup()389 public boolean removeTopLevelPopup() { 390 // Remove the top level popup or dialog box and return true if there's any 391 if (mPopup != null) { 392 dismissPopup(); 393 return true; 394 } 395 return false; 396 } 397 showPopup(AbstractSettingPopup popup)398 public void showPopup(AbstractSettingPopup popup) { 399 mActivity.hideUI(); 400 mBlocker.setVisibility(View.INVISIBLE); 401 setShowMenu(false); 402 mPopup = popup; 403 mPopup.setVisibility(View.VISIBLE); 404 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, 405 LayoutParams.WRAP_CONTENT); 406 lp.gravity = Gravity.CENTER; 407 ((FrameLayout) mRootView).addView(mPopup, lp); 408 mGestures.addTouchReceiver(mPopup); 409 } 410 dismissPopup()411 public void dismissPopup() { 412 dismissPopup(true); 413 } 414 dismissPopup(boolean fullScreen)415 private void dismissPopup(boolean fullScreen) { 416 if (fullScreen) { 417 mActivity.showUI(); 418 mBlocker.setVisibility(View.VISIBLE); 419 } 420 setShowMenu(fullScreen); 421 if (mPopup != null) { 422 mGestures.removeTouchReceiver(mPopup); 423 ((FrameLayout) mRootView).removeView(mPopup); 424 mPopup = null; 425 } 426 mMenu.popupDismissed(); 427 } 428 onShowSwitcherPopup()429 public void onShowSwitcherPopup() { 430 if (mPieRenderer != null && mPieRenderer.showsItems()) { 431 mPieRenderer.hide(); 432 } 433 } 434 setShowMenu(boolean show)435 private void setShowMenu(boolean show) { 436 if (mOnScreenIndicators != null) { 437 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE); 438 } 439 if (mMenuButton != null) { 440 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE); 441 } 442 } 443 collapseCameraControls()444 public boolean collapseCameraControls() { 445 // Remove all the popups/dialog boxes 446 boolean ret = false; 447 if (mPopup != null) { 448 dismissPopup(); 449 ret = true; 450 } 451 onShowSwitcherPopup(); 452 return ret; 453 } 454 showPostCaptureAlert()455 protected void showPostCaptureAlert() { 456 mOnScreenIndicators.setVisibility(View.GONE); 457 mMenuButton.setVisibility(View.GONE); 458 Util.fadeIn(mReviewDoneButton); 459 mShutterButton.setVisibility(View.INVISIBLE); 460 Util.fadeIn(mReviewRetakeButton); 461 pauseFaceDetection(); 462 } 463 hidePostCaptureAlert()464 protected void hidePostCaptureAlert() { 465 mOnScreenIndicators.setVisibility(View.VISIBLE); 466 mMenuButton.setVisibility(View.VISIBLE); 467 Util.fadeOut(mReviewDoneButton); 468 mShutterButton.setVisibility(View.VISIBLE); 469 Util.fadeOut(mReviewRetakeButton); 470 resumeFaceDetection(); 471 } 472 setDisplayOrientation(int orientation)473 public void setDisplayOrientation(int orientation) { 474 if (mFaceView != null) { 475 mFaceView.setDisplayOrientation(orientation); 476 } 477 } 478 479 // shutter button handling 480 isShutterPressed()481 public boolean isShutterPressed() { 482 return mShutterButton.isPressed(); 483 } 484 485 // focus handling 486 487 488 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener { 489 @Override onZoomValueChanged(int index)490 public void onZoomValueChanged(int index) { 491 int newZoom = mController.onZoomChanged(index); 492 if (mZoomRenderer != null) { 493 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom)); 494 } 495 } 496 497 @Override onZoomStart()498 public void onZoomStart() { 499 if (mPieRenderer != null) { 500 mPieRenderer.setBlockFocus(true); 501 } 502 } 503 504 @Override onZoomEnd()505 public void onZoomEnd() { 506 if (mPieRenderer != null) { 507 mPieRenderer.setBlockFocus(false); 508 } 509 } 510 } 511 512 @Override onPieOpened(int centerX, int centerY)513 public void onPieOpened(int centerX, int centerY) { 514 dismissPopup(); 515 mActivity.cancelActivityTouchHandling(); 516 mActivity.setSwipingEnabled(false); 517 if (mFaceView != null) { 518 mFaceView.setBlockDraw(true); 519 } 520 } 521 522 @Override onPieClosed()523 public void onPieClosed() { 524 mActivity.setSwipingEnabled(true); 525 if (mFaceView != null) { 526 mFaceView.setBlockDraw(false); 527 } 528 } 529 530 // Surface Listener 531 532 @Override surfaceChanged(SurfaceHolder holder, int format, int width, int height)533 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 534 Log.v(TAG, "surfaceChanged:" + holder + " width=" + width + ". height=" 535 + height); 536 } 537 538 @Override surfaceCreated(SurfaceHolder holder)539 public void surfaceCreated(SurfaceHolder holder) { 540 Log.v(TAG, "surfaceCreated: " + holder); 541 mSurfaceHolder = holder; 542 mController.onSurfaceCreated(holder); 543 } 544 545 @Override surfaceDestroyed(SurfaceHolder holder)546 public void surfaceDestroyed(SurfaceHolder holder) { 547 Log.v(TAG, "surfaceDestroyed: " + holder); 548 mSurfaceHolder = null; 549 mController.stopPreview(); 550 } 551 getSurfaceTexture()552 public Object getSurfaceTexture() { 553 return mSurfaceTexture; 554 } 555 setSurfaceTexture(Object st)556 public void setSurfaceTexture(Object st) { 557 mSurfaceTexture = st; 558 } 559 getSurfaceHolder()560 public SurfaceHolder getSurfaceHolder() { 561 return mSurfaceHolder; 562 } 563 isCountingDown()564 public boolean isCountingDown() { 565 return mCountDownView.isCountingDown(); 566 } 567 cancelCountDown()568 public void cancelCountDown() { 569 mCountDownView.cancelCountDown(); 570 } 571 startCountDown(int sec, boolean playSound)572 public void startCountDown(int sec, boolean playSound) { 573 mCountDownView.startCountDown(sec, playSound); 574 } 575 showPreferencesToast()576 public void showPreferencesToast() { 577 if (mNotSelectableToast == null) { 578 String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode); 579 mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT); 580 } 581 mNotSelectableToast.show(); 582 } 583 onPause()584 public void onPause() { 585 mCountDownView.cancelCountDown(); 586 // Close the camera now because other activities may need to use it. 587 mSurfaceTexture = null; 588 589 // Clear UI. 590 collapseCameraControls(); 591 if (mFaceView != null) mFaceView.clear(); 592 593 594 mRootView.removeOnLayoutChangeListener(mLayoutListener); 595 mPreviewWidth = 0; 596 mPreviewHeight = 0; 597 } 598 enableShutter(boolean enabled)599 public void enableShutter(boolean enabled) { 600 if (mShutterButton != null) { 601 mShutterButton.setEnabled(enabled); 602 } 603 } 604 pressShutterButton()605 public void pressShutterButton() { 606 if (mShutterButton.isInTouchMode()) { 607 mShutterButton.requestFocusFromTouch(); 608 } else { 609 mShutterButton.requestFocus(); 610 } 611 mShutterButton.setPressed(true); 612 } 613 614 // forward from preview gestures to controller 615 @Override onSingleTapUp(View view, int x, int y)616 public void onSingleTapUp(View view, int x, int y) { 617 mController.onSingleTapUp(view, x, y); 618 } 619 620 // focus UI implementation 621 getFocusIndicator()622 private FocusIndicator getFocusIndicator() { 623 return (mFaceView != null && mFaceView.faceExists()) ? mFaceView : mPieRenderer; 624 } 625 626 @Override hasFaces()627 public boolean hasFaces() { 628 return (mFaceView != null && mFaceView.faceExists()); 629 } 630 clearFaces()631 public void clearFaces() { 632 if (mFaceView != null) mFaceView.clear(); 633 } 634 635 @Override clearFocus()636 public void clearFocus() { 637 FocusIndicator indicator = getFocusIndicator(); 638 if (indicator != null) indicator.clear(); 639 } 640 641 @Override setFocusPosition(int x, int y)642 public void setFocusPosition(int x, int y) { 643 mPieRenderer.setFocus(x, y); 644 } 645 646 @Override onFocusStarted()647 public void onFocusStarted() { 648 getFocusIndicator().showStart(); 649 } 650 651 @Override onFocusSucceeded(boolean timeout)652 public void onFocusSucceeded(boolean timeout) { 653 getFocusIndicator().showSuccess(timeout); 654 } 655 656 @Override onFocusFailed(boolean timeout)657 public void onFocusFailed(boolean timeout) { 658 getFocusIndicator().showFail(timeout); 659 } 660 661 @Override pauseFaceDetection()662 public void pauseFaceDetection() { 663 if (mFaceView != null) mFaceView.pause(); 664 } 665 666 @Override resumeFaceDetection()667 public void resumeFaceDetection() { 668 if (mFaceView != null) mFaceView.resume(); 669 } 670 onStartFaceDetection(int orientation, boolean mirror)671 public void onStartFaceDetection(int orientation, boolean mirror) { 672 mFaceView.clear(); 673 mFaceView.setVisibility(View.VISIBLE); 674 mFaceView.setDisplayOrientation(orientation); 675 mFaceView.setMirror(mirror); 676 mFaceView.resume(); 677 } 678 679 @Override onFaceDetection(Face[] faces, android.hardware.Camera camera)680 public void onFaceDetection(Face[] faces, android.hardware.Camera camera) { 681 mFaceView.setFaces(faces); 682 } 683 684 @Override onSwipe(int direction)685 public void onSwipe(int direction) { 686 if (direction == PreviewGestures.DIR_UP) { 687 openMenu(); 688 } 689 } 690 691 } 692