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
17package com.android.testingcamera2;
18
19import java.util.ArrayList;
20import java.util.List;
21
22import android.content.Context;
23import android.hardware.camera2.CameraCharacteristics;
24import android.hardware.camera2.params.StreamConfigurationMap;
25import android.util.Size;
26import android.util.AttributeSet;
27import android.util.Size;
28import android.view.LayoutInflater;
29import android.view.Surface;
30import android.view.SurfaceHolder;
31import android.view.SurfaceView;
32import android.view.View;
33import android.widget.AdapterView;
34import android.widget.ArrayAdapter;
35import android.widget.LinearLayout;
36import android.widget.Spinner;
37import android.widget.AdapterView.OnItemSelectedListener;
38
39public 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
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
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
116    public void setUiOrientation(int orientation) {
117        mCurrentUiOrientation = orientation;
118        updateAspectRatio();
119    }
120
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
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
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
163    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
164        mSurface = holder.getSurface();
165    }
166
167    @Override
168    public void surfaceCreated(SurfaceHolder holder) {
169
170    }
171
172    @Override
173    public void surfaceDestroyed(SurfaceHolder holder) {
174
175    }
176
177}
178