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 package com.android.cts.verifier.camera.fov; 18 19 import android.app.Activity; 20 import android.app.AlertDialog; 21 import android.app.Dialog; 22 import android.content.Context; 23 import android.content.DialogInterface; 24 import android.content.Intent; 25 import android.content.res.Configuration; 26 import android.graphics.Color; 27 import android.graphics.Matrix; 28 import android.graphics.SurfaceTexture; 29 import android.hardware.Camera; 30 import android.hardware.Camera.PictureCallback; 31 import android.hardware.Camera.ShutterCallback; 32 import android.hardware.camera2.CameraAccessException; 33 import android.hardware.camera2.CameraCharacteristics; 34 import android.hardware.camera2.CameraManager; 35 import android.os.Bundle; 36 import android.os.PowerManager; 37 import android.os.PowerManager.WakeLock; 38 import android.util.Log; 39 import android.view.Surface; 40 import android.view.TextureView; 41 import android.view.View; 42 import android.view.View.OnClickListener; 43 import android.widget.AdapterView; 44 import android.widget.AdapterView.OnItemSelectedListener; 45 import android.widget.ArrayAdapter; 46 import android.widget.Button; 47 import android.widget.Spinner; 48 import android.widget.TextView; 49 import android.widget.Toast; 50 51 import com.android.cts.verifier.R; 52 import com.android.cts.verifier.TestResult; 53 54 import java.io.File; 55 import java.io.FileOutputStream; 56 import java.io.IOException; 57 import java.util.ArrayList; 58 import java.util.List; 59 60 /** 61 * An activity for showing the camera preview and taking a picture. 62 */ 63 public class PhotoCaptureActivity extends Activity 64 implements PictureCallback, TextureView.SurfaceTextureListener { 65 private static final String TAG = PhotoCaptureActivity.class.getSimpleName(); 66 private static final int FOV_REQUEST_CODE = 1006; 67 private static final String PICTURE_FILENAME = "photo.jpg"; 68 private static float mReportedFovDegrees = 0; 69 private float mReportedFovPrePictureTaken = -1; 70 71 private TextureView mPreviewView; 72 private SurfaceTexture mPreviewTexture; 73 private int mPreviewTexWidth; 74 private int mPreviewTexHeight; 75 76 private Spinner mResolutionSpinner; 77 private List<SelectableResolution> mSupportedResolutions; 78 private ArrayAdapter<SelectableResolution> mAdapter; 79 80 private SelectableResolution mSelectedResolution; 81 private Camera mCamera; 82 private boolean mCameraInitialized = false; 83 private boolean mPreviewActive = false; 84 private boolean mTakingPicture = false; 85 private int mResolutionSpinnerIndex = -1; 86 private WakeLock mWakeLock; 87 private long shutterStartTime; 88 private int mPreviewOrientation; 89 private int mJpegOrientation; 90 91 private ArrayList<Integer> mPreviewSizeCamerasToProcess = new ArrayList<Integer>(); 92 93 private Dialog mActiveDialog; 94 95 /** 96 * Selected preview size per camera. If null, preview size should be 97 * automatically detected. 98 */ 99 private Size[] mPreviewSizes = null; 100 getPictureFile(Context context)101 public static File getPictureFile(Context context) { 102 return new File(context.getExternalCacheDir(), PICTURE_FILENAME); 103 } 104 getReportedFovDegrees()105 public static float getReportedFovDegrees() { 106 return mReportedFovDegrees; 107 } 108 109 @Override onCreate(Bundle savedInstanceState)110 protected void onCreate(Bundle savedInstanceState) { 111 super.onCreate(savedInstanceState); 112 setContentView(R.layout.camera_fov_calibration_photo_capture); 113 114 int cameraToBeTested = 0; 115 for (int cameraId = 0; cameraId < Camera.getNumberOfCameras(); ++cameraId) { 116 if (!isExternalCamera(cameraId)) { 117 cameraToBeTested++; 118 } 119 } 120 121 mPreviewView = (TextureView) findViewById(R.id.camera_fov_camera_preview); 122 mPreviewView.setSurfaceTextureListener(this); 123 124 TextView textView = (TextView) findViewById(R.id.camera_fov_tap_to_take_photo); 125 textView.setTextColor(Color.WHITE); 126 127 Button setupButton = (Button) findViewById(R.id.camera_fov_settings_button); 128 setupButton.setOnClickListener(new OnClickListener() { 129 130 @Override 131 public void onClick(View v) { 132 startActivity(new Intent( 133 PhotoCaptureActivity.this, CalibrationPreferenceActivity.class)); 134 } 135 }); 136 137 Button changePreviewSizeButton = (Button) findViewById( 138 R.id.camera_fov_change_preview_size_button); 139 changePreviewSizeButton.setOnClickListener(new OnClickListener() { 140 @Override 141 public void onClick(View v) { 142 // Stop camera until preview sizes have been obtained. 143 if (mCamera != null) { 144 mCamera.stopPreview(); 145 mCamera.release(); 146 mCamera = null; 147 } 148 149 mPreviewSizeCamerasToProcess.clear(); 150 mPreviewSizes = new Size[Camera.getNumberOfCameras()]; 151 for (int cameraId = 0; cameraId < Camera.getNumberOfCameras(); ++cameraId) { 152 if (!isExternalCamera(cameraId)) { 153 mPreviewSizeCamerasToProcess.add(cameraId); 154 } 155 } 156 showNextDialogToChoosePreviewSize(); 157 } 158 }); 159 160 View previewView = findViewById(R.id.camera_fov_preview_overlay); 161 previewView.setOnClickListener(new OnClickListener() { 162 @Override 163 public void onClick(View v) { 164 if (mPreviewActive && !mTakingPicture) { 165 mTakingPicture = true; 166 shutterStartTime = System.currentTimeMillis(); 167 168 mCamera.takePicture(new ShutterCallback() { 169 @Override 170 public void onShutter() { 171 long dT = System.currentTimeMillis() - shutterStartTime; 172 Log.d("CTS", "Shutter Lag: " + dT); 173 } 174 }, null, PhotoCaptureActivity.this); 175 } 176 } 177 }); 178 179 mResolutionSpinner = (Spinner) findViewById(R.id.camera_fov_resolution_selector); 180 mResolutionSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { 181 @Override 182 public void onItemSelected( 183 AdapterView<?> parent, View view, int position, long id) { 184 if (mSupportedResolutions != null) { 185 SelectableResolution resolution = mSupportedResolutions.get(position); 186 switchToCamera(resolution, false); 187 188 // It should be guaranteed that the FOV is correctly updated after 189 // setParameters(). 190 mReportedFovPrePictureTaken = getCameraFov(resolution.cameraId); 191 192 mResolutionSpinnerIndex = position; 193 startPreview(); 194 } 195 } 196 197 @Override 198 public void onNothingSelected(AdapterView<?> arg0) {} 199 }); 200 201 if (cameraToBeTested == 0) { 202 Log.i(TAG, "No cameras needs to be tested. Setting test pass."); 203 Toast.makeText(this, "No cameras needs to be tested. Test pass.", 204 Toast.LENGTH_LONG).show(); 205 206 TestResult.setPassedResult(this, getClass().getName(), 207 "All cameras are external, test skipped!"); 208 finish(); 209 } 210 } 211 212 @Override onResume()213 protected void onResume() { 214 super.onResume(); 215 // Keep the device from going to sleep. 216 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 217 mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, TAG); 218 mWakeLock.acquire(); 219 220 if (mSupportedResolutions == null) { 221 mSupportedResolutions = new ArrayList<SelectableResolution>(); 222 int numCameras = Camera.getNumberOfCameras(); 223 for (int cameraId = 0; cameraId < numCameras; ++cameraId) { 224 if (isExternalCamera(cameraId)) { 225 continue; 226 } 227 228 Camera camera = Camera.open(cameraId); 229 230 // Get the supported picture sizes and fill the spinner. 231 List<Camera.Size> supportedSizes = 232 camera.getParameters().getSupportedPictureSizes(); 233 for (Camera.Size size : supportedSizes) { 234 mSupportedResolutions.add( 235 new SelectableResolution(cameraId, size.width, size.height)); 236 } 237 camera.release(); 238 } 239 } 240 241 // Find the first untested entry. 242 for (mResolutionSpinnerIndex = 0; 243 mResolutionSpinnerIndex < mSupportedResolutions.size(); 244 mResolutionSpinnerIndex++) { 245 if (!mSupportedResolutions.get(mResolutionSpinnerIndex).tested) { 246 break; 247 } 248 } 249 250 mAdapter = new ArrayAdapter<SelectableResolution>( 251 this, android.R.layout.simple_spinner_dropdown_item, 252 mSupportedResolutions); 253 mResolutionSpinner.setAdapter(mAdapter); 254 255 mResolutionSpinner.setSelection(mResolutionSpinnerIndex); 256 setResult(RESULT_CANCELED); 257 } 258 259 @Override onPause()260 public void onPause() { 261 if (mCamera != null) { 262 if (mPreviewActive) { 263 mCamera.stopPreview(); 264 } 265 266 mCamera.release(); 267 mCamera = null; 268 } 269 mPreviewActive = false; 270 mWakeLock.release(); 271 super.onPause(); 272 } 273 274 @Override onConfigurationChanged(Configuration newConfig)275 public void onConfigurationChanged(Configuration newConfig) { 276 super.onConfigurationChanged(newConfig); 277 this.recreate(); 278 } 279 280 @Override onPictureTaken(byte[] data, Camera camera)281 public void onPictureTaken(byte[] data, Camera camera) { 282 File pictureFile = getPictureFile(this); 283 284 mReportedFovDegrees = getCameraFov(mSelectedResolution.cameraId); 285 286 // Show error if FOV does not match the value reported before takePicture(). 287 if (mReportedFovPrePictureTaken != mReportedFovDegrees) { 288 mSupportedResolutions.get(mResolutionSpinnerIndex).tested = true; 289 mSupportedResolutions.get(mResolutionSpinnerIndex).passed = false; 290 291 AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this); 292 dialogBuilder.setTitle(R.string.camera_fov_reported_fov_problem); 293 dialogBuilder.setNeutralButton( 294 android.R.string.ok, new DialogInterface.OnClickListener() { 295 @Override 296 public void onClick(DialogInterface dialog, int which) { 297 if (mActiveDialog != null) { 298 mActiveDialog.dismiss(); 299 mActiveDialog = null; 300 initializeCamera(); 301 } 302 } 303 }); 304 305 String message = getResources().getString(R.string.camera_fov_reported_fov_problem_message); 306 dialogBuilder.setMessage(String.format(message, mReportedFovPrePictureTaken, mReportedFovDegrees)); 307 mActiveDialog = dialogBuilder.show(); 308 mTakingPicture = false; 309 return; 310 } 311 312 try { 313 FileOutputStream fos = new FileOutputStream(pictureFile); 314 fos.write(data); 315 fos.close(); 316 Log.d(TAG, "File saved to " + pictureFile.getAbsolutePath()); 317 318 // Start activity which will use the taken picture to determine the 319 // FOV. 320 startActivityForResult(new Intent(this, DetermineFovActivity.class), 321 FOV_REQUEST_CODE + mResolutionSpinnerIndex, null); 322 } catch (IOException e) { 323 Log.e(TAG, "Could not save picture file.", e); 324 Toast.makeText(this, "Could not save picture file: " + e.getMessage(), 325 Toast.LENGTH_LONG).show(); 326 } 327 mTakingPicture = false; 328 } 329 330 @Override onActivityResult(int requestCode, int resultCode, Intent data)331 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 332 if (resultCode != RESULT_OK) { 333 return; 334 } 335 int testIndex = requestCode - FOV_REQUEST_CODE; 336 SelectableResolution res = mSupportedResolutions.get(testIndex); 337 res.tested = true; 338 float reportedFOV = CtsTestHelper.getReportedFOV(data); 339 float measuredFOV = CtsTestHelper.getMeasuredFOV(data); 340 res.measuredFOV = measuredFOV; 341 if (CtsTestHelper.isResultPassed(reportedFOV, measuredFOV)) { 342 res.passed = true; 343 } 344 345 boolean allTested = true; 346 for (int i = 0; i < mSupportedResolutions.size(); i++) { 347 if (!mSupportedResolutions.get(i).tested) { 348 allTested = false; 349 break; 350 } 351 } 352 if (!allTested) { 353 mAdapter.notifyDataSetChanged(); 354 return; 355 } 356 357 boolean allPassed = true; 358 for (int i = 0; i < mSupportedResolutions.size(); i++) { 359 if (!mSupportedResolutions.get(i).passed) { 360 allPassed = false; 361 break; 362 } 363 } 364 if (allPassed) { 365 TestResult.setPassedResult(this, getClass().getName(), 366 CtsTestHelper.getTestDetails(mSupportedResolutions)); 367 } else { 368 TestResult.setFailedResult(this, getClass().getName(), 369 CtsTestHelper.getTestDetails(mSupportedResolutions)); 370 } 371 finish(); 372 } 373 374 @Override onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)375 public void onSurfaceTextureAvailable(SurfaceTexture surface, 376 int width, int height) { 377 mPreviewTexture = surface; 378 mPreviewTexWidth = width; 379 mPreviewTexHeight = height; 380 initializeCamera(); 381 } 382 383 @Override onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)384 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 385 // Ignored, Camera does all the work for us 386 } 387 388 @Override onSurfaceTextureDestroyed(SurfaceTexture surface)389 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 390 return true; 391 } 392 393 @Override onSurfaceTextureUpdated(SurfaceTexture surface)394 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 395 // Invoked every time there's a new Camera preview frame 396 } 397 showNextDialogToChoosePreviewSize()398 private void showNextDialogToChoosePreviewSize() { 399 final int cameraId = mPreviewSizeCamerasToProcess.remove(0); 400 401 Camera camera = Camera.open(cameraId); 402 final List<Camera.Size> sizes = camera.getParameters() 403 .getSupportedPreviewSizes(); 404 String[] choices = new String[sizes.size()]; 405 for (int i = 0; i < sizes.size(); ++i) { 406 Camera.Size size = sizes.get(i); 407 choices[i] = size.width + " x " + size.height; 408 } 409 410 final AlertDialog.Builder builder = new AlertDialog.Builder(this); 411 String dialogTitle = String.format( 412 getResources().getString(R.string.camera_fov_choose_preview_size_for_camera), 413 cameraId); 414 builder.setTitle( 415 dialogTitle). 416 setOnCancelListener(new DialogInterface.OnCancelListener() { 417 @Override 418 public void onCancel(DialogInterface arg0) { 419 // User cancelled preview size selection. 420 mPreviewSizes = null; 421 switchToCamera(mSelectedResolution, true); 422 } 423 }). 424 setSingleChoiceItems(choices, 0, new DialogInterface.OnClickListener() { 425 @Override 426 public void onClick(DialogInterface dialog, int which) { 427 Camera.Size size = sizes.get(which); 428 mPreviewSizes[cameraId] = new Size( 429 size.width, size.height); 430 dialog.dismiss(); 431 432 if (mPreviewSizeCamerasToProcess.isEmpty()) { 433 // We're done, re-initialize camera. 434 switchToCamera(mSelectedResolution, true); 435 } else { 436 // Process other cameras. 437 showNextDialogToChoosePreviewSize(); 438 } 439 } 440 }).create().show(); 441 camera.release(); 442 } 443 initializeCamera()444 private void initializeCamera() { 445 initializeCamera(true); 446 } 447 setPreviewTransform(Size previewSize)448 private void setPreviewTransform(Size previewSize) { 449 int sensorRotation = mPreviewOrientation; 450 float selectedPreviewAspectRatio; 451 if (sensorRotation == 0 || sensorRotation == 180) { 452 selectedPreviewAspectRatio = (float) previewSize.width 453 / (float) previewSize.height; 454 } else { 455 selectedPreviewAspectRatio = (float) previewSize.height 456 / (float) previewSize.width; 457 } 458 459 Matrix transform = new Matrix(); 460 float viewAspectRatio = (float) mPreviewView.getMeasuredWidth() 461 / (float) mPreviewView.getMeasuredHeight(); 462 float scaleX = 1.0f, scaleY = 1.0f; 463 float translateX = 0, translateY = 0; 464 if (selectedPreviewAspectRatio > viewAspectRatio) { 465 scaleY = viewAspectRatio / selectedPreviewAspectRatio; 466 translateY = (float) mPreviewView.getMeasuredHeight() / 2 467 - (float) mPreviewView.getMeasuredHeight() * scaleY / 2; 468 } else { 469 scaleX = selectedPreviewAspectRatio / viewAspectRatio; 470 translateX = (float) mPreviewView.getMeasuredWidth() / 2 471 - (float) mPreviewView.getMeasuredWidth() * scaleX / 2; 472 } 473 transform.postScale(scaleX, scaleY); 474 transform.postTranslate(translateX, translateY); 475 mPreviewView.setTransform(transform); 476 } 477 initializeCamera(boolean startPreviewAfterInit)478 private void initializeCamera(boolean startPreviewAfterInit) { 479 if (mCamera == null || mPreviewTexture == null) { 480 return; 481 } 482 483 try { 484 mCamera.setPreviewTexture(mPreviewTexture); 485 } catch (Throwable t) { 486 Log.e(TAG, "Could not set preview texture", t); 487 Toast.makeText(this, t.getMessage(), Toast.LENGTH_LONG).show(); 488 return; 489 } 490 491 calculateOrientations(this, mSelectedResolution.cameraId, mCamera); 492 Camera.Parameters params = setCameraParams(mCamera); 493 494 // Either use chosen preview size for current camera or automatically 495 // choose preview size based on view dimensions. 496 Size selectedPreviewSize = null; 497 if (mPreviewSizes != null) { 498 selectedPreviewSize = mPreviewSizes[mSelectedResolution.cameraId]; 499 } else { 500 if (mPreviewOrientation == 0 || mPreviewOrientation == 180) { 501 selectedPreviewSize = getBestPreviewSize( 502 mPreviewTexWidth, mPreviewTexHeight, params); 503 } else { 504 selectedPreviewSize = getBestPreviewSize( 505 mPreviewTexHeight, mPreviewTexWidth, params); 506 } 507 } 508 509 if (selectedPreviewSize != null) { 510 params.setPreviewSize(selectedPreviewSize.width, selectedPreviewSize.height); 511 mCamera.setParameters(params); 512 setPreviewTransform(selectedPreviewSize); 513 mCameraInitialized = true; 514 } 515 516 if (startPreviewAfterInit) { 517 if (selectedPreviewSize == null) { 518 Log.w(TAG, "Preview started without setting preview size"); 519 } 520 startPreview(); 521 } 522 } 523 startPreview()524 private void startPreview() { 525 if (mCameraInitialized && mCamera != null) { 526 mCamera.setDisplayOrientation(mPreviewOrientation); 527 mCamera.startPreview(); 528 mPreviewActive = true; 529 } 530 } 531 switchToCamera(SelectableResolution resolution, boolean startPreview)532 private void switchToCamera(SelectableResolution resolution, boolean startPreview) { 533 if (mCamera != null) { 534 mCamera.stopPreview(); 535 mCamera.release(); 536 } 537 538 mSelectedResolution = resolution; 539 mCamera = Camera.open(mSelectedResolution.cameraId); 540 541 initializeCamera(startPreview); 542 } 543 544 /** 545 * Get the best supported focus mode. 546 * 547 * @param camera - Android camera object. 548 * @return the best supported focus mode. 549 */ getFocusMode(Camera camera)550 private static String getFocusMode(Camera camera) { 551 List<String> modes = camera.getParameters().getSupportedFocusModes(); 552 if (modes != null) { 553 if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) { 554 Log.v(TAG, "Using Focus mode infinity"); 555 return Camera.Parameters.FOCUS_MODE_INFINITY; 556 } 557 if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) { 558 Log.v(TAG, "Using Focus mode fixed"); 559 return Camera.Parameters.FOCUS_MODE_FIXED; 560 } 561 } 562 Log.v(TAG, "Using Focus mode auto."); 563 return Camera.Parameters.FOCUS_MODE_AUTO; 564 } 565 566 /** 567 * Set the common camera parameters on the given camera and returns the 568 * parameter object for further modification, if needed. 569 */ setCameraParams(Camera camera)570 private Camera.Parameters setCameraParams(Camera camera) { 571 // The picture size is taken and set from the spinner selection 572 // callback. 573 Camera.Parameters params = camera.getParameters(); 574 params.setJpegThumbnailSize(0, 0); 575 params.setJpegQuality(100); 576 params.setRotation(mJpegOrientation); 577 params.setFocusMode(getFocusMode(camera)); 578 params.setZoom(0); 579 params.setPictureSize(mSelectedResolution.width, mSelectedResolution.height); 580 return params; 581 } 582 getBestPreviewSize( int width, int height, Camera.Parameters parameters)583 private Size getBestPreviewSize( 584 int width, int height, Camera.Parameters parameters) { 585 Size result = null; 586 587 for (Camera.Size size : parameters.getSupportedPreviewSizes()) { 588 if (size.width <= width && size.height <= height) { 589 if (result == null) { 590 result = new Size(size.width, size.height); 591 } else { 592 int resultArea = result.width * result.height; 593 int newArea = size.width * size.height; 594 595 if (newArea > resultArea) { 596 result = new Size(size.width, size.height); 597 } 598 } 599 } 600 } 601 return result; 602 } 603 getDisplayRotation()604 private int getDisplayRotation() { 605 int displayRotation = getDisplay().getRotation(); 606 int displayRotationDegrees = 0; 607 switch (displayRotation) { 608 case Surface.ROTATION_0: displayRotationDegrees = 0; break; 609 case Surface.ROTATION_90: displayRotationDegrees = 90; break; 610 case Surface.ROTATION_180: displayRotationDegrees = 180; break; 611 case Surface.ROTATION_270: displayRotationDegrees = 270; break; 612 } 613 return displayRotationDegrees; 614 } 615 calculateOrientations(Activity activity, int cameraId, android.hardware.Camera camera)616 private void calculateOrientations(Activity activity, 617 int cameraId, android.hardware.Camera camera) { 618 android.hardware.Camera.CameraInfo info = 619 new android.hardware.Camera.CameraInfo(); 620 android.hardware.Camera.getCameraInfo(cameraId, info); 621 622 int degrees = getDisplayRotation(); 623 if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 624 mJpegOrientation = (info.orientation + degrees) % 360; 625 mPreviewOrientation = (360 - mJpegOrientation) % 360; // compensate the mirror 626 } else { // back-facing 627 mJpegOrientation = (info.orientation - degrees + 360) % 360; 628 mPreviewOrientation = mJpegOrientation; 629 } 630 } 631 isExternalCamera(int cameraId)632 private boolean isExternalCamera(int cameraId) { 633 CameraManager manager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE); 634 try { 635 String cameraIdStr = manager.getCameraIdList()[cameraId]; 636 CameraCharacteristics characteristics = 637 manager.getCameraCharacteristics(cameraIdStr); 638 639 if (characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == 640 CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL) { 641 // External camera doesn't support FOV informations 642 return true; 643 } 644 } catch (CameraAccessException e) { 645 Toast.makeText(this, "Could not access camera " + cameraId + 646 ": " + e.getMessage(), Toast.LENGTH_LONG).show(); 647 } 648 return false; 649 } 650 getCameraFov(int cameraId)651 private float getCameraFov(int cameraId) { 652 if (mPreviewOrientation == 0 || mPreviewOrientation == 180) { 653 return mCamera.getParameters().getHorizontalViewAngle(); 654 } else { 655 return mCamera.getParameters().getVerticalViewAngle(); 656 } 657 } 658 } 659