OSDN Git Service

24c49ba8ae9447916337edb785f9bf22c6bda5a9
[android-x86/packages-apps-Gallery2.git] / src / com / android / camera / CameraActivity.java
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
17 package com.android.camera;
18
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ObjectAnimator;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.ServiceConnection;
26 import android.content.pm.ActivityInfo;
27 import android.content.res.Configuration;
28 import android.graphics.drawable.Drawable;
29 import android.os.Bundle;
30 import android.os.IBinder;
31 import android.provider.MediaStore;
32 import android.provider.Settings;
33 import android.view.KeyEvent;
34 import android.view.LayoutInflater;
35 import android.view.MotionEvent;
36 import android.view.OrientationEventListener;
37 import android.view.View;
38 import android.view.ViewGroup;
39 import android.view.Window;
40 import android.view.WindowManager;
41 import android.widget.FrameLayout;
42
43 import com.android.camera.ui.CameraSwitcher;
44 import com.android.camera.ui.RotatableLayout;
45 import com.android.gallery3d.R;
46 import com.android.gallery3d.app.PhotoPage;
47 import com.android.gallery3d.common.ApiHelper;
48 import com.android.gallery3d.util.LightCycleHelper;
49
50 public class CameraActivity extends ActivityBase
51         implements CameraSwitcher.CameraSwitchListener {
52     public static final int PHOTO_MODULE_INDEX = 0;
53     public static final int VIDEO_MODULE_INDEX = 1;
54     public static final int PANORAMA_MODULE_INDEX = 2;
55     public static final int LIGHTCYCLE_MODULE_INDEX = 3;
56
57     CameraModule mCurrentModule;
58     private FrameLayout mFrame;
59     private ShutterButton mShutter;
60     private CameraSwitcher mSwitcher;
61     private View mCameraControls;
62     private View mControlsBackground;
63     private View mPieMenuButton;
64     private Drawable[] mDrawables;
65     private int mCurrentModuleIndex;
66     private MotionEvent mDown;
67     private boolean mAutoRotateScreen;
68     private int mHeightOrWidth = -1;
69
70     private MyOrientationEventListener mOrientationListener;
71     // The degrees of the device rotated clockwise from its natural orientation.
72     private int mLastRawOrientation = OrientationEventListener.ORIENTATION_UNKNOWN;
73
74     private MediaSaveService mMediaSaveService;
75     private ServiceConnection mConnection = new ServiceConnection() {
76             @Override
77             public void onServiceConnected(ComponentName className, IBinder b) {
78                 mMediaSaveService = ((MediaSaveService.LocalBinder) b).getService();
79                 mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService);
80             }
81             @Override
82             public void onServiceDisconnected(ComponentName className) {
83                 mMediaSaveService = null;
84             }};
85
86     private static final String TAG = "CAM_activity";
87
88     private static final int[] DRAW_IDS = {
89             R.drawable.ic_switch_camera,
90             R.drawable.ic_switch_video,
91             R.drawable.ic_switch_pan,
92             R.drawable.ic_switch_photosphere
93     };
94
95     @Override
96     public void onCreate(Bundle state) {
97         super.onCreate(state);
98         setContentView(R.layout.camera_main);
99         mFrame = (FrameLayout) findViewById(R.id.camera_app_root);
100         mDrawables = new Drawable[DRAW_IDS.length];
101         for (int i = 0; i < DRAW_IDS.length; i++) {
102             mDrawables[i] = getResources().getDrawable(DRAW_IDS[i]);
103         }
104         init();
105         if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())
106                 || MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
107             mCurrentModule = new VideoModule();
108             mCurrentModuleIndex = VIDEO_MODULE_INDEX;
109         } else {
110             mCurrentModule = new PhotoModule();
111             mCurrentModuleIndex = PHOTO_MODULE_INDEX;
112         }
113         mCurrentModule.init(this, mFrame, true);
114         mSwitcher.setCurrentIndex(mCurrentModuleIndex);
115         mOrientationListener = new MyOrientationEventListener(this);
116         bindMediaSaveService();
117     }
118
119     public void init() {
120         boolean landscape = Util.getDisplayRotation(this) % 180 == 90;
121         setMargins(landscape);
122         mControlsBackground = findViewById(R.id.blocker);
123         mCameraControls = findViewById(R.id.camera_controls);
124         mShutter = (ShutterButton) findViewById(R.id.shutter_button);
125         mSwitcher = (CameraSwitcher) findViewById(R.id.camera_switcher);
126         mPieMenuButton = findViewById(R.id.menu);
127         int totaldrawid = (LightCycleHelper.hasLightCycleCapture(this)
128                                 ? DRAW_IDS.length : DRAW_IDS.length - 1);
129         if (!ApiHelper.HAS_OLD_PANORAMA) totaldrawid--;
130
131         int[] drawids = new int[totaldrawid];
132         int[] moduleids = new int[totaldrawid];
133         int ix = 0;
134         for (int i = 0; i < mDrawables.length; i++) {
135             if (i == PANORAMA_MODULE_INDEX && !ApiHelper.HAS_OLD_PANORAMA) {
136                 continue; // not enabled, so don't add to UI
137             }
138             if (i == LIGHTCYCLE_MODULE_INDEX && !LightCycleHelper.hasLightCycleCapture(this)) {
139                 continue; // not enabled, so don't add to UI
140             }
141             moduleids[ix] = i;
142             drawids[ix++] = DRAW_IDS[i];
143         }
144         mSwitcher.setIds(moduleids, drawids);
145         mSwitcher.setSwitchListener(this);
146         mSwitcher.setCurrentIndex(mCurrentModuleIndex);
147     }
148
149     @Override
150     public void onDestroy() {
151         unbindMediaSaveService();
152         super.onDestroy();
153     }
154
155     // Return whether the auto-rotate screen in system settings
156     // is turned on.
157     public boolean isAutoRotateScreen() {
158         return mAutoRotateScreen;
159     }
160
161     private class MyOrientationEventListener
162             extends OrientationEventListener {
163         public MyOrientationEventListener(Context context) {
164             super(context);
165         }
166
167         @Override
168         public void onOrientationChanged(int orientation) {
169             // We keep the last known orientation. So if the user first orient
170             // the camera then point the camera to floor or sky, we still have
171             // the correct orientation.
172             if (orientation == ORIENTATION_UNKNOWN) return;
173             mLastRawOrientation = orientation;
174             mCurrentModule.onOrientationChanged(orientation);
175         }
176     }
177
178     private ObjectAnimator mCameraSwitchAnimator;
179
180     @Override
181     public void onCameraSelected(final int i) {
182         if (mPaused) return;
183         if (i != mCurrentModuleIndex) {
184             mPaused = true;
185             CameraScreenNail screenNail = getCameraScreenNail();
186             if (screenNail != null) {
187                 if (mCameraSwitchAnimator != null && mCameraSwitchAnimator.isRunning()) {
188                     mCameraSwitchAnimator.cancel();
189                 }
190                 mCameraSwitchAnimator = ObjectAnimator.ofFloat(
191                         screenNail, "alpha", screenNail.getAlpha(), 0f);
192                 mCameraSwitchAnimator.addListener(new AnimatorListenerAdapter() {
193                     @Override
194                     public void onAnimationEnd(Animator animation) {
195                         super.onAnimationEnd(animation);
196                         doChangeCamera(i);
197                     }
198                 });
199                 mCameraSwitchAnimator.start();
200             } else {
201                 doChangeCamera(i);
202             }
203         }
204     }
205
206     private void doChangeCamera(int i) {
207         boolean canReuse = canReuseScreenNail();
208         CameraHolder.instance().keep();
209         closeModule(mCurrentModule);
210         mCurrentModuleIndex = i;
211         switch (i) {
212             case VIDEO_MODULE_INDEX:
213                 mCurrentModule = new VideoModule();
214                 break;
215             case PHOTO_MODULE_INDEX:
216                 mCurrentModule = new PhotoModule();
217                 break;
218             case PANORAMA_MODULE_INDEX:
219                 mCurrentModule = new PanoramaModule();
220                 break;
221             case LIGHTCYCLE_MODULE_INDEX:
222                 mCurrentModule = LightCycleHelper.createPanoramaModule();
223                 break;
224         }
225         showPieMenuButton(mCurrentModule.needsPieMenu());
226
227         openModule(mCurrentModule, canReuse);
228         mCurrentModule.onOrientationChanged(mLastRawOrientation);
229         if (mMediaSaveService != null) {
230             mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService);
231         }
232         getCameraScreenNail().setAlpha(0f);
233         getCameraScreenNail().setOnFrameDrawnOneShot(mOnFrameDrawn);
234     }
235
236     public void showPieMenuButton(boolean show) {
237         if (show) {
238             findViewById(R.id.blocker).setVisibility(View.VISIBLE);
239             findViewById(R.id.menu).setVisibility(View.VISIBLE);
240             findViewById(R.id.on_screen_indicators).setVisibility(View.VISIBLE);
241         } else {
242             findViewById(R.id.blocker).setVisibility(View.INVISIBLE);
243             findViewById(R.id.menu).setVisibility(View.INVISIBLE);
244             findViewById(R.id.on_screen_indicators).setVisibility(View.INVISIBLE);
245         }
246     }
247
248     private Runnable mOnFrameDrawn = new Runnable() {
249
250         @Override
251         public void run() {
252             runOnUiThread(mFadeInCameraScreenNail);
253         }
254     };
255
256     private Runnable mFadeInCameraScreenNail = new Runnable() {
257
258         @Override
259         public void run() {
260             mCameraSwitchAnimator = ObjectAnimator.ofFloat(
261                     getCameraScreenNail(), "alpha", 0f, 1f);
262             mCameraSwitchAnimator.setStartDelay(50);
263             mCameraSwitchAnimator.start();
264         }
265     };
266
267     @Override
268     public void onShowSwitcherPopup() {
269         mCurrentModule.onShowSwitcherPopup();
270     }
271
272     private void openModule(CameraModule module, boolean canReuse) {
273         module.init(this, mFrame, canReuse && canReuseScreenNail());
274         mPaused = false;
275         module.onResumeBeforeSuper();
276         module.onResumeAfterSuper();
277     }
278
279     private void closeModule(CameraModule module) {
280         module.onPauseBeforeSuper();
281         module.onPauseAfterSuper();
282         mFrame.removeAllViews();
283     }
284
285     public ShutterButton getShutterButton() {
286         return mShutter;
287     }
288
289     public void hideUI() {
290         mCameraControls.setVisibility(View.INVISIBLE);
291         hideSwitcher();
292         mShutter.setVisibility(View.GONE);
293     }
294
295     public void showUI() {
296         mCameraControls.setVisibility(View.VISIBLE);
297         showSwitcher();
298         mShutter.setVisibility(View.VISIBLE);
299         // Force a layout change to show shutter button
300         mShutter.requestLayout();
301     }
302
303     public void hideSwitcher() {
304         mSwitcher.closePopup();
305         mSwitcher.setVisibility(View.INVISIBLE);
306     }
307
308     public void showSwitcher() {
309         if (mCurrentModule.needsSwitcher()) {
310             mSwitcher.setVisibility(View.VISIBLE);
311         }
312     }
313
314     public boolean isInCameraApp() {
315         return mShowCameraAppView;
316     }
317
318     @Override
319     public void onConfigurationChanged(Configuration config) {
320         super.onConfigurationChanged(config);
321         boolean landscape = (config.orientation == Configuration.ORIENTATION_LANDSCAPE);
322         setMargins(landscape);
323         mCurrentModule.onConfigurationChanged(config);
324     }
325
326     private void setMargins(boolean landscape) {
327         ViewGroup appRoot = (ViewGroup) findViewById(R.id.content);
328         FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) appRoot.getLayoutParams();
329         int navBarWidth = getResources().getDimensionPixelSize(R.dimen.navigation_bar_width);
330         int navBarHeight = getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
331         if (landscape) {
332             lp.setMargins(navBarHeight, 0, navBarHeight - navBarWidth, 0);
333         } else {
334             lp.setMargins(0, navBarHeight, 0, 0);
335         }
336         appRoot.setLayoutParams(lp);
337     }
338
339     @Override
340     public void onPause() {
341         mPaused = true;
342         mOrientationListener.disable();
343         mCurrentModule.onPauseBeforeSuper();
344         super.onPause();
345         mCurrentModule.onPauseAfterSuper();
346     }
347
348     @Override
349     public void onResume() {
350         mPaused = false;
351         if (Settings.System.getInt(getContentResolver(),
352                 Settings.System.ACCELEROMETER_ROTATION, 0) == 0) {// auto-rotate off
353             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
354             mAutoRotateScreen = false;
355         } else {
356             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
357             mAutoRotateScreen = true;
358         }
359         mOrientationListener.enable();
360         mCurrentModule.onResumeBeforeSuper();
361         super.onResume();
362         mCurrentModule.onResumeAfterSuper();
363     }
364
365     private void bindMediaSaveService() {
366         Intent intent = new Intent(this, MediaSaveService.class);
367         startService(intent);  // start service before binding it so the
368                                // service won't be killed if we unbind it.
369         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
370     }
371
372     private void unbindMediaSaveService() {
373         mMediaSaveService.setListener(null);
374         unbindService(mConnection);
375     }
376
377     @Override
378     protected void onFullScreenChanged(boolean full) {
379         if (full) {
380             showUI();
381         } else {
382             hideUI();
383         }
384         super.onFullScreenChanged(full);
385         if (ApiHelper.HAS_ROTATION_ANIMATION) {
386             setRotationAnimation(full);
387         }
388         mCurrentModule.onFullScreenChanged(full);
389     }
390
391     private void setRotationAnimation(boolean fullscreen) {
392         int rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
393         if (fullscreen) {
394             rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
395         }
396         Window win = getWindow();
397         WindowManager.LayoutParams winParams = win.getAttributes();
398         winParams.rotationAnimation = rotationAnimation;
399         win.setAttributes(winParams);
400     }
401
402     @Override
403     protected void onStop() {
404         super.onStop();
405         mCurrentModule.onStop();
406         getStateManager().clearTasks();
407     }
408
409     @Override
410     protected void onNewIntent(Intent intent) {
411         super.onNewIntent(intent);
412         getStateManager().clearActivityResult();
413     }
414
415     @Override
416     protected void installIntentFilter() {
417         super.installIntentFilter();
418         mCurrentModule.installIntentFilter();
419     }
420
421     @Override
422     protected void onActivityResult(
423             int requestCode, int resultCode, Intent data) {
424         // Only PhotoPage understands ProxyLauncher.RESULT_USER_CANCELED
425         if (resultCode == ProxyLauncher.RESULT_USER_CANCELED
426                 && !(getStateManager().getTopState() instanceof PhotoPage)) {
427             resultCode = RESULT_CANCELED;
428         }
429         super.onActivityResult(requestCode, resultCode, data);
430         // Unmap cancel vs. reset
431         if (resultCode == ProxyLauncher.RESULT_USER_CANCELED) {
432             resultCode = RESULT_CANCELED;
433         }
434         mCurrentModule.onActivityResult(requestCode, resultCode, data);
435     }
436
437     // Preview area is touched. Handle touch focus.
438     @Override
439     protected void onSingleTapUp(View view, int x, int y) {
440         mCurrentModule.onSingleTapUp(view, x, y);
441     }
442
443     @Override
444     public void onBackPressed() {
445         if (!mCurrentModule.onBackPressed()) {
446             super.onBackPressed();
447         }
448     }
449
450     @Override
451     public boolean onKeyDown(int keyCode, KeyEvent event) {
452         return mCurrentModule.onKeyDown(keyCode,  event)
453                 || super.onKeyDown(keyCode, event);
454     }
455
456     @Override
457     public boolean onKeyUp(int keyCode, KeyEvent event) {
458         return mCurrentModule.onKeyUp(keyCode,  event)
459                 || super.onKeyUp(keyCode, event);
460     }
461
462     public void cancelActivityTouchHandling() {
463         if (mDown != null) {
464             MotionEvent cancel = MotionEvent.obtain(mDown);
465             cancel.setAction(MotionEvent.ACTION_CANCEL);
466             super.dispatchTouchEvent(cancel);
467         }
468     }
469
470     @Override
471     public boolean dispatchTouchEvent(MotionEvent m) {
472         if (m.getActionMasked() == MotionEvent.ACTION_DOWN) {
473             mDown = m;
474         }
475         if ((mSwitcher != null) && mSwitcher.showsPopup() && !mSwitcher.isInsidePopup(m)) {
476             return mSwitcher.onTouch(null, m);
477         } else if ((mSwitcher != null) && mSwitcher.isInsidePopup(m)) {
478             return superDispatchTouchEvent(m);
479         } else {
480             return mCurrentModule.dispatchTouchEvent(m);
481         }
482     }
483
484     @Override
485     public void startActivityForResult(Intent intent, int requestCode) {
486         Intent proxyIntent = new Intent(this, ProxyLauncher.class);
487         proxyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
488         proxyIntent.putExtra(Intent.EXTRA_INTENT, intent);
489         super.startActivityForResult(proxyIntent, requestCode);
490     }
491
492     public boolean superDispatchTouchEvent(MotionEvent m) {
493         return super.dispatchTouchEvent(m);
494     }
495
496     // Preview texture has been copied. Now camera can be released and the
497     // animation can be started.
498     @Override
499     public void onPreviewTextureCopied() {
500         mCurrentModule.onPreviewTextureCopied();
501     }
502
503     @Override
504     public void onCaptureTextureCopied() {
505         mCurrentModule.onCaptureTextureCopied();
506     }
507
508     @Override
509     public void onUserInteraction() {
510         super.onUserInteraction();
511         mCurrentModule.onUserInteraction();
512     }
513
514     @Override
515     protected boolean updateStorageHintOnResume() {
516         return mCurrentModule.updateStorageHintOnResume();
517     }
518
519     @Override
520     public void updateCameraAppView() {
521         super.updateCameraAppView();
522         mCurrentModule.updateCameraAppView();
523     }
524
525     private boolean canReuseScreenNail() {
526         return mCurrentModuleIndex == PHOTO_MODULE_INDEX
527                 || mCurrentModuleIndex == VIDEO_MODULE_INDEX
528                 || mCurrentModuleIndex == LIGHTCYCLE_MODULE_INDEX;
529     }
530
531     @Override
532     public boolean isPanoramaActivity() {
533         return (mCurrentModuleIndex == PANORAMA_MODULE_INDEX);
534     }
535
536     // Accessor methods for getting latency times used in performance testing
537     public long getAutoFocusTime() {
538         return (mCurrentModule instanceof PhotoModule) ?
539                 ((PhotoModule) mCurrentModule).mAutoFocusTime : -1;
540     }
541
542     public long getShutterLag() {
543         return (mCurrentModule instanceof PhotoModule) ?
544                 ((PhotoModule) mCurrentModule).mShutterLag : -1;
545     }
546
547     public long getShutterToPictureDisplayedTime() {
548         return (mCurrentModule instanceof PhotoModule) ?
549                 ((PhotoModule) mCurrentModule).mShutterToPictureDisplayedTime : -1;
550     }
551
552     public long getPictureDisplayedToJpegCallbackTime() {
553         return (mCurrentModule instanceof PhotoModule) ?
554                 ((PhotoModule) mCurrentModule).mPictureDisplayedToJpegCallbackTime : -1;
555     }
556
557     public long getJpegCallbackFinishTime() {
558         return (mCurrentModule instanceof PhotoModule) ?
559                 ((PhotoModule) mCurrentModule).mJpegCallbackFinishTime : -1;
560     }
561
562     public long getCaptureStartTime() {
563         return (mCurrentModule instanceof PhotoModule) ?
564                 ((PhotoModule) mCurrentModule).mCaptureStartTime : -1;
565     }
566
567     public boolean isRecording() {
568         return (mCurrentModule instanceof VideoModule) ?
569                 ((VideoModule) mCurrentModule).isRecording() : false;
570     }
571
572     public CameraScreenNail getCameraScreenNail() {
573         return (CameraScreenNail) mCameraScreenNail;
574     }
575
576     public MediaSaveService getMediaSaveService() {
577         return mMediaSaveService;
578     }
579 }