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