blob: 02b2567549677cbb805f2687b38dbd1a8a19e2ad [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
19import android.graphics.Bitmap;
Doris Liuc3679c02013-08-08 18:08:43 -070020import android.graphics.Color;
Doris Liu6432cd62013-06-13 17:20:31 -070021import android.graphics.Matrix;
22import android.graphics.SurfaceTexture;
Doris Liuc3679c02013-08-08 18:08:43 -070023import android.graphics.drawable.ColorDrawable;
Doris Liu6827ce22013-03-12 19:24:28 -070024import android.hardware.Camera.Parameters;
Doris Liu6432cd62013-06-13 17:20:31 -070025import android.os.Handler;
26import android.os.Message;
Doris Liu6827ce22013-03-12 19:24:28 -070027import android.util.Log;
28import android.view.Gravity;
Doris Liu6827ce22013-03-12 19:24:28 -070029import android.view.SurfaceHolder;
Doris Liu6432cd62013-06-13 17:20:31 -070030import android.view.SurfaceView;
31import android.view.TextureView;
32import android.view.TextureView.SurfaceTextureListener;
Doris Liu6827ce22013-03-12 19:24:28 -070033import android.view.View;
34import android.view.View.OnClickListener;
Doris Liu6432cd62013-06-13 17:20:31 -070035import android.view.View.OnLayoutChangeListener;
Doris Liu6827ce22013-03-12 19:24:28 -070036import android.view.ViewGroup;
Doris Liu6827ce22013-03-12 19:24:28 -070037import android.widget.FrameLayout.LayoutParams;
38import android.widget.ImageView;
39import android.widget.LinearLayout;
Doris Liuc3679c02013-08-08 18:08:43 -070040import android.widget.PopupWindow;
Doris Liu6827ce22013-03-12 19:24:28 -070041import android.widget.TextView;
42
43import com.android.camera.CameraPreference.OnPreferenceChangedListener;
44import com.android.camera.ui.AbstractSettingPopup;
Doris Liu6432cd62013-06-13 17:20:31 -070045import com.android.camera.ui.CameraControls;
46import com.android.camera.ui.CameraRootView;
Angus Konged15d1a2013-08-19 15:06:12 -070047import com.android.camera.ui.ModuleSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070048import com.android.camera.ui.PieRenderer;
Doris Liu6827ce22013-03-12 19:24:28 -070049import com.android.camera.ui.RenderOverlay;
50import com.android.camera.ui.RotateLayout;
51import com.android.camera.ui.ZoomRenderer;
Angus Kongb50b5cb2013-08-09 14:55:20 -070052import com.android.camera.util.CameraUtil;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070053import com.android.camera2.R;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070054
55import java.util.List;
Doris Liu6827ce22013-03-12 19:24:28 -070056
Doris Liu6432cd62013-06-13 17:20:31 -070057public class VideoUI implements PieRenderer.PieListener,
Michael Kolb3bc96b22013-03-12 10:24:42 -070058 PreviewGestures.SingleTapListener,
Doris Liu6432cd62013-06-13 17:20:31 -070059 CameraRootView.MyDisplayListener,
60 SurfaceTextureListener, SurfaceHolder.Callback {
Angus Kong395ee2d2013-07-15 12:42:41 -070061 private static final String TAG = "CAM_VideoUI";
Doris Liu6432cd62013-06-13 17:20:31 -070062 private static final int UPDATE_TRANSFORM_MATRIX = 1;
Doris Liu6827ce22013-03-12 19:24:28 -070063 // module fields
64 private CameraActivity mActivity;
65 private View mRootView;
Doris Liu6432cd62013-06-13 17:20:31 -070066 private TextureView mTextureView;
Doris Liu6827ce22013-03-12 19:24:28 -070067 // An review image having same size as preview. It is displayed when
68 // recording is stopped in capture intent.
69 private ImageView mReviewImage;
70 private View mReviewCancelButton;
71 private View mReviewDoneButton;
72 private View mReviewPlayButton;
73 private ShutterButton mShutterButton;
Angus Konged15d1a2013-08-19 15:06:12 -070074 private ModuleSwitcher mSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070075 private TextView mRecordingTimeView;
76 private LinearLayout mLabelsLinearLayout;
77 private View mTimeLapseLabel;
78 private RenderOverlay mRenderOverlay;
79 private PieRenderer mPieRenderer;
80 private VideoMenu mVideoMenu;
Doris Liu6432cd62013-06-13 17:20:31 -070081 private CameraControls mCameraControls;
Doris Liuc3679c02013-08-08 18:08:43 -070082 private SettingsPopup mPopup;
Doris Liu6827ce22013-03-12 19:24:28 -070083 private ZoomRenderer mZoomRenderer;
84 private PreviewGestures mGestures;
Doris Liu6432cd62013-06-13 17:20:31 -070085 private View mMenuButton;
Sascha Haeberling140c2632013-04-23 09:58:51 -070086 private OnScreenIndicators mOnScreenIndicators;
Doris Liu6827ce22013-03-12 19:24:28 -070087 private RotateLayout mRecordingTimeRect;
Doris Liufe6596c2013-10-08 11:03:37 -070088 private boolean mRecordingStarted = false;
Doris Liu6432cd62013-06-13 17:20:31 -070089 private SurfaceTexture mSurfaceTexture;
Doris Liu6827ce22013-03-12 19:24:28 -070090 private VideoController mController;
91 private int mZoomMax;
92 private List<Integer> mZoomRatios;
Sascha Haeberling4f91ab52013-05-21 11:26:13 -070093 private View mPreviewThumb;
Sascha Haeberling37f36112013-08-06 14:31:52 -070094 private View mFlashOverlay;
Doris Liu6827ce22013-03-12 19:24:28 -070095
Doris Liu3a45c332013-10-15 19:10:28 -070096 private View mPreviewCover;
Doris Liu6432cd62013-06-13 17:20:31 -070097 private SurfaceView mSurfaceView = null;
98 private int mPreviewWidth = 0;
99 private int mPreviewHeight = 0;
100 private float mSurfaceTextureUncroppedWidth;
101 private float mSurfaceTextureUncroppedHeight;
102 private float mAspectRatio = 4f / 3f;
103 private Matrix mMatrix = null;
Sascha Haeberling37f36112013-08-06 14:31:52 -0700104 private final AnimationManager mAnimationManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700105 private final Handler mHandler = new Handler() {
106 @Override
107 public void handleMessage(Message msg) {
108 switch (msg.what) {
109 case UPDATE_TRANSFORM_MATRIX:
110 setTransformMatrix(mPreviewWidth, mPreviewHeight);
111 break;
112 default:
113 break;
114 }
115 }
116 };
117 private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
118 @Override
119 public void onLayoutChange(View v, int left, int top, int right,
120 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
121 int width = right - left;
122 int height = bottom - top;
123 // Full-screen screennail
124 int w = width;
125 int h = height;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700126 if (CameraUtil.getDisplayRotation(mActivity) % 180 != 0) {
Doris Liu6432cd62013-06-13 17:20:31 -0700127 w = height;
128 h = width;
129 }
130 if (mPreviewWidth != width || mPreviewHeight != height) {
131 mPreviewWidth = width;
132 mPreviewHeight = height;
133 onScreenSizeChanged(width, height, w, h);
134 }
135 }
136 };
137
Doris Liu3a45c332013-10-15 19:10:28 -0700138 public void showPreviewCover() {
139 mPreviewCover.setVisibility(View.VISIBLE);
140 }
141
Doris Liuc3679c02013-08-08 18:08:43 -0700142 private class SettingsPopup extends PopupWindow {
143 public SettingsPopup(View popup) {
144 super(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
145 setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
146 setOutsideTouchable(true);
147 setFocusable(true);
148 popup.setVisibility(View.VISIBLE);
149 setContentView(popup);
150 showAtLocation(mRootView, Gravity.CENTER, 0, 0);
151 }
152
153 public void dismiss(boolean topLevelOnly) {
154 super.dismiss();
155 popupDismissed();
156 showUI();
157 mVideoMenu.popupDismissed(topLevelOnly);
Sascha Haeberling4ec139d2013-10-09 23:46:20 -0700158
159 // Switch back into fullscreen/lights-out mode after popup
160 // is dimissed.
161 mActivity.setSystemBarsVisibility(false);
Doris Liuc3679c02013-08-08 18:08:43 -0700162 }
163
164 @Override
165 public void dismiss() {
166 // Called by Framework when touch outside the popup or hit back key
167 dismiss(true);
168 }
169 }
170
Doris Liu6827ce22013-03-12 19:24:28 -0700171 public VideoUI(CameraActivity activity, VideoController controller, View parent) {
172 mActivity = activity;
173 mController = controller;
174 mRootView = parent;
175 mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true);
Doris Liu3a45c332013-10-15 19:10:28 -0700176 mPreviewCover = mRootView.findViewById(R.id.preview_cover);
Doris Liu6432cd62013-06-13 17:20:31 -0700177 mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content);
178 mTextureView.setSurfaceTextureListener(this);
Doris Liubdd198e2013-08-29 18:06:45 -0700179 mTextureView.addOnLayoutChangeListener(mLayoutListener);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700180 mFlashOverlay = mRootView.findViewById(R.id.flash_overlay);
Doris Liu6432cd62013-06-13 17:20:31 -0700181 mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
Angus Konged15d1a2013-08-19 15:06:12 -0700182 mSwitcher = (ModuleSwitcher) mRootView.findViewById(R.id.camera_switcher);
183 mSwitcher.setCurrentIndex(ModuleSwitcher.VIDEO_MODULE_INDEX);
184 mSwitcher.setSwitchListener(mActivity);
Doris Liu6827ce22013-03-12 19:24:28 -0700185 initializeMiscControls();
186 initializeControlByIntent();
187 initializeOverlay();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700188 mAnimationManager = new AnimationManager();
Doris Liu6827ce22013-03-12 19:24:28 -0700189 }
190
Doris Liu6432cd62013-06-13 17:20:31 -0700191
192 public void initializeSurfaceView() {
193 mSurfaceView = new SurfaceView(mActivity);
194 ((ViewGroup) mRootView).addView(mSurfaceView, 0);
195 mSurfaceView.getHolder().addCallback(this);
196 }
197
Doris Liu6827ce22013-03-12 19:24:28 -0700198 private void initializeControlByIntent() {
Doris Liu2a7f44c2013-08-12 15:18:53 -0700199 mMenuButton = mRootView.findViewById(R.id.menu);
Doris Liu6432cd62013-06-13 17:20:31 -0700200 mMenuButton.setOnClickListener(new OnClickListener() {
Doris Liu6827ce22013-03-12 19:24:28 -0700201 @Override
202 public void onClick(View v) {
203 if (mPieRenderer != null) {
204 mPieRenderer.showInCenter();
205 }
206 }
207 });
Doris Liu6432cd62013-06-13 17:20:31 -0700208
Doris Liu2a7f44c2013-08-12 15:18:53 -0700209 mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls);
Michael Kolbeb8adc12013-04-26 11:09:29 -0700210 mOnScreenIndicators = new OnScreenIndicators(mActivity,
Doris Liu2a7f44c2013-08-12 15:18:53 -0700211 mRootView.findViewById(R.id.on_screen_indicators));
Sascha Haeberling140c2632013-04-23 09:58:51 -0700212 mOnScreenIndicators.resetToDefault();
Doris Liu6827ce22013-03-12 19:24:28 -0700213 if (mController.isVideoCaptureIntent()) {
Doris Liu6432cd62013-06-13 17:20:31 -0700214 hideSwitcher();
215 mActivity.getLayoutInflater().inflate(R.layout.review_module_control,
216 (ViewGroup) mCameraControls);
Doris Liu6827ce22013-03-12 19:24:28 -0700217 // Cannot use RotateImageView for "done" and "cancel" button because
218 // the tablet layout uses RotateLayout, which cannot be cast to
219 // RotateImageView.
Doris Liu2a7f44c2013-08-12 15:18:53 -0700220 mReviewDoneButton = mRootView.findViewById(R.id.btn_done);
221 mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel);
222 mReviewPlayButton = mRootView.findViewById(R.id.btn_play);
Doris Liu6827ce22013-03-12 19:24:28 -0700223 mReviewCancelButton.setVisibility(View.VISIBLE);
224 mReviewDoneButton.setOnClickListener(new OnClickListener() {
225 @Override
226 public void onClick(View v) {
227 mController.onReviewDoneClicked(v);
228 }
229 });
230 mReviewCancelButton.setOnClickListener(new OnClickListener() {
231 @Override
232 public void onClick(View v) {
233 mController.onReviewCancelClicked(v);
234 }
235 });
236 mReviewPlayButton.setOnClickListener(new OnClickListener() {
237 @Override
238 public void onClick(View v) {
239 mController.onReviewPlayClicked(v);
240 }
241 });
242 }
243 }
244
Doris Liu6432cd62013-06-13 17:20:31 -0700245 public void setPreviewSize(int width, int height) {
246 if (width == 0 || height == 0) {
247 Log.w(TAG, "Preview size should not be 0.");
248 return;
249 }
250 if (width > height) {
251 mAspectRatio = (float) width / height;
252 } else {
253 mAspectRatio = (float) height / width;
254 }
255 mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX);
256 }
257
258 public int getPreviewWidth() {
259 return mPreviewWidth;
260 }
261
262 public int getPreviewHeight() {
263 return mPreviewHeight;
264 }
265
266 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
267 setTransformMatrix(width, height);
268 }
269
270 private void setTransformMatrix(int width, int height) {
271 mMatrix = mTextureView.getTransform(mMatrix);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700272 int orientation = CameraUtil.getDisplayRotation(mActivity);
Doris Liu6432cd62013-06-13 17:20:31 -0700273 float scaleX = 1f, scaleY = 1f;
274 float scaledTextureWidth, scaledTextureHeight;
275 if (width > height) {
276 scaledTextureWidth = Math.max(width,
277 (int) (height * mAspectRatio));
278 scaledTextureHeight = Math.max(height,
279 (int)(width / mAspectRatio));
280 } else {
281 scaledTextureWidth = Math.max(width,
282 (int) (height / mAspectRatio));
283 scaledTextureHeight = Math.max(height,
284 (int) (width * mAspectRatio));
285 }
286
287 if (mSurfaceTextureUncroppedWidth != scaledTextureWidth ||
288 mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
289 mSurfaceTextureUncroppedWidth = scaledTextureWidth;
290 mSurfaceTextureUncroppedHeight = scaledTextureHeight;
291 }
292 scaleX = scaledTextureWidth / width;
293 scaleY = scaledTextureHeight / height;
294 mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2);
295 mTextureView.setTransform(mMatrix);
296
297 if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) {
298 LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams();
299 lp.width = (int) mSurfaceTextureUncroppedWidth;
300 lp.height = (int) mSurfaceTextureUncroppedHeight;
301 lp.gravity = Gravity.CENTER;
302 mSurfaceView.requestLayout();
303 }
304 }
305
Sascha Haeberling37f36112013-08-06 14:31:52 -0700306 /**
307 * Starts a flash animation
308 */
309 public void animateFlash() {
310 mAnimationManager.startFlashAnimation(mFlashOverlay);
311 }
312
313 /**
314 * Starts a capture animation
Doris Liu3973deb2013-08-21 13:42:22 -0700315 */
316 public void animateCapture() {
317 Bitmap bitmap = null;
318 if (mTextureView != null) {
319 bitmap = mTextureView.getBitmap((int) mSurfaceTextureUncroppedWidth / 2,
320 (int) mSurfaceTextureUncroppedHeight / 2);
321 }
322 animateCapture(bitmap);
323 }
324
325 /**
326 * Starts a capture animation
Sascha Haeberling37f36112013-08-06 14:31:52 -0700327 * @param bitmap the captured image that we shrink and slide in the animation
328 */
329 public void animateCapture(Bitmap bitmap) {
Doris Liu3973deb2013-08-21 13:42:22 -0700330 if (bitmap == null) {
331 Log.e(TAG, "No valid bitmap for capture animation.");
332 return;
333 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700334 ((ImageView) mPreviewThumb).setImageBitmap(bitmap);
335 mAnimationManager.startCaptureAnimation(mPreviewThumb);
336 }
337
338 /**
339 * Cancels on-going animations
340 */
341 public void cancelAnimations() {
342 mAnimationManager.cancelAnimations();
343 }
344
Doris Liu6432cd62013-06-13 17:20:31 -0700345 public void hideUI() {
346 mCameraControls.setVisibility(View.INVISIBLE);
347 mSwitcher.closePopup();
348 }
349
350 public void showUI() {
351 mCameraControls.setVisibility(View.VISIBLE);
352 }
353
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700354 public boolean arePreviewControlsVisible() {
355 return (mCameraControls.getVisibility() == View.VISIBLE);
356 }
357
Doris Liu6432cd62013-06-13 17:20:31 -0700358 public void hideSwitcher() {
359 mSwitcher.closePopup();
360 mSwitcher.setVisibility(View.INVISIBLE);
361 }
362
363 public void showSwitcher() {
364 mSwitcher.setVisibility(View.VISIBLE);
365 }
366
Doris Liu6827ce22013-03-12 19:24:28 -0700367 public boolean collapseCameraControls() {
368 boolean ret = false;
369 if (mPopup != null) {
370 dismissPopup(false);
371 ret = true;
372 }
373 return ret;
374 }
375
376 public boolean removeTopLevelPopup() {
377 if (mPopup != null) {
378 dismissPopup(true);
379 return true;
380 }
381 return false;
382 }
383
384 public void enableCameraControls(boolean enable) {
385 if (mGestures != null) {
386 mGestures.setZoomOnly(!enable);
387 }
388 if (mPieRenderer != null && mPieRenderer.showsItems()) {
389 mPieRenderer.hide();
390 }
391 }
392
Doris Liu59390062013-10-10 17:20:56 -0700393 public void initDisplayChangeListener() {
394 ((CameraRootView) mRootView).setDisplayChangeListener(this);
395 }
396
397 public void removeDisplayChangeListener() {
398 ((CameraRootView) mRootView).removeDisplayChangeListener();
399 }
400
Doris Liu6827ce22013-03-12 19:24:28 -0700401 public void overrideSettings(final String... keyvalues) {
402 mVideoMenu.overrideSettings(keyvalues);
403 }
404
Doris Liu6827ce22013-03-12 19:24:28 -0700405 public void setOrientationIndicator(int orientation, boolean animation) {
Doris Liu6827ce22013-03-12 19:24:28 -0700406 // We change the orientation of the linearlayout only for phone UI
407 // because when in portrait the width is not enough.
408 if (mLabelsLinearLayout != null) {
409 if (((orientation / 90) & 1) == 0) {
410 mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL);
411 } else {
412 mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
413 }
414 }
415 mRecordingTimeRect.setOrientation(0, animation);
416 }
417
418 public SurfaceHolder getSurfaceHolder() {
Doris Liu6432cd62013-06-13 17:20:31 -0700419 return mSurfaceView.getHolder();
Doris Liu6827ce22013-03-12 19:24:28 -0700420 }
421
422 public void hideSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700423 mSurfaceView.setVisibility(View.GONE);
424 mTextureView.setVisibility(View.VISIBLE);
425 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700426 }
427
428 public void showSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700429 mSurfaceView.setVisibility(View.VISIBLE);
430 mTextureView.setVisibility(View.GONE);
431 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700432 }
433
434 private void initializeOverlay() {
435 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
436 if (mPieRenderer == null) {
437 mPieRenderer = new PieRenderer(mActivity);
438 mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer);
439 mPieRenderer.setPieListener(this);
440 }
441 mRenderOverlay.addRenderer(mPieRenderer);
442 if (mZoomRenderer == null) {
443 mZoomRenderer = new ZoomRenderer(mActivity);
444 }
445 mRenderOverlay.addRenderer(mZoomRenderer);
446 if (mGestures == null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700447 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
448 mRenderOverlay.setGestures(mGestures);
Doris Liu6827ce22013-03-12 19:24:28 -0700449 }
450 mGestures.setRenderOverlay(mRenderOverlay);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700451
Doris Liu2a7f44c2013-08-12 15:18:53 -0700452 mPreviewThumb = mRootView.findViewById(R.id.preview_thumb);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700453 mPreviewThumb.setOnClickListener(new OnClickListener() {
454 @Override
455 public void onClick(View v) {
Doris Liufe6596c2013-10-08 11:03:37 -0700456 // Do not allow navigation to filmstrip during video recording
457 if (!mRecordingStarted) {
458 mActivity.gotoGallery();
459 }
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700460 }
461 });
Doris Liu6827ce22013-03-12 19:24:28 -0700462 }
463
464 public void setPrefChangedListener(OnPreferenceChangedListener listener) {
465 mVideoMenu.setListener(listener);
466 }
467
468 private void initializeMiscControls() {
Doris Liu6827ce22013-03-12 19:24:28 -0700469 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
Doris Liu6827ce22013-03-12 19:24:28 -0700470 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
471 mShutterButton.setOnShutterButtonListener(mController);
472 mShutterButton.setVisibility(View.VISIBLE);
473 mShutterButton.requestFocus();
474 mShutterButton.enableTouch(true);
475 mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
476 mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
477 mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
478 // The R.id.labels can only be found in phone layout.
479 // That is, mLabelsLinearLayout should be null in tablet layout.
480 mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
481 }
482
Michael Kolb87880792013-04-30 15:38:49 -0700483 public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) {
Sascha Haeberling140c2632013-04-23 09:58:51 -0700484 mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode());
Michael Kolb87880792013-04-30 15:38:49 -0700485 boolean location = RecordLocationPreference.get(
486 prefs, mActivity.getContentResolver());
487 mOnScreenIndicators.updateLocationIndicator(location);
488
Doris Liu6827ce22013-03-12 19:24:28 -0700489 }
490
491 public void setAspectRatio(double ratio) {
Doris Liu6432cd62013-06-13 17:20:31 -0700492 // mPreviewFrameLayout.setAspectRatio(ratio);
Doris Liu6827ce22013-03-12 19:24:28 -0700493 }
494
495 public void showTimeLapseUI(boolean enable) {
496 if (mTimeLapseLabel != null) {
497 mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
498 }
499 }
500
Michael Kolb3bc96b22013-03-12 10:24:42 -0700501 private void openMenu() {
502 if (mPieRenderer != null) {
503 mPieRenderer.showInCenter();
504 }
505 }
506
Doris Liu6827ce22013-03-12 19:24:28 -0700507 public void dismissPopup(boolean topLevelOnly) {
Doris Liu69ef5ea2013-05-07 13:48:10 -0700508 // In review mode, we do not want to bring up the camera UI
509 if (mController.isInReviewMode()) return;
Doris Liu6827ce22013-03-12 19:24:28 -0700510 if (mPopup != null) {
Doris Liuc3679c02013-08-08 18:08:43 -0700511 mPopup.dismiss(topLevelOnly);
Doris Liu6827ce22013-03-12 19:24:28 -0700512 }
Doris Liuc3679c02013-08-08 18:08:43 -0700513 }
514
515 private void popupDismissed() {
516 mPopup = null;
517 }
518
519 public void showPopup(AbstractSettingPopup popup) {
520 hideUI();
521
522 if (mPopup != null) {
523 mPopup.dismiss(false);
524 }
525 mPopup = new SettingsPopup(popup);
Doris Liu6827ce22013-03-12 19:24:28 -0700526 }
527
528 public void onShowSwitcherPopup() {
529 hidePieRenderer();
530 }
531
532 public boolean hidePieRenderer() {
533 if (mPieRenderer != null && mPieRenderer.showsItems()) {
534 mPieRenderer.hide();
535 return true;
536 }
537 return false;
538 }
539
Doris Liu61f2b082013-03-27 17:25:43 -0700540 // disable preview gestures after shutter is pressed
541 public void setShutterPressed(boolean pressed) {
542 if (mGestures == null) return;
543 mGestures.setEnabled(!pressed);
544 }
545
Doris Liu6827ce22013-03-12 19:24:28 -0700546 public void enableShutter(boolean enable) {
547 if (mShutterButton != null) {
548 mShutterButton.setEnabled(enable);
549 }
550 }
551
552 // PieListener
553 @Override
554 public void onPieOpened(int centerX, int centerY) {
Doris Liu6432cd62013-06-13 17:20:31 -0700555 setSwipingEnabled(false);
Doris Liu6827ce22013-03-12 19:24:28 -0700556 }
557
558 @Override
559 public void onPieClosed() {
Doris Liu6432cd62013-06-13 17:20:31 -0700560 setSwipingEnabled(true);
561 }
562
563 public void setSwipingEnabled(boolean enable) {
564 mActivity.setSwipingEnabled(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700565 }
566
567 public void showPreviewBorder(boolean enable) {
Doris Liu6432cd62013-06-13 17:20:31 -0700568 // TODO: mPreviewFrameLayout.showBorder(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700569 }
570
571 // SingleTapListener
572 // Preview area is touched. Take a picture.
573 @Override
574 public void onSingleTapUp(View view, int x, int y) {
575 mController.onSingleTapUp(view, x, y);
576 }
577
Doris Liufe6596c2013-10-08 11:03:37 -0700578 public void showRecordingUI(boolean recording) {
579 mRecordingStarted = recording;
Doris Liu6432cd62013-06-13 17:20:31 -0700580 mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700581 mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
582 if (recording) {
583 mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording);
Doris Liu6432cd62013-06-13 17:20:31 -0700584 hideSwitcher();
Doris Liu6827ce22013-03-12 19:24:28 -0700585 mRecordingTimeView.setText("");
586 mRecordingTimeView.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700587 } else {
588 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
Doris Liu2a7f44c2013-08-12 15:18:53 -0700589 if (!mController.isVideoCaptureIntent()) {
590 showSwitcher();
591 }
Doris Liu6827ce22013-03-12 19:24:28 -0700592 mRecordingTimeView.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700593 }
594 }
595
596 public void showReviewImage(Bitmap bitmap) {
597 mReviewImage.setImageBitmap(bitmap);
598 mReviewImage.setVisibility(View.VISIBLE);
599 }
600
601 public void showReviewControls() {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700602 CameraUtil.fadeOut(mShutterButton);
603 CameraUtil.fadeIn(mReviewDoneButton);
604 CameraUtil.fadeIn(mReviewPlayButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700605 mReviewImage.setVisibility(View.VISIBLE);
Doris Liu6432cd62013-06-13 17:20:31 -0700606 mMenuButton.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700607 mOnScreenIndicators.setVisibility(View.GONE);
608 }
609
610 public void hideReviewUI() {
611 mReviewImage.setVisibility(View.GONE);
612 mShutterButton.setEnabled(true);
Doris Liu6432cd62013-06-13 17:20:31 -0700613 mMenuButton.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700614 mOnScreenIndicators.setVisibility(View.VISIBLE);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700615 CameraUtil.fadeOut(mReviewDoneButton);
616 CameraUtil.fadeOut(mReviewPlayButton);
617 CameraUtil.fadeIn(mShutterButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700618 }
619
620 private void setShowMenu(boolean show) {
621 if (mOnScreenIndicators != null) {
622 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
623 }
Doris Liu6432cd62013-06-13 17:20:31 -0700624 if (mMenuButton != null) {
625 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700626 }
627 }
628
ztenghui7b265a62013-09-09 14:58:44 -0700629 public void onPreviewFocusChanged(boolean previewFocused) {
630 if (previewFocused) {
Doris Liu6432cd62013-06-13 17:20:31 -0700631 showUI();
632 } else {
633 hideUI();
634 }
Doris Liu6827ce22013-03-12 19:24:28 -0700635 if (mGestures != null) {
ztenghui7b265a62013-09-09 14:58:44 -0700636 mGestures.setEnabled(previewFocused);
Doris Liu6827ce22013-03-12 19:24:28 -0700637 }
Doris Liu6827ce22013-03-12 19:24:28 -0700638 if (mRenderOverlay != null) {
639 // this can not happen in capture mode
ztenghui7b265a62013-09-09 14:58:44 -0700640 mRenderOverlay.setVisibility(previewFocused ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700641 }
ztenghui7b265a62013-09-09 14:58:44 -0700642 setShowMenu(previewFocused);
Doris Liu6827ce22013-03-12 19:24:28 -0700643 }
644
645 public void initializePopup(PreferenceGroup pref) {
646 mVideoMenu.initialize(pref);
647 }
648
649 public void initializeZoom(Parameters param) {
Doris Liu6432cd62013-06-13 17:20:31 -0700650 if (param == null || !param.isZoomSupported()) {
651 mGestures.setZoomEnabled(false);
652 return;
653 }
654 mGestures.setZoomEnabled(true);
Doris Liu6827ce22013-03-12 19:24:28 -0700655 mZoomMax = param.getMaxZoom();
656 mZoomRatios = param.getZoomRatios();
657 // Currently we use immediate zoom for fast zooming to get better UX and
658 // there is no plan to take advantage of the smooth zoom.
659 mZoomRenderer.setZoomMax(mZoomMax);
660 mZoomRenderer.setZoom(param.getZoom());
661 mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom()));
662 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
663 }
664
665 public void clickShutter() {
666 mShutterButton.performClick();
667 }
668
669 public void pressShutter(boolean pressed) {
670 mShutterButton.setPressed(pressed);
671 }
672
Doris Liu6432cd62013-06-13 17:20:31 -0700673 public View getShutterButton() {
674 return mShutterButton;
Doris Liu6827ce22013-03-12 19:24:28 -0700675 }
676
677 public void setRecordingTime(String text) {
678 mRecordingTimeView.setText(text);
679 }
680
681 public void setRecordingTimeTextColor(int color) {
682 mRecordingTimeView.setTextColor(color);
683 }
684
Doris Liu6432cd62013-06-13 17:20:31 -0700685 public boolean isVisible() {
ztenghui285a5be2013-10-09 15:59:47 -0700686 return mCameraControls.getVisibility() == View.VISIBLE;
Doris Liu6432cd62013-06-13 17:20:31 -0700687 }
688
ztenghui7b265a62013-09-09 14:58:44 -0700689 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700690 public void onDisplayChanged() {
691 mCameraControls.checkLayoutFlip();
692 mController.updateCameraOrientation();
693 }
694
Doris Liu6827ce22013-03-12 19:24:28 -0700695 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
696 @Override
697 public void onZoomValueChanged(int index) {
698 int newZoom = mController.onZoomChanged(index);
699 if (mZoomRenderer != null) {
700 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
701 }
702 }
703
704 @Override
705 public void onZoomStart() {
706 }
707
708 @Override
709 public void onZoomEnd() {
710 }
711 }
Michael Kolb3bc96b22013-03-12 10:24:42 -0700712
Doris Liu6432cd62013-06-13 17:20:31 -0700713 public SurfaceTexture getSurfaceTexture() {
Doris Liu6432cd62013-06-13 17:20:31 -0700714 return mSurfaceTexture;
715 }
716
717 // SurfaceTexture callbacks
Michael Kolb3bc96b22013-03-12 10:24:42 -0700718 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700719 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Angus Kong395ee2d2013-07-15 12:42:41 -0700720 mSurfaceTexture = surface;
Doris Liu3a45c332013-10-15 19:10:28 -0700721 mPreviewCover.setVisibility(View.GONE);
Angus Kong395ee2d2013-07-15 12:42:41 -0700722 mController.onPreviewUIReady();
Michael Kolb3bc96b22013-03-12 10:24:42 -0700723 }
724
Doris Liu6432cd62013-06-13 17:20:31 -0700725 @Override
726 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
727 mSurfaceTexture = null;
Angus Kong395ee2d2013-07-15 12:42:41 -0700728 mController.onPreviewUIDestroyed();
Doris Liu6432cd62013-06-13 17:20:31 -0700729 Log.d(TAG, "surfaceTexture is destroyed");
730 return true;
731 }
732
733 @Override
734 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
735 }
736
737 @Override
738 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
739 }
740
741 // SurfaceHolder callbacks
742 @Override
743 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
744 Log.v(TAG, "Surface changed. width=" + width + ". height=" + height);
745 }
746
747 @Override
748 public void surfaceCreated(SurfaceHolder holder) {
749 Log.v(TAG, "Surface created");
750 }
751
752 @Override
753 public void surfaceDestroyed(SurfaceHolder holder) {
754 Log.v(TAG, "Surface destroyed");
755 mController.stopPreview();
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700756 }
Doris Liu6827ce22013-03-12 19:24:28 -0700757}