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