Home | History | Annotate | Download | only in devcamera
      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