1 /* 2 * Copyright (C) 2016 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 package com.android.devcamera; 17 18 import android.Manifest; 19 import android.content.Intent; 20 import android.content.pm.PackageManager; 21 import android.graphics.Color; 22 import android.hardware.camera2.CameraCharacteristics; 23 import android.hardware.camera2.CaptureResult; 24 import android.hardware.SensorManager; 25 import android.os.Bundle; 26 import android.app.Activity; 27 import android.os.Handler; 28 import android.os.HandlerThread; 29 import android.os.SystemClock; 30 import android.util.DisplayMetrics; 31 import android.util.Log; 32 import android.util.Size; 33 import android.view.Gravity; 34 import android.view.SurfaceHolder; 35 import android.view.SurfaceView; 36 import android.view.View; 37 import android.view.WindowManager; 38 import android.widget.Button; 39 import android.widget.FrameLayout; 40 import android.widget.LinearLayout; 41 import android.widget.TextView; 42 import android.widget.Toast; 43 import android.widget.ToggleButton; 44 45 46 /** 47 * A minimum camera app. 48 * To keep it simple: portrait mode only. 49 */ 50 public class DevCameraActivity extends Activity implements CameraInterface.MyCameraCallback, SurfaceHolder.Callback { 51 private static final String TAG = "DevCamera_UI"; 52 53 private static final boolean LOG_FRAME_DATA = false; 54 private static final int AF_TRIGGER_HOLD_MILLIS = 4000; 55 private static final boolean STARTUP_FULL_YUV_ON = true; 56 private static final boolean START_WITH_FRONT_CAMERA = false; 57 58 private static final int PERMISSIONS_REQUEST_CAMERA = 1; 59 private boolean mPermissionCheckActive = false; 60 61 private SurfaceView mPreviewView; 62 private SurfaceHolder mPreviewHolder; 63 private PreviewOverlay mPreviewOverlay; 64 private FrameLayout mPreviewFrame; 65 66 private TextView mLabel1; 67 private TextView mLabel2; 68 private ToggleButton mToggleFrontCam; // Use front camera 69 private ToggleButton mToggleYuvFull; // full YUV 70 private ToggleButton mToggleYuvVga; // VGA YUV 71 private ToggleButton mToggleRaw; // raw10 72 private Button mButtonNoiseMode; // Noise reduction mode 73 private Button mButtonEdgeModeReprocess; // Edge mode 74 private Button mButtonNoiseModeReprocess; // Noise reduction mode for reprocessing 75 private Button mButtonEdgeMode; // Edge mode for reprocessing 76 private ToggleButton mToggleFace; // Face detection 77 private ToggleButton mToggleShow3A; // 3A info 78 private ToggleButton mToggleGyro; // Gyro 79 private ToggleButton mToggleBurstJpeg; 80 private ToggleButton mToggleSaveSdCard; 81 private LinearLayout mReprocessingGroup; 82 private Handler mMainHandler; 83 private CameraInterface mCamera; 84 85 // Used for saving JPEGs. 86 private HandlerThread mUtilityThread; 87 private Handler mUtilityHandler; 88 89 // send null for initialization 90 View.OnClickListener mTransferUiStateToCameraState = new View.OnClickListener() { 91 @Override 92 public void onClick(View view) { 93 // set capture flow. 94 if (view == mToggleYuvFull || view == mToggleYuvVga || view == mToggleRaw || 95 view == mButtonNoiseMode || view == mButtonEdgeMode || view == mToggleFace || view == null) 96 mCamera.setCaptureFlow( 97 mToggleYuvFull.isChecked(), 98 mToggleYuvVga.isChecked(), 99 mToggleRaw.isChecked(), 100 view == mButtonNoiseMode, /* cycle noise reduction mode */ 101 view == mButtonEdgeMode, /* cycle edge mode */ 102 mToggleFace.isChecked() 103 ); 104 // set reprocessing flow. 105 if (view == mButtonNoiseModeReprocess || view == mButtonEdgeModeReprocess || view == null) { 106 mCamera.setReprocessingFlow(view == mButtonNoiseModeReprocess, view == mButtonEdgeModeReprocess); 107 } 108 // set visibility of cluster of reprocessing controls. 109 int reprocessingViz = mToggleYuvFull.isChecked() && mCamera.isReprocessingAvailable() ? View.VISIBLE : View.GONE; 110 mReprocessingGroup.setVisibility(reprocessingViz); 111 112 // if just turned off YUV1 stream, end burst. 113 if (view == mToggleYuvFull && !mToggleYuvFull.isChecked()) { 114 mToggleBurstJpeg.setChecked(false); 115 mCamera.setBurst(false); 116 } 117 118 if (view == mToggleBurstJpeg) { 119 mCamera.setBurst(mToggleBurstJpeg.isChecked()); 120 } 121 122 if (view == mToggleShow3A || view == null) { 123 mPreviewOverlay.show3AInfo(mToggleShow3A.isChecked()); 124 } 125 if (view == mToggleGyro || view == null) { 126 if (mToggleGyro.isChecked()) { 127 startGyroDisplay(); 128 } else { 129 stopGyroDisplay(); 130 } 131 } 132 } 133 }; 134 135 @Override 136 protected void onCreate(Bundle savedInstanceState) { 137 Log.v(TAG, "onCreate"); 138 CameraTimer.t0 = SystemClock.elapsedRealtime(); 139 140 if (checkPermissions()) { 141 // Go speed racer. 142 openCamera(START_WITH_FRONT_CAMERA); 143 } 144 145 // Initialize UI. 146 setContentView(R.layout.activity_main); 147 mLabel1 = (TextView) findViewById(R.id.label1); 148 mLabel1.setText("Snappy initializing."); 149 mLabel2 = (TextView) findViewById(R.id.label2); 150 mLabel2.setText(" ..."); 151 Button mAfTriggerButton = (Button) findViewById(R.id.af_trigger); 152 mToggleFrontCam = (ToggleButton) findViewById(R.id.toggle_front_cam); 153 mToggleFrontCam.setChecked(START_WITH_FRONT_CAMERA); 154 mToggleYuvFull = (ToggleButton) findViewById(R.id.toggle_yuv_full); 155 mToggleYuvVga = (ToggleButton) findViewById(R.id.toggle_yuv_vga); 156 mToggleRaw = (ToggleButton) findViewById(R.id.toggle_raw); 157 mButtonNoiseMode = (Button) findViewById(R.id.button_noise); 158 mButtonEdgeMode = (Button) findViewById(R.id.button_edge); 159 mButtonNoiseModeReprocess = (Button) findViewById(R.id.button_noise_reprocess); 160 mButtonEdgeModeReprocess = (Button) findViewById(R.id.button_edge_reprocess); 161 162 mToggleFace = (ToggleButton) findViewById(R.id.toggle_face); 163 mToggleShow3A = (ToggleButton) findViewById(R.id.toggle_show_3A); 164 mToggleGyro = (ToggleButton) findViewById(R.id.toggle_show_gyro); 165 Button mGetJpegButton = (Button) findViewById(R.id.jpeg_capture); 166 Button mGalleryButton = (Button) findViewById(R.id.gallery); 167 168 mToggleBurstJpeg = (ToggleButton) findViewById(R.id.toggle_burst_jpeg); 169 mToggleSaveSdCard = (ToggleButton) findViewById(R.id.toggle_save_sdcard); 170 mReprocessingGroup = (LinearLayout) findViewById(R.id.reprocessing_controls); 171 mPreviewView = (SurfaceView) findViewById(R.id.preview_view); 172 mPreviewHolder = mPreviewView.getHolder(); 173 mPreviewHolder.addCallback(this); 174 mPreviewOverlay = (PreviewOverlay) findViewById(R.id.preview_overlay_view); 175 mPreviewFrame = (FrameLayout) findViewById(R.id.preview_frame); 176 177 // Set UI listeners. 178 mAfTriggerButton.setOnClickListener(new View.OnClickListener() { 179 @Override 180 public void onClick(View view) { 181 doAFScan(); 182 } 183 }); 184 mGetJpegButton.setOnClickListener(new View.OnClickListener() { 185 @Override 186 public void onClick(View view) { 187 hitCaptureButton(); 188 } 189 }); 190 mGalleryButton.setOnClickListener(new View.OnClickListener() { 191 @Override 192 public void onClick(View view) { 193 launchPhotosViewer(); 194 } 195 }); 196 mToggleFrontCam.setOnClickListener(new View.OnClickListener() { 197 @Override 198 public void onClick(View view) { 199 Log.v(TAG, "switchCamera()"); 200 CameraTimer.t0 = SystemClock.elapsedRealtime(); 201 // ToggleButton isChecked state will determine which camera is started. 202 openCamera(mToggleFrontCam.isChecked()); 203 startCamera(); 204 } 205 }); 206 mToggleYuvFull.setOnClickListener(mTransferUiStateToCameraState); 207 mToggleYuvVga.setOnClickListener(mTransferUiStateToCameraState); 208 mToggleRaw.setOnClickListener(mTransferUiStateToCameraState); 209 mButtonNoiseMode.setOnClickListener(mTransferUiStateToCameraState); 210 mButtonEdgeMode.setOnClickListener(mTransferUiStateToCameraState); 211 mButtonNoiseModeReprocess.setOnClickListener(mTransferUiStateToCameraState); 212 mButtonEdgeModeReprocess.setOnClickListener(mTransferUiStateToCameraState); 213 mToggleFace.setOnClickListener(mTransferUiStateToCameraState); 214 mToggleShow3A.setOnClickListener(mTransferUiStateToCameraState); 215 mToggleGyro.setOnClickListener(mTransferUiStateToCameraState); 216 mToggleBurstJpeg.setOnClickListener(mTransferUiStateToCameraState); 217 mToggleSaveSdCard.setOnClickListener(mTransferUiStateToCameraState); 218 mToggleSaveSdCard.setChecked(true); 219 220 mMainHandler = new Handler(this.getApplicationContext().getMainLooper()); 221 222 // General utility thread for e.g. saving JPEGs. 223 mUtilityThread = new HandlerThread("UtilityThread"); 224 mUtilityThread.start(); 225 mUtilityHandler = new Handler(mUtilityThread.getLooper()); 226 227 // --- PRINT REPORT --- 228 //CameraDeviceReport.printReport(this, false); 229 super.onCreate(savedInstanceState); 230 } 231 232 // Open camera. No UI required. 233 private void openCamera(boolean frontCamera) { 234 // Close previous camera if required. 235 if (mCamera != null) { 236 mCamera.closeCamera(); 237 } 238 // --- SET UP CAMERA --- 239 mCamera = new Api2Camera(this, frontCamera); 240 mCamera.setCallback(this); 241 mCamera.openCamera(); 242 } 243 244 // Initialize camera related UI and start camera; call openCamera first. 245 private void startCamera() { 246 // --- SET UP USER INTERFACE --- 247 mToggleYuvFull.setChecked(STARTUP_FULL_YUV_ON); 248 mToggleFace.setChecked(true); 249 mToggleRaw.setVisibility(mCamera.isRawAvailable() ? View.VISIBLE : View.GONE); 250 mToggleShow3A.setChecked(true); 251 mTransferUiStateToCameraState.onClick(null); 252 253 // --- SET UP PREVIEW AND OPEN CAMERA --- 254 255 if (mPreviewSurfaceValid) { 256 mCamera.startPreview(mPreviewHolder.getSurface()); 257 } else { 258 // Note that preview is rotated 90 degrees from camera. We just hard code this now. 259 Size previewSize = mCamera.getPreviewSize(); 260 // Render in top 12 x 9 of 16 x 9 display. 261 int renderHeight = 3 * displayHeight() / 4; 262 int renderWidth = renderHeight * previewSize.getHeight() / previewSize.getWidth(); 263 int renderPad = (displayWidth() - renderWidth) / 2; 264 265 mPreviewFrame.setPadding(renderPad, 0, 0, 0); 266 mPreviewFrame.setLayoutParams(new LinearLayout.LayoutParams(renderWidth + renderPad, renderHeight)); 267 // setFixedSize() will trigger surfaceChanged() callback below, which will start preview. 268 mPreviewHolder.setFixedSize(previewSize.getHeight(), previewSize.getWidth()); 269 } 270 } 271 272 boolean mPreviewSurfaceValid = false; 273 274 @Override 275 public synchronized void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 276 Log.v(TAG, String.format("surfaceChanged: format=%x w=%d h=%d", format, width, height)); 277 if (checkPermissions()) { 278 mPreviewSurfaceValid = true; 279 mCamera.startPreview(mPreviewHolder.getSurface()); 280 } 281 } 282 283 Runnable mReturnToCafRunnable = new Runnable() { 284 @Override 285 public void run() { 286 mCamera.setCAF(); 287 } 288 }; 289 290 private void doAFScan() { 291 mCamera.triggerAFScan(); 292 mMainHandler.removeCallbacks(mReturnToCafRunnable); 293 mMainHandler.postDelayed(mReturnToCafRunnable, AF_TRIGGER_HOLD_MILLIS); 294 } 295 296 private int displayWidth() { 297 DisplayMetrics metrics = new DisplayMetrics(); 298 this.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); 299 return metrics.widthPixels; 300 } 301 302 private int displayHeight() { 303 DisplayMetrics metrics = new DisplayMetrics(); 304 this.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); 305 return metrics.heightPixels; 306 } 307 308 @Override 309 public void onStart() { 310 Log.v(TAG, "onStart"); 311 super.onStart(); 312 // Leave screen on. 313 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 314 315 if (!checkPermissions()) return; 316 317 // Can start camera now that we have the above initialized. 318 if (mCamera == null) { 319 openCamera(mToggleFrontCam.isChecked()); 320 } 321 startCamera(); 322 } 323 324 private boolean checkPermissions() { 325 if (mPermissionCheckActive) return false; 326 327 // Check for all runtime permissions 328 if ((checkSelfPermission(Manifest.permission.CAMERA) 329 != PackageManager.PERMISSION_GRANTED ) 330 || (checkSelfPermission(Manifest.permission.RECORD_AUDIO) 331 != PackageManager.PERMISSION_GRANTED) 332 || (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) 333 != PackageManager.PERMISSION_GRANTED)) { 334 Log.i(TAG, "Requested camera/video permissions"); 335 requestPermissions(new String[] { 336 Manifest.permission.CAMERA, 337 Manifest.permission.RECORD_AUDIO, 338 Manifest.permission.WRITE_EXTERNAL_STORAGE}, 339 PERMISSIONS_REQUEST_CAMERA); 340 mPermissionCheckActive = true; 341 return false; 342 } 343 344 return true; 345 } 346 347 @Override 348 public void onRequestPermissionsResult(int requestCode, String[] permissions, 349 int[] grantResults) { 350 mPermissionCheckActive = false; 351 if (requestCode == PERMISSIONS_REQUEST_CAMERA) { 352 for (int i = 0; i < grantResults.length; i++) { 353 if (grantResults[i] == PackageManager.PERMISSION_DENIED) { 354 Log.i(TAG, "At least one permission denied, can't continue: " + permissions[i]); 355 finish(); 356 return; 357 } 358 } 359 360 Log.i(TAG, "All permissions granted"); 361 openCamera(mToggleFrontCam.isChecked()); 362 startCamera(); 363 } 364 } 365 366 @Override 367 public void onStop() { 368 Log.v(TAG, "onStop"); 369 if (mCamera != null) { 370 mCamera.closeCamera(); 371 mCamera = null; 372 } 373 374 // Cancel any pending AF operations. 375 mMainHandler.removeCallbacks(mReturnToCafRunnable); 376 stopGyroDisplay(); // No-op if not running. 377 super.onStop(); 378 } 379 380 public void noCamera2Full() { 381 Toast toast = Toast.makeText(this, "WARNING: this camera does not support camera2 HARDWARE_LEVEL_FULL.", Toast.LENGTH_LONG); 382 toast.setGravity(Gravity.TOP, 0, 0); 383 toast.show(); 384 } 385 386 @Override 387 public void setNoiseEdgeText(final String nrMode, final String edgeMode) { 388 mMainHandler.post(new Runnable() { 389 @Override 390 public void run() { 391 mButtonNoiseMode.setText(nrMode); 392 mButtonEdgeMode.setText(edgeMode); 393 } 394 }); 395 } 396 397 @Override 398 public void setNoiseEdgeTextForReprocessing(final String nrMode, final String edgeMode) { 399 mMainHandler.post(new Runnable() { 400 @Override 401 public void run() { 402 mButtonNoiseModeReprocess.setText(nrMode); 403 mButtonEdgeModeReprocess.setText(edgeMode); 404 } 405 }); 406 } 407 408 int mJpegCounter = 0; 409 long mJpegMillis = 0; 410 411 @Override 412 public void jpegAvailable(final byte[] jpegData, final int x, final int y) { 413 Log.v(TAG, "JPEG returned, size = " + jpegData.length); 414 long now = SystemClock.elapsedRealtime(); 415 final long dt = mJpegMillis > 0 ? now - mJpegMillis : 0; 416 mJpegMillis = now; 417 418 if (mToggleSaveSdCard.isChecked()) { 419 mUtilityHandler.post(new Runnable() { 420 @Override 421 public void run() { 422 final String result = MediaSaver.saveJpeg(getApplicationContext(), jpegData, getContentResolver()); 423 mMainHandler.post(new Runnable() { 424 @Override 425 public void run() { 426 fileNameToast(String.format("Saved %dx%d and %d bytes JPEG to %s in %d ms.", x, y, jpegData.length, result, dt)); 427 } 428 }); 429 430 } 431 }); 432 } else { 433 mMainHandler.post(new Runnable() { 434 @Override 435 public void run() { 436 fileNameToast(String.format("Processing JPEG #%d %dx%d and %d bytes in %d ms.", ++mJpegCounter, x, y, jpegData.length, dt)); 437 } 438 }); 439 } 440 } 441 442 @Override 443 public void receivedFirstFrame() { 444 mMainHandler.post(new Runnable() { 445 @Override 446 public void run() { 447 mPreviewView.setBackgroundColor(Color.TRANSPARENT); 448 } 449 }); 450 } 451 452 Toast mToast; 453 454 public void fileNameToast(String s) { 455 if (mToast != null) { 456 mToast.cancel(); 457 } 458 mToast = Toast.makeText(this, s, Toast.LENGTH_SHORT); 459 mToast.setGravity(Gravity.TOP, 0, 0); 460 mToast.show(); 461 } 462 463 @Override 464 public void frameDataAvailable(final NormalizedFace[] faces, final float normExposure, final float normLens, float fps, int iso, final int afState, int aeState, int awbState) { 465 mMainHandler.post(new Runnable() { 466 @Override 467 public void run() { 468 mPreviewOverlay.setFrameData(faces, normExposure, normLens, afState); 469 } 470 }); 471 // Build info string. 472 String ae = aeStateToString(aeState); 473 String af = afStateToString(afState); 474 String awb = awbStateToString(awbState); 475 final String info = String.format(" %2.0f FPS%5d ISO AF:%s AE:%s AWB:%s", fps, iso, af, ae, awb); 476 mLastInfo = info; 477 478 if (LOG_FRAME_DATA && faces != null) { 479 Log.v(TAG, "normExposure: " + normExposure); 480 Log.v(TAG, "normLens: " + normLens); 481 for (int i = 0; i < faces.length; ++i) { 482 Log.v(TAG, "Face getBounds: " + faces[i].bounds); 483 Log.v(TAG, "Face left eye: " + faces[i].leftEye); 484 Log.v(TAG, "Face right eye: " + faces[i].rightEye); 485 Log.v(TAG, "Face mouth: " + faces[i].mouth); 486 } 487 } 488 489 // Status line 490 mMainHandler.post(new Runnable() { 491 @Override 492 public void run() { 493 mLabel1.setText(info); 494 } 495 }); 496 } 497 498 Integer mTimeToFirstFrame = 0; 499 Integer mHalWaitTime = 0; 500 Float mDroppedFrameCount = 0f; 501 String mLastInfo; 502 503 @Override 504 public void performanceDataAvailable(Integer timeToFirstFrame, Integer halWaitTime, Float droppedFrameCount) { 505 if (timeToFirstFrame != null) { 506 mTimeToFirstFrame = timeToFirstFrame; 507 } 508 if (halWaitTime != null) { 509 mHalWaitTime = halWaitTime; 510 } 511 if (droppedFrameCount != null) { 512 mDroppedFrameCount += droppedFrameCount; 513 } 514 mMainHandler.post(new Runnable() { 515 @Override 516 public void run() { 517 mLabel2.setText(String.format("TTP %dms HAL %dms Framedrops:%.2f", mTimeToFirstFrame, mHalWaitTime, mDroppedFrameCount)); 518 } 519 }); 520 } 521 522 // Hit capture button. 523 private void hitCaptureButton() { 524 Log.v(TAG, "hitCaptureButton"); 525 mCamera.takePicture(); 526 } 527 528 // Hit Photos button. 529 private void launchPhotosViewer() { 530 Intent intent = new Intent(android.content.Intent.ACTION_VIEW); 531 intent.setType("image/*"); 532 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 533 startActivity(intent); 534 } 535 536 /********************************* 537 * Gyro graphics overlay update. * 538 *********************************/ 539 GyroOperations mGyroOperations; 540 541 private void startGyroDisplay() { 542 543 float[] fovs = mCamera.getFieldOfView(); 544 mPreviewOverlay.setFieldOfView(fovs[0], fovs[1]); 545 mPreviewOverlay.setFacingAndOrientation(mToggleFrontCam.isChecked() ? 546 CameraCharacteristics.LENS_FACING_FRONT : CameraCharacteristics.LENS_FACING_BACK, 547 mCamera.getOrientation()); 548 if (mGyroOperations == null) { 549 SensorManager sensorManager = (SensorManager) getSystemService(this.SENSOR_SERVICE); 550 mGyroOperations = new GyroOperations(sensorManager); 551 } 552 mGyroOperations.startListening( 553 new GyroListener() { 554 @Override 555 public void updateGyroAngles(float[] gyroAngles) { 556 mPreviewOverlay.setGyroAngles(gyroAngles); 557 } 558 } 559 ); 560 561 mPreviewOverlay.showGyroGrid(true); 562 } 563 564 private void stopGyroDisplay() { 565 if (mGyroOperations != null) { 566 mGyroOperations.stopListening(); 567 } 568 mPreviewOverlay.showGyroGrid(false); 569 } 570 571 572 /******************************************* 573 * SurfaceView callbacks just for logging. * 574 *******************************************/ 575 576 @Override 577 public void surfaceCreated(SurfaceHolder holder) { 578 Log.v(TAG, "surfaceCreated"); 579 } 580 581 @Override 582 public void surfaceDestroyed(SurfaceHolder holder) { 583 Log.v(TAG, "surfaceDestroyed"); 584 } 585 586 /********************* 587 * UTILITY FUNCTIONS * 588 *********************/ 589 590 private static String awbStateToString(int mode) { 591 switch (mode) { 592 case CaptureResult.CONTROL_AWB_STATE_INACTIVE: 593 return "inactive"; 594 case CaptureResult.CONTROL_AWB_STATE_SEARCHING: 595 return "searching"; 596 case CaptureResult.CONTROL_AWB_STATE_CONVERGED: 597 return "converged"; 598 case CaptureResult.CONTROL_AWB_STATE_LOCKED: 599 return "lock"; 600 default: 601 return "unknown " + Integer.toString(mode); 602 } 603 } 604 605 private static String aeStateToString(int mode) { 606 switch (mode) { 607 case CaptureResult.CONTROL_AE_STATE_INACTIVE: 608 return "inactive"; 609 case CaptureResult.CONTROL_AE_STATE_SEARCHING: 610 return "searching"; 611 case CaptureResult.CONTROL_AE_STATE_PRECAPTURE: 612 return "precapture"; 613 case CaptureResult.CONTROL_AE_STATE_CONVERGED: 614 return "converged"; 615 case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED: 616 return "flashReq"; 617 case CaptureResult.CONTROL_AE_STATE_LOCKED: 618 return "lock"; 619 default: 620 return "unknown " + Integer.toString(mode); 621 } 622 } 623 624 private static String afStateToString(int mode) { 625 switch (mode) { 626 case CaptureResult.CONTROL_AF_STATE_INACTIVE: 627 return "inactive"; 628 case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN: 629 return "passiveScan"; 630 case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED: 631 return "passiveFocused"; 632 case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: 633 return "passiveUnfocused"; 634 case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN: 635 return "activeScan"; 636 case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED: 637 return "focusedLock"; 638 case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: 639 return "notFocusedLock"; 640 default: 641 return "unknown" + Integer.toString(mode); 642 } 643 } 644 645 } 646