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