blob: 1f6505fcfb001e7c89058b03bcb73ea74f033d80 [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
Sascha Haeberling8e963a52013-08-06 11:43:02 -070019import java.util.List;
20
Doris Liu6827ce22013-03-12 19:24:28 -070021import android.graphics.Bitmap;
Doris Liu6432cd62013-06-13 17:20:31 -070022import android.graphics.Matrix;
23import android.graphics.SurfaceTexture;
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;
37import android.widget.FrameLayout;
38import android.widget.FrameLayout.LayoutParams;
39import android.widget.ImageView;
40import android.widget.LinearLayout;
41import 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;
47import com.android.camera.ui.CameraSwitcher;
48import com.android.camera.ui.CameraSwitcher.CameraSwitchListener;
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;
52import com.android.camera.ui.ZoomRenderer;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070053import com.android.camera2.R;
Doris Liu6827ce22013-03-12 19:24:28 -070054import com.android.gallery3d.common.ApiHelper;
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;
Sascha Haeberling37f36112013-08-06 14:31:52 -070094 private View mFlashOverlay;
Doris Liu6827ce22013-03-12 19:24:28 -070095
Doris Liu6432cd62013-06-13 17:20:31 -070096 private SurfaceView mSurfaceView = null;
97 private int mPreviewWidth = 0;
98 private int mPreviewHeight = 0;
99 private float mSurfaceTextureUncroppedWidth;
100 private float mSurfaceTextureUncroppedHeight;
101 private float mAspectRatio = 4f / 3f;
102 private Matrix mMatrix = null;
Sascha Haeberling37f36112013-08-06 14:31:52 -0700103 private final AnimationManager mAnimationManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700104 private final Handler mHandler = new Handler() {
105 @Override
106 public void handleMessage(Message msg) {
107 switch (msg.what) {
108 case UPDATE_TRANSFORM_MATRIX:
109 setTransformMatrix(mPreviewWidth, mPreviewHeight);
110 break;
111 default:
112 break;
113 }
114 }
115 };
116 private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
117 @Override
118 public void onLayoutChange(View v, int left, int top, int right,
119 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
120 int width = right - left;
121 int height = bottom - top;
122 // Full-screen screennail
123 int w = width;
124 int h = height;
125 if (Util.getDisplayRotation(mActivity) % 180 != 0) {
126 w = height;
127 h = width;
128 }
129 if (mPreviewWidth != width || mPreviewHeight != height) {
130 mPreviewWidth = width;
131 mPreviewHeight = height;
132 onScreenSizeChanged(width, height, w, h);
133 }
134 }
135 };
136
Doris Liu6827ce22013-03-12 19:24:28 -0700137 public VideoUI(CameraActivity activity, VideoController controller, View parent) {
138 mActivity = activity;
139 mController = controller;
140 mRootView = parent;
141 mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true);
Doris Liu6432cd62013-06-13 17:20:31 -0700142 mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content);
143 mTextureView.setSurfaceTextureListener(this);
144 mRootView.addOnLayoutChangeListener(mLayoutListener);
145 ((CameraRootView) mRootView).setDisplayChangeListener(this);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700146 mFlashOverlay = mRootView.findViewById(R.id.flash_overlay);
Doris Liu6432cd62013-06-13 17:20:31 -0700147 mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
148 mSwitcher = (CameraSwitcher) mRootView.findViewById(R.id.camera_switcher);
Doris Liu147e26a2013-06-24 15:29:54 -0700149 mSwitcher.setCurrentIndex(CameraSwitcher.VIDEO_MODULE_INDEX);
Doris Liu6432cd62013-06-13 17:20:31 -0700150 mSwitcher.setSwitchListener((CameraSwitchListener) mActivity);
Doris Liu6827ce22013-03-12 19:24:28 -0700151 initializeMiscControls();
152 initializeControlByIntent();
153 initializeOverlay();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700154 mAnimationManager = new AnimationManager();
Doris Liu6827ce22013-03-12 19:24:28 -0700155 }
156
Doris Liu6432cd62013-06-13 17:20:31 -0700157
158 public void initializeSurfaceView() {
159 mSurfaceView = new SurfaceView(mActivity);
160 ((ViewGroup) mRootView).addView(mSurfaceView, 0);
161 mSurfaceView.getHolder().addCallback(this);
162 }
163
Doris Liu6827ce22013-03-12 19:24:28 -0700164 private void initializeControlByIntent() {
165 mBlocker = mActivity.findViewById(R.id.blocker);
Doris Liu6432cd62013-06-13 17:20:31 -0700166 mMenuButton = mActivity.findViewById(R.id.menu);
167 mMenuButton.setOnClickListener(new OnClickListener() {
Doris Liu6827ce22013-03-12 19:24:28 -0700168 @Override
169 public void onClick(View v) {
170 if (mPieRenderer != null) {
171 mPieRenderer.showInCenter();
172 }
173 }
174 });
Doris Liu6432cd62013-06-13 17:20:31 -0700175
176 mCameraControls = (CameraControls) mActivity.findViewById(R.id.camera_controls);
Michael Kolbeb8adc12013-04-26 11:09:29 -0700177 mOnScreenIndicators = new OnScreenIndicators(mActivity,
Sascha Haeberling140c2632013-04-23 09:58:51 -0700178 mActivity.findViewById(R.id.on_screen_indicators));
179 mOnScreenIndicators.resetToDefault();
Doris Liu6827ce22013-03-12 19:24:28 -0700180 if (mController.isVideoCaptureIntent()) {
Doris Liu6432cd62013-06-13 17:20:31 -0700181 hideSwitcher();
182 mActivity.getLayoutInflater().inflate(R.layout.review_module_control,
183 (ViewGroup) mCameraControls);
Doris Liu6827ce22013-03-12 19:24:28 -0700184 // Cannot use RotateImageView for "done" and "cancel" button because
185 // the tablet layout uses RotateLayout, which cannot be cast to
186 // RotateImageView.
187 mReviewDoneButton = mActivity.findViewById(R.id.btn_done);
188 mReviewCancelButton = mActivity.findViewById(R.id.btn_cancel);
189 mReviewPlayButton = mActivity.findViewById(R.id.btn_play);
190 mReviewCancelButton.setVisibility(View.VISIBLE);
191 mReviewDoneButton.setOnClickListener(new OnClickListener() {
192 @Override
193 public void onClick(View v) {
194 mController.onReviewDoneClicked(v);
195 }
196 });
197 mReviewCancelButton.setOnClickListener(new OnClickListener() {
198 @Override
199 public void onClick(View v) {
200 mController.onReviewCancelClicked(v);
201 }
202 });
203 mReviewPlayButton.setOnClickListener(new OnClickListener() {
204 @Override
205 public void onClick(View v) {
206 mController.onReviewPlayClicked(v);
207 }
208 });
209 }
210 }
211
Doris Liu6432cd62013-06-13 17:20:31 -0700212 public void setPreviewSize(int width, int height) {
213 if (width == 0 || height == 0) {
214 Log.w(TAG, "Preview size should not be 0.");
215 return;
216 }
217 if (width > height) {
218 mAspectRatio = (float) width / height;
219 } else {
220 mAspectRatio = (float) height / width;
221 }
222 mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX);
223 }
224
225 public int getPreviewWidth() {
226 return mPreviewWidth;
227 }
228
229 public int getPreviewHeight() {
230 return mPreviewHeight;
231 }
232
233 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
234 setTransformMatrix(width, height);
235 }
236
237 private void setTransformMatrix(int width, int height) {
238 mMatrix = mTextureView.getTransform(mMatrix);
239 int orientation = Util.getDisplayRotation(mActivity);
240 float scaleX = 1f, scaleY = 1f;
241 float scaledTextureWidth, scaledTextureHeight;
242 if (width > height) {
243 scaledTextureWidth = Math.max(width,
244 (int) (height * mAspectRatio));
245 scaledTextureHeight = Math.max(height,
246 (int)(width / mAspectRatio));
247 } else {
248 scaledTextureWidth = Math.max(width,
249 (int) (height / mAspectRatio));
250 scaledTextureHeight = Math.max(height,
251 (int) (width * mAspectRatio));
252 }
253
254 if (mSurfaceTextureUncroppedWidth != scaledTextureWidth ||
255 mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
256 mSurfaceTextureUncroppedWidth = scaledTextureWidth;
257 mSurfaceTextureUncroppedHeight = scaledTextureHeight;
258 }
259 scaleX = scaledTextureWidth / width;
260 scaleY = scaledTextureHeight / height;
261 mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2);
262 mTextureView.setTransform(mMatrix);
263
264 if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) {
265 LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams();
266 lp.width = (int) mSurfaceTextureUncroppedWidth;
267 lp.height = (int) mSurfaceTextureUncroppedHeight;
268 lp.gravity = Gravity.CENTER;
269 mSurfaceView.requestLayout();
270 }
271 }
272
Sascha Haeberling37f36112013-08-06 14:31:52 -0700273 /**
274 * Starts a flash animation
275 */
276 public void animateFlash() {
277 mAnimationManager.startFlashAnimation(mFlashOverlay);
278 }
279
280 /**
281 * Starts a capture animation
282 * @param bitmap the captured image that we shrink and slide in the animation
283 */
284 public void animateCapture(Bitmap bitmap) {
285 ((ImageView) mPreviewThumb).setImageBitmap(bitmap);
286 mAnimationManager.startCaptureAnimation(mPreviewThumb);
287 }
288
289 /**
290 * Cancels on-going animations
291 */
292 public void cancelAnimations() {
293 mAnimationManager.cancelAnimations();
294 }
295
Doris Liu6432cd62013-06-13 17:20:31 -0700296 public void hideUI() {
297 mCameraControls.setVisibility(View.INVISIBLE);
298 mSwitcher.closePopup();
299 }
300
301 public void showUI() {
302 mCameraControls.setVisibility(View.VISIBLE);
303 }
304
305 public void hideSwitcher() {
306 mSwitcher.closePopup();
307 mSwitcher.setVisibility(View.INVISIBLE);
308 }
309
310 public void showSwitcher() {
311 mSwitcher.setVisibility(View.VISIBLE);
312 }
313
Doris Liu6827ce22013-03-12 19:24:28 -0700314 public boolean collapseCameraControls() {
315 boolean ret = false;
316 if (mPopup != null) {
317 dismissPopup(false);
318 ret = true;
319 }
320 return ret;
321 }
322
323 public boolean removeTopLevelPopup() {
324 if (mPopup != null) {
325 dismissPopup(true);
326 return true;
327 }
328 return false;
329 }
330
331 public void enableCameraControls(boolean enable) {
332 if (mGestures != null) {
333 mGestures.setZoomOnly(!enable);
334 }
335 if (mPieRenderer != null && mPieRenderer.showsItems()) {
336 mPieRenderer.hide();
337 }
338 }
339
340 public void overrideSettings(final String... keyvalues) {
341 mVideoMenu.overrideSettings(keyvalues);
342 }
343
Doris Liu6827ce22013-03-12 19:24:28 -0700344 public void setOrientationIndicator(int orientation, boolean animation) {
Doris Liu6827ce22013-03-12 19:24:28 -0700345 // We change the orientation of the linearlayout only for phone UI
346 // because when in portrait the width is not enough.
347 if (mLabelsLinearLayout != null) {
348 if (((orientation / 90) & 1) == 0) {
349 mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL);
350 } else {
351 mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
352 }
353 }
354 mRecordingTimeRect.setOrientation(0, animation);
355 }
356
357 public SurfaceHolder getSurfaceHolder() {
Doris Liu6432cd62013-06-13 17:20:31 -0700358 return mSurfaceView.getHolder();
Doris Liu6827ce22013-03-12 19:24:28 -0700359 }
360
361 public void hideSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700362 mSurfaceView.setVisibility(View.GONE);
363 mTextureView.setVisibility(View.VISIBLE);
364 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700365 }
366
367 public void showSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700368 mSurfaceView.setVisibility(View.VISIBLE);
369 mTextureView.setVisibility(View.GONE);
370 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700371 }
372
373 private void initializeOverlay() {
374 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
375 if (mPieRenderer == null) {
376 mPieRenderer = new PieRenderer(mActivity);
377 mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer);
378 mPieRenderer.setPieListener(this);
379 }
380 mRenderOverlay.addRenderer(mPieRenderer);
381 if (mZoomRenderer == null) {
382 mZoomRenderer = new ZoomRenderer(mActivity);
383 }
384 mRenderOverlay.addRenderer(mZoomRenderer);
385 if (mGestures == null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700386 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
387 mRenderOverlay.setGestures(mGestures);
Doris Liu6827ce22013-03-12 19:24:28 -0700388 }
389 mGestures.setRenderOverlay(mRenderOverlay);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700390
391 mPreviewThumb = mActivity.findViewById(R.id.preview_thumb);
392 mPreviewThumb.setOnClickListener(new OnClickListener() {
393 @Override
394 public void onClick(View v) {
Doris Liu6432cd62013-06-13 17:20:31 -0700395 // TODO: Go to filmstrip view
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700396 }
397 });
Doris Liu6827ce22013-03-12 19:24:28 -0700398 }
399
400 public void setPrefChangedListener(OnPreferenceChangedListener listener) {
401 mVideoMenu.setListener(listener);
402 }
403
404 private void initializeMiscControls() {
Doris Liu6827ce22013-03-12 19:24:28 -0700405 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
Doris Liu6827ce22013-03-12 19:24:28 -0700406 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
407 mShutterButton.setOnShutterButtonListener(mController);
408 mShutterButton.setVisibility(View.VISIBLE);
409 mShutterButton.requestFocus();
410 mShutterButton.enableTouch(true);
411 mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
412 mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
413 mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
414 // The R.id.labels can only be found in phone layout.
415 // That is, mLabelsLinearLayout should be null in tablet layout.
416 mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
417 }
418
Michael Kolb87880792013-04-30 15:38:49 -0700419 public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) {
Sascha Haeberling140c2632013-04-23 09:58:51 -0700420 mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode());
Michael Kolb87880792013-04-30 15:38:49 -0700421 boolean location = RecordLocationPreference.get(
422 prefs, mActivity.getContentResolver());
423 mOnScreenIndicators.updateLocationIndicator(location);
424
Doris Liu6827ce22013-03-12 19:24:28 -0700425 }
426
427 public void setAspectRatio(double ratio) {
Doris Liu6432cd62013-06-13 17:20:31 -0700428 // mPreviewFrameLayout.setAspectRatio(ratio);
Doris Liu6827ce22013-03-12 19:24:28 -0700429 }
430
431 public void showTimeLapseUI(boolean enable) {
432 if (mTimeLapseLabel != null) {
433 mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
434 }
435 }
436
Michael Kolb3bc96b22013-03-12 10:24:42 -0700437 private void openMenu() {
438 if (mPieRenderer != null) {
439 mPieRenderer.showInCenter();
440 }
441 }
442
Doris Liu6827ce22013-03-12 19:24:28 -0700443 public void showPopup(AbstractSettingPopup popup) {
Doris Liu6432cd62013-06-13 17:20:31 -0700444 hideUI();
Doris Liu6827ce22013-03-12 19:24:28 -0700445 mBlocker.setVisibility(View.INVISIBLE);
446 setShowMenu(false);
447 mPopup = popup;
448 mPopup.setVisibility(View.VISIBLE);
449 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
450 LayoutParams.WRAP_CONTENT);
451 lp.gravity = Gravity.CENTER;
452 ((FrameLayout) mRootView).addView(mPopup, lp);
453 }
454
455 public void dismissPopup(boolean topLevelOnly) {
456 dismissPopup(topLevelOnly, true);
457 }
458
459 public void dismissPopup(boolean topLevelPopupOnly, boolean fullScreen) {
Doris Liu69ef5ea2013-05-07 13:48:10 -0700460 // In review mode, we do not want to bring up the camera UI
461 if (mController.isInReviewMode()) return;
462
Doris Liu6827ce22013-03-12 19:24:28 -0700463 if (fullScreen) {
Doris Liu6432cd62013-06-13 17:20:31 -0700464 showUI();
Doris Liu6827ce22013-03-12 19:24:28 -0700465 mBlocker.setVisibility(View.VISIBLE);
466 }
467 setShowMenu(fullScreen);
468 if (mPopup != null) {
469 ((FrameLayout) mRootView).removeView(mPopup);
470 mPopup = null;
471 }
472 mVideoMenu.popupDismissed(topLevelPopupOnly);
473 }
474
475 public void onShowSwitcherPopup() {
476 hidePieRenderer();
477 }
478
479 public boolean hidePieRenderer() {
480 if (mPieRenderer != null && mPieRenderer.showsItems()) {
481 mPieRenderer.hide();
482 return true;
483 }
484 return false;
485 }
486
Doris Liu61f2b082013-03-27 17:25:43 -0700487 // disable preview gestures after shutter is pressed
488 public void setShutterPressed(boolean pressed) {
489 if (mGestures == null) return;
490 mGestures.setEnabled(!pressed);
491 }
492
Doris Liu6827ce22013-03-12 19:24:28 -0700493 public void enableShutter(boolean enable) {
494 if (mShutterButton != null) {
495 mShutterButton.setEnabled(enable);
496 }
497 }
498
499 // PieListener
500 @Override
501 public void onPieOpened(int centerX, int centerY) {
Doris Liu6432cd62013-06-13 17:20:31 -0700502 setSwipingEnabled(false);
Angus Kong91fffb32013-05-29 17:15:15 -0700503 dismissPopup(false, true);
Doris Liu6827ce22013-03-12 19:24:28 -0700504 }
505
506 @Override
507 public void onPieClosed() {
Doris Liu6432cd62013-06-13 17:20:31 -0700508 setSwipingEnabled(true);
509 }
510
511 public void setSwipingEnabled(boolean enable) {
512 mActivity.setSwipingEnabled(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700513 }
514
515 public void showPreviewBorder(boolean enable) {
Doris Liu6432cd62013-06-13 17:20:31 -0700516 // TODO: mPreviewFrameLayout.showBorder(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700517 }
518
519 // SingleTapListener
520 // Preview area is touched. Take a picture.
521 @Override
522 public void onSingleTapUp(View view, int x, int y) {
523 mController.onSingleTapUp(view, x, y);
524 }
525
Doris Liu6827ce22013-03-12 19:24:28 -0700526 public void showRecordingUI(boolean recording, boolean zoomSupported) {
Doris Liu6432cd62013-06-13 17:20:31 -0700527 mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700528 mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
529 if (recording) {
530 mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording);
Doris Liu6432cd62013-06-13 17:20:31 -0700531 hideSwitcher();
Doris Liu6827ce22013-03-12 19:24:28 -0700532 mRecordingTimeView.setText("");
533 mRecordingTimeView.setVisibility(View.VISIBLE);
534 // The camera is not allowed to be accessed in older api levels during
535 // recording. It is therefore necessary to hide the zoom UI on older
536 // platforms.
537 // See the documentation of android.media.MediaRecorder.start() for
538 // further explanation.
539 if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
540 // TODO: disable zoom UI here.
541 }
542 } else {
543 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
Doris Liu6432cd62013-06-13 17:20:31 -0700544 showSwitcher();
Doris Liu6827ce22013-03-12 19:24:28 -0700545 mRecordingTimeView.setVisibility(View.GONE);
546 if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
547 // TODO: enable zoom UI here.
548 }
549 }
550 }
551
552 public void showReviewImage(Bitmap bitmap) {
553 mReviewImage.setImageBitmap(bitmap);
554 mReviewImage.setVisibility(View.VISIBLE);
555 }
556
557 public void showReviewControls() {
558 Util.fadeOut(mShutterButton);
559 Util.fadeIn(mReviewDoneButton);
560 Util.fadeIn(mReviewPlayButton);
561 mReviewImage.setVisibility(View.VISIBLE);
Doris Liu6432cd62013-06-13 17:20:31 -0700562 mMenuButton.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700563 mOnScreenIndicators.setVisibility(View.GONE);
564 }
565
566 public void hideReviewUI() {
567 mReviewImage.setVisibility(View.GONE);
568 mShutterButton.setEnabled(true);
Doris Liu6432cd62013-06-13 17:20:31 -0700569 mMenuButton.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700570 mOnScreenIndicators.setVisibility(View.VISIBLE);
571 Util.fadeOut(mReviewDoneButton);
572 Util.fadeOut(mReviewPlayButton);
573 Util.fadeIn(mShutterButton);
574 }
575
576 private void setShowMenu(boolean show) {
577 if (mOnScreenIndicators != null) {
578 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
579 }
Doris Liu6432cd62013-06-13 17:20:31 -0700580 if (mMenuButton != null) {
581 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700582 }
583 }
584
Doris Liu6432cd62013-06-13 17:20:31 -0700585 public void onSwitchMode(boolean toCamera) {
586 if (toCamera) {
587 showUI();
588 } else {
589 hideUI();
590 }
Doris Liu6827ce22013-03-12 19:24:28 -0700591 if (mGestures != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700592 mGestures.setEnabled(toCamera);
Doris Liu6827ce22013-03-12 19:24:28 -0700593 }
594 if (mPopup != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700595 dismissPopup(false, toCamera);
Doris Liu6827ce22013-03-12 19:24:28 -0700596 }
597 if (mRenderOverlay != null) {
598 // this can not happen in capture mode
Doris Liu6432cd62013-06-13 17:20:31 -0700599 mRenderOverlay.setVisibility(toCamera ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700600 }
Doris Liu6432cd62013-06-13 17:20:31 -0700601 setShowMenu(toCamera);
Doris Liu6827ce22013-03-12 19:24:28 -0700602 }
603
604 public void initializePopup(PreferenceGroup pref) {
605 mVideoMenu.initialize(pref);
606 }
607
608 public void initializeZoom(Parameters param) {
Doris Liu6432cd62013-06-13 17:20:31 -0700609 if (param == null || !param.isZoomSupported()) {
610 mGestures.setZoomEnabled(false);
611 return;
612 }
613 mGestures.setZoomEnabled(true);
Doris Liu6827ce22013-03-12 19:24:28 -0700614 mZoomMax = param.getMaxZoom();
615 mZoomRatios = param.getZoomRatios();
616 // Currently we use immediate zoom for fast zooming to get better UX and
617 // there is no plan to take advantage of the smooth zoom.
618 mZoomRenderer.setZoomMax(mZoomMax);
619 mZoomRenderer.setZoom(param.getZoom());
620 mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom()));
621 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
622 }
623
624 public void clickShutter() {
625 mShutterButton.performClick();
626 }
627
628 public void pressShutter(boolean pressed) {
629 mShutterButton.setPressed(pressed);
630 }
631
Doris Liu6432cd62013-06-13 17:20:31 -0700632 public View getShutterButton() {
633 return mShutterButton;
Doris Liu6827ce22013-03-12 19:24:28 -0700634 }
635
636 public void setRecordingTime(String text) {
637 mRecordingTimeView.setText(text);
638 }
639
640 public void setRecordingTimeTextColor(int color) {
641 mRecordingTimeView.setTextColor(color);
642 }
643
Doris Liu6432cd62013-06-13 17:20:31 -0700644 public boolean isVisible() {
645 return mTextureView.getVisibility() == View.VISIBLE;
646 }
647
648 public void onDisplayChanged() {
649 mCameraControls.checkLayoutFlip();
650 mController.updateCameraOrientation();
651 }
652
Doris Liu6827ce22013-03-12 19:24:28 -0700653 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
654 @Override
655 public void onZoomValueChanged(int index) {
656 int newZoom = mController.onZoomChanged(index);
657 if (mZoomRenderer != null) {
658 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
659 }
660 }
661
662 @Override
663 public void onZoomStart() {
664 }
665
666 @Override
667 public void onZoomEnd() {
668 }
669 }
Michael Kolb3bc96b22013-03-12 10:24:42 -0700670
Doris Liu6432cd62013-06-13 17:20:31 -0700671 public SurfaceTexture getSurfaceTexture() {
Doris Liu6432cd62013-06-13 17:20:31 -0700672 return mSurfaceTexture;
673 }
674
675 // SurfaceTexture callbacks
Michael Kolb3bc96b22013-03-12 10:24:42 -0700676 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700677 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Angus Kong395ee2d2013-07-15 12:42:41 -0700678 mSurfaceTexture = surface;
679 mController.onPreviewUIReady();
Michael Kolb3bc96b22013-03-12 10:24:42 -0700680 }
681
Doris Liu6432cd62013-06-13 17:20:31 -0700682 @Override
683 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
684 mSurfaceTexture = null;
Angus Kong395ee2d2013-07-15 12:42:41 -0700685 mController.onPreviewUIDestroyed();
Doris Liu6432cd62013-06-13 17:20:31 -0700686 Log.d(TAG, "surfaceTexture is destroyed");
687 return true;
688 }
689
690 @Override
691 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
692 }
693
694 @Override
695 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
696 }
697
698 // SurfaceHolder callbacks
699 @Override
700 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
701 Log.v(TAG, "Surface changed. width=" + width + ". height=" + height);
702 }
703
704 @Override
705 public void surfaceCreated(SurfaceHolder holder) {
706 Log.v(TAG, "Surface created");
707 }
708
709 @Override
710 public void surfaceDestroyed(SurfaceHolder holder) {
711 Log.v(TAG, "Surface destroyed");
712 mController.stopPreview();
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700713 }
Doris Liu6827ce22013-03-12 19:24:28 -0700714}