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