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