| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.testingcamera2; |
| |
| import android.content.Context; |
| import android.util.AttributeSet; |
| import android.view.LayoutInflater; |
| import android.view.Surface; |
| import android.view.View; |
| import android.widget.AdapterView; |
| import android.widget.AdapterView.OnItemSelectedListener; |
| import android.widget.ArrayAdapter; |
| import android.widget.Spinner; |
| import android.widget.Button; |
| import android.widget.ToggleButton; |
| |
| import org.xmlpull.v1.XmlPullParser; |
| import org.xmlpull.v1.XmlPullParserException; |
| |
| import java.io.IOException; |
| import java.util.List; |
| import java.util.Locale; |
| |
| public class TargetControlPane extends ControlPane { |
| // XML attributes |
| |
| /** Name of pane tag */ |
| private static final String PANE_NAME = "target_pane"; |
| |
| /** Attribute: ID for pane (integer) */ |
| private static final String PANE_ID = "id"; |
| |
| /** Attribute: Type of output (string), value must be one of OutputViewType.getXmlName() */ |
| private static final String OUTPUT_TYPE = "type"; |
| |
| // End XML attributes |
| |
| /** |
| * Available output view types |
| * |
| * <p>Adding new entries to this list requires updating createOutputView() as |
| * well.</p> |
| */ |
| private enum OutputViewType { |
| SURFACE_VIEW, |
| TEXTURE_VIEW, |
| IMAGE_READER, |
| RENDERSCRIPT, |
| MEDIA_RECORDER, |
| MEDIA_CODEC; |
| |
| static String getXmlName(OutputViewType type) { |
| return type.toString().toLowerCase(Locale.US); |
| } |
| } |
| |
| private static int mTargetPaneIdCounter = 0; |
| |
| private int mPaneId; |
| |
| private List<CameraControlPane> mCameraPanes; |
| |
| private Spinner mCameraSpinner; |
| private ToggleButton mCameraConfigureToggle; |
| private Button mPrepareButton; |
| |
| private Spinner mOutputSpinner; |
| |
| private TargetSubPane mCurrentOutput; |
| |
| private int mOrientation = 0; |
| |
| /** |
| * Constructor for tooling only |
| */ |
| public TargetControlPane(Context context, AttributeSet attrs) { |
| super(context, attrs, null, null); |
| |
| mPaneId = 0; |
| setUpUI(context); |
| } |
| |
| public TargetControlPane(TestingCamera21 tc, AttributeSet attrs, StatusListener listener) { |
| super(tc, attrs, listener, tc.getPaneTracker()); |
| |
| mPaneId = mTargetPaneIdCounter++; |
| setUpUI(tc); |
| |
| } |
| |
| public TargetControlPane(TestingCamera21 tc, XmlPullParser configParser, StatusListener listener) |
| throws XmlPullParserException, IOException { |
| super(tc, null, listener, tc.getPaneTracker()); |
| |
| configParser.require(XmlPullParser.START_TAG, XmlPullParser.NO_NAMESPACE, PANE_NAME); |
| |
| int paneId = getAttributeInt(configParser, PANE_ID, -1); |
| if (paneId == -1) { |
| mPaneId = mTargetPaneIdCounter++; |
| } else { |
| mPaneId = paneId; |
| if (mPaneId >= mTargetPaneIdCounter) { |
| mTargetPaneIdCounter = mPaneId + 1; |
| } |
| } |
| |
| configParser.next(); |
| configParser.require(XmlPullParser.END_TAG, XmlPullParser.NO_NAMESPACE, PANE_NAME); |
| |
| setUpUI(tc); |
| } |
| |
| /** |
| * Get this target's Surface aimed at the given camera pane. If no target |
| * for that camera is defined by this pane, returns null. |
| * |
| * @param paneName ID of the camera pane to return a Surface for |
| * @return a Surface to configure for the camera device, or null if none |
| * available |
| */ |
| public Surface getTargetSurfaceForCameraPane(String paneName) { |
| if (paneName == null || mCurrentOutput == null) return null; |
| |
| boolean isMyTarget = |
| paneName.equals(mCameraSpinner.getSelectedItem()) && |
| mCameraConfigureToggle.isChecked(); |
| mPrepareButton.setEnabled(isMyTarget); |
| return isMyTarget ? mCurrentOutput.getOutputSurface() : null; |
| } |
| |
| public void notifyPaneEvent(ControlPane sourcePane, PaneTracker.PaneEvent event) { |
| switch (event) { |
| case NEW_CAMERA_SELECTED: |
| if (mCameraPanes.size() > 0 |
| && sourcePane == mCameraPanes.get(mCameraSpinner.getSelectedItemPosition())) { |
| if (mCurrentOutput != null) { |
| mCurrentOutput.setTargetCameraPane((CameraControlPane) sourcePane); |
| } |
| } |
| break; |
| default: |
| super.notifyPaneEvent(sourcePane, event); |
| } |
| } |
| |
| public void onOrientationChange(int orientation) { |
| mOrientation = orientation; |
| if (mCurrentOutput != null) { |
| mCurrentOutput.setUiOrientation(mOrientation); |
| } |
| } |
| |
| private void setUpUI(Context context) { |
| |
| String paneTitle = |
| String.format(Locale.US, "%s %d", |
| context.getResources().getString(R.string.target_pane_title), mPaneId); |
| this.setName(paneTitle); |
| |
| LayoutInflater inflater = |
| (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); |
| |
| inflater.inflate(R.layout.target_pane, this); |
| |
| mCameraSpinner = (Spinner) findViewById(R.id.target_pane_camera_spinner); |
| mCameraSpinner.setOnItemSelectedListener(mCameraSpinnerListener); |
| mCameraConfigureToggle = (ToggleButton) findViewById(R.id.target_pane_configure_toggle); |
| mCameraConfigureToggle.setChecked(true); |
| mPrepareButton = (Button) findViewById(R.id.target_pane_prepare_button); |
| mPrepareButton.setEnabled(false); |
| mPrepareButton.setOnClickListener(mPrepareButtonListener); |
| |
| mOutputSpinner = (Spinner) findViewById(R.id.target_pane_output_spinner); |
| mOutputSpinner.setOnItemSelectedListener(mOutputSpinnerListener); |
| |
| OutputViewType[] outputTypes = OutputViewType.values(); |
| String[] outputSpinnerItems = new String[outputTypes.length]; |
| |
| for (int i = 0; i < outputTypes.length; i++) { |
| outputSpinnerItems[i] = outputTypes[i].toString(); |
| } |
| mOutputSpinner.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.spinner_item, |
| outputSpinnerItems)); |
| |
| mPaneTracker.addPaneListener(new CameraPanesListener()); |
| mCameraPanes = mPaneTracker.getPanes(CameraControlPane.class); |
| updateCameraPaneList(); |
| |
| } |
| |
| private class CameraPanesListener extends PaneTracker.PaneSetChangedListener<CameraControlPane> { |
| public CameraPanesListener() { |
| super(CameraControlPane.class); |
| } |
| |
| @Override |
| public void onPaneAdded(ControlPane pane) { |
| mCameraPanes.add((CameraControlPane) pane); |
| updateCameraPaneList(); |
| } |
| |
| @Override |
| public void onPaneRemoved(ControlPane pane) { |
| mCameraPanes.remove((CameraControlPane) pane); |
| updateCameraPaneList(); |
| } |
| } |
| |
| private OnItemSelectedListener mCameraSpinnerListener = new OnItemSelectedListener() { |
| @Override |
| public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { |
| updateSubPaneCamera(); |
| } |
| |
| @Override |
| public void onNothingSelected(AdapterView<?> arg0) { |
| |
| } |
| }; |
| |
| private final OnClickListener mPrepareButtonListener = new OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| CameraControlPane currentCameraPane = mCameraPanes.get( |
| mCameraSpinner.getSelectedItemPosition()); |
| currentCameraPane.prepareSurface(mCurrentOutput.getOutputSurface()); |
| } |
| }; |
| |
| private OnItemSelectedListener mOutputSpinnerListener = new OnItemSelectedListener() { |
| @Override |
| public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { |
| mPrepareButton.setEnabled(false); |
| if (mCurrentOutput != null) { |
| TargetControlPane.this.removeView(mCurrentOutput); |
| } |
| OutputViewType outputType = |
| OutputViewType.valueOf((String) mOutputSpinner.getSelectedItem()); |
| mCurrentOutput = createOutputView(outputType); |
| if (mCurrentOutput != null) { |
| TargetControlPane.this.addView(mCurrentOutput); |
| mCurrentOutput.setUiOrientation(mOrientation); |
| updateSubPaneCamera(); |
| } |
| } |
| |
| @Override |
| public void onNothingSelected(AdapterView<?> arg0) { |
| mPrepareButton.setEnabled(false); |
| if (mCurrentOutput != null) { |
| TargetControlPane.this.removeView(mCurrentOutput); |
| mCurrentOutput = null; |
| } |
| } |
| }; |
| |
| private void updateCameraPaneList() { |
| String currentSelection = (String) mCameraSpinner.getSelectedItem(); |
| int newSelectionIndex = 0; |
| String[] cameraSpinnerItems = new String[mCameraPanes.size()]; |
| for (int i = 0; i < cameraSpinnerItems.length; i++) { |
| cameraSpinnerItems[i] = mCameraPanes.get(i).getPaneName(); |
| if (cameraSpinnerItems[i].equals(currentSelection)) { |
| newSelectionIndex = i; |
| } |
| } |
| mCameraSpinner.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.spinner_item, |
| cameraSpinnerItems)); |
| mCameraSpinner.setSelection(newSelectionIndex); |
| } |
| |
| private void updateSubPaneCamera() { |
| if (mCameraPanes.size() > 0 && mCurrentOutput != null) { |
| mCurrentOutput.setTargetCameraPane(mCameraPanes.get(mCameraSpinner |
| .getSelectedItemPosition())); |
| } |
| } |
| |
| private TargetSubPane createOutputView(OutputViewType type) { |
| TargetSubPane newPane = null; |
| switch (type) { |
| case IMAGE_READER: |
| newPane = new ImageReaderSubPane(getContext(), null); |
| break; |
| case MEDIA_CODEC: |
| case MEDIA_RECORDER: |
| case RENDERSCRIPT: |
| TLog.e("No implementation yet for view type %s", type); |
| break; |
| case SURFACE_VIEW: |
| newPane = new SurfaceViewSubPane(getContext(), null); |
| break; |
| case TEXTURE_VIEW: |
| newPane = new TextureViewSubPane(getContext(), null); |
| break; |
| } |
| return newPane; |
| } |
| } |