blob: 204195f44415cb853c695bee8382cc37e6866067 [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;
Doris Liu6827ce22013-03-12 19:24:28 -070039import android.widget.FrameLayout.LayoutParams;
40import android.widget.ImageView;
41import android.widget.LinearLayout;
Doris Liuc3679c02013-08-08 18:08:43 -070042import android.widget.PopupWindow;
Doris Liu6827ce22013-03-12 19:24:28 -070043import android.widget.TextView;
44
45import com.android.camera.CameraPreference.OnPreferenceChangedListener;
46import com.android.camera.ui.AbstractSettingPopup;
Doris Liu6432cd62013-06-13 17:20:31 -070047import com.android.camera.ui.CameraControls;
48import com.android.camera.ui.CameraRootView;
Angus Konged15d1a2013-08-19 15:06:12 -070049import com.android.camera.ui.ModuleSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070050import com.android.camera.ui.PieRenderer;
Doris Liu6827ce22013-03-12 19:24:28 -070051import com.android.camera.ui.RenderOverlay;
52import com.android.camera.ui.RotateLayout;
53import com.android.camera.ui.ZoomRenderer;
Angus Kongb50b5cb2013-08-09 14:55:20 -070054import com.android.camera.util.CameraUtil;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070055import com.android.camera2.R;
Angus Kongb50b5cb2013-08-09 14:55:20 -070056import com.android.camera.util.ApiHelper;
Doris Liu6827ce22013-03-12 19:24:28 -070057
Doris Liu6432cd62013-06-13 17:20:31 -070058public class VideoUI implements PieRenderer.PieListener,
Michael Kolb3bc96b22013-03-12 10:24:42 -070059 PreviewGestures.SingleTapListener,
Doris Liu6432cd62013-06-13 17:20:31 -070060 CameraRootView.MyDisplayListener,
61 SurfaceTextureListener, SurfaceHolder.Callback {
Angus Kong395ee2d2013-07-15 12:42:41 -070062 private static final String TAG = "CAM_VideoUI";
Doris Liu6432cd62013-06-13 17:20:31 -070063 private static final int UPDATE_TRANSFORM_MATRIX = 1;
Doris Liu6827ce22013-03-12 19:24:28 -070064 // module fields
65 private CameraActivity mActivity;
66 private View mRootView;
Doris Liu6432cd62013-06-13 17:20:31 -070067 private TextureView mTextureView;
Doris Liu6827ce22013-03-12 19:24:28 -070068 // An review image having same size as preview. It is displayed when
69 // recording is stopped in capture intent.
70 private ImageView mReviewImage;
71 private View mReviewCancelButton;
72 private View mReviewDoneButton;
73 private View mReviewPlayButton;
74 private ShutterButton mShutterButton;
Angus Konged15d1a2013-08-19 15:06:12 -070075 private ModuleSwitcher mSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070076 private TextView mRecordingTimeView;
77 private LinearLayout mLabelsLinearLayout;
78 private View mTimeLapseLabel;
79 private RenderOverlay mRenderOverlay;
80 private PieRenderer mPieRenderer;
81 private VideoMenu mVideoMenu;
Doris Liu6432cd62013-06-13 17:20:31 -070082 private CameraControls mCameraControls;
Doris Liuc3679c02013-08-08 18:08:43 -070083 private SettingsPopup mPopup;
Doris Liu6827ce22013-03-12 19:24:28 -070084 private ZoomRenderer mZoomRenderer;
85 private PreviewGestures mGestures;
Doris Liu6432cd62013-06-13 17:20:31 -070086 private View mMenuButton;
Sascha Haeberling140c2632013-04-23 09:58:51 -070087 private OnScreenIndicators mOnScreenIndicators;
Doris Liu6827ce22013-03-12 19:24:28 -070088 private RotateLayout mRecordingTimeRect;
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 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;
Angus Kongb50b5cb2013-08-09 14:55:20 -0700125 if (CameraUtil.getDisplayRotation(mActivity) % 180 != 0) {
Doris Liu6432cd62013-06-13 17:20:31 -0700126 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 Liuc3679c02013-08-08 18:08:43 -0700137 private class SettingsPopup extends PopupWindow {
138 public SettingsPopup(View popup) {
139 super(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
140 setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
141 setOutsideTouchable(true);
142 setFocusable(true);
143 popup.setVisibility(View.VISIBLE);
144 setContentView(popup);
145 showAtLocation(mRootView, Gravity.CENTER, 0, 0);
146 }
147
148 public void dismiss(boolean topLevelOnly) {
149 super.dismiss();
150 popupDismissed();
151 showUI();
152 mVideoMenu.popupDismissed(topLevelOnly);
153 }
154
155 @Override
156 public void dismiss() {
157 // Called by Framework when touch outside the popup or hit back key
158 dismiss(true);
159 }
160 }
161
Doris Liu6827ce22013-03-12 19:24:28 -0700162 public VideoUI(CameraActivity activity, VideoController controller, View parent) {
163 mActivity = activity;
164 mController = controller;
165 mRootView = parent;
166 mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true);
Doris Liu6432cd62013-06-13 17:20:31 -0700167 mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content);
168 mTextureView.setSurfaceTextureListener(this);
Doris Liubdd198e2013-08-29 18:06:45 -0700169 mTextureView.addOnLayoutChangeListener(mLayoutListener);
Doris Liu6432cd62013-06-13 17:20:31 -0700170 ((CameraRootView) mRootView).setDisplayChangeListener(this);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700171 mFlashOverlay = mRootView.findViewById(R.id.flash_overlay);
Doris Liu6432cd62013-06-13 17:20:31 -0700172 mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
Angus Konged15d1a2013-08-19 15:06:12 -0700173 mSwitcher = (ModuleSwitcher) mRootView.findViewById(R.id.camera_switcher);
174 mSwitcher.setCurrentIndex(ModuleSwitcher.VIDEO_MODULE_INDEX);
175 mSwitcher.setSwitchListener(mActivity);
Doris Liu6827ce22013-03-12 19:24:28 -0700176 initializeMiscControls();
177 initializeControlByIntent();
178 initializeOverlay();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700179 mAnimationManager = new AnimationManager();
Doris Liu6827ce22013-03-12 19:24:28 -0700180 }
181
Doris Liu6432cd62013-06-13 17:20:31 -0700182
183 public void initializeSurfaceView() {
184 mSurfaceView = new SurfaceView(mActivity);
185 ((ViewGroup) mRootView).addView(mSurfaceView, 0);
186 mSurfaceView.getHolder().addCallback(this);
187 }
188
Doris Liu6827ce22013-03-12 19:24:28 -0700189 private void initializeControlByIntent() {
Doris Liu2a7f44c2013-08-12 15:18:53 -0700190 mMenuButton = mRootView.findViewById(R.id.menu);
Doris Liu6432cd62013-06-13 17:20:31 -0700191 mMenuButton.setOnClickListener(new OnClickListener() {
Doris Liu6827ce22013-03-12 19:24:28 -0700192 @Override
193 public void onClick(View v) {
194 if (mPieRenderer != null) {
195 mPieRenderer.showInCenter();
196 }
197 }
198 });
Doris Liu6432cd62013-06-13 17:20:31 -0700199
Doris Liu2a7f44c2013-08-12 15:18:53 -0700200 mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls);
Michael Kolbeb8adc12013-04-26 11:09:29 -0700201 mOnScreenIndicators = new OnScreenIndicators(mActivity,
Doris Liu2a7f44c2013-08-12 15:18:53 -0700202 mRootView.findViewById(R.id.on_screen_indicators));
Sascha Haeberling140c2632013-04-23 09:58:51 -0700203 mOnScreenIndicators.resetToDefault();
Doris Liu6827ce22013-03-12 19:24:28 -0700204 if (mController.isVideoCaptureIntent()) {
Doris Liu6432cd62013-06-13 17:20:31 -0700205 hideSwitcher();
206 mActivity.getLayoutInflater().inflate(R.layout.review_module_control,
207 (ViewGroup) mCameraControls);
Doris Liu6827ce22013-03-12 19:24:28 -0700208 // Cannot use RotateImageView for "done" and "cancel" button because
209 // the tablet layout uses RotateLayout, which cannot be cast to
210 // RotateImageView.
Doris Liu2a7f44c2013-08-12 15:18:53 -0700211 mReviewDoneButton = mRootView.findViewById(R.id.btn_done);
212 mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel);
213 mReviewPlayButton = mRootView.findViewById(R.id.btn_play);
Doris Liu6827ce22013-03-12 19:24:28 -0700214 mReviewCancelButton.setVisibility(View.VISIBLE);
215 mReviewDoneButton.setOnClickListener(new OnClickListener() {
216 @Override
217 public void onClick(View v) {
218 mController.onReviewDoneClicked(v);
219 }
220 });
221 mReviewCancelButton.setOnClickListener(new OnClickListener() {
222 @Override
223 public void onClick(View v) {
224 mController.onReviewCancelClicked(v);
225 }
226 });
227 mReviewPlayButton.setOnClickListener(new OnClickListener() {
228 @Override
229 public void onClick(View v) {
230 mController.onReviewPlayClicked(v);
231 }
232 });
233 }
234 }
235
Doris Liu6432cd62013-06-13 17:20:31 -0700236 public void setPreviewSize(int width, int height) {
237 if (width == 0 || height == 0) {
238 Log.w(TAG, "Preview size should not be 0.");
239 return;
240 }
241 if (width > height) {
242 mAspectRatio = (float) width / height;
243 } else {
244 mAspectRatio = (float) height / width;
245 }
246 mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX);
247 }
248
249 public int getPreviewWidth() {
250 return mPreviewWidth;
251 }
252
253 public int getPreviewHeight() {
254 return mPreviewHeight;
255 }
256
257 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
258 setTransformMatrix(width, height);
259 }
260
261 private void setTransformMatrix(int width, int height) {
262 mMatrix = mTextureView.getTransform(mMatrix);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700263 int orientation = CameraUtil.getDisplayRotation(mActivity);
Doris Liu6432cd62013-06-13 17:20:31 -0700264 float scaleX = 1f, scaleY = 1f;
265 float scaledTextureWidth, scaledTextureHeight;
266 if (width > height) {
267 scaledTextureWidth = Math.max(width,
268 (int) (height * mAspectRatio));
269 scaledTextureHeight = Math.max(height,
270 (int)(width / mAspectRatio));
271 } else {
272 scaledTextureWidth = Math.max(width,
273 (int) (height / mAspectRatio));
274 scaledTextureHeight = Math.max(height,
275 (int) (width * mAspectRatio));
276 }
277
278 if (mSurfaceTextureUncroppedWidth != scaledTextureWidth ||
279 mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
280 mSurfaceTextureUncroppedWidth = scaledTextureWidth;
281 mSurfaceTextureUncroppedHeight = scaledTextureHeight;
282 }
283 scaleX = scaledTextureWidth / width;
284 scaleY = scaledTextureHeight / height;
285 mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2);
286 mTextureView.setTransform(mMatrix);
287
288 if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) {
289 LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams();
290 lp.width = (int) mSurfaceTextureUncroppedWidth;
291 lp.height = (int) mSurfaceTextureUncroppedHeight;
292 lp.gravity = Gravity.CENTER;
293 mSurfaceView.requestLayout();
294 }
295 }
296
Sascha Haeberling37f36112013-08-06 14:31:52 -0700297 /**
298 * Starts a flash animation
299 */
300 public void animateFlash() {
301 mAnimationManager.startFlashAnimation(mFlashOverlay);
302 }
303
304 /**
305 * Starts a capture animation
Doris Liu3973deb2013-08-21 13:42:22 -0700306 */
307 public void animateCapture() {
308 Bitmap bitmap = null;
309 if (mTextureView != null) {
310 bitmap = mTextureView.getBitmap((int) mSurfaceTextureUncroppedWidth / 2,
311 (int) mSurfaceTextureUncroppedHeight / 2);
312 }
313 animateCapture(bitmap);
314 }
315
316 /**
317 * Starts a capture animation
Sascha Haeberling37f36112013-08-06 14:31:52 -0700318 * @param bitmap the captured image that we shrink and slide in the animation
319 */
320 public void animateCapture(Bitmap bitmap) {
Doris Liu3973deb2013-08-21 13:42:22 -0700321 if (bitmap == null) {
322 Log.e(TAG, "No valid bitmap for capture animation.");
323 return;
324 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700325 ((ImageView) mPreviewThumb).setImageBitmap(bitmap);
326 mAnimationManager.startCaptureAnimation(mPreviewThumb);
327 }
328
329 /**
330 * Cancels on-going animations
331 */
332 public void cancelAnimations() {
333 mAnimationManager.cancelAnimations();
334 }
335
Doris Liu6432cd62013-06-13 17:20:31 -0700336 public void hideUI() {
337 mCameraControls.setVisibility(View.INVISIBLE);
338 mSwitcher.closePopup();
339 }
340
341 public void showUI() {
342 mCameraControls.setVisibility(View.VISIBLE);
343 }
344
345 public void hideSwitcher() {
346 mSwitcher.closePopup();
347 mSwitcher.setVisibility(View.INVISIBLE);
348 }
349
350 public void showSwitcher() {
351 mSwitcher.setVisibility(View.VISIBLE);
352 }
353
Doris Liu6827ce22013-03-12 19:24:28 -0700354 public boolean collapseCameraControls() {
355 boolean ret = false;
356 if (mPopup != null) {
357 dismissPopup(false);
358 ret = true;
359 }
360 return ret;
361 }
362
363 public boolean removeTopLevelPopup() {
364 if (mPopup != null) {
365 dismissPopup(true);
366 return true;
367 }
368 return false;
369 }
370
371 public void enableCameraControls(boolean enable) {
372 if (mGestures != null) {
373 mGestures.setZoomOnly(!enable);
374 }
375 if (mPieRenderer != null && mPieRenderer.showsItems()) {
376 mPieRenderer.hide();
377 }
378 }
379
380 public void overrideSettings(final String... keyvalues) {
381 mVideoMenu.overrideSettings(keyvalues);
382 }
383
Doris Liu6827ce22013-03-12 19:24:28 -0700384 public void setOrientationIndicator(int orientation, boolean animation) {
Doris Liu6827ce22013-03-12 19:24:28 -0700385 // We change the orientation of the linearlayout only for phone UI
386 // because when in portrait the width is not enough.
387 if (mLabelsLinearLayout != null) {
388 if (((orientation / 90) & 1) == 0) {
389 mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL);
390 } else {
391 mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
392 }
393 }
394 mRecordingTimeRect.setOrientation(0, animation);
395 }
396
397 public SurfaceHolder getSurfaceHolder() {
Doris Liu6432cd62013-06-13 17:20:31 -0700398 return mSurfaceView.getHolder();
Doris Liu6827ce22013-03-12 19:24:28 -0700399 }
400
401 public void hideSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700402 mSurfaceView.setVisibility(View.GONE);
403 mTextureView.setVisibility(View.VISIBLE);
404 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700405 }
406
407 public void showSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700408 mSurfaceView.setVisibility(View.VISIBLE);
409 mTextureView.setVisibility(View.GONE);
410 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700411 }
412
413 private void initializeOverlay() {
414 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
415 if (mPieRenderer == null) {
416 mPieRenderer = new PieRenderer(mActivity);
417 mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer);
418 mPieRenderer.setPieListener(this);
419 }
420 mRenderOverlay.addRenderer(mPieRenderer);
421 if (mZoomRenderer == null) {
422 mZoomRenderer = new ZoomRenderer(mActivity);
423 }
424 mRenderOverlay.addRenderer(mZoomRenderer);
425 if (mGestures == null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700426 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
427 mRenderOverlay.setGestures(mGestures);
Doris Liu6827ce22013-03-12 19:24:28 -0700428 }
429 mGestures.setRenderOverlay(mRenderOverlay);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700430
Doris Liu2a7f44c2013-08-12 15:18:53 -0700431 mPreviewThumb = mRootView.findViewById(R.id.preview_thumb);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700432 mPreviewThumb.setOnClickListener(new OnClickListener() {
433 @Override
434 public void onClick(View v) {
Angus Kong734598c2013-08-21 15:25:05 -0700435 mActivity.gotoGallery();
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700436 }
437 });
Doris Liu6827ce22013-03-12 19:24:28 -0700438 }
439
440 public void setPrefChangedListener(OnPreferenceChangedListener listener) {
441 mVideoMenu.setListener(listener);
442 }
443
444 private void initializeMiscControls() {
Doris Liu6827ce22013-03-12 19:24:28 -0700445 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
Doris Liu6827ce22013-03-12 19:24:28 -0700446 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
447 mShutterButton.setOnShutterButtonListener(mController);
448 mShutterButton.setVisibility(View.VISIBLE);
449 mShutterButton.requestFocus();
450 mShutterButton.enableTouch(true);
451 mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
452 mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
453 mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
454 // The R.id.labels can only be found in phone layout.
455 // That is, mLabelsLinearLayout should be null in tablet layout.
456 mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
457 }
458
Michael Kolb87880792013-04-30 15:38:49 -0700459 public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) {
Sascha Haeberling140c2632013-04-23 09:58:51 -0700460 mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode());
Michael Kolb87880792013-04-30 15:38:49 -0700461 boolean location = RecordLocationPreference.get(
462 prefs, mActivity.getContentResolver());
463 mOnScreenIndicators.updateLocationIndicator(location);
464
Doris Liu6827ce22013-03-12 19:24:28 -0700465 }
466
467 public void setAspectRatio(double ratio) {
Doris Liu6432cd62013-06-13 17:20:31 -0700468 // mPreviewFrameLayout.setAspectRatio(ratio);
Doris Liu6827ce22013-03-12 19:24:28 -0700469 }
470
471 public void showTimeLapseUI(boolean enable) {
472 if (mTimeLapseLabel != null) {
473 mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
474 }
475 }
476
Michael Kolb3bc96b22013-03-12 10:24:42 -0700477 private void openMenu() {
478 if (mPieRenderer != null) {
479 mPieRenderer.showInCenter();
480 }
481 }
482
Doris Liu6827ce22013-03-12 19:24:28 -0700483 public void dismissPopup(boolean topLevelOnly) {
Doris Liu69ef5ea2013-05-07 13:48:10 -0700484 // In review mode, we do not want to bring up the camera UI
485 if (mController.isInReviewMode()) return;
Doris Liu6827ce22013-03-12 19:24:28 -0700486 if (mPopup != null) {
Doris Liuc3679c02013-08-08 18:08:43 -0700487 mPopup.dismiss(topLevelOnly);
Doris Liu6827ce22013-03-12 19:24:28 -0700488 }
Doris Liuc3679c02013-08-08 18:08:43 -0700489 }
490
491 private void popupDismissed() {
492 mPopup = null;
493 }
494
495 public void showPopup(AbstractSettingPopup popup) {
496 hideUI();
497
498 if (mPopup != null) {
499 mPopup.dismiss(false);
500 }
501 mPopup = new SettingsPopup(popup);
Doris Liu6827ce22013-03-12 19:24:28 -0700502 }
503
504 public void onShowSwitcherPopup() {
505 hidePieRenderer();
506 }
507
508 public boolean hidePieRenderer() {
509 if (mPieRenderer != null && mPieRenderer.showsItems()) {
510 mPieRenderer.hide();
511 return true;
512 }
513 return false;
514 }
515
Doris Liu61f2b082013-03-27 17:25:43 -0700516 // disable preview gestures after shutter is pressed
517 public void setShutterPressed(boolean pressed) {
518 if (mGestures == null) return;
519 mGestures.setEnabled(!pressed);
520 }
521
Doris Liu6827ce22013-03-12 19:24:28 -0700522 public void enableShutter(boolean enable) {
523 if (mShutterButton != null) {
524 mShutterButton.setEnabled(enable);
525 }
526 }
527
528 // PieListener
529 @Override
530 public void onPieOpened(int centerX, int centerY) {
Doris Liu6432cd62013-06-13 17:20:31 -0700531 setSwipingEnabled(false);
Doris Liu6827ce22013-03-12 19:24:28 -0700532 }
533
534 @Override
535 public void onPieClosed() {
Doris Liu6432cd62013-06-13 17:20:31 -0700536 setSwipingEnabled(true);
537 }
538
539 public void setSwipingEnabled(boolean enable) {
540 mActivity.setSwipingEnabled(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700541 }
542
543 public void showPreviewBorder(boolean enable) {
Doris Liu6432cd62013-06-13 17:20:31 -0700544 // TODO: mPreviewFrameLayout.showBorder(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700545 }
546
547 // SingleTapListener
548 // Preview area is touched. Take a picture.
549 @Override
550 public void onSingleTapUp(View view, int x, int y) {
551 mController.onSingleTapUp(view, x, y);
552 }
553
Doris Liu6827ce22013-03-12 19:24:28 -0700554 public void showRecordingUI(boolean recording, boolean zoomSupported) {
Doris Liu6432cd62013-06-13 17:20:31 -0700555 mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700556 mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
557 if (recording) {
558 mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording);
Doris Liu6432cd62013-06-13 17:20:31 -0700559 hideSwitcher();
Doris Liu6827ce22013-03-12 19:24:28 -0700560 mRecordingTimeView.setText("");
561 mRecordingTimeView.setVisibility(View.VISIBLE);
562 // The camera is not allowed to be accessed in older api levels during
563 // recording. It is therefore necessary to hide the zoom UI on older
564 // platforms.
565 // See the documentation of android.media.MediaRecorder.start() for
566 // further explanation.
567 if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
568 // TODO: disable zoom UI here.
569 }
570 } else {
571 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
Doris Liu2a7f44c2013-08-12 15:18:53 -0700572 if (!mController.isVideoCaptureIntent()) {
573 showSwitcher();
574 }
Doris Liu6827ce22013-03-12 19:24:28 -0700575 mRecordingTimeView.setVisibility(View.GONE);
576 if (!ApiHelper.HAS_ZOOM_WHEN_RECORDING && zoomSupported) {
577 // TODO: enable zoom UI here.
578 }
579 }
580 }
581
582 public void showReviewImage(Bitmap bitmap) {
583 mReviewImage.setImageBitmap(bitmap);
584 mReviewImage.setVisibility(View.VISIBLE);
585 }
586
587 public void showReviewControls() {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700588 CameraUtil.fadeOut(mShutterButton);
589 CameraUtil.fadeIn(mReviewDoneButton);
590 CameraUtil.fadeIn(mReviewPlayButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700591 mReviewImage.setVisibility(View.VISIBLE);
Doris Liu6432cd62013-06-13 17:20:31 -0700592 mMenuButton.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700593 mOnScreenIndicators.setVisibility(View.GONE);
594 }
595
596 public void hideReviewUI() {
597 mReviewImage.setVisibility(View.GONE);
598 mShutterButton.setEnabled(true);
Doris Liu6432cd62013-06-13 17:20:31 -0700599 mMenuButton.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700600 mOnScreenIndicators.setVisibility(View.VISIBLE);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700601 CameraUtil.fadeOut(mReviewDoneButton);
602 CameraUtil.fadeOut(mReviewPlayButton);
603 CameraUtil.fadeIn(mShutterButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700604 }
605
606 private void setShowMenu(boolean show) {
607 if (mOnScreenIndicators != null) {
608 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
609 }
Doris Liu6432cd62013-06-13 17:20:31 -0700610 if (mMenuButton != null) {
611 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700612 }
613 }
614
ztenghui7b265a62013-09-09 14:58:44 -0700615 public void onPreviewFocusChanged(boolean previewFocused) {
616 if (previewFocused) {
Doris Liu6432cd62013-06-13 17:20:31 -0700617 showUI();
618 } else {
619 hideUI();
620 }
Doris Liu6827ce22013-03-12 19:24:28 -0700621 if (mGestures != null) {
ztenghui7b265a62013-09-09 14:58:44 -0700622 mGestures.setEnabled(previewFocused);
Doris Liu6827ce22013-03-12 19:24:28 -0700623 }
Doris Liu6827ce22013-03-12 19:24:28 -0700624 if (mRenderOverlay != null) {
625 // this can not happen in capture mode
ztenghui7b265a62013-09-09 14:58:44 -0700626 mRenderOverlay.setVisibility(previewFocused ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700627 }
ztenghui7b265a62013-09-09 14:58:44 -0700628 setShowMenu(previewFocused);
Doris Liu6827ce22013-03-12 19:24:28 -0700629 }
630
631 public void initializePopup(PreferenceGroup pref) {
632 mVideoMenu.initialize(pref);
633 }
634
635 public void initializeZoom(Parameters param) {
Doris Liu6432cd62013-06-13 17:20:31 -0700636 if (param == null || !param.isZoomSupported()) {
637 mGestures.setZoomEnabled(false);
638 return;
639 }
640 mGestures.setZoomEnabled(true);
Doris Liu6827ce22013-03-12 19:24:28 -0700641 mZoomMax = param.getMaxZoom();
642 mZoomRatios = param.getZoomRatios();
643 // Currently we use immediate zoom for fast zooming to get better UX and
644 // there is no plan to take advantage of the smooth zoom.
645 mZoomRenderer.setZoomMax(mZoomMax);
646 mZoomRenderer.setZoom(param.getZoom());
647 mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom()));
648 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
649 }
650
651 public void clickShutter() {
652 mShutterButton.performClick();
653 }
654
655 public void pressShutter(boolean pressed) {
656 mShutterButton.setPressed(pressed);
657 }
658
Doris Liu6432cd62013-06-13 17:20:31 -0700659 public View getShutterButton() {
660 return mShutterButton;
Doris Liu6827ce22013-03-12 19:24:28 -0700661 }
662
663 public void setRecordingTime(String text) {
664 mRecordingTimeView.setText(text);
665 }
666
667 public void setRecordingTimeTextColor(int color) {
668 mRecordingTimeView.setTextColor(color);
669 }
670
Doris Liu6432cd62013-06-13 17:20:31 -0700671 public boolean isVisible() {
672 return mTextureView.getVisibility() == View.VISIBLE;
673 }
674
ztenghui7b265a62013-09-09 14:58:44 -0700675 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700676 public void onDisplayChanged() {
677 mCameraControls.checkLayoutFlip();
678 mController.updateCameraOrientation();
679 }
680
Doris Liu6827ce22013-03-12 19:24:28 -0700681 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
682 @Override
683 public void onZoomValueChanged(int index) {
684 int newZoom = mController.onZoomChanged(index);
685 if (mZoomRenderer != null) {
686 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
687 }
688 }
689
690 @Override
691 public void onZoomStart() {
692 }
693
694 @Override
695 public void onZoomEnd() {
696 }
697 }
Michael Kolb3bc96b22013-03-12 10:24:42 -0700698
Doris Liu6432cd62013-06-13 17:20:31 -0700699 public SurfaceTexture getSurfaceTexture() {
Doris Liu6432cd62013-06-13 17:20:31 -0700700 return mSurfaceTexture;
701 }
702
703 // SurfaceTexture callbacks
Michael Kolb3bc96b22013-03-12 10:24:42 -0700704 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700705 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Angus Kong395ee2d2013-07-15 12:42:41 -0700706 mSurfaceTexture = surface;
707 mController.onPreviewUIReady();
Michael Kolb3bc96b22013-03-12 10:24:42 -0700708 }
709
Doris Liu6432cd62013-06-13 17:20:31 -0700710 @Override
711 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
712 mSurfaceTexture = null;
Angus Kong395ee2d2013-07-15 12:42:41 -0700713 mController.onPreviewUIDestroyed();
Doris Liu6432cd62013-06-13 17:20:31 -0700714 Log.d(TAG, "surfaceTexture is destroyed");
715 return true;
716 }
717
718 @Override
719 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
720 }
721
722 @Override
723 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
724 }
725
726 // SurfaceHolder callbacks
727 @Override
728 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
729 Log.v(TAG, "Surface changed. width=" + width + ". height=" + height);
730 }
731
732 @Override
733 public void surfaceCreated(SurfaceHolder holder) {
734 Log.v(TAG, "Surface created");
735 }
736
737 @Override
738 public void surfaceDestroyed(SurfaceHolder holder) {
739 Log.v(TAG, "Surface destroyed");
740 mController.stopPreview();
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700741 }
Doris Liu6827ce22013-03-12 19:24:28 -0700742}