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