blob: 551b7259616326c4ed214985cd11a96d5f648477 [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 Liu6432cd62013-06-13 17:20:31 -070020import android.graphics.Matrix;
21import android.graphics.SurfaceTexture;
Doris Liu6827ce22013-03-12 19:24:28 -070022import android.hardware.Camera.Parameters;
Doris Liu6432cd62013-06-13 17:20:31 -070023import android.os.Handler;
24import android.os.Message;
Doris Liu6827ce22013-03-12 19:24:28 -070025import android.util.Log;
26import android.view.Gravity;
Doris Liu6827ce22013-03-12 19:24:28 -070027import android.view.SurfaceHolder;
Doris Liu6432cd62013-06-13 17:20:31 -070028import android.view.SurfaceView;
29import android.view.TextureView;
30import android.view.TextureView.SurfaceTextureListener;
Doris Liu6827ce22013-03-12 19:24:28 -070031import android.view.View;
32import android.view.View.OnClickListener;
Doris Liu6432cd62013-06-13 17:20:31 -070033import android.view.View.OnLayoutChangeListener;
Doris Liu6827ce22013-03-12 19:24:28 -070034import android.view.ViewGroup;
35import android.widget.FrameLayout;
36import android.widget.FrameLayout.LayoutParams;
37import android.widget.ImageView;
38import android.widget.LinearLayout;
39import android.widget.TextView;
40
41import com.android.camera.CameraPreference.OnPreferenceChangedListener;
42import com.android.camera.ui.AbstractSettingPopup;
Doris Liu6432cd62013-06-13 17:20:31 -070043import com.android.camera.ui.CameraControls;
44import com.android.camera.ui.CameraRootView;
45import com.android.camera.ui.CameraSwitcher;
46import com.android.camera.ui.CameraSwitcher.CameraSwitchListener;
Doris Liu6827ce22013-03-12 19:24:28 -070047import com.android.camera.ui.PieRenderer;
Doris Liu6827ce22013-03-12 19:24:28 -070048import com.android.camera.ui.RenderOverlay;
49import com.android.camera.ui.RotateLayout;
50import com.android.camera.ui.ZoomRenderer;
51import com.android.gallery3d.R;
52import com.android.gallery3d.common.ApiHelper;
53
54import java.util.List;
55
Doris Liu6432cd62013-06-13 17:20:31 -070056public class VideoUI implements PieRenderer.PieListener,
Michael Kolb3bc96b22013-03-12 10:24:42 -070057 PreviewGestures.SingleTapListener,
Doris Liu6432cd62013-06-13 17:20:31 -070058 CameraRootView.MyDisplayListener,
59 SurfaceTextureListener, SurfaceHolder.Callback {
Angus Kong395ee2d2013-07-15 12:42:41 -070060 private static final String TAG = "CAM_VideoUI";
Doris Liu6432cd62013-06-13 17:20:31 -070061 private static final int UPDATE_TRANSFORM_MATRIX = 1;
Doris Liu6827ce22013-03-12 19:24:28 -070062 // module fields
63 private CameraActivity mActivity;
64 private View mRootView;
Doris Liu6432cd62013-06-13 17:20:31 -070065 private TextureView mTextureView;
Doris Liu6827ce22013-03-12 19:24:28 -070066 // An review image having same size as preview. It is displayed when
67 // recording is stopped in capture intent.
68 private ImageView mReviewImage;
69 private View mReviewCancelButton;
70 private View mReviewDoneButton;
71 private View mReviewPlayButton;
72 private ShutterButton mShutterButton;
Doris Liu6432cd62013-06-13 17:20:31 -070073 private CameraSwitcher mSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070074 private TextView mRecordingTimeView;
75 private LinearLayout mLabelsLinearLayout;
76 private View mTimeLapseLabel;
77 private RenderOverlay mRenderOverlay;
78 private PieRenderer mPieRenderer;
79 private VideoMenu mVideoMenu;
Doris Liu6432cd62013-06-13 17:20:31 -070080 private CameraControls mCameraControls;
Doris Liu6827ce22013-03-12 19:24:28 -070081 private AbstractSettingPopup mPopup;
82 private ZoomRenderer mZoomRenderer;
83 private PreviewGestures mGestures;
Doris Liu6432cd62013-06-13 17:20:31 -070084 private View mMenuButton;
Doris Liu6827ce22013-03-12 19:24:28 -070085 private View mBlocker;
Sascha Haeberling140c2632013-04-23 09:58:51 -070086 private OnScreenIndicators mOnScreenIndicators;
Doris Liu6827ce22013-03-12 19:24:28 -070087 private RotateLayout mRecordingTimeRect;
Doris Liu6432cd62013-06-13 17:20:31 -070088 private final Object mLock = new Object();
89 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;
Doris Liu6827ce22013-03-12 19:24:28 -070094
Doris Liu6432cd62013-06-13 17:20:31 -070095 private SurfaceView mSurfaceView = null;
96 private int mPreviewWidth = 0;
97 private int mPreviewHeight = 0;
98 private float mSurfaceTextureUncroppedWidth;
99 private float mSurfaceTextureUncroppedHeight;
100 private float mAspectRatio = 4f / 3f;
101 private Matrix mMatrix = null;
102 private final Handler mHandler = new Handler() {
103 @Override
104 public void handleMessage(Message msg) {
105 switch (msg.what) {
106 case UPDATE_TRANSFORM_MATRIX:
107 setTransformMatrix(mPreviewWidth, mPreviewHeight);
108 break;
109 default:
110 break;
111 }
112 }
113 };
114 private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
115 @Override
116 public void onLayoutChange(View v, int left, int top, int right,
117 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
118 int width = right - left;
119 int height = bottom - top;
120 // Full-screen screennail
121 int w = width;
122 int h = height;
123 if (Util.getDisplayRotation(mActivity) % 180 != 0) {
124 w = height;
125 h = width;
126 }
127 if (mPreviewWidth != width || mPreviewHeight != height) {
128 mPreviewWidth = width;
129 mPreviewHeight = height;
130 onScreenSizeChanged(width, height, w, h);
131 }
132 }
133 };
134
Doris Liu6827ce22013-03-12 19:24:28 -0700135 public VideoUI(CameraActivity activity, VideoController controller, View parent) {
136 mActivity = activity;
137 mController = controller;
138 mRootView = parent;
139 mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true);
Doris Liu6432cd62013-06-13 17:20:31 -0700140 mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content);
141 mTextureView.setSurfaceTextureListener(this);
142 mRootView.addOnLayoutChangeListener(mLayoutListener);
143 ((CameraRootView) mRootView).setDisplayChangeListener(this);
144 mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
145 mSwitcher = (CameraSwitcher) mRootView.findViewById(R.id.camera_switcher);
Doris Liu147e26a2013-06-24 15:29:54 -0700146 mSwitcher.setCurrentIndex(CameraSwitcher.VIDEO_MODULE_INDEX);
Doris Liu6432cd62013-06-13 17:20:31 -0700147 mSwitcher.setSwitchListener((CameraSwitchListener) mActivity);
Doris Liu6827ce22013-03-12 19:24:28 -0700148 initializeMiscControls();
149 initializeControlByIntent();
150 initializeOverlay();
151 }
152
Doris Liu6432cd62013-06-13 17:20:31 -0700153
154 public void initializeSurfaceView() {
155 mSurfaceView = new SurfaceView(mActivity);
156 ((ViewGroup) mRootView).addView(mSurfaceView, 0);
157 mSurfaceView.getHolder().addCallback(this);
158 }
159
Doris Liu6827ce22013-03-12 19:24:28 -0700160 private void initializeControlByIntent() {
161 mBlocker = mActivity.findViewById(R.id.blocker);
Doris Liu6432cd62013-06-13 17:20:31 -0700162 mMenuButton = mActivity.findViewById(R.id.menu);
163 mMenuButton.setOnClickListener(new OnClickListener() {
Doris Liu6827ce22013-03-12 19:24:28 -0700164 @Override
165 public void onClick(View v) {
166 if (mPieRenderer != null) {
167 mPieRenderer.showInCenter();
168 }
169 }
170 });
Doris Liu6432cd62013-06-13 17:20:31 -0700171
172 mCameraControls = (CameraControls) mActivity.findViewById(R.id.camera_controls);
Michael Kolbeb8adc12013-04-26 11:09:29 -0700173 mOnScreenIndicators = new OnScreenIndicators(mActivity,
Sascha Haeberling140c2632013-04-23 09:58:51 -0700174 mActivity.findViewById(R.id.on_screen_indicators));
175 mOnScreenIndicators.resetToDefault();
Doris Liu6827ce22013-03-12 19:24:28 -0700176 if (mController.isVideoCaptureIntent()) {
Doris Liu6432cd62013-06-13 17:20:31 -0700177 hideSwitcher();
178 mActivity.getLayoutInflater().inflate(R.layout.review_module_control,
179 (ViewGroup) mCameraControls);
Doris Liu6827ce22013-03-12 19:24:28 -0700180 // Cannot use RotateImageView for "done" and "cancel" button because
181 // the tablet layout uses RotateLayout, which cannot be cast to
182 // RotateImageView.
183 mReviewDoneButton = mActivity.findViewById(R.id.btn_done);
184 mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel);
185 mReviewPlayButton = mActivity.findViewById(R.id.btn_play);
186 mReviewCancelButton.setVisibility(View.VISIBLE);
187 mReviewDoneButton.setOnClickListener(new OnClickListener() {
188 @Override
189 public void onClick(View v) {
190 mController.onReviewDoneClicked(v);
191 }
192 });
193 mReviewCancelButton.setOnClickListener(new OnClickListener() {
194 @Override
195 public void onClick(View v) {
196 mController.onReviewCancelClicked(v);
197 }
198 });
199 mReviewPlayButton.setOnClickListener(new OnClickListener() {
200 @Override
201 public void onClick(View v) {
202 mController.onReviewPlayClicked(v);
203 }
204 });
205 }
206 }
207
Doris Liu6432cd62013-06-13 17:20:31 -0700208 public void setPreviewSize(int width, int height) {
209 if (width == 0 || height == 0) {
210 Log.w(TAG, "Preview size should not be 0.");
211 return;
212 }
213 if (width > height) {
214 mAspectRatio = (float) width / height;
215 } else {
216 mAspectRatio = (float) height / width;
217 }
218 mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX);
219 }
220
221 public int getPreviewWidth() {
222 return mPreviewWidth;
223 }
224
225 public int getPreviewHeight() {
226 return mPreviewHeight;
227 }
228
229 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
230 setTransformMatrix(width, height);
231 }
232
233 private void setTransformMatrix(int width, int height) {
234 mMatrix = mTextureView.getTransform(mMatrix);
235 int orientation = Util.getDisplayRotation(mActivity);
236 float scaleX = 1f, scaleY = 1f;
237 float scaledTextureWidth, scaledTextureHeight;
238 if (width > height) {
239 scaledTextureWidth = Math.max(width,
240 (int) (height * mAspectRatio));
241 scaledTextureHeight = Math.max(height,
242 (int)(width / mAspectRatio));
243 } else {
244 scaledTextureWidth = Math.max(width,
245 (int) (height / mAspectRatio));
246 scaledTextureHeight = Math.max(height,
247 (int) (width * mAspectRatio));
248 }
249
250 if (mSurfaceTextureUncroppedWidth != scaledTextureWidth ||
251 mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
252 mSurfaceTextureUncroppedWidth = scaledTextureWidth;
253 mSurfaceTextureUncroppedHeight = scaledTextureHeight;
254 }
255 scaleX = scaledTextureWidth / width;
256 scaleY = scaledTextureHeight / height;
257 mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2);
258 mTextureView.setTransform(mMatrix);
259
260 if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) {
261 LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams();
262 lp.width = (int) mSurfaceTextureUncroppedWidth;
263 lp.height = (int) mSurfaceTextureUncroppedHeight;
264 lp.gravity = Gravity.CENTER;
265 mSurfaceView.requestLayout();
266 }
267 }
268
269 public void hideUI() {
270 mCameraControls.setVisibility(View.INVISIBLE);
271 mSwitcher.closePopup();
272 }
273
274 public void showUI() {
275 mCameraControls.setVisibility(View.VISIBLE);
276 }
277
278 public void hideSwitcher() {
279 mSwitcher.closePopup();
280 mSwitcher.setVisibility(View.INVISIBLE);
281 }
282
283 public void showSwitcher() {
284 mSwitcher.setVisibility(View.VISIBLE);
285 }
286
Doris Liu6827ce22013-03-12 19:24:28 -0700287 public boolean collapseCameraControls() {
288 boolean ret = false;
289 if (mPopup != null) {
290 dismissPopup(false);
291 ret = true;
292 }
293 return ret;
294 }
295
296 public boolean removeTopLevelPopup() {
297 if (mPopup != null) {
298 dismissPopup(true);
299 return true;
300 }
301 return false;
302 }
303
304 public void enableCameraControls(boolean enable) {
305 if (mGestures != null) {
306 mGestures.setZoomOnly(!enable);
307 }
308 if (mPieRenderer != null && mPieRenderer.showsItems()) {
309 mPieRenderer.hide();
310 }
311 }
312
313 public void overrideSettings(final String... keyvalues) {
314 mVideoMenu.overrideSettings(keyvalues);
315 }
316
Doris Liu6827ce22013-03-12 19:24:28 -0700317 public void setOrientationIndicator(int orientation, boolean animation) {
Doris Liu6827ce22013-03-12 19:24:28 -0700318 // We change the orientation of the linearlayout only for phone UI
319 // because when in portrait the width is not enough.
320 if (mLabelsLinearLayout != null) {
321 if (((orientation / 90) & 1) == 0) {
322 mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL);
323 } else {
324 mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
325 }
326 }
327 mRecordingTimeRect.setOrientation(0, animation);
328 }
329
330 public SurfaceHolder getSurfaceHolder() {
Doris Liu6432cd62013-06-13 17:20:31 -0700331 return mSurfaceView.getHolder();
Doris Liu6827ce22013-03-12 19:24:28 -0700332 }
333
334 public void hideSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700335 mSurfaceView.setVisibility(View.GONE);
336 mTextureView.setVisibility(View.VISIBLE);
337 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700338 }
339
340 public void showSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700341 mSurfaceView.setVisibility(View.VISIBLE);
342 mTextureView.setVisibility(View.GONE);
343 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700344 }
345
346 private void initializeOverlay() {
347 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
348 if (mPieRenderer == null) {
349 mPieRenderer = new PieRenderer(mActivity);
350 mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer);
351 mPieRenderer.setPieListener(this);
352 }
353 mRenderOverlay.addRenderer(mPieRenderer);
354 if (mZoomRenderer == null) {
355 mZoomRenderer = new ZoomRenderer(mActivity);
356 }
357 mRenderOverlay.addRenderer(mZoomRenderer);
358 if (mGestures == null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700359 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
360 mRenderOverlay.setGestures(mGestures);
Doris Liu6827ce22013-03-12 19:24:28 -0700361 }
362 mGestures.setRenderOverlay(mRenderOverlay);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700363
364 mPreviewThumb = mActivity.findViewById(R.id.preview_thumb);
365 mPreviewThumb.setOnClickListener(new OnClickListener() {
366 @Override
367 public void onClick(View v) {
Doris Liu6432cd62013-06-13 17:20:31 -0700368 // TODO: Go to filmstrip view
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700369 }
370 });
Doris Liu6827ce22013-03-12 19:24:28 -0700371 }
372
373 public void setPrefChangedListener(OnPreferenceChangedListener listener) {
374 mVideoMenu.setListener(listener);
375 }
376
377 private void initializeMiscControls() {
Doris Liu6827ce22013-03-12 19:24:28 -0700378 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
Doris Liu6827ce22013-03-12 19:24:28 -0700379 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
380 mShutterButton.setOnShutterButtonListener(mController);
381 mShutterButton.setVisibility(View.VISIBLE);
382 mShutterButton.requestFocus();
383 mShutterButton.enableTouch(true);
384 mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
385 mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
386 mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
387 // The R.id.labels can only be found in phone layout.
388 // That is, mLabelsLinearLayout should be null in tablet layout.
389 mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
390 }
391
Michael Kolb87880792013-04-30 15:38:49 -0700392 public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) {
Sascha Haeberling140c2632013-04-23 09:58:51 -0700393 mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode());
Michael Kolb87880792013-04-30 15:38:49 -0700394 boolean location = RecordLocationPreference.get(
395 prefs, mActivity.getContentResolver());
396 mOnScreenIndicators.updateLocationIndicator(location);
397
Doris Liu6827ce22013-03-12 19:24:28 -0700398 }
399
400 public void setAspectRatio(double ratio) {
Doris Liu6432cd62013-06-13 17:20:31 -0700401 // mPreviewFrameLayout.setAspectRatio(ratio);
Doris Liu6827ce22013-03-12 19:24:28 -0700402 }
403
404 public void showTimeLapseUI(boolean enable) {
405 if (mTimeLapseLabel != null) {
406 mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
407 }
408 }
409
Michael Kolb3bc96b22013-03-12 10:24:42 -0700410 private void openMenu() {
411 if (mPieRenderer != null) {
412 mPieRenderer.showInCenter();
413 }
414 }
415
Doris Liu6827ce22013-03-12 19:24:28 -0700416 public void showPopup(AbstractSettingPopup popup) {
Doris Liu6432cd62013-06-13 17:20:31 -0700417 hideUI();
Doris Liu6827ce22013-03-12 19:24:28 -0700418 mBlocker.setVisibility(View.INVISIBLE);
419 setShowMenu(false);
420 mPopup = popup;
421 mPopup.setVisibility(View.VISIBLE);
422 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
423 LayoutParams.WRAP_CONTENT);
424 lp.gravity = Gravity.CENTER;
425 ((FrameLayout) mRootView).addView(mPopup, lp);
426 }
427
428 public void dismissPopup(boolean topLevelOnly) {
429 dismissPopup(topLevelOnly, true);
430 }
431
432 public void dismissPopup(boolean topLevelPopupOnly, boolean fullScreen) {
Doris Liu69ef5ea2013-05-07 13:48:10 -0700433 // In review mode, we do not want to bring up the camera UI
434 if (mController.isInReviewMode()) return;
435
Doris Liu6827ce22013-03-12 19:24:28 -0700436 if (fullScreen) {
Doris Liu6432cd62013-06-13 17:20:31 -0700437 showUI();
Doris Liu6827ce22013-03-12 19:24:28 -0700438 mBlocker.setVisibility(View.VISIBLE);
439 }
440 setShowMenu(fullScreen);
441 if (mPopup != null) {
442 ((FrameLayout) mRootView).removeView(mPopup);
443 mPopup = null;
444 }
445 mVideoMenu.popupDismissed(topLevelPopupOnly);
446 }
447
448 public void onShowSwitcherPopup() {
449 hidePieRenderer();
450 }
451
452 public boolean hidePieRenderer() {
453 if (mPieRenderer != null && mPieRenderer.showsItems()) {
454 mPieRenderer.hide();
455 return true;
456 }
457 return false;
458 }
459
Doris Liu61f2b082013-03-27 17:25:43 -0700460 // disable preview gestures after shutter is pressed
461 public void setShutterPressed(boolean pressed) {
462 if (mGestures == null) return;
463 mGestures.setEnabled(!pressed);
464 }
465
Doris Liu6827ce22013-03-12 19:24:28 -0700466 public void enableShutter(boolean enable) {
467 if (mShutterButton != null) {
468 mShutterButton.setEnabled(enable);
469 }
470 }
471
472 // PieListener
473 @Override
474 public void onPieOpened(int centerX, int centerY) {
Doris Liu6432cd62013-06-13 17:20:31 -0700475 setSwipingEnabled(false);
Angus Kong91fffb32013-05-29 17:15:15 -0700476 dismissPopup(false, true);
Doris Liu6827ce22013-03-12 19:24:28 -0700477 }
478
479 @Override
480 public void onPieClosed() {
Doris Liu6432cd62013-06-13 17:20:31 -0700481 setSwipingEnabled(true);
482 }
483
484 public void setSwipingEnabled(boolean enable) {
485 mActivity.setSwipingEnabled(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700486 }
487
488 public void showPreviewBorder(boolean enable) {
Doris Liu6432cd62013-06-13 17:20:31 -0700489 // TODO: mPreviewFrameLayout.showBorder(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700490 }
491
492 // SingleTapListener
493 // Preview area is touched. Take a picture.
494 @Override
495 public void onSingleTapUp(View view, int x, int y) {
496 mController.onSingleTapUp(view, x, y);
497 }
498
Doris Liu6827ce22013-03-12 19:24:28 -0700499 public void showRecordingUI(boolean recording, boolean zoomSupported) {
Doris Liu6432cd62013-06-13 17:20:31 -0700500 mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700501 mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
502 if (recording) {
503 mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording);
Doris Liu6432cd62013-06-13 17:20:31 -0700504 hideSwitcher();
Doris Liu6827ce22013-03-12 19:24:28 -0700505 mRecordingTimeView.setText("");
506 mRecordingTimeView.setVisibility(View.VISIBLE);
507 // The camera is not allowed to be accessed in older api levels during
508 // recording. It is therefore necessary to hide the zoom UI on older
509 // platforms.
510 // See the documentation of android.media.MediaRecorder.start() for
511 // further explanation.
512 if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
513 // TODO: disable zoom UI here.
514 }
515 } else {
516 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
Doris Liu6432cd62013-06-13 17:20:31 -0700517 showSwitcher();
Doris Liu6827ce22013-03-12 19:24:28 -0700518 mRecordingTimeView.setVisibility(View.GONE);
519 if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
520 // TODO: enable zoom UI here.
521 }
522 }
523 }
524
525 public void showReviewImage(Bitmap bitmap) {
526 mReviewImage.setImageBitmap(bitmap);
527 mReviewImage.setVisibility(View.VISIBLE);
528 }
529
530 public void showReviewControls() {
531 Util.fadeOut(mShutterButton);
532 Util.fadeIn(mReviewDoneButton);
533 Util.fadeIn(mReviewPlayButton);
534 mReviewImage.setVisibility(View.VISIBLE);
Doris Liu6432cd62013-06-13 17:20:31 -0700535 mMenuButton.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700536 mOnScreenIndicators.setVisibility(View.GONE);
537 }
538
539 public void hideReviewUI() {
540 mReviewImage.setVisibility(View.GONE);
541 mShutterButton.setEnabled(true);
Doris Liu6432cd62013-06-13 17:20:31 -0700542 mMenuButton.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700543 mOnScreenIndicators.setVisibility(View.VISIBLE);
544 Util.fadeOut(mReviewDoneButton);
545 Util.fadeOut(mReviewPlayButton);
546 Util.fadeIn(mShutterButton);
547 }
548
549 private void setShowMenu(boolean show) {
550 if (mOnScreenIndicators != null) {
551 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
552 }
Doris Liu6432cd62013-06-13 17:20:31 -0700553 if (mMenuButton != null) {
554 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700555 }
556 }
557
Doris Liu6432cd62013-06-13 17:20:31 -0700558 public void onSwitchMode(boolean toCamera) {
559 if (toCamera) {
560 showUI();
561 } else {
562 hideUI();
563 }
Doris Liu6827ce22013-03-12 19:24:28 -0700564 if (mGestures != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700565 mGestures.setEnabled(toCamera);
Doris Liu6827ce22013-03-12 19:24:28 -0700566 }
567 if (mPopup != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700568 dismissPopup(false, toCamera);
Doris Liu6827ce22013-03-12 19:24:28 -0700569 }
570 if (mRenderOverlay != null) {
571 // this can not happen in capture mode
Doris Liu6432cd62013-06-13 17:20:31 -0700572 mRenderOverlay.setVisibility(toCamera ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700573 }
Doris Liu6432cd62013-06-13 17:20:31 -0700574 setShowMenu(toCamera);
Doris Liu6827ce22013-03-12 19:24:28 -0700575 }
576
577 public void initializePopup(PreferenceGroup pref) {
578 mVideoMenu.initialize(pref);
579 }
580
581 public void initializeZoom(Parameters param) {
Doris Liu6432cd62013-06-13 17:20:31 -0700582 if (param == null || !param.isZoomSupported()) {
583 mGestures.setZoomEnabled(false);
584 return;
585 }
586 mGestures.setZoomEnabled(true);
Doris Liu6827ce22013-03-12 19:24:28 -0700587 mZoomMax = param.getMaxZoom();
588 mZoomRatios = param.getZoomRatios();
589 // Currently we use immediate zoom for fast zooming to get better UX and
590 // there is no plan to take advantage of the smooth zoom.
591 mZoomRenderer.setZoomMax(mZoomMax);
592 mZoomRenderer.setZoom(param.getZoom());
593 mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom()));
594 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
595 }
596
597 public void clickShutter() {
598 mShutterButton.performClick();
599 }
600
601 public void pressShutter(boolean pressed) {
602 mShutterButton.setPressed(pressed);
603 }
604
Doris Liu6432cd62013-06-13 17:20:31 -0700605 public View getShutterButton() {
606 return mShutterButton;
Doris Liu6827ce22013-03-12 19:24:28 -0700607 }
608
609 public void setRecordingTime(String text) {
610 mRecordingTimeView.setText(text);
611 }
612
613 public void setRecordingTimeTextColor(int color) {
614 mRecordingTimeView.setTextColor(color);
615 }
616
Doris Liu6432cd62013-06-13 17:20:31 -0700617 public boolean isVisible() {
618 return mTextureView.getVisibility() == View.VISIBLE;
619 }
620
621 public void onDisplayChanged() {
622 mCameraControls.checkLayoutFlip();
623 mController.updateCameraOrientation();
624 }
625
626 /**
627 * Enable or disable the preview thumbnail for click events.
628 */
629 public void enablePreviewThumb(boolean enabled) {
630 if (enabled) {
631 mPreviewThumb.setVisibility(View.VISIBLE);
632 } else {
633 mPreviewThumb.setVisibility(View.GONE);
634 }
635 }
636
Doris Liu6827ce22013-03-12 19:24:28 -0700637 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
638 @Override
639 public void onZoomValueChanged(int index) {
640 int newZoom = mController.onZoomChanged(index);
641 if (mZoomRenderer != null) {
642 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
643 }
644 }
645
646 @Override
647 public void onZoomStart() {
648 }
649
650 @Override
651 public void onZoomEnd() {
652 }
653 }
Michael Kolb3bc96b22013-03-12 10:24:42 -0700654
Doris Liu6432cd62013-06-13 17:20:31 -0700655 public SurfaceTexture getSurfaceTexture() {
Doris Liu6432cd62013-06-13 17:20:31 -0700656 return mSurfaceTexture;
657 }
658
659 // SurfaceTexture callbacks
Michael Kolb3bc96b22013-03-12 10:24:42 -0700660 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700661 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Angus Kong395ee2d2013-07-15 12:42:41 -0700662 mSurfaceTexture = surface;
663 mController.onPreviewUIReady();
Michael Kolb3bc96b22013-03-12 10:24:42 -0700664 }
665
Doris Liu6432cd62013-06-13 17:20:31 -0700666 @Override
667 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
668 mSurfaceTexture = null;
Angus Kong395ee2d2013-07-15 12:42:41 -0700669 mController.onPreviewUIDestroyed();
Doris Liu6432cd62013-06-13 17:20:31 -0700670 Log.d(TAG, "surfaceTexture is destroyed");
671 return true;
672 }
673
674 @Override
675 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
676 }
677
678 @Override
679 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
680 }
681
682 // SurfaceHolder callbacks
683 @Override
684 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
685 Log.v(TAG, "Surface changed. width=" + width + ". height=" + height);
686 }
687
688 @Override
689 public void surfaceCreated(SurfaceHolder holder) {
690 Log.v(TAG, "Surface created");
691 }
692
693 @Override
694 public void surfaceDestroyed(SurfaceHolder holder) {
695 Log.v(TAG, "Surface destroyed");
696 mController.stopPreview();
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700697 }
Doris Liu6827ce22013-03-12 19:24:28 -0700698}