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 java.util.ArrayList; 20 import java.util.List; 21 22 import android.content.Context; 23 import android.hardware.camera2.CameraCharacteristics; 24 import android.hardware.camera2.params.StreamConfigurationMap; 25 import android.util.Size; 26 import android.util.AttributeSet; 27 import android.util.Size; 28 import android.view.LayoutInflater; 29 import android.view.Surface; 30 import android.view.SurfaceHolder; 31 import android.view.SurfaceView; 32 import android.view.View; 33 import android.widget.AdapterView; 34 import android.widget.ArrayAdapter; 35 import android.widget.LinearLayout; 36 import android.widget.Spinner; 37 import android.widget.AdapterView.OnItemSelectedListener; 38 39 public class SurfaceViewSubPane extends TargetSubPane implements SurfaceHolder.Callback { 40 41 private static final int NO_SIZE = -1; 42 private final FixedAspectSurfaceView mFixedSurfaceView; 43 private Surface mSurface; 44 45 private final Spinner mSizeSpinner; 46 private Size[] mSizes; 47 private int mCurrentCameraOrientation = 0; 48 private int mCurrentUiOrientation = 0; 49 50 private int mCurrentSizeId = NO_SIZE; 51 private CameraControlPane mCurrentCamera; 52 53 private float mAspectRatio = DEFAULT_ASPECT_RATIO; 54 55 private static final float DEFAULT_ASPECT_RATIO = 1.5f; 56 SurfaceViewSubPane(Context context, AttributeSet attrs)57 public SurfaceViewSubPane(Context context, AttributeSet attrs) { 58 super(context, attrs); 59 60 LayoutInflater inflater = 61 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 62 63 inflater.inflate(R.layout.surfaceview_target_subpane, this); 64 this.setOrientation(VERTICAL); 65 66 mFixedSurfaceView = (FixedAspectSurfaceView) this.findViewById(R.id.target_subpane_surface_view_view); 67 mFixedSurfaceView.getHolder().addCallback(this); 68 mSizeSpinner = (Spinner) this.findViewById(R.id.target_subpane_surface_view_size_spinner); 69 mSizeSpinner.setOnItemSelectedListener(mSizeSpinnerListener); 70 } 71 72 @Override setTargetCameraPane(CameraControlPane target)73 public void setTargetCameraPane(CameraControlPane target) { 74 if (target != null) { 75 Size oldSize = null; 76 if (mCurrentSizeId != NO_SIZE) { 77 oldSize = mSizes[mCurrentSizeId]; 78 } 79 80 CameraCharacteristics info = target.getCharacteristics(); 81 { 82 StreamConfigurationMap streamConfigMap = 83 info.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 84 mSizes = streamConfigMap.getOutputSizes(SurfaceHolder.class); 85 } 86 87 int newSelectionId = 0; 88 for (int i = 0; i < mSizes.length; i++) { 89 if (mSizes[i].equals(oldSize)) { 90 newSelectionId = i; 91 break; 92 } 93 } 94 String[] outputSizeItems = new String[mSizes.length]; 95 for (int i = 0; i < outputSizeItems.length; i++) { 96 outputSizeItems[i] = mSizes[i].toString(); 97 } 98 99 mSizeSpinner.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.spinner_item, 100 outputSizeItems)); 101 mSizeSpinner.setSelection(newSelectionId); 102 103 // Map sensor orientation to Surface.ROTATE_* constants 104 final int SENSOR_ORIENTATION_TO_SURFACE_ROTATE = 90; 105 mCurrentCameraOrientation = info.get(CameraCharacteristics.SENSOR_ORIENTATION) / 106 SENSOR_ORIENTATION_TO_SURFACE_ROTATE; 107 108 updateAspectRatio(); 109 } else { 110 mSizeSpinner.setAdapter(null); 111 mCurrentSizeId = NO_SIZE; 112 } 113 } 114 115 @Override setUiOrientation(int orientation)116 public void setUiOrientation(int orientation) { 117 mCurrentUiOrientation = orientation; 118 updateAspectRatio(); 119 } 120 updateSizes()121 private void updateSizes() { 122 if (mCurrentSizeId != NO_SIZE) { 123 Size s = mSizes[mCurrentSizeId]; 124 mFixedSurfaceView.getHolder().setFixedSize(s.getWidth(), s.getHeight()); 125 mAspectRatio = ((float) s.getWidth()) / s.getHeight(); 126 } else { 127 // Make sure the view has some reasonable size even when there's no 128 // target camera for aspect-ratio correct sizing 129 mAspectRatio = DEFAULT_ASPECT_RATIO; 130 } 131 updateAspectRatio(); 132 } 133 updateAspectRatio()134 private void updateAspectRatio() { 135 // Swap aspect ratios when the UI orientation and the camera orientation don't line up 136 boolean swapAspect = Math.abs(mCurrentUiOrientation - mCurrentCameraOrientation) % 2 == 1; 137 if (swapAspect) { 138 mFixedSurfaceView.setAspectRatio(1/mAspectRatio); 139 } else { 140 mFixedSurfaceView.setAspectRatio(mAspectRatio); 141 } 142 } 143 144 @Override getOutputSurface()145 public Surface getOutputSurface() { 146 return mSurface; 147 } 148 149 private final OnItemSelectedListener mSizeSpinnerListener = new OnItemSelectedListener() { 150 @Override 151 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 152 mCurrentSizeId = pos; 153 updateSizes(); 154 }; 155 156 @Override 157 public void onNothingSelected(AdapterView<?> parent) { 158 mCurrentSizeId = NO_SIZE; 159 }; 160 }; 161 162 @Override surfaceChanged(SurfaceHolder holder, int format, int width, int height)163 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 164 mSurface = holder.getSurface(); 165 } 166 167 @Override surfaceCreated(SurfaceHolder holder)168 public void surfaceCreated(SurfaceHolder holder) { 169 170 } 171 172 @Override surfaceDestroyed(SurfaceHolder holder)173 public void surfaceDestroyed(SurfaceHolder holder) { 174 175 } 176 177 } 178