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