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