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.content.Context;
     20 import android.content.Intent;
     21 import android.content.res.Configuration;
     22 import android.graphics.drawable.Drawable;
     23 import android.os.Bundle;
     24 import android.provider.MediaStore;
     25 import android.view.KeyEvent;
     26 import android.view.LayoutInflater;
     27 import android.view.MotionEvent;
     28 import android.view.OrientationEventListener;
     29 import android.view.View;
     30 import android.view.ViewGroup;
     31 import android.widget.FrameLayout;
     32 
     33 import com.android.camera.ui.CameraSwitcher;
     34 import com.android.gallery3d.app.PhotoPage;
     35 import com.android.gallery3d.common.ApiHelper;
     36 import com.android.gallery3d.util.LightCycleHelper;
     37 
     38 public class CameraActivity extends ActivityBase
     39         implements CameraSwitcher.CameraSwitchListener {
     40     public static final int PHOTO_MODULE_INDEX = 0;
     41     public static final int VIDEO_MODULE_INDEX = 1;
     42     public static final int PANORAMA_MODULE_INDEX = 2;
     43     public static final int LIGHTCYCLE_MODULE_INDEX = 3;
     44 
     45     CameraModule mCurrentModule;
     46     private FrameLayout mFrame;
     47     private ShutterButton mShutter;
     48     private CameraSwitcher mSwitcher;
     49     private View mShutterSwitcher;
     50     private View mControlsBackground;
     51     private Drawable[] mDrawables;
     52     private int mCurrentModuleIndex;
     53     private MotionEvent mDown;
     54 
     55     private MyOrientationEventListener mOrientationListener;
     56     // The degrees of the device rotated clockwise from its natural orientation.
     57     private int mLastRawOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
     58 
     59     private static final String TAG = "CAM_activity";
     60 
     61     private static final int[] DRAW_IDS = {
     62             R.drawable.ic_switch_camera,
     63             R.drawable.ic_switch_video,
     64             R.drawable.ic_switch_pan,
     65             R.drawable.ic_switch_photosphere
     66     };
     67 
     68     @Override
     69     public void onCreate(Bundle state) {
     70         super.onCreate(state);
     71         setContentView(R.layout.camera_main);
     72         mFrame = (FrameLayout) findViewById(R.id.main_content);
     73         mDrawables = new Drawable[DRAW_IDS.length];
     74         for (int i = 0; i < DRAW_IDS.length; i++) {
     75             mDrawables[i] = getResources().getDrawable(DRAW_IDS[i]);
     76         }
     77         init();
     78         if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
     79                 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
     80             mCurrentModule = new VideoModule();
     81             mCurrentModuleIndex = VIDEO_MODULE_INDEX;
     82         } else {
     83             mCurrentModule = new PhotoModule();
     84             mCurrentModuleIndex = PHOTO_MODULE_INDEX;
     85         }
     86         mCurrentModule.init(this, mFrame, true);
     87         mSwitcher.setCurrentIndex(mCurrentModuleIndex);
     88         mOrientationListener = new MyOrientationEventListener(this);
     89     }
     90 
     91     public void init() {
     92         mControlsBackground = findViewById(R.id.controls);
     93         mShutterSwitcher = findViewById(R.id.camera_shutter_switcher);
     94         mShutter = (ShutterButton) findViewById(R.id.shutter_button);
     95         mSwitcher = (CameraSwitcher) findViewById(R.id.camera_switcher);
     96         int totaldrawid = (LightCycleHelper.hasLightCycleCapture(this)
     97                                 ? DRAW_IDS.length : DRAW_IDS.length - 1);
     98         if (!ApiHelper.HAS_OLD_PANORAMA) totaldrawid--;
     99 
    100         int[] drawids = new int[totaldrawid];
    101         int[] moduleids = new int[totaldrawid];
    102         int ix = 0;
    103         for (int i = 0; i < mDrawables.length; i++) {
    104             if (i == PANORAMA_MODULE_INDEX && !ApiHelper.HAS_OLD_PANORAMA) {
    105                 continue; // not enabled, so don't add to UI
    106             }
    107             if (i == LIGHTCYCLE_MODULE_INDEX && !LightCycleHelper.hasLightCycleCapture(this)) {
    108                 continue; // not enabled, so don't add to UI
    109             }
    110             moduleids[ix] = i;
    111             drawids[ix++] = DRAW_IDS[i];
    112         }
    113         mSwitcher.setIds(moduleids, drawids);
    114         mSwitcher.setSwitchListener(this);
    115         mSwitcher.setCurrentIndex(mCurrentModuleIndex);
    116     }
    117 
    118     private class MyOrientationEventListener
    119             extends OrientationEventListener {
    120         public MyOrientationEventListener(Context context) {
    121             super(context);
    122         }
    123 
    124         @Override
    125         public void onOrientationChanged(int orientation) {
    126             // We keep the last known orientation. So if the user first orient
    127             // the camera then point the camera to floor or sky, we still have
    128             // the correct orientation.
    129             if (orientation == ORIENTATION_UNKNOWN) return;
    130             mLastRawOrientation = orientation;
    131             mCurrentModule.onOrientationChanged(orientation);
    132         }
    133     }
    134 
    135     @Override
    136     public void onCameraSelected(int i) {
    137         if (mPaused) return;
    138         if (i != mCurrentModuleIndex) {
    139             mPaused = true;
    140             boolean canReuse = canReuseScreenNail();
    141             CameraHolder.instance().keep();
    142             closeModule(mCurrentModule);
    143             mCurrentModuleIndex = i;
    144             switch (i) {
    145                 case VIDEO_MODULE_INDEX:
    146                     mCurrentModule = new VideoModule();
    147                     break;
    148                 case PHOTO_MODULE_INDEX:
    149                     mCurrentModule = new PhotoModule();
    150                     break;
    151                 case PANORAMA_MODULE_INDEX:
    152                     mCurrentModule = new PanoramaModule();
    153                     break;
    154                 case LIGHTCYCLE_MODULE_INDEX:
    155                     mCurrentModule = LightCycleHelper.createPanoramaModule();
    156                     break;
    157             }
    158             openModule(mCurrentModule, canReuse);
    159             mCurrentModule.onOrientationChanged(mLastRawOrientation);
    160         }
    161     }
    162 
    163     @Override
    164     public void onShowSwitcherPopup() {
    165         mCurrentModule.onShowSwitcherPopup();
    166     }
    167 
    168     private void openModule(CameraModule module, boolean canReuse) {
    169         module.init(this, mFrame, canReuse && canReuseScreenNail());
    170         mPaused = false;
    171         module.onResumeBeforeSuper();
    172         module.onResumeAfterSuper();
    173     }
    174 
    175     private void closeModule(CameraModule module) {
    176         module.onPauseBeforeSuper();
    177         module.onPauseAfterSuper();
    178         mFrame.removeAllViews();
    179     }
    180 
    181     public ShutterButton getShutterButton() {
    182         return mShutter;
    183     }
    184 
    185     public void hideUI() {
    186         mControlsBackground.setVisibility(View.INVISIBLE);
    187         hideSwitcher();
    188         mShutter.setVisibility(View.GONE);
    189     }
    190 
    191     public void showUI() {
    192         mControlsBackground.setVisibility(View.VISIBLE);
    193         showSwitcher();
    194         mShutter.setVisibility(View.VISIBLE);
    195         // Force a layout change to show shutter button
    196         mShutter.requestLayout();
    197     }
    198 
    199     public void hideSwitcher() {
    200         mSwitcher.closePopup();
    201         mSwitcher.setVisibility(View.INVISIBLE);
    202     }
    203 
    204     public void showSwitcher() {
    205         if (mCurrentModule.needsSwitcher()) {
    206             mSwitcher.setVisibility(View.VISIBLE);
    207         }
    208     }
    209 
    210     public boolean isInCameraApp() {
    211         return mShowCameraAppView;
    212     }
    213 
    214     @Override
    215     public void onConfigurationChanged(Configuration config) {
    216         super.onConfigurationChanged(config);
    217 
    218         ViewGroup appRoot = (ViewGroup) findViewById(R.id.content);
    219         // remove old switcher, shutter and shutter icon
    220         View cameraControlsView = findViewById(R.id.camera_shutter_switcher);
    221         appRoot.removeView(cameraControlsView);
    222 
    223         // create new layout with the current orientation
    224         LayoutInflater inflater = getLayoutInflater();
    225         inflater.inflate(R.layout.camera_shutter_switcher, appRoot);
    226         init();
    227 
    228         if (mShowCameraAppView) {
    229             showUI();
    230         } else {
    231             hideUI();
    232         }
    233         mCurrentModule.onConfigurationChanged(config);
    234     }
    235 
    236     @Override
    237     public void onPause() {
    238         mPaused = true;
    239         mOrientationListener.disable();
    240         mCurrentModule.onPauseBeforeSuper();
    241         super.onPause();
    242         mCurrentModule.onPauseAfterSuper();
    243     }
    244 
    245     @Override
    246     public void onResume() {
    247         mPaused = false;
    248         mOrientationListener.enable();
    249         mCurrentModule.onResumeBeforeSuper();
    250         super.onResume();
    251         mCurrentModule.onResumeAfterSuper();
    252     }
    253 
    254     @Override
    255     protected void onFullScreenChanged(boolean full) {
    256         if (full) {
    257             showUI();
    258         } else {
    259             hideUI();
    260         }
    261         super.onFullScreenChanged(full);
    262         mCurrentModule.onFullScreenChanged(full);
    263     }
    264 
    265     @Override
    266     protected void onStop() {
    267         super.onStop();
    268         mCurrentModule.onStop();
    269         getStateManager().clearTasks();
    270     }
    271 
    272     @Override
    273     protected void onNewIntent(Intent intent) {
    274         super.onNewIntent(intent);
    275         getStateManager().clearActivityResult();
    276     }
    277 
    278     @Override
    279     protected void installIntentFilter() {
    280         super.installIntentFilter();
    281         mCurrentModule.installIntentFilter();
    282     }
    283 
    284     @Override
    285     protected void onActivityResult(
    286             int requestCode, int resultCode, Intent data) {
    287         // Only PhotoPage understands ProxyLauncher.RESULT_USER_CANCELED
    288         if (resultCode == ProxyLauncher.RESULT_USER_CANCELED
    289                 && !(getStateManager().getTopState() instanceof PhotoPage)) {
    290             resultCode = RESULT_CANCELED;
    291         }
    292         super.onActivityResult(requestCode, resultCode, data);
    293         // Unmap cancel vs. reset
    294         if (resultCode == ProxyLauncher.RESULT_USER_CANCELED) {
    295             resultCode = RESULT_CANCELED;
    296         }
    297         mCurrentModule.onActivityResult(requestCode, resultCode, data);
    298     }
    299 
    300     // Preview area is touched. Handle touch focus.
    301     @Override
    302     protected void onSingleTapUp(View view, int x, int y) {
    303         mCurrentModule.onSingleTapUp(view, x, y);
    304     }
    305 
    306     @Override
    307     public void onBackPressed() {
    308         if (!mCurrentModule.onBackPressed()) {
    309             super.onBackPressed();
    310         }
    311     }
    312 
    313     @Override
    314     public boolean onKeyDown(int keyCode, KeyEvent event) {
    315         return mCurrentModule.onKeyDown(keyCode,  event)
    316                 || super.onKeyDown(keyCode, event);
    317     }
    318 
    319     @Override
    320     public boolean onKeyUp(int keyCode, KeyEvent event) {
    321         return mCurrentModule.onKeyUp(keyCode,  event)
    322                 || super.onKeyUp(keyCode, event);
    323     }
    324 
    325     public void cancelActivityTouchHandling() {
    326         if (mDown != null) {
    327             MotionEvent cancel = MotionEvent.obtain(mDown);
    328             cancel.setAction(MotionEvent.ACTION_CANCEL);
    329             super.dispatchTouchEvent(cancel);
    330         }
    331     }
    332 
    333     @Override
    334     public boolean dispatchTouchEvent(MotionEvent m) {
    335         if (m.getActionMasked() == MotionEvent.ACTION_DOWN) {
    336             mDown = m;
    337         }
    338         if ((mSwitcher != null) && mSwitcher.showsPopup() && !mSwitcher.isInsidePopup(m)) {
    339             return mSwitcher.onTouch(null, m);
    340         } else {
    341             return mShutterSwitcher.dispatchTouchEvent(m)
    342                     || mCurrentModule.dispatchTouchEvent(m);
    343         }
    344     }
    345 
    346     @Override
    347     public void startActivityForResult(Intent intent, int requestCode) {
    348         Intent proxyIntent = new Intent(this, ProxyLauncher.class);
    349         proxyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
    350         proxyIntent.putExtra(Intent.EXTRA_INTENT, intent);
    351         super.startActivityForResult(proxyIntent, requestCode);
    352     }
    353 
    354     public boolean superDispatchTouchEvent(MotionEvent m) {
    355         return super.dispatchTouchEvent(m);
    356     }
    357 
    358     // Preview texture has been copied. Now camera can be released and the
    359     // animation can be started.
    360     @Override
    361     public void onPreviewTextureCopied() {
    362         mCurrentModule.onPreviewTextureCopied();
    363     }
    364 
    365     @Override
    366     public void onCaptureTextureCopied() {
    367         mCurrentModule.onCaptureTextureCopied();
    368     }
    369 
    370     @Override
    371     public void onUserInteraction() {
    372         super.onUserInteraction();
    373         mCurrentModule.onUserInteraction();
    374     }
    375 
    376     @Override
    377     protected boolean updateStorageHintOnResume() {
    378         return mCurrentModule.updateStorageHintOnResume();
    379     }
    380 
    381     @Override
    382     public void updateCameraAppView() {
    383         super.updateCameraAppView();
    384         mCurrentModule.updateCameraAppView();
    385     }
    386 
    387     private boolean canReuseScreenNail() {
    388         return mCurrentModuleIndex == PHOTO_MODULE_INDEX
    389                 || mCurrentModuleIndex == VIDEO_MODULE_INDEX
    390                 || mCurrentModuleIndex == LIGHTCYCLE_MODULE_INDEX;
    391     }
    392 
    393     @Override
    394     public boolean isPanoramaActivity() {
    395         return (mCurrentModuleIndex == PANORAMA_MODULE_INDEX);
    396     }
    397 
    398     // Accessor methods for getting latency times used in performance testing
    399     public long getAutoFocusTime() {
    400         return (mCurrentModule instanceof PhotoModule) ?
    401                 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1;
    402     }
    403 
    404     public long getShutterLag() {
    405         return (mCurrentModule instanceof PhotoModule) ?
    406                 ((PhotoModule) mCurrentModule).mShutterLag : -1;
    407     }
    408 
    409     public long getShutterToPictureDisplayedTime() {
    410         return (mCurrentModule instanceof PhotoModule) ?
    411                 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1;
    412     }
    413 
    414     public long getPictureDisplayedToJpegCallbackTime() {
    415         return (mCurrentModule instanceof PhotoModule) ?
    416                 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1;
    417     }
    418 
    419     public long getJpegCallbackFinishTime() {
    420         return (mCurrentModule instanceof PhotoModule) ?
    421                 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1;
    422     }
    423 
    424     public long getCaptureStartTime() {
    425         return (mCurrentModule instanceof PhotoModule) ?
    426                 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1;
    427     }
    428 
    429     public boolean isRecording() {
    430         return (mCurrentModule instanceof VideoModule) ?
    431                 ((VideoModule) mCurrentModule).isRecording() : false;
    432     }
    433 
    434     public CameraScreenNail getCameraScreenNail() {
    435         return (CameraScreenNail) mCameraScreenNail;
    436     }
    437 }
    438