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