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
onCreate(Bundle savedInstanceState)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.
openCamera(boolean frontCamera)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.
startCamera()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
surfaceChanged(SurfaceHolder holder, int format, int width, int height)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 
doAFScan()290     private void doAFScan() {
291         mCamera.triggerAFScan();
292         mMainHandler.removeCallbacks(mReturnToCafRunnable);
293         mMainHandler.postDelayed(mReturnToCafRunnable, AF_TRIGGER_HOLD_MILLIS);
294     }
295 
displayWidth()296     private int displayWidth() {
297         DisplayMetrics metrics = new DisplayMetrics();
298         this.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
299         return metrics.widthPixels;
300     }
301 
displayHeight()302     private int displayHeight() {
303         DisplayMetrics metrics = new DisplayMetrics();
304         this.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
305         return metrics.heightPixels;
306     }
307 
308     @Override
onStart()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 
checkPermissions()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
onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)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
onStop()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 
noCamera2Full()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
setNoiseEdgeText(final String nrMode, final String edgeMode)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
setNoiseEdgeTextForReprocessing(final String nrMode, final String edgeMode)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
jpegAvailable(final byte[] jpegData, final int x, final int y)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
receivedFirstFrame()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 
fileNameToast(String s)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
frameDataAvailable(final NormalizedFace[] faces, final float normExposure, final float normLens, float fps, int iso, final int afState, int aeState, int awbState)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
performanceDataAvailable(Integer timeToFirstFrame, Integer halWaitTime, Float droppedFrameCount)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.
hitCaptureButton()523     private void hitCaptureButton() {
524         Log.v(TAG, "hitCaptureButton");
525         mCamera.takePicture();
526     }
527 
528     // Hit Photos button.
launchPhotosViewer()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 
startGyroDisplay()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 
stopGyroDisplay()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
surfaceCreated(SurfaceHolder holder)577     public void surfaceCreated(SurfaceHolder holder) {
578         Log.v(TAG, "surfaceCreated");
579     }
580 
581     @Override
surfaceDestroyed(SurfaceHolder holder)582     public void surfaceDestroyed(SurfaceHolder holder) {
583         Log.v(TAG, "surfaceDestroyed");
584     }
585 
586     /*********************
587      * UTILITY FUNCTIONS *
588      *********************/
589 
awbStateToString(int mode)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 
aeStateToString(int mode)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 
afStateToString(int mode)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