blob: 23d08dbb43f21acb3566c172758c6ed2d0e0d4f8 [file] [log] [blame]
Doris Liu6827ce22013-03-12 19:24:28 -07001/*
Doris Liu6432cd62013-06-13 17:20:31 -07002 * Copyright (C) 2012 The Android Open Source Project
Doris Liu6827ce22013-03-12 19:24:28 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
19import android.graphics.Bitmap;
Doris Liuc3679c02013-08-08 18:08:43 -070020import android.graphics.Color;
Doris Liu6432cd62013-06-13 17:20:31 -070021import android.graphics.Matrix;
22import android.graphics.SurfaceTexture;
Doris Liuc3679c02013-08-08 18:08:43 -070023import android.graphics.drawable.ColorDrawable;
Doris Liu6827ce22013-03-12 19:24:28 -070024import android.hardware.Camera.Parameters;
Doris Liu6432cd62013-06-13 17:20:31 -070025import android.os.Handler;
26import android.os.Message;
Doris Liu6827ce22013-03-12 19:24:28 -070027import android.util.Log;
28import android.view.Gravity;
Doris Liu6827ce22013-03-12 19:24:28 -070029import android.view.SurfaceHolder;
Doris Liu6432cd62013-06-13 17:20:31 -070030import android.view.SurfaceView;
31import android.view.TextureView;
32import android.view.TextureView.SurfaceTextureListener;
Doris Liu6827ce22013-03-12 19:24:28 -070033import android.view.View;
34import android.view.View.OnClickListener;
Doris Liu6432cd62013-06-13 17:20:31 -070035import android.view.View.OnLayoutChangeListener;
Doris Liu6827ce22013-03-12 19:24:28 -070036import android.view.ViewGroup;
Doris Liu6827ce22013-03-12 19:24:28 -070037import android.widget.FrameLayout.LayoutParams;
38import android.widget.ImageView;
39import android.widget.LinearLayout;
Doris Liuc3679c02013-08-08 18:08:43 -070040import android.widget.PopupWindow;
Doris Liu6827ce22013-03-12 19:24:28 -070041import android.widget.TextView;
42
43import com.android.camera.CameraPreference.OnPreferenceChangedListener;
44import com.android.camera.ui.AbstractSettingPopup;
Doris Liu6432cd62013-06-13 17:20:31 -070045import com.android.camera.ui.CameraControls;
46import com.android.camera.ui.CameraRootView;
Angus Konged15d1a2013-08-19 15:06:12 -070047import com.android.camera.ui.ModuleSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070048import com.android.camera.ui.PieRenderer;
Doris Liu6827ce22013-03-12 19:24:28 -070049import com.android.camera.ui.RenderOverlay;
50import com.android.camera.ui.RotateLayout;
51import com.android.camera.ui.ZoomRenderer;
Angus Kongb50b5cb2013-08-09 14:55:20 -070052import com.android.camera.util.CameraUtil;
Sascha Haeberling8e963a52013-08-06 11:43:02 -070053import com.android.camera2.R;
Sascha Haeberling638e6f02013-09-18 14:28:51 -070054
55import java.util.List;
Doris Liu6827ce22013-03-12 19:24:28 -070056
Doris Liu6432cd62013-06-13 17:20:31 -070057public class VideoUI implements PieRenderer.PieListener,
Michael Kolb3bc96b22013-03-12 10:24:42 -070058 PreviewGestures.SingleTapListener,
Doris Liu6432cd62013-06-13 17:20:31 -070059 CameraRootView.MyDisplayListener,
60 SurfaceTextureListener, SurfaceHolder.Callback {
Angus Kong395ee2d2013-07-15 12:42:41 -070061 private static final String TAG = "CAM_VideoUI";
Doris Liu6432cd62013-06-13 17:20:31 -070062 private static final int UPDATE_TRANSFORM_MATRIX = 1;
Doris Liu6827ce22013-03-12 19:24:28 -070063 // module fields
64 private CameraActivity mActivity;
65 private View mRootView;
Doris Liu6432cd62013-06-13 17:20:31 -070066 private TextureView mTextureView;
Doris Liu6827ce22013-03-12 19:24:28 -070067 // An review image having same size as preview. It is displayed when
68 // recording is stopped in capture intent.
69 private ImageView mReviewImage;
70 private View mReviewCancelButton;
71 private View mReviewDoneButton;
72 private View mReviewPlayButton;
73 private ShutterButton mShutterButton;
Angus Konged15d1a2013-08-19 15:06:12 -070074 private ModuleSwitcher mSwitcher;
Doris Liu6827ce22013-03-12 19:24:28 -070075 private TextView mRecordingTimeView;
76 private LinearLayout mLabelsLinearLayout;
77 private View mTimeLapseLabel;
78 private RenderOverlay mRenderOverlay;
79 private PieRenderer mPieRenderer;
80 private VideoMenu mVideoMenu;
Doris Liu6432cd62013-06-13 17:20:31 -070081 private CameraControls mCameraControls;
Doris Liuc3679c02013-08-08 18:08:43 -070082 private SettingsPopup mPopup;
Doris Liu6827ce22013-03-12 19:24:28 -070083 private ZoomRenderer mZoomRenderer;
84 private PreviewGestures mGestures;
Doris Liu6432cd62013-06-13 17:20:31 -070085 private View mMenuButton;
Sascha Haeberling140c2632013-04-23 09:58:51 -070086 private OnScreenIndicators mOnScreenIndicators;
Doris Liu6827ce22013-03-12 19:24:28 -070087 private RotateLayout mRecordingTimeRect;
Doris Liufe6596c2013-10-08 11:03:37 -070088 private boolean mRecordingStarted = false;
Doris Liu6432cd62013-06-13 17:20:31 -070089 private SurfaceTexture mSurfaceTexture;
Doris Liu6827ce22013-03-12 19:24:28 -070090 private VideoController mController;
91 private int mZoomMax;
92 private List<Integer> mZoomRatios;
Sascha Haeberling4f91ab52013-05-21 11:26:13 -070093 private View mPreviewThumb;
Sascha Haeberling37f36112013-08-06 14:31:52 -070094 private View mFlashOverlay;
Doris Liu6827ce22013-03-12 19:24:28 -070095
Doris 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);
Sascha Haeberling4ec139d2013-10-09 23:46:20 -0700153
154 // Switch back into fullscreen/lights-out mode after popup
155 // is dimissed.
156 mActivity.setSystemBarsVisibility(false);
Doris Liuc3679c02013-08-08 18:08:43 -0700157 }
158
159 @Override
160 public void dismiss() {
161 // Called by Framework when touch outside the popup or hit back key
162 dismiss(true);
163 }
164 }
165
Doris Liu6827ce22013-03-12 19:24:28 -0700166 public VideoUI(CameraActivity activity, VideoController controller, View parent) {
167 mActivity = activity;
168 mController = controller;
169 mRootView = parent;
170 mActivity.getLayoutInflater().inflate(R.layout.video_module, (ViewGroup) mRootView, true);
Doris Liu6432cd62013-06-13 17:20:31 -0700171 mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content);
172 mTextureView.setSurfaceTextureListener(this);
Doris Liubdd198e2013-08-29 18:06:45 -0700173 mTextureView.addOnLayoutChangeListener(mLayoutListener);
Sascha Haeberling37f36112013-08-06 14:31:52 -0700174 mFlashOverlay = mRootView.findViewById(R.id.flash_overlay);
Doris Liu6432cd62013-06-13 17:20:31 -0700175 mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button);
Angus Konged15d1a2013-08-19 15:06:12 -0700176 mSwitcher = (ModuleSwitcher) mRootView.findViewById(R.id.camera_switcher);
177 mSwitcher.setCurrentIndex(ModuleSwitcher.VIDEO_MODULE_INDEX);
178 mSwitcher.setSwitchListener(mActivity);
Doris Liu6827ce22013-03-12 19:24:28 -0700179 initializeMiscControls();
180 initializeControlByIntent();
181 initializeOverlay();
Sascha Haeberling37f36112013-08-06 14:31:52 -0700182 mAnimationManager = new AnimationManager();
Doris Liu6827ce22013-03-12 19:24:28 -0700183 }
184
Doris Liu6432cd62013-06-13 17:20:31 -0700185
186 public void initializeSurfaceView() {
187 mSurfaceView = new SurfaceView(mActivity);
188 ((ViewGroup) mRootView).addView(mSurfaceView, 0);
189 mSurfaceView.getHolder().addCallback(this);
190 }
191
Doris Liu6827ce22013-03-12 19:24:28 -0700192 private void initializeControlByIntent() {
Doris Liu2a7f44c2013-08-12 15:18:53 -0700193 mMenuButton = mRootView.findViewById(R.id.menu);
Doris Liu6432cd62013-06-13 17:20:31 -0700194 mMenuButton.setOnClickListener(new OnClickListener() {
Doris Liu6827ce22013-03-12 19:24:28 -0700195 @Override
196 public void onClick(View v) {
197 if (mPieRenderer != null) {
198 mPieRenderer.showInCenter();
199 }
200 }
201 });
Doris Liu6432cd62013-06-13 17:20:31 -0700202
Doris Liu2a7f44c2013-08-12 15:18:53 -0700203 mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls);
Michael Kolbeb8adc12013-04-26 11:09:29 -0700204 mOnScreenIndicators = new OnScreenIndicators(mActivity,
Doris Liu2a7f44c2013-08-12 15:18:53 -0700205 mRootView.findViewById(R.id.on_screen_indicators));
Sascha Haeberling140c2632013-04-23 09:58:51 -0700206 mOnScreenIndicators.resetToDefault();
Doris Liu6827ce22013-03-12 19:24:28 -0700207 if (mController.isVideoCaptureIntent()) {
Doris Liu6432cd62013-06-13 17:20:31 -0700208 hideSwitcher();
209 mActivity.getLayoutInflater().inflate(R.layout.review_module_control,
210 (ViewGroup) mCameraControls);
Doris Liu6827ce22013-03-12 19:24:28 -0700211 // Cannot use RotateImageView for "done" and "cancel" button because
212 // the tablet layout uses RotateLayout, which cannot be cast to
213 // RotateImageView.
Doris Liu2a7f44c2013-08-12 15:18:53 -0700214 mReviewDoneButton = mRootView.findViewById(R.id.btn_done);
215 mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel);
216 mReviewPlayButton = mRootView.findViewById(R.id.btn_play);
Doris Liu6827ce22013-03-12 19:24:28 -0700217 mReviewCancelButton.setVisibility(View.VISIBLE);
218 mReviewDoneButton.setOnClickListener(new OnClickListener() {
219 @Override
220 public void onClick(View v) {
221 mController.onReviewDoneClicked(v);
222 }
223 });
224 mReviewCancelButton.setOnClickListener(new OnClickListener() {
225 @Override
226 public void onClick(View v) {
227 mController.onReviewCancelClicked(v);
228 }
229 });
230 mReviewPlayButton.setOnClickListener(new OnClickListener() {
231 @Override
232 public void onClick(View v) {
233 mController.onReviewPlayClicked(v);
234 }
235 });
236 }
237 }
238
Doris Liu6432cd62013-06-13 17:20:31 -0700239 public void setPreviewSize(int width, int height) {
240 if (width == 0 || height == 0) {
241 Log.w(TAG, "Preview size should not be 0.");
242 return;
243 }
244 if (width > height) {
245 mAspectRatio = (float) width / height;
246 } else {
247 mAspectRatio = (float) height / width;
248 }
249 mHandler.sendEmptyMessage(UPDATE_TRANSFORM_MATRIX);
250 }
251
252 public int getPreviewWidth() {
253 return mPreviewWidth;
254 }
255
256 public int getPreviewHeight() {
257 return mPreviewHeight;
258 }
259
260 public void onScreenSizeChanged(int width, int height, int previewWidth, int previewHeight) {
261 setTransformMatrix(width, height);
262 }
263
264 private void setTransformMatrix(int width, int height) {
265 mMatrix = mTextureView.getTransform(mMatrix);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700266 int orientation = CameraUtil.getDisplayRotation(mActivity);
Doris Liu6432cd62013-06-13 17:20:31 -0700267 float scaleX = 1f, scaleY = 1f;
268 float scaledTextureWidth, scaledTextureHeight;
269 if (width > height) {
270 scaledTextureWidth = Math.max(width,
271 (int) (height * mAspectRatio));
272 scaledTextureHeight = Math.max(height,
273 (int)(width / mAspectRatio));
274 } else {
275 scaledTextureWidth = Math.max(width,
276 (int) (height / mAspectRatio));
277 scaledTextureHeight = Math.max(height,
278 (int) (width * mAspectRatio));
279 }
280
281 if (mSurfaceTextureUncroppedWidth != scaledTextureWidth ||
282 mSurfaceTextureUncroppedHeight != scaledTextureHeight) {
283 mSurfaceTextureUncroppedWidth = scaledTextureWidth;
284 mSurfaceTextureUncroppedHeight = scaledTextureHeight;
285 }
286 scaleX = scaledTextureWidth / width;
287 scaleY = scaledTextureHeight / height;
288 mMatrix.setScale(scaleX, scaleY, (float) width / 2, (float) height / 2);
289 mTextureView.setTransform(mMatrix);
290
291 if (mSurfaceView != null && mSurfaceView.getVisibility() == View.VISIBLE) {
292 LayoutParams lp = (LayoutParams) mSurfaceView.getLayoutParams();
293 lp.width = (int) mSurfaceTextureUncroppedWidth;
294 lp.height = (int) mSurfaceTextureUncroppedHeight;
295 lp.gravity = Gravity.CENTER;
296 mSurfaceView.requestLayout();
297 }
298 }
299
Sascha Haeberling37f36112013-08-06 14:31:52 -0700300 /**
301 * Starts a flash animation
302 */
303 public void animateFlash() {
304 mAnimationManager.startFlashAnimation(mFlashOverlay);
305 }
306
307 /**
308 * Starts a capture animation
Doris Liu3973deb2013-08-21 13:42:22 -0700309 */
310 public void animateCapture() {
311 Bitmap bitmap = null;
312 if (mTextureView != null) {
313 bitmap = mTextureView.getBitmap((int) mSurfaceTextureUncroppedWidth / 2,
314 (int) mSurfaceTextureUncroppedHeight / 2);
315 }
316 animateCapture(bitmap);
317 }
318
319 /**
320 * Starts a capture animation
Sascha Haeberling37f36112013-08-06 14:31:52 -0700321 * @param bitmap the captured image that we shrink and slide in the animation
322 */
323 public void animateCapture(Bitmap bitmap) {
Doris Liu3973deb2013-08-21 13:42:22 -0700324 if (bitmap == null) {
325 Log.e(TAG, "No valid bitmap for capture animation.");
326 return;
327 }
Sascha Haeberling37f36112013-08-06 14:31:52 -0700328 ((ImageView) mPreviewThumb).setImageBitmap(bitmap);
329 mAnimationManager.startCaptureAnimation(mPreviewThumb);
330 }
331
332 /**
333 * Cancels on-going animations
334 */
335 public void cancelAnimations() {
336 mAnimationManager.cancelAnimations();
337 }
338
Doris Liu6432cd62013-06-13 17:20:31 -0700339 public void hideUI() {
340 mCameraControls.setVisibility(View.INVISIBLE);
341 mSwitcher.closePopup();
342 }
343
344 public void showUI() {
345 mCameraControls.setVisibility(View.VISIBLE);
346 }
347
Erin Dahlgren3044d8c2013-10-10 18:23:45 -0700348 public boolean arePreviewControlsVisible() {
349 return (mCameraControls.getVisibility() == View.VISIBLE);
350 }
351
Doris Liu6432cd62013-06-13 17:20:31 -0700352 public void hideSwitcher() {
353 mSwitcher.closePopup();
354 mSwitcher.setVisibility(View.INVISIBLE);
355 }
356
357 public void showSwitcher() {
358 mSwitcher.setVisibility(View.VISIBLE);
359 }
360
Doris Liu6827ce22013-03-12 19:24:28 -0700361 public boolean collapseCameraControls() {
362 boolean ret = false;
363 if (mPopup != null) {
364 dismissPopup(false);
365 ret = true;
366 }
367 return ret;
368 }
369
370 public boolean removeTopLevelPopup() {
371 if (mPopup != null) {
372 dismissPopup(true);
373 return true;
374 }
375 return false;
376 }
377
378 public void enableCameraControls(boolean enable) {
379 if (mGestures != null) {
380 mGestures.setZoomOnly(!enable);
381 }
382 if (mPieRenderer != null && mPieRenderer.showsItems()) {
383 mPieRenderer.hide();
384 }
385 }
386
Doris Liu59390062013-10-10 17:20:56 -0700387 public void initDisplayChangeListener() {
388 ((CameraRootView) mRootView).setDisplayChangeListener(this);
389 }
390
391 public void removeDisplayChangeListener() {
392 ((CameraRootView) mRootView).removeDisplayChangeListener();
393 }
394
Doris Liu6827ce22013-03-12 19:24:28 -0700395 public void overrideSettings(final String... keyvalues) {
396 mVideoMenu.overrideSettings(keyvalues);
397 }
398
Doris Liu6827ce22013-03-12 19:24:28 -0700399 public void setOrientationIndicator(int orientation, boolean animation) {
Doris Liu6827ce22013-03-12 19:24:28 -0700400 // We change the orientation of the linearlayout only for phone UI
401 // because when in portrait the width is not enough.
402 if (mLabelsLinearLayout != null) {
403 if (((orientation / 90) & 1) == 0) {
404 mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL);
405 } else {
406 mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
407 }
408 }
409 mRecordingTimeRect.setOrientation(0, animation);
410 }
411
412 public SurfaceHolder getSurfaceHolder() {
Doris Liu6432cd62013-06-13 17:20:31 -0700413 return mSurfaceView.getHolder();
Doris Liu6827ce22013-03-12 19:24:28 -0700414 }
415
416 public void hideSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700417 mSurfaceView.setVisibility(View.GONE);
418 mTextureView.setVisibility(View.VISIBLE);
419 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700420 }
421
422 public void showSurfaceView() {
Doris Liu6432cd62013-06-13 17:20:31 -0700423 mSurfaceView.setVisibility(View.VISIBLE);
424 mTextureView.setVisibility(View.GONE);
425 setTransformMatrix(mPreviewWidth, mPreviewHeight);
Doris Liu6827ce22013-03-12 19:24:28 -0700426 }
427
428 private void initializeOverlay() {
429 mRenderOverlay = (RenderOverlay) mRootView.findViewById(R.id.render_overlay);
430 if (mPieRenderer == null) {
431 mPieRenderer = new PieRenderer(mActivity);
432 mVideoMenu = new VideoMenu(mActivity, this, mPieRenderer);
433 mPieRenderer.setPieListener(this);
434 }
435 mRenderOverlay.addRenderer(mPieRenderer);
436 if (mZoomRenderer == null) {
437 mZoomRenderer = new ZoomRenderer(mActivity);
438 }
439 mRenderOverlay.addRenderer(mZoomRenderer);
440 if (mGestures == null) {
Doris Liu6432cd62013-06-13 17:20:31 -0700441 mGestures = new PreviewGestures(mActivity, this, mZoomRenderer, mPieRenderer);
442 mRenderOverlay.setGestures(mGestures);
Doris Liu6827ce22013-03-12 19:24:28 -0700443 }
444 mGestures.setRenderOverlay(mRenderOverlay);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700445
Doris Liu2a7f44c2013-08-12 15:18:53 -0700446 mPreviewThumb = mRootView.findViewById(R.id.preview_thumb);
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700447 mPreviewThumb.setOnClickListener(new OnClickListener() {
448 @Override
449 public void onClick(View v) {
Doris Liufe6596c2013-10-08 11:03:37 -0700450 // Do not allow navigation to filmstrip during video recording
451 if (!mRecordingStarted) {
452 mActivity.gotoGallery();
453 }
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700454 }
455 });
Doris Liu6827ce22013-03-12 19:24:28 -0700456 }
457
458 public void setPrefChangedListener(OnPreferenceChangedListener listener) {
459 mVideoMenu.setListener(listener);
460 }
461
462 private void initializeMiscControls() {
Doris Liu6827ce22013-03-12 19:24:28 -0700463 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
Doris Liu6827ce22013-03-12 19:24:28 -0700464 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
465 mShutterButton.setOnShutterButtonListener(mController);
466 mShutterButton.setVisibility(View.VISIBLE);
467 mShutterButton.requestFocus();
468 mShutterButton.enableTouch(true);
469 mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time);
470 mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect);
471 mTimeLapseLabel = mRootView.findViewById(R.id.time_lapse_label);
472 // The R.id.labels can only be found in phone layout.
473 // That is, mLabelsLinearLayout should be null in tablet layout.
474 mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels);
475 }
476
Michael Kolb87880792013-04-30 15:38:49 -0700477 public void updateOnScreenIndicators(Parameters param, ComboPreferences prefs) {
Sascha Haeberling140c2632013-04-23 09:58:51 -0700478 mOnScreenIndicators.updateFlashOnScreenIndicator(param.getFlashMode());
Michael Kolb87880792013-04-30 15:38:49 -0700479 boolean location = RecordLocationPreference.get(
480 prefs, mActivity.getContentResolver());
481 mOnScreenIndicators.updateLocationIndicator(location);
482
Doris Liu6827ce22013-03-12 19:24:28 -0700483 }
484
485 public void setAspectRatio(double ratio) {
Doris Liu6432cd62013-06-13 17:20:31 -0700486 // mPreviewFrameLayout.setAspectRatio(ratio);
Doris Liu6827ce22013-03-12 19:24:28 -0700487 }
488
489 public void showTimeLapseUI(boolean enable) {
490 if (mTimeLapseLabel != null) {
491 mTimeLapseLabel.setVisibility(enable ? View.VISIBLE : View.GONE);
492 }
493 }
494
Michael Kolb3bc96b22013-03-12 10:24:42 -0700495 private void openMenu() {
496 if (mPieRenderer != null) {
497 mPieRenderer.showInCenter();
498 }
499 }
500
Doris Liu6827ce22013-03-12 19:24:28 -0700501 public void dismissPopup(boolean topLevelOnly) {
Doris Liu69ef5ea2013-05-07 13:48:10 -0700502 // In review mode, we do not want to bring up the camera UI
503 if (mController.isInReviewMode()) return;
Doris Liu6827ce22013-03-12 19:24:28 -0700504 if (mPopup != null) {
Doris Liuc3679c02013-08-08 18:08:43 -0700505 mPopup.dismiss(topLevelOnly);
Doris Liu6827ce22013-03-12 19:24:28 -0700506 }
Doris Liuc3679c02013-08-08 18:08:43 -0700507 }
508
509 private void popupDismissed() {
510 mPopup = null;
511 }
512
513 public void showPopup(AbstractSettingPopup popup) {
514 hideUI();
515
516 if (mPopup != null) {
517 mPopup.dismiss(false);
518 }
519 mPopup = new SettingsPopup(popup);
Doris Liu6827ce22013-03-12 19:24:28 -0700520 }
521
522 public void onShowSwitcherPopup() {
523 hidePieRenderer();
524 }
525
526 public boolean hidePieRenderer() {
527 if (mPieRenderer != null && mPieRenderer.showsItems()) {
528 mPieRenderer.hide();
529 return true;
530 }
531 return false;
532 }
533
Doris Liu61f2b082013-03-27 17:25:43 -0700534 // disable preview gestures after shutter is pressed
535 public void setShutterPressed(boolean pressed) {
536 if (mGestures == null) return;
537 mGestures.setEnabled(!pressed);
538 }
539
Doris Liu6827ce22013-03-12 19:24:28 -0700540 public void enableShutter(boolean enable) {
541 if (mShutterButton != null) {
542 mShutterButton.setEnabled(enable);
543 }
544 }
545
546 // PieListener
547 @Override
548 public void onPieOpened(int centerX, int centerY) {
Doris Liu6432cd62013-06-13 17:20:31 -0700549 setSwipingEnabled(false);
Doris Liu6827ce22013-03-12 19:24:28 -0700550 }
551
552 @Override
553 public void onPieClosed() {
Doris Liu6432cd62013-06-13 17:20:31 -0700554 setSwipingEnabled(true);
555 }
556
557 public void setSwipingEnabled(boolean enable) {
558 mActivity.setSwipingEnabled(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700559 }
560
561 public void showPreviewBorder(boolean enable) {
Doris Liu6432cd62013-06-13 17:20:31 -0700562 // TODO: mPreviewFrameLayout.showBorder(enable);
Doris Liu6827ce22013-03-12 19:24:28 -0700563 }
564
565 // SingleTapListener
566 // Preview area is touched. Take a picture.
567 @Override
568 public void onSingleTapUp(View view, int x, int y) {
569 mController.onSingleTapUp(view, x, y);
570 }
571
Doris Liufe6596c2013-10-08 11:03:37 -0700572 public void showRecordingUI(boolean recording) {
573 mRecordingStarted = recording;
Doris Liu6432cd62013-06-13 17:20:31 -0700574 mMenuButton.setVisibility(recording ? View.GONE : View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700575 mOnScreenIndicators.setVisibility(recording ? View.GONE : View.VISIBLE);
576 if (recording) {
577 mShutterButton.setImageResource(R.drawable.btn_shutter_video_recording);
Doris Liu6432cd62013-06-13 17:20:31 -0700578 hideSwitcher();
Doris Liu6827ce22013-03-12 19:24:28 -0700579 mRecordingTimeView.setText("");
580 mRecordingTimeView.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700581 } else {
582 mShutterButton.setImageResource(R.drawable.btn_new_shutter_video);
Doris Liu2a7f44c2013-08-12 15:18:53 -0700583 if (!mController.isVideoCaptureIntent()) {
584 showSwitcher();
585 }
Doris Liu6827ce22013-03-12 19:24:28 -0700586 mRecordingTimeView.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700587 }
588 }
589
590 public void showReviewImage(Bitmap bitmap) {
591 mReviewImage.setImageBitmap(bitmap);
592 mReviewImage.setVisibility(View.VISIBLE);
593 }
594
595 public void showReviewControls() {
Angus Kongb50b5cb2013-08-09 14:55:20 -0700596 CameraUtil.fadeOut(mShutterButton);
597 CameraUtil.fadeIn(mReviewDoneButton);
598 CameraUtil.fadeIn(mReviewPlayButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700599 mReviewImage.setVisibility(View.VISIBLE);
Doris Liu6432cd62013-06-13 17:20:31 -0700600 mMenuButton.setVisibility(View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700601 mOnScreenIndicators.setVisibility(View.GONE);
602 }
603
604 public void hideReviewUI() {
605 mReviewImage.setVisibility(View.GONE);
606 mShutterButton.setEnabled(true);
Doris Liu6432cd62013-06-13 17:20:31 -0700607 mMenuButton.setVisibility(View.VISIBLE);
Doris Liu6827ce22013-03-12 19:24:28 -0700608 mOnScreenIndicators.setVisibility(View.VISIBLE);
Angus Kongb50b5cb2013-08-09 14:55:20 -0700609 CameraUtil.fadeOut(mReviewDoneButton);
610 CameraUtil.fadeOut(mReviewPlayButton);
611 CameraUtil.fadeIn(mShutterButton);
Doris Liu6827ce22013-03-12 19:24:28 -0700612 }
613
614 private void setShowMenu(boolean show) {
615 if (mOnScreenIndicators != null) {
616 mOnScreenIndicators.setVisibility(show ? View.VISIBLE : View.GONE);
617 }
Doris Liu6432cd62013-06-13 17:20:31 -0700618 if (mMenuButton != null) {
619 mMenuButton.setVisibility(show ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700620 }
621 }
622
ztenghui7b265a62013-09-09 14:58:44 -0700623 public void onPreviewFocusChanged(boolean previewFocused) {
624 if (previewFocused) {
Doris Liu6432cd62013-06-13 17:20:31 -0700625 showUI();
626 } else {
627 hideUI();
628 }
Doris Liu6827ce22013-03-12 19:24:28 -0700629 if (mGestures != null) {
ztenghui7b265a62013-09-09 14:58:44 -0700630 mGestures.setEnabled(previewFocused);
Doris Liu6827ce22013-03-12 19:24:28 -0700631 }
Doris Liu6827ce22013-03-12 19:24:28 -0700632 if (mRenderOverlay != null) {
633 // this can not happen in capture mode
ztenghui7b265a62013-09-09 14:58:44 -0700634 mRenderOverlay.setVisibility(previewFocused ? View.VISIBLE : View.GONE);
Doris Liu6827ce22013-03-12 19:24:28 -0700635 }
ztenghui7b265a62013-09-09 14:58:44 -0700636 setShowMenu(previewFocused);
Doris Liu6827ce22013-03-12 19:24:28 -0700637 }
638
639 public void initializePopup(PreferenceGroup pref) {
640 mVideoMenu.initialize(pref);
641 }
642
643 public void initializeZoom(Parameters param) {
Doris Liu6432cd62013-06-13 17:20:31 -0700644 if (param == null || !param.isZoomSupported()) {
645 mGestures.setZoomEnabled(false);
646 return;
647 }
648 mGestures.setZoomEnabled(true);
Doris Liu6827ce22013-03-12 19:24:28 -0700649 mZoomMax = param.getMaxZoom();
650 mZoomRatios = param.getZoomRatios();
651 // Currently we use immediate zoom for fast zooming to get better UX and
652 // there is no plan to take advantage of the smooth zoom.
653 mZoomRenderer.setZoomMax(mZoomMax);
654 mZoomRenderer.setZoom(param.getZoom());
655 mZoomRenderer.setZoomValue(mZoomRatios.get(param.getZoom()));
656 mZoomRenderer.setOnZoomChangeListener(new ZoomChangeListener());
657 }
658
659 public void clickShutter() {
660 mShutterButton.performClick();
661 }
662
663 public void pressShutter(boolean pressed) {
664 mShutterButton.setPressed(pressed);
665 }
666
Doris Liu6432cd62013-06-13 17:20:31 -0700667 public View getShutterButton() {
668 return mShutterButton;
Doris Liu6827ce22013-03-12 19:24:28 -0700669 }
670
671 public void setRecordingTime(String text) {
672 mRecordingTimeView.setText(text);
673 }
674
675 public void setRecordingTimeTextColor(int color) {
676 mRecordingTimeView.setTextColor(color);
677 }
678
Doris Liu6432cd62013-06-13 17:20:31 -0700679 public boolean isVisible() {
ztenghui285a5be2013-10-09 15:59:47 -0700680 return mCameraControls.getVisibility() == View.VISIBLE;
Doris Liu6432cd62013-06-13 17:20:31 -0700681 }
682
ztenghui7b265a62013-09-09 14:58:44 -0700683 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700684 public void onDisplayChanged() {
685 mCameraControls.checkLayoutFlip();
686 mController.updateCameraOrientation();
687 }
688
Doris Liu6827ce22013-03-12 19:24:28 -0700689 private class ZoomChangeListener implements ZoomRenderer.OnZoomChangedListener {
690 @Override
691 public void onZoomValueChanged(int index) {
692 int newZoom = mController.onZoomChanged(index);
693 if (mZoomRenderer != null) {
694 mZoomRenderer.setZoomValue(mZoomRatios.get(newZoom));
695 }
696 }
697
698 @Override
699 public void onZoomStart() {
700 }
701
702 @Override
703 public void onZoomEnd() {
704 }
705 }
Michael Kolb3bc96b22013-03-12 10:24:42 -0700706
Doris Liu6432cd62013-06-13 17:20:31 -0700707 public SurfaceTexture getSurfaceTexture() {
Doris Liu6432cd62013-06-13 17:20:31 -0700708 return mSurfaceTexture;
709 }
710
711 // SurfaceTexture callbacks
Michael Kolb3bc96b22013-03-12 10:24:42 -0700712 @Override
Doris Liu6432cd62013-06-13 17:20:31 -0700713 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Angus Kong395ee2d2013-07-15 12:42:41 -0700714 mSurfaceTexture = surface;
715 mController.onPreviewUIReady();
Michael Kolb3bc96b22013-03-12 10:24:42 -0700716 }
717
Doris Liu6432cd62013-06-13 17:20:31 -0700718 @Override
719 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
720 mSurfaceTexture = null;
Angus Kong395ee2d2013-07-15 12:42:41 -0700721 mController.onPreviewUIDestroyed();
Doris Liu6432cd62013-06-13 17:20:31 -0700722 Log.d(TAG, "surfaceTexture is destroyed");
723 return true;
724 }
725
726 @Override
727 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
728 }
729
730 @Override
731 public void onSurfaceTextureUpdated(SurfaceTexture surface) {
732 }
733
734 // SurfaceHolder callbacks
735 @Override
736 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
737 Log.v(TAG, "Surface changed. width=" + width + ". height=" + height);
738 }
739
740 @Override
741 public void surfaceCreated(SurfaceHolder holder) {
742 Log.v(TAG, "Surface created");
743 }
744
745 @Override
746 public void surfaceDestroyed(SurfaceHolder holder) {
747 Log.v(TAG, "Surface destroyed");
748 mController.stopPreview();
Sascha Haeberling4f91ab52013-05-21 11:26:13 -0700749 }
Doris Liu6827ce22013-03-12 19:24:28 -0700750}