blob: 622ffa3d333cc35344e693860a6be3eaa783bafd [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 Liuc3679c02013-08-08 18:08:43 -070022import android.graphics.Color;
Doris Liu6432cd62013-06-13 17:20:31 -070023import android.graphics.Matrix;
24import android.graphics.SurfaceTexture;
Doris Liuc3679c02013-08-08 18:08:43 -070025import android.graphics.drawable.ColorDrawable;
Doris Liu6827ce22013-03-12 19:24:28 -070026import android.hardware.Camera.Parameters;
Doris Liu6432cd62013-06-13 17:20:31 -070027import android.os.Handler;
28import android.os.Message;
Doris Liu6827ce22013-03-12 19:24:28 -070029import android.util.Log;
30import android.view.Gravity;
Doris Liu6827ce22013-03-12 19:24:28 -070031import android.view.SurfaceHolder;
Doris Liu6432cd62013-06-13 17:20:31 -070032import android.view.SurfaceView;
33import android.view.TextureView;
34import android.view.TextureView.SurfaceTextureListener;
Doris Liu6827ce22013-03-12 19:24:28 -070035import android.view.View;
36import android.view.View.OnClickListener;
Doris Liu6432cd62013-06-13 17:20:31 -070037import android.view.View.OnLayoutChangeListener;
Doris Liu6827ce22013-03-12 19:24:28 -070038import android.view.ViewGroup;
39import android.widget.FrameLayout;
40import android.widget.FrameLayout.LayoutParams;
41import android.widget.ImageView;
42import android.widget.LinearLayout;
Doris Liuc3679c02013-08-08 18:08:43 -070043import android.widget.PopupWindow;
Doris Liu6827ce22013-03-12 19:24:28 -070044import android.widget.TextView;
45
46import com.android.camera.CameraPreference.OnPreferenceChangedListener;
47import com.android.camera.ui.AbstractSettingPopup;
Doris Liu6432cd62013-06-13 17:20:31 -070048import com.android.camera.ui.CameraControls;
49import com.android.camera.ui.CameraRootView;
50import com.android.camera.ui.CameraSwitcher;
51import com.android.camera.ui.CameraSwitcher.CameraSwitchListener;
Doris Liu6827ce22013-03-12 19:24:28 -070052import com.android.camera.ui.PieRenderer;
Doris Liu6827ce22013-03-12 19:24:28 -070053import com.android.camera.ui.RenderOverlay;
54import com.android.camera.ui.RotateLayout;
55import com.android.camera.ui.ZoomRenderer;
Angus Kongb50b5cb2013-08-09 14:55:20 -070056import com.android.camera.util.CameraUtil;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070057import com.android.camera2.R;
Angus Kongb50b5cb2013-08-09 14:55:20 -070058import com.android.camera.util.ApiHelper;
Doris Liu6827ce22013-03-12 19:24:28 -070059
Doris Liu6432cd62013-06-13 17:20:31 -070060public class VideoUI implements PieRenderer.PieListener,
Michael Kolb3bc96b22013-03-12 10:24:42 -070061 PreviewGestures.SingleTapListener,
Doris Liu6432cd62013-06-13 17:20:31 -070062 CameraRootView.MyDisplayListener,
63 SurfaceTextureListener, SurfaceHolder.Callback {
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;
Doris Liu6432cd62013-06-13 17:20:31 -070077 private CameraSwitcher mSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070078 private TextView mRecordingTimeView;
79 private LinearLayout mLabelsLinearLayout;
80 private View mTimeLapseLabel;
81 private RenderOverlay mRenderOverlay;
82 private PieRenderer mPieRenderer;
83 private VideoMenu mVideoMenu;
Doris Liu6432cd62013-06-13 17:20:31 -070084 private CameraControls mCameraControls;
Doris Liuc3679c02013-08-08 18:08:43 -070085 private SettingsPopup mPopup;
Doris Liu6827ce22013-03-12 19:24:28 -070086 private ZoomRenderer mZoomRenderer;
87 private PreviewGestures mGestures;
Doris Liu6432cd62013-06-13 17:20:31 -070088 private View mMenuButton;
Sascha Haeberling140c2632013-04-23 09:58:51 -070089 private OnScreenIndicators mOnScreenIndicators;
Doris Liu6827ce22013-03-12 19:24:28 -070090 private RotateLayout mRecordingTimeRect;
Doris Liu6432cd62013-06-13 17:20:31 -070091 private SurfaceTexture mSurfaceTexture;
Doris Liu6827ce22013-03-12 19:24:28 -070092 private VideoController mController;
93 private int mZoomMax;
94 private List<Integer> mZoomRatios;
Sascha Haeberling4f91ab52013-05-21 11:26:13 -070095 private View mPreviewThumb;
Sascha Haeberling37f36112013-08-06 14:31:52 -070096 private View mFlashOverlay;
Doris Liu6827ce22013-03-12 19:24:28 -070097
Doris Liu6432cd62013-06-13 17:20:31 -070098 private SurfaceView mSurfaceView = null;
99 private int mPreviewWidth = 0;
100 private int mPreviewHeight = 0;
101 private float mSurfaceTextureUncroppedWidth;
102 private float mSurfaceTextureUncroppedHeight;
103 private float mAspectRatio = 4f / 3f;
104 private Matrix mMatrix = null;
Sascha Haeberling37f36112013-08-06 14:31:52 -0700105 private final AnimationManager mAnimationManager;
Doris Liu6432cd62013-06-13 17:20:31 -0700106 private final Handler mHandler = new Handler() {
107 @Override
108 public void handleMessage(Message msg) {
109 switch (msg.what) {
110 case UPDATE_TRANSFORM_MATRIX:
111 setTransformMatrix(mPreviewWidth, mPreviewHeight);
112 break;
113 default:
114 break;
115 }
116 }
117 };
118 private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
119 @Override
120 public void onLayoutChange(View v, int left, int top, int right,
121 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
122 int width = right - left;
123 int height = bottom - top;
124 // Full-screen screennail
125 int w = width;
126 int h = height;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700127 if (CameraUtil.getDisplayRotation(mActivity) % 180 != 0) {
Doris Liu6432cd62013-06-13 17:20:31 -0700128 w = height;
129 h = width;
130 }
131 if (mPreviewWidth != width || mPreviewHeight != height) {
132 mPreviewWidth = width;
133 mPreviewHeight = height;
134 onScreenSizeChanged(width, height, w, h);
135 }
136 }
137 };
138
Doris Liuc3679c02013-08-08 18:08:43 -0700139 private class SettingsPopup extends PopupWindow {
140 public SettingsPopup(View popup) {
141 super(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
142 setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
143 setOutsideTouchable(true);
144 setFocusable(true);
145 popup.setVisibility(View.VISIBLE);
146 setContentView(popup);
147 showAtLocation(mRootView, Gravity.CENTER, 0, 0);
148 }
149
150 public void dismiss(boolean topLevelOnly) {
151 super.dismiss();
152 popupDismissed();
153 showUI();
154 mVideoMenu.popupDismissed(topLevelOnly);
155 }
156
157 @Override
158 public void dismiss() {
159 // Called by Framework when touch outside the popup or hit back key
160 dismiss(true);
161 }
162 }
163
Doris Liu6827ce22013-03-12 19:24:28 -0700164 public VideoUI(CameraActivity activity, VideoController controller, View parent) {
165 mActivity = activity;
166 mController = controller;
167 mRootView = parent;
168 mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true);
Doris Liu6432cd62013-06-13 17:20:31 -0700169 mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content);
170 mTextureView.setSurfaceTextureListener(this);
171 mRootView.addOnLayoutChangeListener(mLayoutListener);
172 ((CameraRootView) mRootView).setDisplayChangeListener(this);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700173 mFlashOverlay = mRootView.findViewById(R.id.flash_overlay);
Doris Liu6432cd62013-06-13 17:20:31 -0700174 mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
175 mSwitcher = (CameraSwitcher) mRootView.findViewById(R.id.camera_switcher);
Doris Liu147e26a2013-06-24 15:29:54 -0700176 mSwitcher.setCurrentIndex(CameraSwitcher.VIDEO_MODULE_INDEX);
Doris Liu6432cd62013-06-13 17:20:31 -0700177 mSwitcher.setSwitchListener((CameraSwitchListener) mActivity);
Doris Liu6827ce22013-03-12 19:24:28 -0700178 initializeMiscControls();
179 initializeControlByIntent();
180 initializeOverlay();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700181 mAnimationManager = new AnimationManager();
Doris Liu6827ce22013-03-12 19:24:28 -0700182 }
183
Doris Liu6432cd62013-06-13 17:20:31 -0700184
185 public void initializeSurfaceView() {
186 mSurfaceView = new SurfaceView(mActivity);
187 ((ViewGroup) mRootView).addView(mSurfaceView, 0);
188 mSurfaceView.getHolder().addCallback(this);
189 }
190
Doris Liu6827ce22013-03-12 19:24:28 -0700191 private void initializeControlByIntent() {
Doris Liu2a7f44c2013-08-12 15:18:53 -0700192 mMenuButton = mRootView.findViewById(R.id.menu);
Doris Liu6432cd62013-06-13 17:20:31 -0700193 mMenuButton.setOnClickListener(new OnClickListener() {
Doris Liu6827ce22013-03-12 19:24:28 -0700194 @Override
195 public void onClick(View v) {
196 if (mPieRenderer != null) {
197 mPieRenderer.showInCenter();
198 }
199 }
200 });
Doris Liu6432cd62013-06-13 17:20:31 -0700201
Doris Liu2a7f44c2013-08-12 15:18:53 -0700202 mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls);
Michael Kolbeb8adc12013-04-26 11:09:29 -0700203 mOnScreenIndicators = new OnScreenIndicators(mActivity,
Doris Liu2a7f44c2013-08-12 15:18:53 -0700204 mRootView.findViewById(R.id.on_screen_indicators));
Sascha Haeberling140c2632013-04-23 09:58:51 -0700205 mOnScreenIndicators.resetToDefault();
Doris Liu6827ce22013-03-12 19:24:28 -0700206 if (mController.isVideoCaptureIntent()) {
Doris Liu6432cd62013-06-13 17:20:31 -0700207 hideSwitcher();
208 mActivity.getLayoutInflater().inflate(R.layout.review_module_control,
209 (ViewGroup) mCameraControls);
Doris Liu6827ce22013-03-12 19:24:28 -0700210 // Cannot use RotateImageView for "done" and "cancel" button because
211 // the tablet layout uses RotateLayout, which cannot be cast to
212 // RotateImageView.
Doris Liu2a7f44c2013-08-12 15:18:53 -0700213 mReviewDoneButton = mRootView.findViewById(R.id.btn_done);
214 mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel);
215 mReviewPlayButton = mRootView.findViewById(R.id.btn_play);
Doris Liu6827ce22013-03-12 19:24:28 -0700216 mReviewCancelButton.setVisibility(View.VISIBLE);
217 mReviewDoneButton.setOnClickListener(new OnClickListener() {
218 @Override
219 public void onClick(View v) {
220 mController.onReviewDoneClicked(v);
221 }
222 });
223 mReviewCancelButton.setOnClickListener(new OnClickListener() {
224 @Override
225 public void onClick(View v) {
226 mController.onReviewCancelClicked(v);
227 }
228 });
229 mReviewPlayButton.setOnClickListener(new OnClickListener() {
230 @Override
231 public void onClick(View v) {
232 mController.onReviewPlayClicked(v);
233 }
234 });
235 }
236 }
237
Doris Liu6432cd62013-06-13 17:20:31 -0700238 public void setPreviewSize(int width, int height) {
239 if (width == 0 || height == 0) {
240 Log.w(TAG, "Preview size should not be 0.");
241 return;
242 }
243 if (width > height) {
244 mAspectRatio = (float) width / height;
245 } else {
246 mAspectRatio = (float) height / width;
247 }
248 mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX);
249 }
250
251 public int getPreviewWidth() {
252 return mPreviewWidth;
253 }
254
255 public int getPreviewHeight() {
256 return mPreviewHeight;
257 }
258
259 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
260 setTransformMatrix(width, height);
261 }
262
263 private void setTransformMatrix(int width, int height) {
264 mMatrix = mTextureView.getTransform(mMatrix);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700265 int orientation = CameraUtil.getDisplayRotation(mActivity);
Doris Liu6432cd62013-06-13 17:20:31 -0700266 float scaleX = 1f, scaleY = 1f;
267 float scaledTextureWidth, scaledTextureHeight;
268 if (width > height) {
269 scaledTextureWidth = Math.max(width,
270 (int) (height * mAspectRatio));
271 scaledTextureHeight = Math.max(height,
272 (int)(width / mAspectRatio));
273 } else {
274 scaledTextureWidth = Math.max(width,
275 (int) (height / mAspectRatio));
276 scaledTextureHeight = Math.max(height,
277 (int) (width * mAspectRatio));
278 }
279
280 if (mSurfaceTextureUncroppedWidth != scaledTextureWidth ||
281 mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
282 mSurfaceTextureUncroppedWidth = scaledTextureWidth;
283 mSurfaceTextureUncroppedHeight = scaledTextureHeight;
284 }
285 scaleX = scaledTextureWidth / width;
286 scaleY = scaledTextureHeight / height;
287 mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2);
288 mTextureView.setTransform(mMatrix);
289
290 if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) {
291 LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams();
292 lp.width = (int) mSurfaceTextureUncroppedWidth;
293 lp.height = (int) mSurfaceTextureUncroppedHeight;
294 lp.gravity = Gravity.CENTER;
295 mSurfaceView.requestLayout();
296 }
297 }
298
Sascha Haeberling37f36112013-08-06 14:31:52 -0700299 /**
300 * Starts a flash animation
301 */
302 public void animateFlash() {
303 mAnimationManager.startFlashAnimation(mFlashOverlay);
304 }
305
306 /**
307 * Starts a capture animation
Doris Liu3973deb2013-08-21 13:42:22 -0700308 */
309 public void animateCapture() {
310 Bitmap bitmap = null;
311 if (mTextureView != null) {
312 bitmap = mTextureView.getBitmap((int) mSurfaceTextureUncroppedWidth / 2,
313 (int) mSurfaceTextureUncroppedHeight / 2);
314 }
315 animateCapture(bitmap);
316 }
317
318 /**
319 * Starts a capture animation
Sascha Haeberling37f36112013-08-06 14:31:52 -0700320 * @param bitmap the captured image that we shrink and slide in the animation
321 */
322 public void animateCapture(Bitmap bitmap) {
Doris Liu3973deb2013-08-21 13:42:22 -0700323 if (bitmap == null) {
324 Log.e(TAG, "No valid bitmap for capture animation.");
325 return;
326 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700327 ((ImageView) mPreviewThumb).setImageBitmap(bitmap);
328 mAnimationManager.startCaptureAnimation(mPreviewThumb);
329 }
330
331 /**
332 * Cancels on-going animations
333 */
334 public void cancelAnimations() {
335 mAnimationManager.cancelAnimations();
336 }
337
Doris Liu6432cd62013-06-13 17:20:31 -0700338 public void hideUI() {
339 mCameraControls.setVisibility(View.INVISIBLE);
340 mSwitcher.closePopup();
341 }
342
343 public void showUI() {
344 mCameraControls.setVisibility(View.VISIBLE);
345 }
346
347 public void hideSwitcher() {
348 mSwitcher.closePopup();
349 mSwitcher.setVisibility(View.INVISIBLE);
350 }
351
352 public void showSwitcher() {
353 mSwitcher.setVisibility(View.VISIBLE);
354 }
355
Doris Liu6827ce22013-03-12 19:24:28 -0700356 public boolean collapseCameraControls() {
357 boolean ret = false;
358 if (mPopup != null) {
359 dismissPopup(false);
360 ret = true;
361 }
362 return ret;
363 }
364
365 public boolean removeTopLevelPopup() {
366 if (mPopup != null) {
367 dismissPopup(true);
368 return true;
369 }
370 return false;
371 }
372
373 public void enableCameraControls(boolean enable) {
374 if (mGestures != null) {
375 mGestures.setZoomOnly(!enable);
376 }
377 if (mPieRenderer != null && mPieRenderer.showsItems()) {
378 mPieRenderer.hide();
379 }
380 }
381
382 public void overrideSettings(final String... keyvalues) {
383 mVideoMenu.overrideSettings(keyvalues);
384 }
385
Doris Liu6827ce22013-03-12 19:24:28 -0700386 public void setOrientationIndicator(int orientation, boolean animation) {
Doris Liu6827ce22013-03-12 19:24:28 -0700387 // We change the orientation of the linearlayout only for phone UI
388 // because when in portrait the width is not enough.
389 if (mLabelsLinearLayout != null) {
390 if (((orientation / 90) & 1) == 0) {
391 mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL);
392 } else {
393 mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
394 }
395 }
396 mRecordingTimeRect.setOrientation(0, animation);
397 }
398
399 public SurfaceHolder getSurfaceHolder() {
Doris Liu6432cd62013-06-13 17:20:31 -0700400 return mSurfaceView.getHolder();
Doris Liu6827ce22013-03-12 19:24:28 -0700401 }
402
403 public void hideSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700404 mSurfaceView.setVisibility(View.GONE);
405 mTextureView.setVisibility(View.VISIBLE);
406 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700407 }
408
409 public void showSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700410 mSurfaceView.setVisibility(View.VISIBLE);
411 mTextureView.setVisibility(View.GONE);
412 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700413 }
414
415 private void initializeOverlay() {
416 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
417 if (mPieRenderer == null) {
418 mPieRenderer = new PieRenderer(mActivity);
419 mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer);
420 mPieRenderer.setPieListener(this);
421 }
422 mRenderOverlay.addRenderer(mPieRenderer);
423 if (mZoomRenderer == null) {
424 mZoomRenderer = new ZoomRenderer(mActivity);
425 }
426 mRenderOverlay.addRenderer(mZoomRenderer);
427 if (mGestures == null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700428 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
429 mRenderOverlay.setGestures(mGestures);
Doris Liu6827ce22013-03-12 19:24:28 -0700430 }
431 mGestures.setRenderOverlay(mRenderOverlay);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700432
Doris Liu2a7f44c2013-08-12 15:18:53 -0700433 mPreviewThumb = mRootView.findViewById(R.id.preview_thumb);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700434 mPreviewThumb.setOnClickListener(new OnClickListener() {
435 @Override
436 public void onClick(View v) {
Doris Liu6432cd62013-06-13 17:20:31 -0700437 // TODO: Go to filmstrip view
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700438 }
439 });
Doris Liu6827ce22013-03-12 19:24:28 -0700440 }
441
442 public void setPrefChangedListener(OnPreferenceChangedListener listener) {
443 mVideoMenu.setListener(listener);
444 }
445
446 private void initializeMiscControls() {
Doris Liu6827ce22013-03-12 19:24:28 -0700447 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
Doris Liu6827ce22013-03-12 19:24:28 -0700448 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
449 mShutterButton.setOnShutterButtonListener(mController);
450 mShutterButton.setVisibility(View.VISIBLE);
451 mShutterButton.requestFocus();
452 mShutterButton.enableTouch(true);
453 mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
454 mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
455 mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
456 // The R.id.labels can only be found in phone layout.
457 // That is, mLabelsLinearLayout should be null in tablet layout.
458 mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
459 }
460
Michael Kolb87880792013-04-30 15:38:49 -0700461 public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) {
Sascha Haeberling140c2632013-04-23 09:58:51 -0700462 mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode());
Michael Kolb87880792013-04-30 15:38:49 -0700463 boolean location = RecordLocationPreference.get(
464 prefs, mActivity.getContentResolver());
465 mOnScreenIndicators.updateLocationIndicator(location);
466
Doris Liu6827ce22013-03-12 19:24:28 -0700467 }
468
469 public void setAspectRatio(double ratio) {
Doris Liu6432cd62013-06-13 17:20:31 -0700470 // mPreviewFrameLayout.setAspectRatio(ratio);
Doris Liu6827ce22013-03-12 19:24:28 -0700471 }
472
473 public void showTimeLapseUI(boolean enable) {
474 if (mTimeLapseLabel != null) {
475 mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
476 }
477 }
478
Michael Kolb3bc96b22013-03-12 10:24:42 -0700479 private void openMenu() {
480 if (mPieRenderer != null) {
481 mPieRenderer.showInCenter();
482 }
483 }
484
Doris Liu6827ce22013-03-12 19:24:28 -0700485 public void dismissPopup(boolean topLevelOnly) {
Doris Liu69ef5ea2013-05-07 13:48:10 -0700486 // In review mode, we do not want to bring up the camera UI
487 if (mController.isInReviewMode()) return;
Doris Liu6827ce22013-03-12 19:24:28 -0700488 if (mPopup != null) {
Doris Liuc3679c02013-08-08 18:08:43 -0700489 mPopup.dismiss(topLevelOnly);
Doris Liu6827ce22013-03-12 19:24:28 -0700490 }
Doris Liuc3679c02013-08-08 18:08:43 -0700491 }
492
493 private void popupDismissed() {
494 mPopup = null;
495 }
496
497 public void showPopup(AbstractSettingPopup popup) {
498 hideUI();
499
500 if (mPopup != null) {
501 mPopup.dismiss(false);
502 }
503 mPopup = new SettingsPopup(popup);
Doris Liu6827ce22013-03-12 19:24:28 -0700504 }
505
506 public void onShowSwitcherPopup() {
507 hidePieRenderer();
508 }
509
510 public boolean hidePieRenderer() {
511 if (mPieRenderer != null && mPieRenderer.showsItems()) {
512 mPieRenderer.hide();
513 return true;
514 }
515 return false;
516 }
517
Doris Liu61f2b082013-03-27 17:25:43 -0700518 // disable preview gestures after shutter is pressed
519 public void setShutterPressed(boolean pressed) {
520 if (mGestures == null) return;
521 mGestures.setEnabled(!pressed);
522 }
523
Doris Liu6827ce22013-03-12 19:24:28 -0700524 public void enableShutter(boolean enable) {
525 if (mShutterButton != null) {
526 mShutterButton.setEnabled(enable);
527 }
528 }
529
530 // PieListener
531 @Override
532 public void onPieOpened(int centerX, int centerY) {
Doris Liu6432cd62013-06-13 17:20:31 -0700533 setSwipingEnabled(false);
Doris Liu6827ce22013-03-12 19:24:28 -0700534 }
535
536 @Override
537 public void onPieClosed() {
Doris Liu6432cd62013-06-13 17:20:31 -0700538 setSwipingEnabled(true);
539 }
540
541 public void setSwipingEnabled(boolean enable) {
542 mActivity.setSwipingEnabled(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700543 }
544
545 public void showPreviewBorder(boolean enable) {
Doris Liu6432cd62013-06-13 17:20:31 -0700546 // TODO: mPreviewFrameLayout.showBorder(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700547 }
548
549 // SingleTapListener
550 // Preview area is touched. Take a picture.
551 @Override
552 public void onSingleTapUp(View view, int x, int y) {
553 mController.onSingleTapUp(view, x, y);
554 }
555
Doris Liu6827ce22013-03-12 19:24:28 -0700556 public void showRecordingUI(boolean recording, boolean zoomSupported) {
Doris Liu6432cd62013-06-13 17:20:31 -0700557 mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700558 mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
559 if (recording) {
560 mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording);
Doris Liu6432cd62013-06-13 17:20:31 -0700561 hideSwitcher();
Doris Liu6827ce22013-03-12 19:24:28 -0700562 mRecordingTimeView.setText("");
563 mRecordingTimeView.setVisibility(View.VISIBLE);
564 // The camera is not allowed to be accessed in older api levels during
565 // recording. It is therefore necessary to hide the zoom UI on older
566 // platforms.
567 // See the documentation of android.media.MediaRecorder.start() for
568 // further explanation.
569 if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
570 // TODO: disable zoom UI here.
571 }
572 } else {
573 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
Doris Liu2a7f44c2013-08-12 15:18:53 -0700574 if (!mController.isVideoCaptureIntent()) {
575 showSwitcher();
576 }
Doris Liu6827ce22013-03-12 19:24:28 -0700577 mRecordingTimeView.setVisibility(View.GONE);
578 if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
579 // TODO: enable zoom UI here.
580 }
581 }
582 }
583
584 public void showReviewImage(Bitmap bitmap) {
585 mReviewImage.setImageBitmap(bitmap);
586 mReviewImage.setVisibility(View.VISIBLE);
587 }
588
589 public void showReviewControls() {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700590 CameraUtil.fadeOut(mShutterButton);
591 CameraUtil.fadeIn(mReviewDoneButton);
592 CameraUtil.fadeIn(mReviewPlayButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700593 mReviewImage.setVisibility(View.VISIBLE);
Doris Liu6432cd62013-06-13 17:20:31 -0700594 mMenuButton.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700595 mOnScreenIndicators.setVisibility(View.GONE);
596 }
597
598 public void hideReviewUI() {
599 mReviewImage.setVisibility(View.GONE);
600 mShutterButton.setEnabled(true);
Doris Liu6432cd62013-06-13 17:20:31 -0700601 mMenuButton.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700602 mOnScreenIndicators.setVisibility(View.VISIBLE);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700603 CameraUtil.fadeOut(mReviewDoneButton);
604 CameraUtil.fadeOut(mReviewPlayButton);
605 CameraUtil.fadeIn(mShutterButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700606 }
607
608 private void setShowMenu(boolean show) {
609 if (mOnScreenIndicators != null) {
610 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
611 }
Doris Liu6432cd62013-06-13 17:20:31 -0700612 if (mMenuButton != null) {
613 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700614 }
615 }
616
Doris Liu6432cd62013-06-13 17:20:31 -0700617 public void onSwitchMode(boolean toCamera) {
618 if (toCamera) {
619 showUI();
620 } else {
621 hideUI();
622 }
Doris Liu6827ce22013-03-12 19:24:28 -0700623 if (mGestures != null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700624 mGestures.setEnabled(toCamera);
Doris Liu6827ce22013-03-12 19:24:28 -0700625 }
Doris Liu6827ce22013-03-12 19:24:28 -0700626 if (mRenderOverlay != null) {
627 // this can not happen in capture mode
Doris Liu6432cd62013-06-13 17:20:31 -0700628 mRenderOverlay.setVisibility(toCamera ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700629 }
Doris Liu6432cd62013-06-13 17:20:31 -0700630 setShowMenu(toCamera);
Doris Liu6827ce22013-03-12 19:24:28 -0700631 }
632
633 public void initializePopup(PreferenceGroup pref) {
634 mVideoMenu.initialize(pref);
635 }
636
637 public void initializeZoom(Parameters param) {
Doris Liu6432cd62013-06-13 17:20:31 -0700638 if (param == null || !param.isZoomSupported()) {
639 mGestures.setZoomEnabled(false);
640 return;
641 }
642 mGestures.setZoomEnabled(true);
Doris Liu6827ce22013-03-12 19:24:28 -0700643 mZoomMax = param.getMaxZoom();
644 mZoomRatios = param.getZoomRatios();
645 // Currently we use immediate zoom for fast zooming to get better UX and
646 // there is no plan to take advantage of the smooth zoom.
647 mZoomRenderer.setZoomMax(mZoomMax);
648 mZoomRenderer.setZoom(param.getZoom());
649 mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom()));
650 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
651 }
652
653 public void clickShutter() {
654 mShutterButton.performClick();
655 }
656
657 public void pressShutter(boolean pressed) {
658 mShutterButton.setPressed(pressed);
659 }
660
Doris Liu6432cd62013-06-13 17:20:31 -0700661 public View getShutterButton() {
662 return mShutterButton;
Doris Liu6827ce22013-03-12 19:24:28 -0700663 }
664
665 public void setRecordingTime(String text) {
666 mRecordingTimeView.setText(text);
667 }
668
669 public void setRecordingTimeTextColor(int color) {
670 mRecordingTimeView.setTextColor(color);
671 }
672
Doris Liu6432cd62013-06-13 17:20:31 -0700673 public boolean isVisible() {
674 return mTextureView.getVisibility() == View.VISIBLE;
675 }
676
677 public void onDisplayChanged() {
678 mCameraControls.checkLayoutFlip();
679 mController.updateCameraOrientation();
680 }
681
Doris Liu6827ce22013-03-12 19:24:28 -0700682 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
683 @Override
684 public void onZoomValueChanged(int index) {
685 int newZoom = mController.onZoomChanged(index);
686 if (mZoomRenderer != null) {
687 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
688 }
689 }
690
691 @Override
692 public void onZoomStart() {
693 }
694
695 @Override
696 public void onZoomEnd() {
697 }
698 }
Michael Kolb3bc96b22013-03-12 10:24:42 -0700699
Doris Liu6432cd62013-06-13 17:20:31 -0700700 public SurfaceTexture getSurfaceTexture() {
Doris Liu6432cd62013-06-13 17:20:31 -0700701 return mSurfaceTexture;
702 }
703
704 // SurfaceTexture callbacks
Michael Kolb3bc96b22013-03-12 10:24:42 -0700705 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700706 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Angus Kong395ee2d2013-07-15 12:42:41 -0700707 mSurfaceTexture = surface;
708 mController.onPreviewUIReady();
Michael Kolb3bc96b22013-03-12 10:24:42 -0700709 }
710
Doris Liu6432cd62013-06-13 17:20:31 -0700711 @Override
712 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
713 mSurfaceTexture = null;
Angus Kong395ee2d2013-07-15 12:42:41 -0700714 mController.onPreviewUIDestroyed();
Doris Liu6432cd62013-06-13 17:20:31 -0700715 Log.d(TAG, "surfaceTexture is destroyed");
716 return true;
717 }
718
719 @Override
720 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
721 }
722
723 @Override
724 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
725 }
726
727 // SurfaceHolder callbacks
728 @Override
729 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
730 Log.v(TAG, "Surface changed. width=" + width + ". height=" + height);
731 }
732
733 @Override
734 public void surfaceCreated(SurfaceHolder holder) {
735 Log.v(TAG, "Surface created");
736 }
737
738 @Override
739 public void surfaceDestroyed(SurfaceHolder holder) {
740 Log.v(TAG, "Surface destroyed");
741 mController.stopPreview();
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700742 }
Doris Liu6827ce22013-03-12 19:24:28 -0700743}