1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 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 17 package com.android.camera; 18 19 import android.graphics.Bitmap; 20 import android.graphics.Point; 21 import android.graphics.SurfaceTexture; 22 import android.view.GestureDetector; 23 import android.view.MotionEvent; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.widget.ImageView; 27 import android.widget.LinearLayout; 28 import android.widget.TextView; 29 30 import com.android.camera.app.OrientationManager; 31 import com.android.camera.debug.Log; 32 import com.android.camera.ui.PreviewOverlay; 33 import com.android.camera.ui.PreviewStatusListener; 34 import com.android.camera.ui.RotateLayout; 35 import com.android.camera.ui.focus.FocusRing; 36 import com.android.camera2.R; 37 import com.android.ex.camera2.portability.CameraCapabilities; 38 import com.android.ex.camera2.portability.CameraSettings; 39 40 public class VideoUI implements PreviewStatusListener { 41 private static final Log.Tag TAG = new Log.Tag("VideoUI"); 42 43 private final static float UNSET = 0f; 44 private final PreviewOverlay mPreviewOverlay; 45 // module fields 46 private final CameraActivity mActivity; 47 private final View mRootView; 48 private final FocusRing mFocusRing; 49 // An review image having same size as preview. It is displayed when 50 // recording is stopped in capture intent. 51 private ImageView mReviewImage; 52 private TextView mRecordingTimeView; 53 private LinearLayout mLabelsLinearLayout; 54 private RotateLayout mRecordingTimeRect; 55 private boolean mRecordingStarted = false; 56 private final VideoController mController; 57 private float mZoomMax; 58 59 private float mAspectRatio = UNSET; 60 private final AnimationManager mAnimationManager; 61 62 @Override onPreviewLayoutChanged(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)63 public void onPreviewLayoutChanged(View v, int left, int top, int right, 64 int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { 65 } 66 67 @Override shouldAutoAdjustTransformMatrixOnLayout()68 public boolean shouldAutoAdjustTransformMatrixOnLayout() { 69 return true; 70 } 71 72 @Override onPreviewFlipped()73 public void onPreviewFlipped() { 74 mController.updateCameraOrientation(); 75 } 76 77 private final GestureDetector.OnGestureListener mPreviewGestureListener 78 = new GestureDetector.SimpleOnGestureListener() { 79 @Override 80 public boolean onSingleTapUp(MotionEvent ev) { 81 mController.onSingleTapUp(null, (int) ev.getX(), (int) ev.getY()); 82 return true; 83 } 84 }; 85 VideoUI(CameraActivity activity, VideoController controller, View parent)86 public VideoUI(CameraActivity activity, VideoController controller, View parent) { 87 mActivity = activity; 88 mController = controller; 89 mRootView = parent; 90 ViewGroup moduleRoot = (ViewGroup) mRootView.findViewById(R.id.module_layout); 91 mActivity.getLayoutInflater().inflate(R.layout.video_module, 92 moduleRoot, true); 93 94 mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay); 95 96 initializeMiscControls(); 97 mAnimationManager = new AnimationManager(); 98 mFocusRing = (FocusRing) mRootView.findViewById(R.id.focus_ring); 99 } 100 setPreviewSize(int width, int height)101 public void setPreviewSize(int width, int height) { 102 if (width == 0 || height == 0) { 103 Log.w(TAG, "Preview size should not be 0."); 104 return; 105 } 106 float aspectRatio; 107 if (width > height) { 108 aspectRatio = (float) width / height; 109 } else { 110 aspectRatio = (float) height / width; 111 } 112 setAspectRatio(aspectRatio); 113 } 114 getFocusRing()115 public FocusRing getFocusRing() { 116 return mFocusRing; 117 } 118 119 /** 120 * Cancels on-going animations 121 */ cancelAnimations()122 public void cancelAnimations() { 123 mAnimationManager.cancelAnimations(); 124 } 125 setOrientationIndicator(int orientation, boolean animation)126 public void setOrientationIndicator(int orientation, boolean animation) { 127 // We change the orientation of the linearlayout only for phone UI 128 // because when in portrait the width is not enough. 129 if (mLabelsLinearLayout != null) { 130 if (((orientation / 90) & 1) == 0) { 131 mLabelsLinearLayout.setOrientation(LinearLayout.VERTICAL); 132 } else { 133 mLabelsLinearLayout.setOrientation(LinearLayout.HORIZONTAL); 134 } 135 } 136 mRecordingTimeRect.setOrientation(0, animation); 137 } 138 initializeMiscControls()139 private void initializeMiscControls() { 140 mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image); 141 mRecordingTimeView = (TextView) mRootView.findViewById(R.id.recording_time); 142 mRecordingTimeRect = (RotateLayout) mRootView.findViewById(R.id.recording_time_rect); 143 // The R.id.labels can only be found in phone layout. 144 // That is, mLabelsLinearLayout should be null in tablet layout. 145 mLabelsLinearLayout = (LinearLayout) mRootView.findViewById(R.id.labels); 146 } 147 updateOnScreenIndicators(CameraSettings settings)148 public void updateOnScreenIndicators(CameraSettings settings) { 149 } 150 setAspectRatio(float ratio)151 public void setAspectRatio(float ratio) { 152 if (ratio <= 0) { 153 return; 154 } 155 float aspectRatio = ratio > 1 ? ratio : 1 / ratio; 156 if (aspectRatio != mAspectRatio) { 157 mAspectRatio = aspectRatio; 158 mController.updatePreviewAspectRatio(mAspectRatio); 159 } 160 } 161 setSwipingEnabled(boolean enable)162 public void setSwipingEnabled(boolean enable) { 163 mActivity.setSwipingEnabled(enable); 164 } 165 showPreviewBorder(boolean enable)166 public void showPreviewBorder(boolean enable) { 167 // TODO: mPreviewFrameLayout.showBorder(enable); 168 } 169 showRecordingUI(boolean recording)170 public void showRecordingUI(boolean recording) { 171 mRecordingStarted = recording; 172 if (recording) { 173 mRecordingTimeView.setText(""); 174 mRecordingTimeView.setVisibility(View.VISIBLE); 175 mRecordingTimeView.announceForAccessibility( 176 mActivity.getResources().getString(R.string.video_recording_started)); 177 } else { 178 mRecordingTimeView.announceForAccessibility( 179 mActivity.getResources().getString(R.string.video_recording_stopped)); 180 mRecordingTimeView.setVisibility(View.GONE); 181 } 182 } 183 showReviewImage(Bitmap bitmap)184 public void showReviewImage(Bitmap bitmap) { 185 mReviewImage.setImageBitmap(bitmap); 186 mReviewImage.setVisibility(View.VISIBLE); 187 } 188 showReviewControls()189 public void showReviewControls() { 190 mActivity.getCameraAppUI().transitionToIntentReviewLayout(); 191 mReviewImage.setVisibility(View.VISIBLE); 192 } 193 initializeZoom(CameraSettings settings, CameraCapabilities capabilities)194 public void initializeZoom(CameraSettings settings, CameraCapabilities capabilities) { 195 mZoomMax = capabilities.getMaxZoomRatio(); 196 // Currently we use immediate zoom for fast zooming to get better UX and 197 // there is no plan to take advantage of the smooth zoom. 198 // TODO: setup zoom through App UI. 199 mPreviewOverlay.setupZoom(mZoomMax, settings.getCurrentZoomRatio(), 200 new ZoomChangeListener()); 201 } 202 setRecordingTime(String text)203 public void setRecordingTime(String text) { 204 mRecordingTimeView.setText(text); 205 } 206 setRecordingTimeTextColor(int color)207 public void setRecordingTimeTextColor(int color) { 208 mRecordingTimeView.setTextColor(color); 209 } 210 isVisible()211 public boolean isVisible() { 212 return false; 213 } 214 215 @Override getGestureListener()216 public GestureDetector.OnGestureListener getGestureListener() { 217 return mPreviewGestureListener; 218 } 219 220 @Override getTouchListener()221 public View.OnTouchListener getTouchListener() { 222 return null; 223 } 224 225 /** 226 * Hide the focus indicator. 227 */ hidePassiveFocusIndicator()228 public void hidePassiveFocusIndicator() { 229 if (mFocusRing != null) { 230 Log.v(TAG, "mFocusRing.stopFocusAnimations()"); 231 mFocusRing.stopFocusAnimations(); 232 } 233 } 234 235 /** 236 * Show the passive focus indicator. 237 */ showPassiveFocusIndicator()238 public void showPassiveFocusIndicator() { 239 if (mFocusRing != null) { 240 mFocusRing.startPassiveFocus(); 241 } 242 } 243 244 245 /** 246 * @return The size of the available preview area. 247 */ getPreviewScreenSize()248 public Point getPreviewScreenSize() { 249 return new Point(mRootView.getMeasuredWidth(), mRootView.getMeasuredHeight()); 250 } 251 252 /** 253 * Adjust UI to an orientation change if necessary. 254 */ onOrientationChanged(OrientationManager orientationManager, OrientationManager.DeviceOrientation deviceOrientation)255 public void onOrientationChanged(OrientationManager orientationManager, 256 OrientationManager.DeviceOrientation deviceOrientation) { 257 // do nothing. 258 } 259 260 private class ZoomChangeListener implements PreviewOverlay.OnZoomChangedListener { 261 @Override onZoomValueChanged(float ratio)262 public void onZoomValueChanged(float ratio) { 263 mController.onZoomChanged(ratio); 264 } 265 266 @Override onZoomStart()267 public void onZoomStart() { 268 } 269 270 @Override onZoomEnd()271 public void onZoomEnd() { 272 } 273 } 274 275 // SurfaceTexture callbacks 276 @Override onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height)277 public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 278 mController.onPreviewUIReady(); 279 } 280 281 @Override onSurfaceTextureDestroyed(SurfaceTexture surface)282 public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 283 mController.onPreviewUIDestroyed(); 284 Log.d(TAG, "surfaceTexture is destroyed"); 285 return true; 286 } 287 288 @Override onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height)289 public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 290 } 291 292 @Override onSurfaceTextureUpdated(SurfaceTexture surface)293 public void onSurfaceTextureUpdated(SurfaceTexture surface) { 294 } 295 onPause()296 public void onPause() { 297 // recalculate aspect ratio when restarting. 298 mAspectRatio = 0.0f; 299 } 300 } 301