1 /* 2 * Copyright (C) 2017 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.dialer.simulator.impl; 18 19 import android.content.Context; 20 import android.graphics.SurfaceTexture; 21 import android.hardware.camera2.CameraAccessException; 22 import android.hardware.camera2.CameraCaptureSession; 23 import android.hardware.camera2.CameraCharacteristics; 24 import android.hardware.camera2.CameraDevice; 25 import android.hardware.camera2.CameraManager; 26 import android.hardware.camera2.CameraMetadata; 27 import android.hardware.camera2.CaptureRequest; 28 import android.hardware.camera2.params.StreamConfigurationMap; 29 import android.support.annotation.NonNull; 30 import android.support.annotation.Nullable; 31 import android.telecom.VideoProfile.CameraCapabilities; 32 import android.util.Size; 33 import android.view.Surface; 34 import com.android.dialer.common.Assert; 35 import com.android.dialer.common.LogUtil; 36 import java.util.Arrays; 37 38 /** 39 * Used by the video provider to draw the local camera. The in-call UI is responsible for setting 40 * the camera (front or back) and the view to draw to. The video provider then uses this class to 41 * capture frames from the given camera and draw to the given view. 42 */ 43 final class SimulatorPreviewCamera { 44 @NonNull private final Context context; 45 @NonNull private final String cameraId; 46 @NonNull private final Surface surface; 47 @Nullable private CameraDevice camera; 48 private boolean isStopped; 49 SimulatorPreviewCamera( @onNull Context context, @NonNull String cameraId, @NonNull Surface surface)50 SimulatorPreviewCamera( 51 @NonNull Context context, @NonNull String cameraId, @NonNull Surface surface) { 52 this.context = Assert.isNotNull(context); 53 this.cameraId = Assert.isNotNull(cameraId); 54 this.surface = Assert.isNotNull(surface); 55 } 56 startCamera()57 void startCamera() { 58 LogUtil.enterBlock("SimulatorPreviewCamera.startCamera"); 59 Assert.checkState(!isStopped); 60 try { 61 context 62 .getSystemService(CameraManager.class) 63 .openCamera(cameraId, new CameraListener(), null /* handler */); 64 } catch (CameraAccessException | SecurityException e) { 65 throw Assert.createIllegalStateFailException("camera error: " + e); 66 } 67 } 68 stopCamera()69 void stopCamera() { 70 LogUtil.enterBlock("SimulatorPreviewCamera.stopCamera"); 71 isStopped = true; 72 if (camera != null) { 73 camera.close(); 74 camera = null; 75 } 76 } 77 78 @Nullable getCameraCapabilities( @onNull Context context, @Nullable String cameraId)79 static CameraCapabilities getCameraCapabilities( 80 @NonNull Context context, @Nullable String cameraId) { 81 if (cameraId == null) { 82 LogUtil.e("SimulatorPreviewCamera.getCameraCapabilities", "null camera ID"); 83 return null; 84 } 85 86 CameraManager cameraManager = context.getSystemService(CameraManager.class); 87 CameraCharacteristics characteristics; 88 try { 89 characteristics = cameraManager.getCameraCharacteristics(cameraId); 90 } catch (CameraAccessException e) { 91 throw Assert.createIllegalStateFailException("camera error: " + e); 92 } 93 94 StreamConfigurationMap map = 95 characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 96 Size previewSize = map.getOutputSizes(SurfaceTexture.class)[0]; 97 LogUtil.i("SimulatorPreviewCamera.getCameraCapabilities", "preview size: " + previewSize); 98 return new CameraCapabilities(previewSize.getWidth(), previewSize.getHeight()); 99 } 100 101 private final class CameraListener extends CameraDevice.StateCallback { 102 @Override onOpened(CameraDevice camera)103 public void onOpened(CameraDevice camera) { 104 LogUtil.enterBlock("SimulatorPreviewCamera.CameraListener.onOpened"); 105 SimulatorPreviewCamera.this.camera = camera; 106 if (isStopped) { 107 LogUtil.i("SimulatorPreviewCamera.CameraListener.onOpened", "stopped"); 108 stopCamera(); 109 return; 110 } 111 112 try { 113 camera.createCaptureSession( 114 Arrays.asList(Assert.isNotNull(surface)), 115 new CaptureSessionCallback(), 116 null /* handler */); 117 } catch (CameraAccessException e) { 118 throw Assert.createIllegalStateFailException("camera error: " + e); 119 } 120 } 121 122 @Override onError(CameraDevice camera, int error)123 public void onError(CameraDevice camera, int error) { 124 LogUtil.i("SimulatorPreviewCamera.CameraListener.onError", "error: " + error); 125 stopCamera(); 126 } 127 128 @Override onDisconnected(CameraDevice camera)129 public void onDisconnected(CameraDevice camera) { 130 LogUtil.enterBlock("SimulatorPreviewCamera.CameraListener.onDisconnected"); 131 stopCamera(); 132 } 133 134 @Override onClosed(CameraDevice camera)135 public void onClosed(CameraDevice camera) { 136 LogUtil.enterBlock("SimulatorPreviewCamera.CameraListener.onCLosed"); 137 } 138 } 139 140 private final class CaptureSessionCallback extends CameraCaptureSession.StateCallback { 141 @Override onConfigured(@onNull CameraCaptureSession session)142 public void onConfigured(@NonNull CameraCaptureSession session) { 143 LogUtil.enterBlock("SimulatorPreviewCamera.CaptureSessionCallback.onConfigured"); 144 145 if (isStopped) { 146 LogUtil.i("SimulatorPreviewCamera.CaptureSessionCallback.onConfigured", "stopped"); 147 stopCamera(); 148 return; 149 } 150 try { 151 CaptureRequest.Builder builder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 152 builder.addTarget(surface); 153 builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); 154 session.setRepeatingRequest( 155 builder.build(), null /* captureCallback */, null /* handler */); 156 } catch (CameraAccessException e) { 157 throw Assert.createIllegalStateFailException("camera error: " + e); 158 } 159 } 160 161 @Override onConfigureFailed(@onNull CameraCaptureSession cameraCaptureSession)162 public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { 163 LogUtil.enterBlock("SimulatorPreviewCamera.CaptureSessionCallback.onConfigureFailed"); 164 } 165 } 166 } 167