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