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