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.util.AttributeSet; 21 import android.view.LayoutInflater; 22 import android.view.Surface; 23 import android.view.View; 24 import android.widget.AdapterView; 25 import android.widget.AdapterView.OnItemSelectedListener; 26 import android.widget.ArrayAdapter; 27 import android.widget.Spinner; 28 import android.widget.Button; 29 import android.widget.ToggleButton; 30 31 import org.xmlpull.v1.XmlPullParser; 32 import org.xmlpull.v1.XmlPullParserException; 33 34 import java.io.IOException; 35 import java.util.List; 36 import java.util.Locale; 37 38 public class TargetControlPane extends ControlPane { 39 // XML attributes 40 41 /** Name of pane tag */ 42 private static final String PANE_NAME = "target_pane"; 43 44 /** Attribute: ID for pane (integer) */ 45 private static final String PANE_ID = "id"; 46 47 /** Attribute: Type of output (string), value must be one of OutputViewType.getXmlName() */ 48 private static final String OUTPUT_TYPE = "type"; 49 50 // End XML attributes 51 52 /** 53 * Available output view types 54 * 55 * <p>Adding new entries to this list requires updating createOutputView() as 56 * well.</p> 57 */ 58 private enum OutputViewType { 59 SURFACE_VIEW, 60 TEXTURE_VIEW, 61 IMAGE_READER, 62 RENDERSCRIPT, 63 MEDIA_RECORDER, 64 MEDIA_CODEC; 65 getXmlName(OutputViewType type)66 static String getXmlName(OutputViewType type) { 67 return type.toString().toLowerCase(Locale.US); 68 } 69 } 70 71 private static int mTargetPaneIdCounter = 0; 72 73 private int mPaneId; 74 75 private List<CameraControlPane> mCameraPanes; 76 77 private Spinner mCameraSpinner; 78 private ToggleButton mCameraConfigureToggle; 79 private Button mPrepareButton; 80 81 private Spinner mOutputSpinner; 82 83 private TargetSubPane mCurrentOutput; 84 85 private int mOrientation = 0; 86 87 /** 88 * Constructor for tooling only 89 */ TargetControlPane(Context context, AttributeSet attrs)90 public TargetControlPane(Context context, AttributeSet attrs) { 91 super(context, attrs, null, null); 92 93 mPaneId = 0; 94 setUpUI(context); 95 } 96 TargetControlPane(TestingCamera21 tc, AttributeSet attrs, StatusListener listener)97 public TargetControlPane(TestingCamera21 tc, AttributeSet attrs, StatusListener listener) { 98 super(tc, attrs, listener, tc.getPaneTracker()); 99 100 mPaneId = mTargetPaneIdCounter++; 101 setUpUI(tc); 102 103 } 104 TargetControlPane(TestingCamera21 tc, XmlPullParser configParser, StatusListener listener)105 public TargetControlPane(TestingCamera21 tc, XmlPullParser configParser, StatusListener listener) 106 throws XmlPullParserException, IOException { 107 super(tc, null, listener, tc.getPaneTracker()); 108 109 configParser.require(XmlPullParser.START_TAG, XmlPullParser.NO_NAMESPACE, PANE_NAME); 110 111 int paneId = getAttributeInt(configParser, PANE_ID, -1); 112 if (paneId == -1) { 113 mPaneId = mTargetPaneIdCounter++; 114 } else { 115 mPaneId = paneId; 116 if (mPaneId >= mTargetPaneIdCounter) { 117 mTargetPaneIdCounter = mPaneId + 1; 118 } 119 } 120 121 configParser.next(); 122 configParser.require(XmlPullParser.END_TAG, XmlPullParser.NO_NAMESPACE, PANE_NAME); 123 124 setUpUI(tc); 125 } 126 127 /** 128 * Get this target's Surface aimed at the given camera pane. If no target 129 * for that camera is defined by this pane, returns null. 130 * 131 * @param paneName ID of the camera pane to return a Surface for 132 * @return a Surface to configure for the camera device, or null if none 133 * available 134 */ getTargetSurfaceForCameraPane(String paneName)135 public Surface getTargetSurfaceForCameraPane(String paneName) { 136 if (paneName == null || mCurrentOutput == null) return null; 137 138 boolean isMyTarget = 139 paneName.equals(mCameraSpinner.getSelectedItem()) && 140 mCameraConfigureToggle.isChecked(); 141 mPrepareButton.setEnabled(isMyTarget); 142 return isMyTarget ? mCurrentOutput.getOutputSurface() : null; 143 } 144 notifyPaneEvent(ControlPane sourcePane, PaneTracker.PaneEvent event)145 public void notifyPaneEvent(ControlPane sourcePane, PaneTracker.PaneEvent event) { 146 switch (event) { 147 case NEW_CAMERA_SELECTED: 148 if (mCameraPanes.size() > 0 149 && sourcePane == mCameraPanes.get(mCameraSpinner.getSelectedItemPosition())) { 150 if (mCurrentOutput != null) { 151 mCurrentOutput.setTargetCameraPane((CameraControlPane) sourcePane); 152 } 153 } 154 break; 155 default: 156 super.notifyPaneEvent(sourcePane, event); 157 } 158 } 159 onOrientationChange(int orientation)160 public void onOrientationChange(int orientation) { 161 mOrientation = orientation; 162 if (mCurrentOutput != null) { 163 mCurrentOutput.setUiOrientation(mOrientation); 164 } 165 } 166 setUpUI(Context context)167 private void setUpUI(Context context) { 168 169 String paneTitle = 170 String.format(Locale.US, "%s %d", 171 context.getResources().getString(R.string.target_pane_title), mPaneId); 172 this.setName(paneTitle); 173 174 LayoutInflater inflater = 175 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 176 177 inflater.inflate(R.layout.target_pane, this); 178 179 mCameraSpinner = (Spinner) findViewById(R.id.target_pane_camera_spinner); 180 mCameraSpinner.setOnItemSelectedListener(mCameraSpinnerListener); 181 mCameraConfigureToggle = (ToggleButton) findViewById(R.id.target_pane_configure_toggle); 182 mCameraConfigureToggle.setChecked(true); 183 mPrepareButton = (Button) findViewById(R.id.target_pane_prepare_button); 184 mPrepareButton.setEnabled(false); 185 mPrepareButton.setOnClickListener(mPrepareButtonListener); 186 187 mOutputSpinner = (Spinner) findViewById(R.id.target_pane_output_spinner); 188 mOutputSpinner.setOnItemSelectedListener(mOutputSpinnerListener); 189 190 OutputViewType[] outputTypes = OutputViewType.values(); 191 String[] outputSpinnerItems = new String[outputTypes.length]; 192 193 for (int i = 0; i < outputTypes.length; i++) { 194 outputSpinnerItems[i] = outputTypes[i].toString(); 195 } 196 mOutputSpinner.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.spinner_item, 197 outputSpinnerItems)); 198 199 mPaneTracker.addPaneListener(new CameraPanesListener()); 200 mCameraPanes = mPaneTracker.getPanes(CameraControlPane.class); 201 updateCameraPaneList(); 202 203 } 204 205 private class CameraPanesListener extends PaneTracker.PaneSetChangedListener<CameraControlPane> { CameraPanesListener()206 public CameraPanesListener() { 207 super(CameraControlPane.class); 208 } 209 210 @Override onPaneAdded(ControlPane pane)211 public void onPaneAdded(ControlPane pane) { 212 mCameraPanes.add((CameraControlPane) pane); 213 updateCameraPaneList(); 214 } 215 216 @Override onPaneRemoved(ControlPane pane)217 public void onPaneRemoved(ControlPane pane) { 218 mCameraPanes.remove((CameraControlPane) pane); 219 updateCameraPaneList(); 220 } 221 } 222 223 private OnItemSelectedListener mCameraSpinnerListener = new OnItemSelectedListener() { 224 @Override 225 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 226 updateSubPaneCamera(); 227 } 228 229 @Override 230 public void onNothingSelected(AdapterView<?> arg0) { 231 232 } 233 }; 234 235 private final OnClickListener mPrepareButtonListener = new OnClickListener() { 236 @Override 237 public void onClick(View v) { 238 CameraControlPane currentCameraPane = mCameraPanes.get( 239 mCameraSpinner.getSelectedItemPosition()); 240 currentCameraPane.prepareSurface(mCurrentOutput.getOutputSurface()); 241 } 242 }; 243 244 private OnItemSelectedListener mOutputSpinnerListener = new OnItemSelectedListener() { 245 @Override 246 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 247 mPrepareButton.setEnabled(false); 248 if (mCurrentOutput != null) { 249 TargetControlPane.this.removeView(mCurrentOutput); 250 } 251 OutputViewType outputType = 252 OutputViewType.valueOf((String) mOutputSpinner.getSelectedItem()); 253 mCurrentOutput = createOutputView(outputType); 254 if (mCurrentOutput != null) { 255 TargetControlPane.this.addView(mCurrentOutput); 256 mCurrentOutput.setUiOrientation(mOrientation); 257 updateSubPaneCamera(); 258 } 259 } 260 261 @Override 262 public void onNothingSelected(AdapterView<?> arg0) { 263 mPrepareButton.setEnabled(false); 264 if (mCurrentOutput != null) { 265 TargetControlPane.this.removeView(mCurrentOutput); 266 mCurrentOutput = null; 267 } 268 } 269 }; 270 updateCameraPaneList()271 private void updateCameraPaneList() { 272 String currentSelection = (String) mCameraSpinner.getSelectedItem(); 273 int newSelectionIndex = 0; 274 String[] cameraSpinnerItems = new String[mCameraPanes.size()]; 275 for (int i = 0; i < cameraSpinnerItems.length; i++) { 276 cameraSpinnerItems[i] = mCameraPanes.get(i).getPaneName(); 277 if (cameraSpinnerItems[i].equals(currentSelection)) { 278 newSelectionIndex = i; 279 } 280 } 281 mCameraSpinner.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.spinner_item, 282 cameraSpinnerItems)); 283 mCameraSpinner.setSelection(newSelectionIndex); 284 } 285 updateSubPaneCamera()286 private void updateSubPaneCamera() { 287 if (mCameraPanes.size() > 0 && mCurrentOutput != null) { 288 mCurrentOutput.setTargetCameraPane(mCameraPanes.get(mCameraSpinner 289 .getSelectedItemPosition())); 290 } 291 } 292 createOutputView(OutputViewType type)293 private TargetSubPane createOutputView(OutputViewType type) { 294 TargetSubPane newPane = null; 295 switch (type) { 296 case IMAGE_READER: 297 newPane = new ImageReaderSubPane(getContext(), null); 298 break; 299 case MEDIA_CODEC: 300 case MEDIA_RECORDER: 301 case RENDERSCRIPT: 302 TLog.e("No implementation yet for view type %s", type); 303 break; 304 case SURFACE_VIEW: 305 newPane = new SurfaceViewSubPane(getContext(), null); 306 break; 307 case TEXTURE_VIEW: 308 newPane = new TextureViewSubPane(getContext(), null); 309 break; 310 } 311 return newPane; 312 } 313 } 314