17c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala/* 27c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * Copyright (C) 2014 The Android Open Source Project 37c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * 47c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License"); 57c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * you may not use this file except in compliance with the License. 67c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * You may obtain a copy of the License at 77c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * 87c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * http://www.apache.org/licenses/LICENSE-2.0 97c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * 107c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * Unless required by applicable law or agreed to in writing, software 117c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS, 127c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * See the License for the specific language governing permissions and 147c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala * limitations under the License. 157c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala */ 167c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 177c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalapackage com.android.testingcamera2; 187c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 197c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport java.util.ArrayList; 207c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport java.util.List; 217c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 227c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.content.Context; 237c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.hardware.camera2.CameraCharacteristics; 24684d44a36b4ac32e2e162caf9ce4e625bd13b555Igor Murashkinimport android.hardware.camera2.params.StreamConfigurationMap; 25e82937211409e869f32c8398ee16ce6bb77bfce6Igor Murashkinimport android.util.Size; 267c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.util.AttributeSet; 270b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvalaimport android.util.Size; 287c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.view.LayoutInflater; 297c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.view.Surface; 307c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.view.SurfaceHolder; 317c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.view.SurfaceView; 327c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.view.View; 337c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.widget.AdapterView; 347c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.widget.ArrayAdapter; 357c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.widget.LinearLayout; 367c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.widget.Spinner; 377c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport android.widget.AdapterView.OnItemSelectedListener; 387c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 397c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalapublic class SurfaceViewSubPane extends TargetSubPane implements SurfaceHolder.Callback { 407c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 417c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala private static final int NO_SIZE = -1; 420b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala private final FixedAspectSurfaceView mFixedSurfaceView; 437c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala private Surface mSurface; 447c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 45684d44a36b4ac32e2e162caf9ce4e625bd13b555Igor Murashkin private final Spinner mSizeSpinner; 467c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala private Size[] mSizes; 470b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala private int mCurrentCameraOrientation = 0; 480b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala private int mCurrentUiOrientation = 0; 490b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala 507c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala private int mCurrentSizeId = NO_SIZE; 517c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala private CameraControlPane mCurrentCamera; 527c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 530b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala private float mAspectRatio = DEFAULT_ASPECT_RATIO; 540b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala 550b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala private static final float DEFAULT_ASPECT_RATIO = 1.5f; 560b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala 577c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala public SurfaceViewSubPane(Context context, AttributeSet attrs) { 587c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala super(context, attrs); 597c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 607c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala LayoutInflater inflater = 617c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 627c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 637c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala inflater.inflate(R.layout.surfaceview_target_subpane, this); 647c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala this.setOrientation(VERTICAL); 657c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 660b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala mFixedSurfaceView = (FixedAspectSurfaceView) this.findViewById(R.id.target_subpane_surface_view_view); 670b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala mFixedSurfaceView.getHolder().addCallback(this); 687c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala mSizeSpinner = (Spinner) this.findViewById(R.id.target_subpane_surface_view_size_spinner); 697c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala mSizeSpinner.setOnItemSelectedListener(mSizeSpinnerListener); 707c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 717c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 727c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala @Override 737c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala public void setTargetCameraPane(CameraControlPane target) { 747c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala if (target != null) { 757c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala Size oldSize = null; 767c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala if (mCurrentSizeId != NO_SIZE) { 777c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala oldSize = mSizes[mCurrentSizeId]; 787c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 797c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 800b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala CameraCharacteristics info = target.getCharacteristics(); 81e82937211409e869f32c8398ee16ce6bb77bfce6Igor Murashkin { 82e82937211409e869f32c8398ee16ce6bb77bfce6Igor Murashkin StreamConfigurationMap streamConfigMap = 83e82937211409e869f32c8398ee16ce6bb77bfce6Igor Murashkin info.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 84e82937211409e869f32c8398ee16ce6bb77bfce6Igor Murashkin mSizes = streamConfigMap.getOutputSizes(SurfaceHolder.class); 857c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 86684d44a36b4ac32e2e162caf9ce4e625bd13b555Igor Murashkin 877c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala int newSelectionId = 0; 887c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala for (int i = 0; i < mSizes.length; i++) { 897c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala if (mSizes[i].equals(oldSize)) { 907c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala newSelectionId = i; 917c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala break; 927c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 937c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 947c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala String[] outputSizeItems = new String[mSizes.length]; 957c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala for (int i = 0; i < outputSizeItems.length; i++) { 967c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala outputSizeItems[i] = mSizes[i].toString(); 977c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 987c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 997c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala mSizeSpinner.setAdapter(new ArrayAdapter<String>(getContext(), R.layout.spinner_item, 1007c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala outputSizeItems)); 1017c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala mSizeSpinner.setSelection(newSelectionId); 1020b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala 1030b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala // Map sensor orientation to Surface.ROTATE_* constants 1040b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala final int SENSOR_ORIENTATION_TO_SURFACE_ROTATE = 90; 1050b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala mCurrentCameraOrientation = info.get(CameraCharacteristics.SENSOR_ORIENTATION) / 1060b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala SENSOR_ORIENTATION_TO_SURFACE_ROTATE; 1070b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala 1080b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala updateAspectRatio(); 1097c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } else { 1107c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala mSizeSpinner.setAdapter(null); 1117c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala mCurrentSizeId = NO_SIZE; 1127c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 1137c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 1147c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 1150b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala @Override 1160b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala public void setUiOrientation(int orientation) { 1170b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala mCurrentUiOrientation = orientation; 1180b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala updateAspectRatio(); 1190b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala } 1200b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala 1217c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala private void updateSizes() { 1227c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala if (mCurrentSizeId != NO_SIZE) { 1237c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala Size s = mSizes[mCurrentSizeId]; 1240b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala mFixedSurfaceView.getHolder().setFixedSize(s.getWidth(), s.getHeight()); 1250b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala mAspectRatio = ((float) s.getWidth()) / s.getHeight(); 1267c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } else { 1277c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala // Make sure the view has some reasonable size even when there's no 1287c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala // target camera for aspect-ratio correct sizing 1290b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala mAspectRatio = DEFAULT_ASPECT_RATIO; 1300b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala } 1310b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala updateAspectRatio(); 1320b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala } 1330b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala 1340b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala private void updateAspectRatio() { 1350b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala // Swap aspect ratios when the UI orientation and the camera orientation don't line up 1360b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala boolean swapAspect = Math.abs(mCurrentUiOrientation - mCurrentCameraOrientation) % 2 == 1; 1370b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala if (swapAspect) { 1380b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala mFixedSurfaceView.setAspectRatio(1/mAspectRatio); 1390b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala } else { 1400b631a014c90c9053a8e17be141351abab66d30eEino-Ville Talvala mFixedSurfaceView.setAspectRatio(mAspectRatio); 1417c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 1427c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 1437c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 1447c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala @Override 1457c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala public Surface getOutputSurface() { 1467c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala return mSurface; 1477c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 1487c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 149684d44a36b4ac32e2e162caf9ce4e625bd13b555Igor Murashkin private final OnItemSelectedListener mSizeSpinnerListener = new OnItemSelectedListener() { 1507c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala @Override 1517c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 1527c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala mCurrentSizeId = pos; 1537c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala updateSizes(); 1547c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala }; 1557c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 1567c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala @Override 1577c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala public void onNothingSelected(AdapterView<?> parent) { 1587c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala mCurrentSizeId = NO_SIZE; 1597c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala }; 1607c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala }; 1617c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 1627c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala @Override 1637c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 1647c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala mSurface = holder.getSurface(); 1657c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 1667c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 1677c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala @Override 1687c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala public void surfaceCreated(SurfaceHolder holder) { 1697c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 1707c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 1717c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 1727c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala @Override 1737c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala public void surfaceDestroyed(SurfaceHolder holder) { 1747c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 1757c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala } 1767c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala 1777c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala} 178