blob: 8ea709141c5d35f954a6aede5759bba6870aecde [file] [log] [blame]
Doris Liu6827ce22013-03-12 19:24:28 -07001/*
Doris Liu6432cd62013-06-13 17:20:31 -07002 * Copyright (C) 2012 The Android Open Source Project
Doris Liu6827ce22013-03-12 19:24:28 -07003 *
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.camera;
18
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +053019import android.content.res.Configuration;
Doris Liu6827ce22013-03-12 19:24:28 -070020import android.graphics.Bitmap;
Doris Liuc3679c02013-08-08 18:08:43 -070021import android.graphics.Color;
Doris Liu6432cd62013-06-13 17:20:31 -070022import android.graphics.Matrix;
23import android.graphics.SurfaceTexture;
Doris Liuc3679c02013-08-08 18:08:43 -070024import android.graphics.drawable.ColorDrawable;
Doris Liu6827ce22013-03-12 19:24:28 -070025import android.hardware.Camera.Parameters;
Doris Liu6432cd62013-06-13 17:20:31 -070026import android.os.Handler;
27import android.os.Message;
Doris Liu6827ce22013-03-12 19:24:28 -070028import android.util.Log;
29import android.view.Gravity;
Doris Liu6827ce22013-03-12 19:24:28 -070030import android.view.SurfaceHolder;
Doris Liu6432cd62013-06-13 17:20:31 -070031import android.view.SurfaceView;
32import android.view.TextureView;
33import android.view.TextureView.SurfaceTextureListener;
Doris Liu6827ce22013-03-12 19:24:28 -070034import android.view.View;
35import android.view.View.OnClickListener;
Doris Liu6432cd62013-06-13 17:20:31 -070036import android.view.View.OnLayoutChangeListener;
Doris Liu6827ce22013-03-12 19:24:28 -070037import android.view.ViewGroup;
Doris Liu6827ce22013-03-12 19:24:28 -070038import android.widget.FrameLayout.LayoutParams;
39import android.widget.ImageView;
40import android.widget.LinearLayout;
Doris Liuc3679c02013-08-08 18:08:43 -070041import android.widget.PopupWindow;
Doris Liu6827ce22013-03-12 19:24:28 -070042import android.widget.TextView;
43
44import com.android.camera.CameraPreference.OnPreferenceChangedListener;
45import com.android.camera.ui.AbstractSettingPopup;
Doris Liu6432cd62013-06-13 17:20:31 -070046import com.android.camera.ui.CameraControls;
47import com.android.camera.ui.CameraRootView;
Angus Konged15d1a2013-08-19 15:06:12 -070048import com.android.camera.ui.ModuleSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070049import com.android.camera.ui.PieRenderer;
Doris Liu6827ce22013-03-12 19:24:28 -070050import com.android.camera.ui.RenderOverlay;
51import com.android.camera.ui.RotateLayout;
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +053052import com.android.camera.PauseButton.OnPauseButtonListener;
Doris Liu6827ce22013-03-12 19:24:28 -070053import com.android.camera.ui.ZoomRenderer;
Angus Kongb50b5cb2013-08-09 14:55:20 -070054import com.android.camera.util.CameraUtil;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070055import com.android.camera2.R;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070056
57import java.util.List;
Doris Liu6827ce22013-03-12 19:24:28 -070058
Doris Liu6432cd62013-06-13 17:20:31 -070059public class VideoUI implements PieRenderer.PieListener,
Michael Kolb3bc96b22013-03-12 10:24:42 -070060 PreviewGestures.SingleTapListener,
Doris Liu6432cd62013-06-13 17:20:31 -070061 CameraRootView.MyDisplayListener,
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +053062 SurfaceTextureListener, SurfaceHolder.Callback,
63 PauseButton.OnPauseButtonListener {
Angus Kong395ee2d2013-07-15 12:42:41 -070064 private static final String TAG = "CAM_VideoUI";
Doris Liu6432cd62013-06-13 17:20:31 -070065 private static final int UPDATE_TRANSFORM_MATRIX = 1;
Doris Liu6827ce22013-03-12 19:24:28 -070066 // module fields
67 private CameraActivity mActivity;
68 private View mRootView;
Doris Liu6432cd62013-06-13 17:20:31 -070069 private TextureView mTextureView;
Doris Liu6827ce22013-03-12 19:24:28 -070070 // An review image having same size as preview. It is displayed when
71 // recording is stopped in capture intent.
72 private ImageView mReviewImage;
73 private View mReviewCancelButton;
74 private View mReviewDoneButton;
75 private View mReviewPlayButton;
76 private ShutterButton mShutterButton;
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +053077 private PauseButton mPauseButton;
Angus Konged15d1a2013-08-19 15:06:12 -070078 private ModuleSwitcher mSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070079 private TextView mRecordingTimeView;
80 private LinearLayout mLabelsLinearLayout;
81 private View mTimeLapseLabel;
82 private RenderOverlay mRenderOverlay;
83 private PieRenderer mPieRenderer;
84 private VideoMenu mVideoMenu;
Doris Liu6432cd62013-06-13 17:20:31 -070085 private CameraControls mCameraControls;
Doris Liuc3679c02013-08-08 18:08:43 -070086 private SettingsPopup mPopup;
Doris Liu6827ce22013-03-12 19:24:28 -070087 private ZoomRenderer mZoomRenderer;
88 private PreviewGestures mGestures;
Doris Liu6432cd62013-06-13 17:20:31 -070089 private View mMenuButton;
Sascha Haeberling140c2632013-04-23 09:58:51 -070090 private OnScreenIndicators mOnScreenIndicators;
Doris Liu6827ce22013-03-12 19:24:28 -070091 private RotateLayout mRecordingTimeRect;
Doris Liufe6596c2013-10-08 11:03:37 -070092 private boolean mRecordingStarted = false;
Doris Liu6432cd62013-06-13 17:20:31 -070093 private SurfaceTexture mSurfaceTexture;
Doris Liu6827ce22013-03-12 19:24:28 -070094 private VideoController mController;
95 private int mZoomMax;
96 private List<Integer> mZoomRatios;
Sascha Haeberling4f91ab52013-05-21 11:26:13 -070097 private View mPreviewThumb;
Sascha Haeberling37f36112013-08-06 14:31:52 -070098 private View mFlashOverlay;
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +053099 private boolean mOrientationResize;
100 private boolean mPrevOrientationResize;
Doris Liu6827ce22013-03-12 19:24:28 -0700101
Doris Liu3a45c332013-10-15 19:10:28 -0700102 private View mPreviewCover;
Doris Liu6432cd62013-06-13 17:20:31 -0700103 private SurfaceView mSurfaceView = null;
104 private int mPreviewWidth = 0;
105 private int mPreviewHeight = 0;
106 private float mSurfaceTextureUncroppedWidth;
107 private float mSurfaceTextureUncroppedHeight;
108 private float mAspectRatio = 4f / 3f;
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530109 private boolean mAspectRatioResize;
Doris Liu6432cd62013-06-13 17:20:31 -0700110 private Matrix mMatrix = null;
Sascha Haeberling37f36112013-08-06 14:31:52 -0700111 private final AnimationManager mAnimationManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700112 private final Handler mHandler = new Handler() {
113 @Override
114 public void handleMessage(Message msg) {
115 switch (msg.what) {
116 case UPDATE_TRANSFORM_MATRIX:
117 setTransformMatrix(mPreviewWidth, mPreviewHeight);
118 break;
119 default:
120 break;
121 }
122 }
123 };
124 private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
125 @Override
126 public void onLayoutChange(View v, int left, int top, int right,
127 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
128 int width = right - left;
129 int height = bottom - top;
130 // Full-screen screennail
131 int w = width;
132 int h = height;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700133 if (CameraUtil.getDisplayRotation(mActivity) % 180 != 0) {
Doris Liu6432cd62013-06-13 17:20:31 -0700134 w = height;
135 h = width;
136 }
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530137 if (mPreviewWidth != width || mPreviewHeight != height
138 || (mOrientationResize != mPrevOrientationResize)
139 || (mAspectRatioResize)) {
Doris Liu6432cd62013-06-13 17:20:31 -0700140 mPreviewWidth = width;
141 mPreviewHeight = height;
142 onScreenSizeChanged(width, height, w, h);
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530143 mAspectRatioResize = false;
Doris Liu6432cd62013-06-13 17:20:31 -0700144 }
145 }
146 };
147
Doris Liu3a45c332013-10-15 19:10:28 -0700148 public void showPreviewCover() {
149 mPreviewCover.setVisibility(View.VISIBLE);
150 }
151
Doris Liuc3679c02013-08-08 18:08:43 -0700152 private class SettingsPopup extends PopupWindow {
153 public SettingsPopup(View popup) {
154 super(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
155 setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
156 setOutsideTouchable(true);
157 setFocusable(true);
158 popup.setVisibility(View.VISIBLE);
159 setContentView(popup);
160 showAtLocation(mRootView, Gravity.CENTER, 0, 0);
161 }
162
163 public void dismiss(boolean topLevelOnly) {
164 super.dismiss();
165 popupDismissed();
166 showUI();
167 mVideoMenu.popupDismissed(topLevelOnly);
Sascha Haeberling4ec139d2013-10-09 23:46:20 -0700168
169 // Switch back into fullscreen/lights-out mode after popup
170 // is dimissed.
171 mActivity.setSystemBarsVisibility(false);
Doris Liuc3679c02013-08-08 18:08:43 -0700172 }
173
174 @Override
175 public void dismiss() {
176 // Called by Framework when touch outside the popup or hit back key
177 dismiss(true);
178 }
179 }
180
Doris Liu6827ce22013-03-12 19:24:28 -0700181 public VideoUI(CameraActivity activity, VideoController controller, View parent) {
182 mActivity = activity;
183 mController = controller;
184 mRootView = parent;
185 mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true);
Doris Liu3a45c332013-10-15 19:10:28 -0700186 mPreviewCover = mRootView.findViewById(R.id.preview_cover);
Doris Liu6432cd62013-06-13 17:20:31 -0700187 mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content);
188 mTextureView.setSurfaceTextureListener(this);
Doris Liubdd198e2013-08-29 18:06:45 -0700189 mTextureView.addOnLayoutChangeListener(mLayoutListener);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700190 mFlashOverlay = mRootView.findViewById(R.id.flash_overlay);
Doris Liu6432cd62013-06-13 17:20:31 -0700191 mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
Angus Konged15d1a2013-08-19 15:06:12 -0700192 mSwitcher = (ModuleSwitcher) mRootView.findViewById(R.id.camera_switcher);
193 mSwitcher.setCurrentIndex(ModuleSwitcher.VIDEO_MODULE_INDEX);
194 mSwitcher.setSwitchListener(mActivity);
Doris Liu6827ce22013-03-12 19:24:28 -0700195 initializeMiscControls();
196 initializeControlByIntent();
197 initializeOverlay();
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +0530198 initializePauseButton();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700199 mAnimationManager = new AnimationManager();
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530200 mOrientationResize = false;
201 mPrevOrientationResize = false;
Doris Liu6827ce22013-03-12 19:24:28 -0700202 }
203
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530204 public void cameraOrientationPreviewResize(boolean orientation){
205 mPrevOrientationResize = mOrientationResize;
206 mOrientationResize = orientation;
207 }
Doris Liu6432cd62013-06-13 17:20:31 -0700208
209 public void initializeSurfaceView() {
210 mSurfaceView = new SurfaceView(mActivity);
211 ((ViewGroup) mRootView).addView(mSurfaceView, 0);
212 mSurfaceView.getHolder().addCallback(this);
213 }
214
Doris Liu6827ce22013-03-12 19:24:28 -0700215 private void initializeControlByIntent() {
Doris Liu2a7f44c2013-08-12 15:18:53 -0700216 mMenuButton = mRootView.findViewById(R.id.menu);
Doris Liu6432cd62013-06-13 17:20:31 -0700217 mMenuButton.setOnClickListener(new OnClickListener() {
Doris Liu6827ce22013-03-12 19:24:28 -0700218 @Override
219 public void onClick(View v) {
220 if (mPieRenderer != null) {
221 mPieRenderer.showInCenter();
222 }
223 }
224 });
Doris Liu6432cd62013-06-13 17:20:31 -0700225
Doris Liu2a7f44c2013-08-12 15:18:53 -0700226 mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls);
Michael Kolbeb8adc12013-04-26 11:09:29 -0700227 mOnScreenIndicators = new OnScreenIndicators(mActivity,
Doris Liu2a7f44c2013-08-12 15:18:53 -0700228 mRootView.findViewById(R.id.on_screen_indicators));
Sascha Haeberling140c2632013-04-23 09:58:51 -0700229 mOnScreenIndicators.resetToDefault();
Doris Liu6827ce22013-03-12 19:24:28 -0700230 if (mController.isVideoCaptureIntent()) {
Doris Liu6432cd62013-06-13 17:20:31 -0700231 hideSwitcher();
232 mActivity.getLayoutInflater().inflate(R.layout.review_module_control,
233 (ViewGroup) mCameraControls);
Doris Liu6827ce22013-03-12 19:24:28 -0700234 // Cannot use RotateImageView for "done" and "cancel" button because
235 // the tablet layout uses RotateLayout, which cannot be cast to
236 // RotateImageView.
Doris Liu2a7f44c2013-08-12 15:18:53 -0700237 mReviewDoneButton = mRootView.findViewById(R.id.btn_done);
238 mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel);
239 mReviewPlayButton = mRootView.findViewById(R.id.btn_play);
Doris Liu6827ce22013-03-12 19:24:28 -0700240 mReviewCancelButton.setVisibility(View.VISIBLE);
241 mReviewDoneButton.setOnClickListener(new OnClickListener() {
242 @Override
243 public void onClick(View v) {
244 mController.onReviewDoneClicked(v);
245 }
246 });
247 mReviewCancelButton.setOnClickListener(new OnClickListener() {
248 @Override
249 public void onClick(View v) {
250 mController.onReviewCancelClicked(v);
251 }
252 });
253 mReviewPlayButton.setOnClickListener(new OnClickListener() {
254 @Override
255 public void onClick(View v) {
256 mController.onReviewPlayClicked(v);
257 }
258 });
259 }
260 }
261
Doris Liu6432cd62013-06-13 17:20:31 -0700262 public void setPreviewSize(int width, int height) {
263 if (width == 0 || height == 0) {
264 Log.w(TAG, "Preview size should not be 0.");
265 return;
266 }
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530267 float ratio;
Doris Liu6432cd62013-06-13 17:20:31 -0700268 if (width > height) {
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530269 ratio = (float) width / height;
Doris Liu6432cd62013-06-13 17:20:31 -0700270 } else {
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530271 ratio = (float) height / width;
272 }
273 if (mOrientationResize &&
274 mActivity.getResources().getConfiguration().orientation
275 != Configuration.ORIENTATION_PORTRAIT) {
276 ratio = 1 / ratio;
277 }
278
279 if (ratio != mAspectRatio){
280 mAspectRatioResize = true;
281 mAspectRatio = ratio;
Doris Liu6432cd62013-06-13 17:20:31 -0700282 }
283 mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX);
284 }
285
286 public int getPreviewWidth() {
287 return mPreviewWidth;
288 }
289
290 public int getPreviewHeight() {
291 return mPreviewHeight;
292 }
293
294 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
295 setTransformMatrix(width, height);
296 }
297
298 private void setTransformMatrix(int width, int height) {
299 mMatrix = mTextureView.getTransform(mMatrix);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700300 int orientation = CameraUtil.getDisplayRotation(mActivity);
Doris Liu6432cd62013-06-13 17:20:31 -0700301 float scaleX = 1f, scaleY = 1f;
302 float scaledTextureWidth, scaledTextureHeight;
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530303 if (mOrientationResize){
304 if (width/mAspectRatio > height){
305 scaledTextureHeight = height;
306 scaledTextureWidth = (int)(height * mAspectRatio + 0.5f);
307 } else {
308 scaledTextureWidth = width;
309 scaledTextureHeight = (int)(width / mAspectRatio + 0.5f);
310 }
Doris Liu6432cd62013-06-13 17:20:31 -0700311 } else {
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530312 if (width > height) {
313 scaledTextureWidth = Math.max(width,
314 (int) (height * mAspectRatio));
315 scaledTextureHeight = Math.max(height,
316 (int)(width / mAspectRatio));
317 } else {
318 scaledTextureWidth = Math.max(width,
319 (int) (height / mAspectRatio));
320 scaledTextureHeight = Math.max(height,
321 (int) (width * mAspectRatio));
322 }
Doris Liu6432cd62013-06-13 17:20:31 -0700323 }
324
325 if (mSurfaceTextureUncroppedWidth != scaledTextureWidth ||
326 mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
327 mSurfaceTextureUncroppedWidth = scaledTextureWidth;
328 mSurfaceTextureUncroppedHeight = scaledTextureHeight;
329 }
330 scaleX = scaledTextureWidth / width;
331 scaleY = scaledTextureHeight / height;
332 mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2);
333 mTextureView.setTransform(mMatrix);
334
335 if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) {
336 LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams();
337 lp.width = (int) mSurfaceTextureUncroppedWidth;
338 lp.height = (int) mSurfaceTextureUncroppedHeight;
339 lp.gravity = Gravity.CENTER;
340 mSurfaceView.requestLayout();
341 }
342 }
343
Sascha Haeberling37f36112013-08-06 14:31:52 -0700344 /**
345 * Starts a flash animation
346 */
347 public void animateFlash() {
348 mAnimationManager.startFlashAnimation(mFlashOverlay);
349 }
350
351 /**
352 * Starts a capture animation
Doris Liu3973deb2013-08-21 13:42:22 -0700353 */
354 public void animateCapture() {
355 Bitmap bitmap = null;
356 if (mTextureView != null) {
357 bitmap = mTextureView.getBitmap((int) mSurfaceTextureUncroppedWidth / 2,
358 (int) mSurfaceTextureUncroppedHeight / 2);
359 }
360 animateCapture(bitmap);
361 }
362
363 /**
364 * Starts a capture animation
Sascha Haeberling37f36112013-08-06 14:31:52 -0700365 * @param bitmap the captured image that we shrink and slide in the animation
366 */
367 public void animateCapture(Bitmap bitmap) {
Doris Liu3973deb2013-08-21 13:42:22 -0700368 if (bitmap == null) {
369 Log.e(TAG, "No valid bitmap for capture animation.");
370 return;
371 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700372 ((ImageView) mPreviewThumb).setImageBitmap(bitmap);
373 mAnimationManager.startCaptureAnimation(mPreviewThumb);
374 }
375
376 /**
377 * Cancels on-going animations
378 */
379 public void cancelAnimations() {
380 mAnimationManager.cancelAnimations();
381 }
382
Doris Liu6432cd62013-06-13 17:20:31 -0700383 public void hideUI() {
384 mCameraControls.setVisibility(View.INVISIBLE);
385 mSwitcher.closePopup();
386 }
387
388 public void showUI() {
389 mCameraControls.setVisibility(View.VISIBLE);
390 }
391
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700392 public boolean arePreviewControlsVisible() {
393 return (mCameraControls.getVisibility() == View.VISIBLE);
394 }
395
Doris Liu6432cd62013-06-13 17:20:31 -0700396 public void hideSwitcher() {
397 mSwitcher.closePopup();
398 mSwitcher.setVisibility(View.INVISIBLE);
399 }
400
401 public void showSwitcher() {
402 mSwitcher.setVisibility(View.VISIBLE);
403 }
404
Doris Liu6827ce22013-03-12 19:24:28 -0700405 public boolean collapseCameraControls() {
406 boolean ret = false;
407 if (mPopup != null) {
408 dismissPopup(false);
409 ret = true;
410 }
411 return ret;
412 }
413
414 public boolean removeTopLevelPopup() {
415 if (mPopup != null) {
416 dismissPopup(true);
417 return true;
418 }
419 return false;
420 }
421
422 public void enableCameraControls(boolean enable) {
423 if (mGestures != null) {
424 mGestures.setZoomOnly(!enable);
425 }
426 if (mPieRenderer != null && mPieRenderer.showsItems()) {
427 mPieRenderer.hide();
428 }
429 }
430
Doris Liu59390062013-10-10 17:20:56 -0700431 public void initDisplayChangeListener() {
432 ((CameraRootView) mRootView).setDisplayChangeListener(this);
433 }
434
435 public void removeDisplayChangeListener() {
436 ((CameraRootView) mRootView).removeDisplayChangeListener();
437 }
438
Doris Liu6827ce22013-03-12 19:24:28 -0700439 public void overrideSettings(final String... keyvalues) {
440 mVideoMenu.overrideSettings(keyvalues);
441 }
442
Doris Liu6827ce22013-03-12 19:24:28 -0700443 public void setOrientationIndicator(int orientation, boolean animation) {
Doris Liu6827ce22013-03-12 19:24:28 -0700444 // We change the orientation of the linearlayout only for phone UI
445 // because when in portrait the width is not enough.
446 if (mLabelsLinearLayout != null) {
447 if (((orientation / 90) & 1) == 0) {
448 mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL);
449 } else {
450 mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
451 }
452 }
453 mRecordingTimeRect.setOrientation(0, animation);
454 }
455
456 public SurfaceHolder getSurfaceHolder() {
Doris Liu6432cd62013-06-13 17:20:31 -0700457 return mSurfaceView.getHolder();
Doris Liu6827ce22013-03-12 19:24:28 -0700458 }
459
460 public void hideSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700461 mSurfaceView.setVisibility(View.GONE);
462 mTextureView.setVisibility(View.VISIBLE);
463 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700464 }
465
466 public void showSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700467 mSurfaceView.setVisibility(View.VISIBLE);
468 mTextureView.setVisibility(View.GONE);
469 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700470 }
471
472 private void initializeOverlay() {
473 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
474 if (mPieRenderer == null) {
475 mPieRenderer = new PieRenderer(mActivity);
476 mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer);
477 mPieRenderer.setPieListener(this);
478 }
479 mRenderOverlay.addRenderer(mPieRenderer);
480 if (mZoomRenderer == null) {
481 mZoomRenderer = new ZoomRenderer(mActivity);
482 }
483 mRenderOverlay.addRenderer(mZoomRenderer);
484 if (mGestures == null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700485 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
486 mRenderOverlay.setGestures(mGestures);
Doris Liu6827ce22013-03-12 19:24:28 -0700487 }
488 mGestures.setRenderOverlay(mRenderOverlay);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700489
Doris Liu2a7f44c2013-08-12 15:18:53 -0700490 mPreviewThumb = mRootView.findViewById(R.id.preview_thumb);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700491 mPreviewThumb.setOnClickListener(new OnClickListener() {
492 @Override
493 public void onClick(View v) {
Doris Liufe6596c2013-10-08 11:03:37 -0700494 // Do not allow navigation to filmstrip during video recording
495 if (!mRecordingStarted) {
496 mActivity.gotoGallery();
497 }
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700498 }
499 });
Doris Liu6827ce22013-03-12 19:24:28 -0700500 }
501
502 public void setPrefChangedListener(OnPreferenceChangedListener listener) {
503 mVideoMenu.setListener(listener);
504 }
505
506 private void initializeMiscControls() {
Doris Liu6827ce22013-03-12 19:24:28 -0700507 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
Doris Liu6827ce22013-03-12 19:24:28 -0700508 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
509 mShutterButton.setOnShutterButtonListener(mController);
510 mShutterButton.setVisibility(View.VISIBLE);
511 mShutterButton.requestFocus();
512 mShutterButton.enableTouch(true);
513 mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
514 mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
515 mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
516 // The R.id.labels can only be found in phone layout.
517 // That is, mLabelsLinearLayout should be null in tablet layout.
518 mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
519 }
520
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +0530521 private void initializePauseButton() {
522 mPauseButton = (PauseButton) mRootView.findViewById(R.id.video_pause);
523 mPauseButton.setOnPauseButtonListener(this);
524 }
525
Michael Kolb87880792013-04-30 15:38:49 -0700526 public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) {
Sascha Haeberling140c2632013-04-23 09:58:51 -0700527 mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode());
Michael Kolb87880792013-04-30 15:38:49 -0700528 boolean location = RecordLocationPreference.get(
529 prefs, mActivity.getContentResolver());
530 mOnScreenIndicators.updateLocationIndicator(location);
531
Doris Liu6827ce22013-03-12 19:24:28 -0700532 }
533
534 public void setAspectRatio(double ratio) {
Santhosh Kumar H E6bc53a12013-10-25 13:14:10 +0530535 if (mOrientationResize &&
536 mActivity.getResources().getConfiguration().orientation
537 != Configuration.ORIENTATION_PORTRAIT) {
538 ratio = 1 / ratio;
539 }
540
541 if (ratio != mAspectRatio){
542 mAspectRatioResize = true;
543 mAspectRatio = (float)ratio;
544 }
545 mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX);
546
Doris Liu6827ce22013-03-12 19:24:28 -0700547 }
548
549 public void showTimeLapseUI(boolean enable) {
550 if (mTimeLapseLabel != null) {
551 mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
552 }
553 }
554
Michael Kolb3bc96b22013-03-12 10:24:42 -0700555 private void openMenu() {
556 if (mPieRenderer != null) {
557 mPieRenderer.showInCenter();
558 }
559 }
560
Doris Liu6827ce22013-03-12 19:24:28 -0700561 public void dismissPopup(boolean topLevelOnly) {
Doris Liu69ef5ea2013-05-07 13:48:10 -0700562 // In review mode, we do not want to bring up the camera UI
563 if (mController.isInReviewMode()) return;
Doris Liu6827ce22013-03-12 19:24:28 -0700564 if (mPopup != null) {
Doris Liuc3679c02013-08-08 18:08:43 -0700565 mPopup.dismiss(topLevelOnly);
Doris Liu6827ce22013-03-12 19:24:28 -0700566 }
Doris Liuc3679c02013-08-08 18:08:43 -0700567 }
568
569 private void popupDismissed() {
570 mPopup = null;
571 }
572
573 public void showPopup(AbstractSettingPopup popup) {
574 hideUI();
575
576 if (mPopup != null) {
577 mPopup.dismiss(false);
578 }
579 mPopup = new SettingsPopup(popup);
Doris Liu6827ce22013-03-12 19:24:28 -0700580 }
581
582 public void onShowSwitcherPopup() {
583 hidePieRenderer();
584 }
585
586 public boolean hidePieRenderer() {
587 if (mPieRenderer != null && mPieRenderer.showsItems()) {
588 mPieRenderer.hide();
589 return true;
590 }
591 return false;
592 }
593
Doris Liu61f2b082013-03-27 17:25:43 -0700594 // disable preview gestures after shutter is pressed
595 public void setShutterPressed(boolean pressed) {
596 if (mGestures == null) return;
597 mGestures.setEnabled(!pressed);
598 }
599
Doris Liu6827ce22013-03-12 19:24:28 -0700600 public void enableShutter(boolean enable) {
601 if (mShutterButton != null) {
602 mShutterButton.setEnabled(enable);
603 }
604 }
605
606 // PieListener
607 @Override
608 public void onPieOpened(int centerX, int centerY) {
Doris Liu6432cd62013-06-13 17:20:31 -0700609 setSwipingEnabled(false);
Andy Huibers249653e2013-11-11 22:30:49 -0800610 // Close module selection menu when pie menu is opened.
611 mSwitcher.closePopup();
Doris Liu6827ce22013-03-12 19:24:28 -0700612 }
613
614 @Override
615 public void onPieClosed() {
Doris Liu6432cd62013-06-13 17:20:31 -0700616 setSwipingEnabled(true);
617 }
618
619 public void setSwipingEnabled(boolean enable) {
620 mActivity.setSwipingEnabled(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700621 }
622
623 public void showPreviewBorder(boolean enable) {
Doris Liu6432cd62013-06-13 17:20:31 -0700624 // TODO: mPreviewFrameLayout.showBorder(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700625 }
626
627 // SingleTapListener
628 // Preview area is touched. Take a picture.
629 @Override
630 public void onSingleTapUp(View view, int x, int y) {
631 mController.onSingleTapUp(view, x, y);
632 }
633
Doris Liufe6596c2013-10-08 11:03:37 -0700634 public void showRecordingUI(boolean recording) {
635 mRecordingStarted = recording;
Doris Liu6432cd62013-06-13 17:20:31 -0700636 mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700637 mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
638 if (recording) {
639 mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording);
Doris Liu6432cd62013-06-13 17:20:31 -0700640 hideSwitcher();
Doris Liu6827ce22013-03-12 19:24:28 -0700641 mRecordingTimeView.setText("");
642 mRecordingTimeView.setVisibility(View.VISIBLE);
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +0530643 mPauseButton.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700644 } else {
645 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
Doris Liu2a7f44c2013-08-12 15:18:53 -0700646 if (!mController.isVideoCaptureIntent()) {
647 showSwitcher();
648 }
Doris Liu6827ce22013-03-12 19:24:28 -0700649 mRecordingTimeView.setVisibility(View.GONE);
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +0530650 mPauseButton.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700651 }
652 }
653
654 public void showReviewImage(Bitmap bitmap) {
655 mReviewImage.setImageBitmap(bitmap);
656 mReviewImage.setVisibility(View.VISIBLE);
657 }
658
659 public void showReviewControls() {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700660 CameraUtil.fadeOut(mShutterButton);
661 CameraUtil.fadeIn(mReviewDoneButton);
662 CameraUtil.fadeIn(mReviewPlayButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700663 mReviewImage.setVisibility(View.VISIBLE);
Doris Liu6432cd62013-06-13 17:20:31 -0700664 mMenuButton.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700665 mOnScreenIndicators.setVisibility(View.GONE);
666 }
667
668 public void hideReviewUI() {
669 mReviewImage.setVisibility(View.GONE);
670 mShutterButton.setEnabled(true);
Doris Liu6432cd62013-06-13 17:20:31 -0700671 mMenuButton.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700672 mOnScreenIndicators.setVisibility(View.VISIBLE);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700673 CameraUtil.fadeOut(mReviewDoneButton);
674 CameraUtil.fadeOut(mReviewPlayButton);
675 CameraUtil.fadeIn(mShutterButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700676 }
677
678 private void setShowMenu(boolean show) {
679 if (mOnScreenIndicators != null) {
680 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
681 }
Doris Liu6432cd62013-06-13 17:20:31 -0700682 if (mMenuButton != null) {
683 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700684 }
685 }
686
ztenghui7b265a62013-09-09 14:58:44 -0700687 public void onPreviewFocusChanged(boolean previewFocused) {
688 if (previewFocused) {
Doris Liu6432cd62013-06-13 17:20:31 -0700689 showUI();
690 } else {
691 hideUI();
692 }
Doris Liu6827ce22013-03-12 19:24:28 -0700693 if (mGestures != null) {
ztenghui7b265a62013-09-09 14:58:44 -0700694 mGestures.setEnabled(previewFocused);
Doris Liu6827ce22013-03-12 19:24:28 -0700695 }
Doris Liu6827ce22013-03-12 19:24:28 -0700696 if (mRenderOverlay != null) {
697 // this can not happen in capture mode
ztenghui7b265a62013-09-09 14:58:44 -0700698 mRenderOverlay.setVisibility(previewFocused ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700699 }
ztenghui7b265a62013-09-09 14:58:44 -0700700 setShowMenu(previewFocused);
Doris Liu6827ce22013-03-12 19:24:28 -0700701 }
702
703 public void initializePopup(PreferenceGroup pref) {
704 mVideoMenu.initialize(pref);
705 }
706
707 public void initializeZoom(Parameters param) {
Doris Liu6432cd62013-06-13 17:20:31 -0700708 if (param == null || !param.isZoomSupported()) {
709 mGestures.setZoomEnabled(false);
710 return;
711 }
712 mGestures.setZoomEnabled(true);
Doris Liu6827ce22013-03-12 19:24:28 -0700713 mZoomMax = param.getMaxZoom();
714 mZoomRatios = param.getZoomRatios();
715 // Currently we use immediate zoom for fast zooming to get better UX and
716 // there is no plan to take advantage of the smooth zoom.
717 mZoomRenderer.setZoomMax(mZoomMax);
718 mZoomRenderer.setZoom(param.getZoom());
719 mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom()));
720 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
721 }
722
723 public void clickShutter() {
724 mShutterButton.performClick();
725 }
726
727 public void pressShutter(boolean pressed) {
728 mShutterButton.setPressed(pressed);
729 }
730
Doris Liu6432cd62013-06-13 17:20:31 -0700731 public View getShutterButton() {
732 return mShutterButton;
Doris Liu6827ce22013-03-12 19:24:28 -0700733 }
734
735 public void setRecordingTime(String text) {
736 mRecordingTimeView.setText(text);
737 }
738
739 public void setRecordingTimeTextColor(int color) {
740 mRecordingTimeView.setTextColor(color);
741 }
742
Doris Liu6432cd62013-06-13 17:20:31 -0700743 public boolean isVisible() {
ztenghui285a5be2013-10-09 15:59:47 -0700744 return mCameraControls.getVisibility() == View.VISIBLE;
Doris Liu6432cd62013-06-13 17:20:31 -0700745 }
746
ztenghui7b265a62013-09-09 14:58:44 -0700747 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700748 public void onDisplayChanged() {
749 mCameraControls.checkLayoutFlip();
750 mController.updateCameraOrientation();
751 }
752
Doris Liu6827ce22013-03-12 19:24:28 -0700753 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
754 @Override
755 public void onZoomValueChanged(int index) {
756 int newZoom = mController.onZoomChanged(index);
757 if (mZoomRenderer != null) {
758 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
759 }
760 }
761
762 @Override
763 public void onZoomStart() {
Alok Kediya23f3cf52013-10-02 17:42:36 +0530764 if (mPieRenderer != null) {
Santhosh Kumar H E78702742013-10-25 19:01:33 +0530765 if (!mRecordingStarted) mPieRenderer.hide();
Alok Kediya23f3cf52013-10-02 17:42:36 +0530766 mPieRenderer.setBlockFocus(true);
767 }
Doris Liu6827ce22013-03-12 19:24:28 -0700768 }
769
770 @Override
771 public void onZoomEnd() {
Alok Kediya23f3cf52013-10-02 17:42:36 +0530772 if (mPieRenderer != null) {
773 mPieRenderer.setBlockFocus(false);
774 }
Doris Liu6827ce22013-03-12 19:24:28 -0700775 }
776 }
Michael Kolb3bc96b22013-03-12 10:24:42 -0700777
Doris Liu6432cd62013-06-13 17:20:31 -0700778 public SurfaceTexture getSurfaceTexture() {
Doris Liu6432cd62013-06-13 17:20:31 -0700779 return mSurfaceTexture;
780 }
781
782 // SurfaceTexture callbacks
Michael Kolb3bc96b22013-03-12 10:24:42 -0700783 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700784 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Angus Kong395ee2d2013-07-15 12:42:41 -0700785 mSurfaceTexture = surface;
786 mController.onPreviewUIReady();
Michael Kolb3bc96b22013-03-12 10:24:42 -0700787 }
788
Doris Liu6432cd62013-06-13 17:20:31 -0700789 @Override
790 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
791 mSurfaceTexture = null;
Angus Kong395ee2d2013-07-15 12:42:41 -0700792 mController.onPreviewUIDestroyed();
Doris Liu6432cd62013-06-13 17:20:31 -0700793 Log.d(TAG, "surfaceTexture is destroyed");
794 return true;
795 }
796
797 @Override
798 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
799 }
800
801 @Override
802 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
Andy Huibersfccf83b2013-11-06 14:37:26 -0800803 // Make sure preview cover is hidden if preview data is available.
804 if (mPreviewCover.getVisibility() != View.GONE) {
805 mPreviewCover.setVisibility(View.GONE);
806 }
Doris Liu6432cd62013-06-13 17:20:31 -0700807 }
808
809 // SurfaceHolder callbacks
810 @Override
811 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
812 Log.v(TAG, "Surface changed. width=" + width + ". height=" + height);
813 }
814
815 @Override
816 public void surfaceCreated(SurfaceHolder holder) {
817 Log.v(TAG, "Surface created");
818 }
819
820 @Override
821 public void surfaceDestroyed(SurfaceHolder holder) {
822 Log.v(TAG, "Surface destroyed");
823 mController.stopPreview();
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700824 }
Manikanta Kanamarlapudiae019672014-01-06 14:31:43 +0530825
826 @Override
827 public void onButtonPause() {
828 mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
829 R.drawable.ic_pausing_indicator, 0, 0, 0);
830 mController.onButtonPause();
831 }
832
833 @Override
834 public void onButtonContinue() {
835 mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
836 R.drawable.ic_recording_indicator, 0, 0, 0);
837 mController.onButtonContinue();
838 }
839
840 public void resetPauseButton() {
841 mRecordingTimeView.setCompoundDrawablesWithIntrinsicBounds(
842 R.drawable.ic_recording_indicator, 0, 0, 0);
843 mPauseButton.setPaused(false);
844 }
Doris Liu6827ce22013-03-12 19:24:28 -0700845}