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