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.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
     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
     68     public boolean shouldAutoAdjustTransformMatrixOnLayout() {
     69         return true;
     70     }
     71 
     72     @Override
     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 
     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 
    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 
    115     public FocusRing getFocusRing() {
    116         return mFocusRing;
    117     }
    118 
    119     /**
    120      * Cancels on-going animations
    121      */
    122     public void cancelAnimations() {
    123         mAnimationManager.cancelAnimations();
    124     }
    125 
    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 
    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 
    148     public void updateOnScreenIndicators(CameraSettings settings) {
    149     }
    150 
    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 
    162     public void setSwipingEnabled(boolean enable) {
    163         mActivity.setSwipingEnabled(enable);
    164     }
    165 
    166     public void showPreviewBorder(boolean enable) {
    167        // TODO: mPreviewFrameLayout.showBorder(enable);
    168     }
    169 
    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 
    184     public void showReviewImage(Bitmap bitmap) {
    185         mReviewImage.setImageBitmap(bitmap);
    186         mReviewImage.setVisibility(View.VISIBLE);
    187     }
    188 
    189     public void showReviewControls() {
    190         mActivity.getCameraAppUI().transitionToIntentReviewLayout();
    191         mReviewImage.setVisibility(View.VISIBLE);
    192     }
    193 
    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 
    203     public void setRecordingTime(String text) {
    204         mRecordingTimeView.setText(text);
    205     }
    206 
    207     public void setRecordingTimeTextColor(int color) {
    208         mRecordingTimeView.setTextColor(color);
    209     }
    210 
    211     public boolean isVisible() {
    212         return false;
    213     }
    214 
    215     @Override
    216     public GestureDetector.OnGestureListener getGestureListener() {
    217         return mPreviewGestureListener;
    218     }
    219 
    220     @Override
    221     public View.OnTouchListener getTouchListener() {
    222         return null;
    223     }
    224 
    225     /**
    226      * Hide the focus indicator.
    227      */
    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      */
    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      */
    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      */
    255     public void onOrientationChanged(OrientationManager orientationManager,
    256                                      OrientationManager.DeviceOrientation deviceOrientation) {
    257         // do nothing.
    258     }
    259 
    260     private class ZoomChangeListener implements PreviewOverlay.OnZoomChangedListener {
    261         @Override
    262         public void onZoomValueChanged(float ratio) {
    263             mController.onZoomChanged(ratio);
    264         }
    265 
    266         @Override
    267         public void onZoomStart() {
    268         }
    269 
    270         @Override
    271         public void onZoomEnd() {
    272         }
    273     }
    274 
    275     // SurfaceTexture callbacks
    276     @Override
    277     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
    278         mController.onPreviewUIReady();
    279     }
    280 
    281     @Override
    282     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
    283         mController.onPreviewUIDestroyed();
    284         Log.d(TAG, "surfaceTexture is destroyed");
    285         return true;
    286     }
    287 
    288     @Override
    289     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
    290     }
    291 
    292     @Override
    293     public void onSurfaceTextureUpdated(SurfaceTexture surface) {
    294     }
    295 
    296     public void onPause() {
    297         // recalculate aspect ratio when restarting.
    298         mAspectRatio = 0.0f;
    299     }
    300 }
    301