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