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