1 /* 2 * Copyright (C) 2014 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.camera.one.v2.autofocus; 18 19 import static com.android.camera.one.v2.core.ResponseListeners.forPartialMetadata; 20 21 import android.hardware.camera2.CameraAccessException; 22 import android.hardware.camera2.CaptureRequest; 23 24 import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionClosedException; 25 import com.android.camera.one.v2.commands.CameraCommand; 26 import com.android.camera.one.v2.core.FrameServer; 27 import com.android.camera.one.v2.core.RequestBuilder; 28 import com.android.camera.one.v2.core.ResourceAcquisitionFailedException; 29 30 import java.util.Arrays; 31 32 import javax.annotation.Nullable; 33 import javax.annotation.ParametersAreNonnullByDefault; 34 35 /** 36 * Performs a full auto focus scan. 37 */ 38 @ParametersAreNonnullByDefault 39 final class FullAFScanCommand implements CameraCommand { 40 private final FrameServer mFrameServer; 41 private final RequestBuilder.Factory mBuilderFactory; 42 private final int mTemplateType; 43 44 /** 45 * @param frameServer Used for sending requests to the camera. 46 * @param builder Used for building requests. 47 * @param templateType See 48 * {@link android.hardware.camera2.CameraDevice#createCaptureRequest} 49 */ FullAFScanCommand(FrameServer frameServer, RequestBuilder.Factory builder, int templateType)50 public FullAFScanCommand(FrameServer frameServer, RequestBuilder.Factory builder, int 51 templateType) { 52 mFrameServer = frameServer; 53 mBuilderFactory = builder; 54 mTemplateType = templateType; 55 } 56 57 /** 58 * Performs an auto-focus scan, blocking until the scan starts, runs, and 59 * completes. 60 */ 61 @Override run()62 public void run() throws InterruptedException, CameraAccessException, 63 CameraCaptureSessionClosedException, ResourceAcquisitionFailedException { 64 FrameServer.Session session = mFrameServer.tryCreateExclusiveSession(); 65 if (session == null) { 66 // If there are already other commands interacting with the 67 // FrameServer, don't wait to run the AF command, instead just 68 // abort. 69 return; 70 } 71 try { 72 AFTriggerResult afScanResult = new AFTriggerResult(); 73 74 // Start a repeating sequence of idle requests 75 RequestBuilder idleBuilder = createAFIdleRequest(null); 76 session.submitRequest(Arrays.asList(idleBuilder.build()), 77 FrameServer.RequestType.REPEATING); 78 79 // Workaround for Nexus 6: 80 // Sending an AF_TRIGGER_START, followed immediately by another 81 // AF_TRIGGER_START may result in the driver deadlocking in its AF 82 // state machine, in certain cases 83 // (it's easy to reproduce this issue in relatively dark scenes 84 // ~1-3inches from the device with AF_MODE_ON_ALWAYS_FLASH). 85 // So, to avoid triggering this issue, always send an 86 // AF_TRIGGER_CANCEL before *every* AF_TRIGGER_START. 87 RequestBuilder cancelBuilder = createAFCancelRequest(null); 88 session.submitRequest(Arrays.asList(cancelBuilder.build()), 89 FrameServer.RequestType.NON_REPEATING); 90 91 // Start a repeating sequence of idle requests 92 idleBuilder = createAFIdleRequest(afScanResult); 93 session.submitRequest(Arrays.asList(idleBuilder.build()), 94 FrameServer.RequestType.REPEATING); 95 96 // Build a request to send a single AF_TRIGGER 97 RequestBuilder triggerBuilder = createAFTriggerRequest(afScanResult); 98 session.submitRequest(Arrays.asList(triggerBuilder.build()), 99 FrameServer.RequestType.NON_REPEATING); 100 101 // Block until the scan is done. 102 // TODO If the HAL never transitions out of scanning mode, this will 103 // block forever (or until interrupted because the app is paused). 104 // So, maybe use a generous timeout and log as HAL errors. 105 afScanResult.get(); 106 } finally { 107 session.close(); 108 } 109 } 110 createAFIdleRequest(@ullable AFTriggerResult triggerResultListener)111 private RequestBuilder createAFIdleRequest(@Nullable AFTriggerResult triggerResultListener) 112 throws CameraAccessException { 113 RequestBuilder idleBuilder = mBuilderFactory.create(mTemplateType); 114 if (triggerResultListener != null) { 115 idleBuilder.addResponseListener(forPartialMetadata(triggerResultListener)); 116 } 117 idleBuilder.setParam(CaptureRequest.CONTROL_MODE, CaptureRequest 118 .CONTROL_MODE_AUTO); 119 idleBuilder.setParam(CaptureRequest.CONTROL_AF_MODE, CaptureRequest 120 .CONTROL_AF_MODE_AUTO); 121 idleBuilder.setParam(CaptureRequest.CONTROL_AF_TRIGGER, 122 CaptureRequest.CONTROL_AF_TRIGGER_IDLE); 123 return idleBuilder; 124 } 125 createAFTriggerRequest(AFTriggerResult afScanResult)126 private RequestBuilder createAFTriggerRequest(AFTriggerResult afScanResult) throws 127 CameraAccessException { 128 RequestBuilder triggerBuilder = mBuilderFactory.create(mTemplateType); 129 triggerBuilder.addResponseListener(forPartialMetadata(afScanResult)); 130 triggerBuilder.setParam(CaptureRequest.CONTROL_MODE, CaptureRequest 131 .CONTROL_MODE_AUTO); 132 triggerBuilder.setParam(CaptureRequest.CONTROL_AF_MODE, CaptureRequest 133 .CONTROL_AF_MODE_AUTO); 134 triggerBuilder.setParam(CaptureRequest.CONTROL_AF_TRIGGER, 135 CaptureRequest.CONTROL_AF_TRIGGER_START); 136 return triggerBuilder; 137 } 138 createAFCancelRequest(@ullable AFTriggerResult afScanResult)139 private RequestBuilder createAFCancelRequest(@Nullable AFTriggerResult afScanResult) throws 140 CameraAccessException { 141 RequestBuilder triggerBuilder = mBuilderFactory.create(mTemplateType); 142 if (afScanResult != null) { 143 triggerBuilder.addResponseListener(forPartialMetadata(afScanResult)); 144 } 145 triggerBuilder.setParam(CaptureRequest.CONTROL_MODE, CaptureRequest 146 .CONTROL_MODE_AUTO); 147 triggerBuilder.setParam(CaptureRequest.CONTROL_AF_MODE, CaptureRequest 148 .CONTROL_AF_MODE_AUTO); 149 triggerBuilder.setParam(CaptureRequest.CONTROL_AF_TRIGGER, 150 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); 151 return triggerBuilder; 152 } 153 } 154