• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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