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.testingcamera2;
18 
19 import android.content.Context;
20 import android.hardware.camera2.CameraDevice;
21 import android.hardware.camera2.CaptureRequest;
22 import android.util.AttributeSet;
23 import android.view.LayoutInflater;
24 import android.view.Surface;
25 import android.view.View;
26 import android.widget.AdapterView;
27 import android.widget.ArrayAdapter;
28 import android.widget.Button;
29 import android.widget.ListView;
30 import android.widget.Spinner;
31 
32 import org.xmlpull.v1.XmlPullParser;
33 import org.xmlpull.v1.XmlPullParserException;
34 
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.Locale;
39 
40 public class RequestControlPane extends ControlPane {
41     // XML attributes
42 
43     /** Name of pane tag */
44     private static final String PANE_NAME = "request_pane";
45 
46     /** Attribute: ID for pane (integer) */
47     private static final String PANE_ID = "id";
48 
49     // End XML attributes
50 
51     private enum TemplateType {
52         MANUAL(CameraDevice.TEMPLATE_MANUAL),
53         PREVIEW(CameraDevice.TEMPLATE_PREVIEW),
54         RECORD(CameraDevice.TEMPLATE_RECORD),
55         STILL_CAPTURE(CameraDevice.TEMPLATE_STILL_CAPTURE),
56         VIDEO_SNAPSHOT(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT),
57         ZERO_SHUTTER_LAG(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
58 
59         private int mTemplateVal;
60 
TemplateType(int templateVal)61         TemplateType(int templateVal) {
62             mTemplateVal = templateVal;
63         }
64 
getTemplateValue()65         int getTemplateValue() {
66             return mTemplateVal;
67         }
68     }
69 
70     private static int mRequestPaneIdCounter = 0;
71 
72     private final int mPaneId;
73 
74     private List<CameraControlPane> mCameraPanes;
75     private final List<TargetControlPane> mTargetPanes = new ArrayList<TargetControlPane>();
76 
77     private Spinner mCameraSpinner;
78     private Spinner mTemplateSpinner;
79     private ListView mOutputListView;
80 
81     private CheckableListAdapter mOutputAdapter;
82 
83     /**
84      * Constructor for tooling only
85      */
RequestControlPane(Context context, AttributeSet attrs)86     public RequestControlPane(Context context, AttributeSet attrs) {
87         super(context, attrs, null, null);
88 
89         mPaneId = 0;
90         setUpUI(context);
91     }
92 
RequestControlPane(TestingCamera21 tc, AttributeSet attrs, StatusListener listener)93     public RequestControlPane(TestingCamera21 tc, AttributeSet attrs, StatusListener listener) {
94         super(tc, attrs, listener, tc.getPaneTracker());
95 
96         mPaneId = mRequestPaneIdCounter++;
97         setUpUI(tc);
98     }
99 
RequestControlPane(TestingCamera21 tc, XmlPullParser configParser, StatusListener listener)100     public RequestControlPane(TestingCamera21 tc, XmlPullParser configParser,
101             StatusListener listener) throws XmlPullParserException, IOException {
102         super(tc, null, listener, tc.getPaneTracker());
103 
104         this.setName(tc.getResources().getString(R.string.request_pane_title));
105 
106         configParser.require(XmlPullParser.START_TAG, XmlPullParser.NO_NAMESPACE, PANE_NAME);
107 
108         int paneId = getAttributeInt(configParser, PANE_ID, -1);
109         if (paneId == -1) {
110             mPaneId = mRequestPaneIdCounter++;
111         } else {
112             mPaneId = paneId;
113             if (mPaneId >= mRequestPaneIdCounter) {
114                 mRequestPaneIdCounter = mPaneId + 1;
115             }
116         }
117 
118         configParser.next();
119         configParser.require(XmlPullParser.END_TAG, XmlPullParser.NO_NAMESPACE, PANE_NAME);
120 
121         setUpUI(tc);
122     }
123 
notifyPaneEvent(ControlPane sourcePane, PaneTracker.PaneEvent event)124     public void notifyPaneEvent(ControlPane sourcePane, PaneTracker.PaneEvent event) {
125         switch (event) {
126             case NEW_CAMERA_SELECTED:
127                 if (mCameraPanes.size() > 0
128                         && sourcePane == mCameraPanes.get(mCameraSpinner.getSelectedItemPosition())) {
129                     updateOutputList();
130                 }
131                 break;
132             case CAMERA_CONFIGURED:
133                 if (mCameraPanes.size() > 0
134                         && sourcePane == mCameraPanes.get(mCameraSpinner.getSelectedItemPosition())) {
135                     updateOutputList();
136                 }
137                 break;
138             default:
139                 super.notifyPaneEvent(sourcePane, event);
140         }
141     }
142 
setUpUI(Context context)143     private void setUpUI(Context context) {
144         String paneName =
145                 String.format(Locale.US, "%s %d",
146                         context.getResources().getString(R.string.request_pane_title), mPaneId);
147         this.setName(paneName);
148 
149         LayoutInflater inflater =
150                 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
151 
152         inflater.inflate(R.layout.request_pane, this);
153 
154         Button captureButton = (Button) findViewById(R.id.request_pane_capture_button);
155         captureButton.setOnClickListener(mCaptureButtonListener);
156         Button repeatButton = (Button) findViewById(R.id.request_pane_repeat_button);
157         repeatButton.setOnClickListener(mRepeatButtonListener);
158 
159         mCameraSpinner = (Spinner) findViewById(R.id.request_pane_camera_spinner);
160         mTemplateSpinner = (Spinner) findViewById(R.id.request_pane_template_spinner);
161         mOutputListView = (ListView) findViewById(R.id.request_pane_output_listview);
162 
163         mCameraSpinner.setOnItemSelectedListener(mCameraSpinnerListener);
164 
165         mOutputAdapter = new CheckableListAdapter(context, R.layout.checkable_list_item,
166                 new ArrayList<CheckableListAdapter.CheckableItem>());
167         mOutputListView.setAdapter(mOutputAdapter);
168 
169         String[] templateNames = new String[TemplateType.values().length];
170         for (int i = 0; i < templateNames.length; i++) {
171             templateNames[i] = TemplateType.values()[i].toString();
172         }
173         mTemplateSpinner.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.spinner_item,
174                 templateNames));
175 
176         mPaneTracker.addPaneListener(new CameraPanesListener());
177         mCameraPanes = mPaneTracker.getPanes(CameraControlPane.class);
178         updateCameraPaneList();
179     }
180 
181     private class CameraPanesListener extends PaneTracker.PaneSetChangedListener<CameraControlPane> {
CameraPanesListener()182         public CameraPanesListener() {
183             super(CameraControlPane.class);
184         }
185 
186         @Override
onPaneAdded(ControlPane pane)187         public void onPaneAdded(ControlPane pane) {
188             mCameraPanes.add((CameraControlPane) pane);
189             updateCameraPaneList();
190         }
191 
192         @Override
onPaneRemoved(ControlPane pane)193         public void onPaneRemoved(ControlPane pane) {
194             mCameraPanes.remove((CameraControlPane) pane);
195             updateCameraPaneList();
196         }
197     }
198 
199     private AdapterView.OnItemSelectedListener mCameraSpinnerListener = new AdapterView.OnItemSelectedListener() {
200         @Override
201         public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
202             updateOutputList();
203         }
204 
205         @Override
206         public void onNothingSelected(AdapterView<?> parent) {
207             updateOutputList();
208         }
209     };
210 
211     private OnClickListener mCaptureButtonListener = new OnClickListener() {
212         @Override
213         public void onClick(View v) {
214             if (mCameraPanes.size() == 0) {
215                 TLog.e("No camera selected for request");
216                 return;
217             }
218             CameraControlPane camera = mCameraPanes.get(mCameraSpinner.getSelectedItemPosition());
219 
220             CaptureRequest request = createRequest(camera);
221             if (request != null) {
222                 camera.capture(request);
223             }
224         }
225     };
226 
227     private OnClickListener mRepeatButtonListener = new OnClickListener() {
228         @Override
229         public void onClick(View v) {
230             if (mCameraPanes.size() == 0) {
231                 TLog.e("No camera selected for request");
232                 return;
233             }
234             CameraControlPane camera = mCameraPanes.get(mCameraSpinner.getSelectedItemPosition());
235 
236             CaptureRequest request = createRequest(camera);
237             if (request != null) {
238                 camera.repeat(request);
239             }
240         }
241     };
242 
createRequest(CameraControlPane camera)243     private CaptureRequest createRequest(CameraControlPane camera) {
244         if (mTargetPanes.size() == 0) {
245             TLog.e("No target(s) selected for request");
246             return null;
247         }
248 
249 
250         TemplateType template = TemplateType.valueOf((String) mTemplateSpinner.getSelectedItem());
251         CaptureRequest.Builder builder = camera.getRequestBuilder(template.getTemplateValue());
252         // TODO: Add setting overrides
253 
254         List<Integer> targetPostions = mOutputAdapter.getCheckedPositions();
255         for (int i : targetPostions) {
256             TargetControlPane target = mTargetPanes.get(i);
257             Surface targetSurface = target.getTargetSurfaceForCameraPane(camera.getPaneName());
258             if (targetSurface == null) {
259                 TLog.e("Target not configured for camera");
260                 return null;
261             }
262             builder.addTarget(targetSurface);
263         }
264 
265         CaptureRequest request = builder.build();
266         return request;
267     }
268 
updateCameraPaneList()269     private void updateCameraPaneList() {
270         String currentSelection = (String) mCameraSpinner.getSelectedItem();
271         int newSelectionIndex = 0;
272         String[] cameraSpinnerItems = new String[mCameraPanes.size()];
273         for (int i = 0; i < cameraSpinnerItems.length; i++) {
274             cameraSpinnerItems[i] = mCameraPanes.get(i).getPaneName();
275             if (cameraSpinnerItems[i].equals(currentSelection)) {
276                 newSelectionIndex = i;
277             }
278         }
279         mCameraSpinner.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.spinner_item,
280                 cameraSpinnerItems));
281         mCameraSpinner.setSelection(newSelectionIndex);
282 
283         updateOutputList();
284     }
285 
updateOutputList()286     private void updateOutputList() {
287         if (mCameraPanes.size() > 0) {
288             CameraControlPane currentCamera =
289                     mCameraPanes.get(mCameraSpinner.getSelectedItemPosition());
290             mTargetPanes.clear();
291             List<TargetControlPane> newPanes = currentCamera.getCurrentConfiguredTargets();
292             if (newPanes != null) {
293                 mTargetPanes.addAll(currentCamera.getCurrentConfiguredTargets());
294             }
295 
296             String[] outputSpinnerItems = new String[mTargetPanes.size()];
297             for (int i = 0; i < outputSpinnerItems.length; i++) {
298                 outputSpinnerItems[i] = mTargetPanes.get(i).getPaneName();
299             }
300 
301             mOutputAdapter.updateItems(outputSpinnerItems);
302 
303         }
304     }
305 
306 }
307