1ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala/*
2ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala * Copyright (C) 2013 The Android Open Source Project
3ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala *
4ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala * Licensed under the Apache License, Version 2.0 (the "License");
5ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala * you may not use this file except in compliance with the License.
6ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala * You may obtain a copy of the License at
7ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala *
8ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala *      http://www.apache.org/licenses/LICENSE-2.0
9ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala *
10ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala * Unless required by applicable law or agreed to in writing, software
11ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala * distributed under the License is distributed on an "AS IS" BASIS,
12ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala * See the License for the specific language governing permissions and
14ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala * limitations under the License.
15ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala */
16ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
177c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalapackage com.android.testingcamera2.v1;
18ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
19ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvalaimport android.app.Activity;
200e50db98503df09a94369445c421c9c6530b9458Igor Murashkinimport android.content.res.Configuration;
21819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.graphics.Bitmap;
22819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.graphics.BitmapFactory;
23819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.graphics.ImageFormat;
24d7d287b826fb83916ba526027719eb39a33ec872Igor Murashkinimport android.hardware.camera2.CameraCharacteristics;
255345b93fd44823f695794ab4a7cceb23a82d8f17Eino-Ville Talvalaimport android.hardware.camera2.CameraCaptureSession;
26419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun Heimport android.hardware.camera2.CameraDevice;
27dc82bfc6ce14c4989518c2ca49a0f6067768388dIgor Murashkinimport android.hardware.camera2.CaptureFailure;
28419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun Heimport android.hardware.camera2.CaptureRequest;
29419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun Heimport android.hardware.camera2.CaptureResult;
303ca1329990a74c72fe534c1a06890b50581017c3Igor Murashkinimport android.hardware.camera2.TotalCaptureResult;
31819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.media.Image;
32f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shihimport android.media.MediaMuxer;
33819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.os.AsyncTask;
34ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvalaimport android.os.Bundle;
35819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.os.Handler;
36ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvalaimport android.util.Log;
3717b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunkimport android.util.Range;
38be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhangimport android.view.OrientationEventListener;
39ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvalaimport android.view.SurfaceHolder;
40ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvalaimport android.view.SurfaceView;
41819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.view.View;
420e50db98503df09a94369445c421c9c6530b9458Igor Murashkinimport android.view.ViewGroup.LayoutParams;
43819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.view.WindowManager;
448704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkinimport android.widget.AdapterView;
458704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkinimport android.widget.AdapterView.OnItemSelectedListener;
468704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkinimport android.widget.ArrayAdapter;
47819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.widget.Button;
48be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhangimport android.widget.CompoundButton;
49be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhangimport android.widget.CheckBox;
50819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport android.widget.ImageView;
51f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shihimport android.widget.RadioGroup;
52419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun Heimport android.widget.SeekBar;
53419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun Heimport android.widget.SeekBar.OnSeekBarChangeListener;
548704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkinimport android.widget.Spinner;
55419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun Heimport android.widget.TextView;
56419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun Heimport android.widget.ToggleButton;
57ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
58819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvalaimport java.nio.ByteBuffer;
598704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkinimport java.util.ArrayList;
60967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkinimport java.util.Arrays;
61419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun Heimport java.util.HashSet;
628704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkinimport java.util.List;
63419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun Heimport java.util.Set;
64ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
657c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvalaimport com.android.testingcamera2.R;
667c5f2935442e974ce30158e35d142f7e2c3ee1a2Eino-Ville Talvala
67ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvalapublic class TestingCamera2 extends Activity implements SurfaceHolder.Callback {
68ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
69ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    private static final String TAG = "TestingCamera2";
70419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
71ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    private CameraOps mCameraOps;
72419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private static final int mSeekBarMax = 100;
73419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private static final long MAX_EXPOSURE = 200000000L; // 200ms
74419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private static final long MIN_EXPOSURE = 100000L; // 100us
75419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private static final long MAX_FRAME_DURATION = 1000000000L; // 1s
76419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    // Manual control change step size
77419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private static final int STEP_SIZE = 100;
78419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    // Min and max sensitivity ISO values
79419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private static final int MIN_SENSITIVITY = 100;
80419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private static final int MAX_SENSITIVITY = 1600;
810e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private static final int ORIENTATION_UNINITIALIZED = -1;
82ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
830e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private int mLastOrientation = ORIENTATION_UNINITIALIZED;
84be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang    private OrientationEventListener mOrientationEventListener;
85ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    private SurfaceView mPreviewView;
86819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala    private ImageView mStillView;
87819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala
88819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala    private SurfaceHolder mCurrentPreviewHolder = null;
89819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala
90819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala    private Button mInfoButton;
918e330563835a9c1011509577382a315466684802Eino-Ville Talvala    private Button mFlushButton;
928704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin    private ToggleButton mFocusLockToggle;
938704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin    private Spinner mFocusModeSpinner;
94be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang    private CheckBox mUseMediaCodecCheckBox;
95ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
96419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private SeekBar mSensitivityBar;
97419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private SeekBar mExposureBar;
98419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private SeekBar mFrameDurationBar;
99419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
100419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private TextView mSensitivityInfoView;
101419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private TextView mExposureInfoView;
102419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private TextView mFrameDurationInfoView;
103419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private TextView mCaptureResultView;
104419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private ToggleButton mRecordingToggle;
105419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private ToggleButton mManualCtrlToggle;
106419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
107419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private CameraControls mCameraControl = null;
1080e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private final Set<View> mManualControls = new HashSet<View>();
1098704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin    private final Set<View> mAutoControls = new HashSet<View>();
1108704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
1118704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
112419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
113419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    Handler mMainHandler;
114be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang    boolean mUseMediaCodec;
115419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
116ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    @Override
117ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    public void onCreate(Bundle savedInstanceState) {
118ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        super.onCreate(savedInstanceState);
119ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
120819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
121819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                WindowManager.LayoutParams.FLAG_FULLSCREEN);
122819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala
123ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        setContentView(R.layout.main);
124ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
125819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        mPreviewView = (SurfaceView) findViewById(R.id.preview_view);
126ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        mPreviewView.getHolder().addCallback(this);
127ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
128819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        mStillView = (ImageView) findViewById(R.id.still_view);
129819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala
130819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        mInfoButton  = (Button) findViewById(R.id.info_button);
131819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        mInfoButton.setOnClickListener(mInfoButtonListener);
1328e330563835a9c1011509577382a315466684802Eino-Ville Talvala        mFlushButton  = (Button) findViewById(R.id.flush_button);
1338e330563835a9c1011509577382a315466684802Eino-Ville Talvala        mFlushButton.setOnClickListener(mFlushButtonListener);
1348704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
1358704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        mFocusLockToggle = (ToggleButton) findViewById(R.id.focus_button);
1368704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        mFocusLockToggle.setOnClickListener(mFocusLockToggleListener);
1378704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        mFocusModeSpinner = (Spinner) findViewById(R.id.focus_mode_spinner);
1388704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        mAutoControls.add(mFocusLockToggle);
1398704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
140419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mRecordingToggle = (ToggleButton) findViewById(R.id.start_recording);
141419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mRecordingToggle.setOnClickListener(mRecordingToggleListener);
142be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        mUseMediaCodecCheckBox = (CheckBox) findViewById(R.id.use_media_codec);
143be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        mUseMediaCodecCheckBox.setOnCheckedChangeListener(mUseMediaCodecListener);
144be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        mUseMediaCodecCheckBox.setChecked(mUseMediaCodec);
145419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
146419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mManualCtrlToggle = (ToggleButton) findViewById(R.id.manual_control);
147419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mManualCtrlToggle.setOnClickListener(mControlToggleListener);
148419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
149419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mSensitivityBar = (SeekBar) findViewById(R.id.sensitivity_seekbar);
150419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mSensitivityBar.setOnSeekBarChangeListener(mSensitivitySeekBarListener);
151419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mSensitivityBar.setMax(mSeekBarMax);
152419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mManualControls.add(mSensitivityBar);
153419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
154419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mExposureBar = (SeekBar) findViewById(R.id.exposure_time_seekbar);
155419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mExposureBar.setOnSeekBarChangeListener(mExposureSeekBarListener);
156419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mExposureBar.setMax(mSeekBarMax);
157419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mManualControls.add(mExposureBar);
158819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala
159419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mFrameDurationBar = (SeekBar) findViewById(R.id.frame_duration_seekbar);
160419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mFrameDurationBar.setOnSeekBarChangeListener(mFrameDurationSeekBarListener);
161419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mFrameDurationBar.setMax(mSeekBarMax);
162419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mManualControls.add(mFrameDurationBar);
163419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
164419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mSensitivityInfoView = (TextView) findViewById(R.id.sensitivity_bar_label);
165419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mExposureInfoView = (TextView) findViewById(R.id.exposure_time_bar_label);
166419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mFrameDurationInfoView = (TextView) findViewById(R.id.frame_duration_bar_label);
167419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mCaptureResultView = (TextView) findViewById(R.id.capture_result_info_label);
168419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
169419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        enableManualControls(false);
170419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mCameraControl = new CameraControls();
171419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
172419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        // Get UI handler
173419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        mMainHandler = new Handler();
174819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala
175ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        try {
1768704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            mCameraOps = CameraOps.create(this, mCameraOpsListener, mMainHandler);
177ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        } catch(ApiFailureException e) {
178ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala            logException("Cannot create camera ops!",e);
179ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        }
1800e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
181be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        mOrientationEventListener = new OrientationEventListener(this) {
182be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang            @Override
183be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang            public void onOrientationChanged(int orientation) {
184be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang                if (orientation == ORIENTATION_UNKNOWN) {
185be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang                    orientation = 0;
186be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang                }
187be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang                mCameraOps.updateOrientation(orientation);
188be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang            }
189be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        };
190be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        mOrientationEventListener.enable();
1910e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        // Process the initial configuration (for i.e. initial orientation)
1920e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        // We need this because #onConfigurationChanged doesn't get called when the app launches
1930e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        maybeUpdateConfiguration(getResources().getConfiguration());
194ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    }
195ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
196ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    @Override
197ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    public void onResume() {
198ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        super.onResume();
199819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        try {
2000e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            if (VERBOSE) Log.v(TAG, String.format("onResume"));
2010e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
202819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            mCameraOps.minimalPreviewConfig(mPreviewView.getHolder());
203819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            mCurrentPreviewHolder = mPreviewView.getHolder();
204819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        } catch (ApiFailureException e) {
205819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            logException("Can't configure preview surface: ",e);
206819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        }
207ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    }
208ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
209ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    @Override
210ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    public void onPause() {
211ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        super.onPause();
212ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        try {
2130e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            if (VERBOSE) Log.v(TAG, String.format("onPause"));
2140e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
215ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala            mCameraOps.closeDevice();
216ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        } catch (ApiFailureException e) {
217ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala            logException("Can't close device: ",e);
218ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        }
219819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        mCurrentPreviewHolder = null;
220ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    }
221ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
2220e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    @Override
223be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang    protected void onDestroy() {
224be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        mOrientationEventListener.disable();
225be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        super.onDestroy();
226be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang    }
227be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang
228be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang    @Override
2290e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    public void onConfigurationChanged(Configuration newConfig) {
2300e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        super.onConfigurationChanged(newConfig);
2310e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
2320e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        if (VERBOSE) {
2330e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            Log.v(TAG, String.format("onConfiguredChanged: orientation %x",
2340e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                    newConfig.orientation));
2350e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        }
2360e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
2370e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        maybeUpdateConfiguration(newConfig);
2380e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    }
2390e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
2400e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private void maybeUpdateConfiguration(Configuration newConfig) {
2410e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        if (VERBOSE) {
2420e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            Log.v(TAG, String.format("handleConfiguration: orientation %x",
2430e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                    newConfig.orientation));
2440e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        }
2450e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
2460e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        if (mLastOrientation != newConfig.orientation) {
2470e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            mLastOrientation = newConfig.orientation;
2480e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            updatePreviewOrientation();
2490e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        }
2500e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    }
2510e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
2520e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private void updatePreviewOrientation() {
2530e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        LayoutParams params = mPreviewView.getLayoutParams();
2540e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        int width = params.width;
2550e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        int height = params.height;
2560e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
2570e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        if (VERBOSE) {
2580e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            Log.v(TAG, String.format(
2590e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                    "onConfiguredChanged: current layout is %dx%d", width,
2600e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                    height));
2610e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        }
2620e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        /**
2630e50db98503df09a94369445c421c9c6530b9458Igor Murashkin         * Force wide aspect ratios for landscape
2640e50db98503df09a94369445c421c9c6530b9458Igor Murashkin         * Force narrow aspect ratios for portrait
2650e50db98503df09a94369445c421c9c6530b9458Igor Murashkin         */
2660e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        if (mLastOrientation == Configuration.ORIENTATION_LANDSCAPE) {
2670e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            if (height > width) {
2680e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                int tmp = width;
2690e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                width = height;
2700e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                height = tmp;
2710e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            }
2720e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        } else if (mLastOrientation == Configuration.ORIENTATION_PORTRAIT) {
2730e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            if (width > height) {
2740e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                int tmp = width;
2750e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                width = height;
2760e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                height = tmp;
2770e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            }
2780e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        }
2790e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
2800e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        if (width != params.width && height != params.height) {
2810e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            if (VERBOSE) {
2820e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                Log.v(TAG, String.format(
2830e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                        "onConfiguredChanged: updating preview size to %dx%d", width,
2840e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                        height));
2850e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            }
2860e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            params.width = width;
2870e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            params.height = height;
2880e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
2890e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            mPreviewView.setLayoutParams(params);
2900e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        }
2910e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    }
2920e50db98503df09a94369445c421c9c6530b9458Igor Murashkin
293ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    /** SurfaceHolder.Callback methods */
294ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    @Override
295ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    public void surfaceChanged(SurfaceHolder holder,
296ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala            int format,
297ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala            int width,
298ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala            int height) {
2990e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        if (VERBOSE) {
3000e50db98503df09a94369445c421c9c6530b9458Igor Murashkin            Log.v(TAG, String.format("surfaceChanged: format %x, width %d, height %d", format,
3010e50db98503df09a94369445c421c9c6530b9458Igor Murashkin                    width, height));
3020e50db98503df09a94369445c421c9c6530b9458Igor Murashkin        }
303819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        if (mCurrentPreviewHolder != null && holder == mCurrentPreviewHolder) {
304819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            try {
305d5b98fdbb048b7a94cd8628f13faa4334e2c8bf9Zhijun He                mCameraOps.minimalPreview(holder, mCameraControl);
306819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            } catch (ApiFailureException e) {
307819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                logException("Can't start minimal preview: ", e);
308819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            }
309ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        }
310ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    }
311ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
312ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    @Override
313ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    public void surfaceCreated(SurfaceHolder holder) {
314ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
315ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    }
316ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
317ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    @Override
318ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    public void surfaceDestroyed(SurfaceHolder holder) {
319ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    }
320ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala
3210e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private final Button.OnClickListener mInfoButtonListener = new Button.OnClickListener() {
322819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        @Override
323819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        public void onClick(View v) {
324819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            final Handler uiHandler = new Handler();
325819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            AsyncTask.execute(new Runnable() {
326419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                @Override
327819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                public void run() {
328819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                    try {
329b6dca4d979f37748eeb53184a3c3184dbe04d123Eino-Ville Talvala                        mCameraOps.minimalJpegCapture(mCaptureCallback, mCaptureResultListener,
330419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                                uiHandler, mCameraControl);
331819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                        if (mCurrentPreviewHolder != null) {
332d5b98fdbb048b7a94cd8628f13faa4334e2c8bf9Zhijun He                            mCameraOps.minimalPreview(mCurrentPreviewHolder, mCameraControl);
333819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                        }
334819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                    } catch (ApiFailureException e) {
335819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                        logException("Can't take a JPEG! ", e);
336819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                    }
337819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                }
338819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            });
339819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        }
340819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala    };
341819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala
3428704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin    private final Button.OnClickListener mFlushButtonListener = new Button.OnClickListener() {
3438e330563835a9c1011509577382a315466684802Eino-Ville Talvala        @Override
3448e330563835a9c1011509577382a315466684802Eino-Ville Talvala        public void onClick(View v) {
3458e330563835a9c1011509577382a315466684802Eino-Ville Talvala            AsyncTask.execute(new Runnable() {
3468e330563835a9c1011509577382a315466684802Eino-Ville Talvala                @Override
3478e330563835a9c1011509577382a315466684802Eino-Ville Talvala                public void run() {
3488e330563835a9c1011509577382a315466684802Eino-Ville Talvala                    try {
3498e330563835a9c1011509577382a315466684802Eino-Ville Talvala                        mCameraOps.flush();
3508e330563835a9c1011509577382a315466684802Eino-Ville Talvala                    } catch (ApiFailureException e) {
3518e330563835a9c1011509577382a315466684802Eino-Ville Talvala                        logException("Can't flush!", e);
3528e330563835a9c1011509577382a315466684802Eino-Ville Talvala                    }
3538e330563835a9c1011509577382a315466684802Eino-Ville Talvala                }
3548e330563835a9c1011509577382a315466684802Eino-Ville Talvala            });
3558e330563835a9c1011509577382a315466684802Eino-Ville Talvala        }
3568e330563835a9c1011509577382a315466684802Eino-Ville Talvala    };
3578e330563835a9c1011509577382a315466684802Eino-Ville Talvala
358419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    /**
359419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He     * UI controls enable/disable for all manual controls
360419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He     */
361419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    private void enableManualControls(boolean enabled) {
362419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        for (View v : mManualControls) {
363419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            v.setEnabled(enabled);
364419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        }
3658704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
3668704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        for (View v : mAutoControls) {
3678704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            v.setEnabled(!enabled);
3688704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        }
369419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    }
370419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
371b6dca4d979f37748eeb53184a3c3184dbe04d123Eino-Ville Talvala    private final CameraOps.CaptureCallback mCaptureCallback = new CameraOps.CaptureCallback() {
372419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        @Override
373819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        public void onCaptureAvailable(Image capture) {
374819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            if (capture.getFormat() != ImageFormat.JPEG) {
375819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                Log.e(TAG, "Unexpected format: " + capture.getFormat());
376819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala                return;
377819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            }
378819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            ByteBuffer jpegBuffer = capture.getPlanes()[0].getBuffer();
379819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            byte[] jpegData = new byte[jpegBuffer.capacity()];
380819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            jpegBuffer.get(jpegData);
381819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala
382819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            Bitmap b = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
383819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala            mStillView.setImageBitmap(b);
384819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala        }
385819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala    };
386819a53c75fac8f13b1a01eadf50f36e81f8bf164Eino-Ville Talvala
387419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    // TODO: this callback is not called for each capture, need figure out why.
3880e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private final CameraOps.CaptureResultListener mCaptureResultListener =
389419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            new CameraOps.CaptureResultListener() {
390419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
391419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                @Override
3925345b93fd44823f695794ab4a7cceb23a82d8f17Eino-Ville Talvala                public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
393aba26d0b61ece36e969dae46bd4302c5e48a4cddEino-Ville Talvala                        long timestamp, long frameNumber) {
394a04e462a07854595122f19b1df9f19c78e5dc030Eino-Ville Talvala                }
395a04e462a07854595122f19b1df9f19c78e5dc030Eino-Ville Talvala
396a04e462a07854595122f19b1df9f19c78e5dc030Eino-Ville Talvala                @Override
397a04e462a07854595122f19b1df9f19c78e5dc030Eino-Ville Talvala                public void onCaptureCompleted(
3985345b93fd44823f695794ab4a7cceb23a82d8f17Eino-Ville Talvala                        CameraCaptureSession session, CaptureRequest request,
3995345b93fd44823f695794ab4a7cceb23a82d8f17Eino-Ville Talvala                        TotalCaptureResult result) {
400419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    Log.i(TAG, "Capture result is available");
40115b81b00441923ad495120c75eabc6b6ba5c89c3Eino-Ville Talvala                    Integer reqCtrlMode;
40215b81b00441923ad495120c75eabc6b6ba5c89c3Eino-Ville Talvala                    Integer resCtrlMode;
403419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    if (request == null || result ==null) {
404419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                        Log.e(TAG, "request/result is invalid");
405419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                        return;
406419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    }
407419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    Log.i(TAG, "Capture complete");
408419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    final StringBuffer info = new StringBuffer("Capture Result:\n");
40915b81b00441923ad495120c75eabc6b6ba5c89c3Eino-Ville Talvala
4105b4dd6ff9eb56d1e859613cdf1dfe94fb2236a53Eino-Ville Talvala                    reqCtrlMode = request.get(CaptureRequest.CONTROL_MODE);
4115b4dd6ff9eb56d1e859613cdf1dfe94fb2236a53Eino-Ville Talvala                    resCtrlMode = result.get(CaptureResult.CONTROL_MODE);
412419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    info.append("Control mode: request " + reqCtrlMode + ". result " + resCtrlMode);
413419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    info.append("\n");
414419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
41515b81b00441923ad495120c75eabc6b6ba5c89c3Eino-Ville Talvala                    Integer reqSen = request.get(CaptureRequest.SENSOR_SENSITIVITY);
41615b81b00441923ad495120c75eabc6b6ba5c89c3Eino-Ville Talvala                    Integer resSen = result.get(CaptureResult.SENSOR_SENSITIVITY);
417419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    info.append("Sensitivity: request " + reqSen + ". result " + resSen);
418419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    info.append("\n");
419419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
42015b81b00441923ad495120c75eabc6b6ba5c89c3Eino-Ville Talvala                    Long reqExp = request.get(CaptureRequest.SENSOR_EXPOSURE_TIME);
42115b81b00441923ad495120c75eabc6b6ba5c89c3Eino-Ville Talvala                    Long resExp = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
422419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    info.append("Exposure: request " + reqExp + ". result " + resExp);
423419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    info.append("\n");
424419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
42515b81b00441923ad495120c75eabc6b6ba5c89c3Eino-Ville Talvala                    Long reqFD = request.get(CaptureRequest.SENSOR_FRAME_DURATION);
42615b81b00441923ad495120c75eabc6b6ba5c89c3Eino-Ville Talvala                    Long resFD = result.get(CaptureResult.SENSOR_FRAME_DURATION);
4275b4dd6ff9eb56d1e859613cdf1dfe94fb2236a53Eino-Ville Talvala                    info.append("Frame duration: request " + reqFD + ". result " + resFD);
428419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    info.append("\n");
429419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
430967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin                    List<CaptureResult.Key<?>> resultKeys = result.getKeys();
431967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin                    if (VERBOSE) {
432967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin                        CaptureResult.Key<?>[] arrayKeys =
433967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin                                resultKeys.toArray(new CaptureResult.Key<?>[0]);
434967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin                        Log.v(TAG, "onCaptureCompleted - dumping keys: " +
435967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin                                Arrays.toString(arrayKeys));
436967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin                    }
437967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin                    info.append("Total keys: " + resultKeys.size());
438967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin                    info.append("\n");
439967ea9a1e5d76c7908d5307c0cc1f46aae2b40aaIgor Murashkin
440419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    if (mMainHandler != null) {
441419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                        mMainHandler.post (new Runnable() {
442419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                            @Override
443419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                            public void run() {
444419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                                // Update UI for capture result
445419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                                mCaptureResultView.setText(info);
446419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                            }
447419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                        });
448419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    }
449419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                }
450419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
451419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                @Override
4525345b93fd44823f695794ab4a7cceb23a82d8f17Eino-Ville Talvala                public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
453dc82bfc6ce14c4989518c2ca49a0f6067768388dIgor Murashkin                        CaptureFailure failure) {
454419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                    Log.e(TAG, "Capture failed");
455419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                }
456419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    };
457419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
458ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    private void logException(String msg, Throwable e) {
459ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala        Log.e(TAG, msg + Log.getStackTraceString(e));
460ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala    }
461419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
4628704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin    private RadioGroup getRadioFmt() {
463f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih      return (RadioGroup)findViewById(R.id.radio_fmt);
464f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih    }
465f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih
466f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih    private int getOutputFormat() {
4678704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        RadioGroup fmt = getRadioFmt();
468f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih        switch (fmt.getCheckedRadioButtonId()) {
469f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih            case R.id.radio_mp4:
470f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih                return MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
471f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih
472f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih            case R.id.radio_webm:
473f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih                return MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
474f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih
475f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih            default:
476f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih                throw new IllegalStateException("Checked button unrecognized.");
477f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih        }
478f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih    }
479f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih
4800e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private final OnSeekBarChangeListener mSensitivitySeekBarListener =
481419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            new OnSeekBarChangeListener() {
482419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
483419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              @Override
484419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
48517b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  Range<Integer> defaultRange = new Range<Integer>(MIN_SENSITIVITY,
48617b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                          MAX_SENSITIVITY);
487d7d287b826fb83916ba526027719eb39a33ec872Igor Murashkin                  CameraCharacteristics properties = mCameraOps.getCameraCharacteristics();
48817b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  Range<Integer> sensitivityRange = properties.get(
489d7d287b826fb83916ba526027719eb39a33ec872Igor Murashkin                          CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
49017b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  if (sensitivityRange == null || sensitivityRange.getLower() > MIN_SENSITIVITY ||
49117b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                          sensitivityRange.getUpper() < MAX_SENSITIVITY) {
492419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                      Log.e(TAG, "unable to get sensitivity range, use default range");
493419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                      sensitivityRange = defaultRange;
494419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  }
49517b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  int min = sensitivityRange.getLower();
49617b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  int max = sensitivityRange.getUpper();
497419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  float progressFactor = progress / (float)mSeekBarMax;
498419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  int curSensitivity = (int) (min + (max - min) * progressFactor);
499419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  curSensitivity = (curSensitivity / STEP_SIZE ) * STEP_SIZE;
5008704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                  mCameraControl.getManualControls().setSensitivity(curSensitivity);
501419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  // Update the sensitivity info
502419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  StringBuffer info = new StringBuffer("Sensitivity(ISO):");
503419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  info.append("" + curSensitivity);
504419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  mSensitivityInfoView.setText(info);
505419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  mCameraOps.updatePreview(mCameraControl);
506419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              }
507419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
508419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              @Override
509419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              public void onStartTrackingTouch(SeekBar seekBar) {
510419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              }
511419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
512419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              @Override
513419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              public void onStopTrackingTouch(SeekBar seekBar) {
514419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              }
515419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    };
516419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
5170e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private final OnSeekBarChangeListener mExposureSeekBarListener =
518419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            new OnSeekBarChangeListener() {
519419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
520419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              @Override
521419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
52217b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  Range<Long> defaultRange = new Range<Long>(MIN_EXPOSURE, MAX_EXPOSURE);
523d7d287b826fb83916ba526027719eb39a33ec872Igor Murashkin                  CameraCharacteristics properties = mCameraOps.getCameraCharacteristics();
52417b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  Range<Long> exposureRange = properties.get(
525d7d287b826fb83916ba526027719eb39a33ec872Igor Murashkin                          CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
526419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  // Not enforce the max value check here, most of the devices don't support
527419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  // larger than 30s exposure time
52817b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  if (exposureRange == null || exposureRange.getLower() > MIN_EXPOSURE ||
52917b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                          exposureRange.getUpper() < 0) {
530419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                      exposureRange = defaultRange;
531419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                      Log.e(TAG, "exposure time range is invalid, use default range");
532419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  }
53317b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  long min = exposureRange.getLower();
53417b37c186563e86d7d2f992bdc73443b4c6e5e80Ruben Brunk                  long max = exposureRange.getUpper();
535419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  float progressFactor = progress / (float)mSeekBarMax;
536419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  long curExposureTime = (long) (min + (max - min) * progressFactor);
5378704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                  mCameraControl.getManualControls().setExposure(curExposureTime);
538419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  // Update the sensitivity info
539419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  StringBuffer info = new StringBuffer("Exposure Time:");
540419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  info.append("" + curExposureTime / 1000000.0 + "ms");
541419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  mExposureInfoView.setText(info);
542419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  mCameraOps.updatePreview(mCameraControl);
543419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              }
544419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
545419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              @Override
546419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              public void onStartTrackingTouch(SeekBar seekBar) {
547419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              }
548419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
549419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              @Override
550419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              public void onStopTrackingTouch(SeekBar seekBar) {
551419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              }
552419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    };
553419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
5540e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private final OnSeekBarChangeListener mFrameDurationSeekBarListener =
555419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            new OnSeekBarChangeListener() {
556419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
557419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              @Override
558419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
559d7d287b826fb83916ba526027719eb39a33ec872Igor Murashkin                  CameraCharacteristics properties = mCameraOps.getCameraCharacteristics();
560419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  Long frameDurationMax = properties.get(
561d7d287b826fb83916ba526027719eb39a33ec872Igor Murashkin                          CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION);
562419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  if (frameDurationMax == null || frameDurationMax <= 0) {
563419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                      frameDurationMax = MAX_FRAME_DURATION;
564419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                      Log.e(TAG, "max frame duration is invalid, set to " + frameDurationMax);
565419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  }
566419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  // Need calculate from different resolution, hard code to 10ms for now.
567419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  long min = 10000000L;
568419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  long max = frameDurationMax;
569419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  float progressFactor = progress / (float)mSeekBarMax;
570419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  long curFrameDuration = (long) (min + (max - min) * progressFactor);
5718704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                  mCameraControl.getManualControls().setFrameDuration(curFrameDuration);
572419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  // Update the sensitivity info
573419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  StringBuffer info = new StringBuffer("Frame Duration:");
574419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  info.append("" + curFrameDuration / 1000000.0 + "ms");
575419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  mFrameDurationInfoView.setText(info);
576419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                  mCameraOps.updatePreview(mCameraControl);
577419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              }
578419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
579419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              @Override
580419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              public void onStartTrackingTouch(SeekBar seekBar) {
581419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              }
582419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
583419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              @Override
584419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              public void onStopTrackingTouch(SeekBar seekBar) {
585419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He              }
586419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    };
587419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
5880e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private final View.OnClickListener mControlToggleListener =
589419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            new View.OnClickListener() {
590419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        @Override
591419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        public void onClick(View v) {
592419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            boolean enableManual;
593419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            if (mManualCtrlToggle.isChecked()) {
594419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                enableManual = true;
595419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            } else {
596419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He                enableManual = false;
597419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            }
5988704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            mCameraControl.getManualControls().setManualControlEnabled(enableManual);
599419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            enableManualControls(enableManual);
600419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            mCameraOps.updatePreview(mCameraControl);
601419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        }
602419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    };
603419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He
6040e50db98503df09a94369445c421c9c6530b9458Igor Murashkin    private final View.OnClickListener mRecordingToggleListener =
605419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            new View.OnClickListener() {
606419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        @Override
607419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        public void onClick(View v) {
608419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            if (mRecordingToggle.isChecked()) {
6099d42c135c172cab66b7eca856cd578ed85d512f6Zhijun He                try {
610be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang                    Log.i(TAG, "start recording, useMediaCodec = " + mUseMediaCodec);
6118704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                    RadioGroup fmt = getRadioFmt();
612f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih                    fmt.setActivated(false);
613f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih                    mCameraOps.startRecording(
614f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih                            /* applicationContext */ TestingCamera2.this,
615f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih                            /* useMediaCodec */ mUseMediaCodec,
616f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih                            /* outputFormat */ getOutputFormat());
6179d42c135c172cab66b7eca856cd578ed85d512f6Zhijun He                } catch (ApiFailureException e) {
6189d42c135c172cab66b7eca856cd578ed85d512f6Zhijun He                    logException("Failed to start recording", e);
6199d42c135c172cab66b7eca856cd578ed85d512f6Zhijun He                }
620419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            } else {
6219d42c135c172cab66b7eca856cd578ed85d512f6Zhijun He                try {
622f3dc34a8f0ae74a9e1cf153aff7bcf31c92bc194Robert Shih                    mCameraOps.stopRecording(TestingCamera2.this);
6238704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                    getRadioFmt().setActivated(true);
6249d42c135c172cab66b7eca856cd578ed85d512f6Zhijun He                } catch (ApiFailureException e) {
6259d42c135c172cab66b7eca856cd578ed85d512f6Zhijun He                    logException("Failed to stop recording", e);
6269d42c135c172cab66b7eca856cd578ed85d512f6Zhijun He                }
627419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He            }
628419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He        }
629419fb8918fcdb643dabc58437bcb0a8026a25604Zhijun He    };
630be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang
6318704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin    private final View.OnClickListener mFocusLockToggleListener =
6328704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            new View.OnClickListener() {
6338704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        @Override
6348704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        public void onClick(View v) {
6358704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            if (VERBOSE) {
6368704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                Log.v(TAG, "focus_lock#onClick - start");
6378704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            }
6388704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6398704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            CameraAutoFocusControls afControls = mCameraControl.getAfControls();
6408704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6418704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            if (mFocusLockToggle.isChecked()) {
6428704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                Log.i(TAG, "lock focus");
6438704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6448704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                afControls.setPendingTriggerStart();
6458704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            } else {
6468704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                Log.i(TAG, "unlock focus");
6478704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6488704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                afControls.setPendingTriggerCancel();
6498704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            }
6508704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6518704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            mCameraOps.updatePreview(mCameraControl);
6528704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6538704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            if (VERBOSE) {
6548704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                Log.v(TAG, "focus_lock#onClick - end");
6558704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            }
6568704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        }
6578704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin    };
6588704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
659be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang    private final CompoundButton.OnCheckedChangeListener mUseMediaCodecListener =
660be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang            new CompoundButton.OnCheckedChangeListener() {
661be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        @Override
662be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
663be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang            mUseMediaCodec = isChecked;
664be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang        }
665be9ee01b4c6f1660b9f0cbfdcb2ea57335e5394cChong Zhang    };
6668704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6678704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin    private final CameraOps.Listener mCameraOpsListener = new CameraOps.Listener() {
6688704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        @Override
6698704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        public void onCameraOpened(String cameraId, CameraCharacteristics characteristics) {
6708704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            /*
6718704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin             * Populate dynamic per-camera settings
6728704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin             */
6738704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6748704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            // Map available AF Modes -> AF mode spinner dropdown list of strings
6758704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            int[] availableAfModes =
6768704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                    characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
6778704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6788704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            String[] allAfModes = getResources().getStringArray(R.array.focus_mode_spinner_arrays);
6798704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6808704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            final List<String> afModeList = new ArrayList<>();
6818704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            final int[] afModePositions = new int[availableAfModes.length];
6828704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6838704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            int i = 0;
6848704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            for (int mode : availableAfModes) {
6858704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                afModeList.add(allAfModes[mode]);
6868704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                afModePositions[i++] = mode;
6878704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            }
6888704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6898704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            ArrayAdapter<String> dataAdapter = new ArrayAdapter<>(TestingCamera2.this,
6908704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                    android.R.layout.simple_spinner_item, afModeList);
6918704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
6928704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            mFocusModeSpinner.setAdapter(dataAdapter);
6938704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6948704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            /*
6958704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin             * Change the AF mode and update preview when AF spinner's selected item changes
6968704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin             */
6978704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            mFocusModeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
6988704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
6998704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                @Override
7008704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                public void onItemSelected(AdapterView<?> parent, View view, int position,
7018704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                        long id) {
7028704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                    int afMode = afModePositions[position];
7038704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
7048704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                    Log.i(TAG, "Change auto-focus mode to " + afModeList.get(position)
7058704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                            + " " + afMode);
7068704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
7078704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                    mCameraControl.getAfControls().setAfMode(afMode);
7088704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
7098704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                    mCameraOps.updatePreview(mCameraControl);
7108704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                }
7118704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin
7128704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                @Override
7138704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                public void onNothingSelected(AdapterView<?> parent) {
7148704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                    // Do nothing
7158704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin                }
7168704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin            });
7178704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin        }
7188704abb0e447c24f1d8599a71e9446f7521b9e1eIgor Murashkin    };
719ccdcb50e3b688be8c4a11d7c827e7ac9bbb2f1d5Eino-Ville Talvala}
720