OSDN Git Service

Reset aspect ratio on pause
[android-x86/packages-apps-Camera2.git] / src / com / android / camera / PhotoModule.java
index 8e642de..f0998a0 100644 (file)
@@ -29,9 +29,7 @@ import android.hardware.SensorEvent;
 import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.location.Location;
-import android.media.AudioManager;
 import android.media.CameraProfile;
-import android.media.SoundPool;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Build;
@@ -72,6 +70,7 @@ import com.android.camera.ui.TouchCoordinate;
 import com.android.camera.util.ApiHelper;
 import com.android.camera.util.CameraUtil;
 import com.android.camera.util.GcamHelper;
+import com.android.camera.util.GservicesHelper;
 import com.android.camera.util.SessionStatsCollector;
 import com.android.camera.util.UsageStatistics;
 import com.android.camera.widget.AspectRatioSelector;
@@ -81,6 +80,7 @@ import com.android.ex.camera2.portability.CameraAgent.CameraAFMoveCallback;
 import com.android.ex.camera2.portability.CameraAgent.CameraPictureCallback;
 import com.android.ex.camera2.portability.CameraAgent.CameraProxy;
 import com.android.ex.camera2.portability.CameraAgent.CameraShutterCallback;
+import com.android.ex.camera2.portability.CameraAgent.CameraStartPreviewCallback;
 import com.android.ex.camera2.portability.CameraCapabilities;
 import com.android.ex.camera2.portability.CameraDeviceInfo.Characteristics;
 import com.android.ex.camera2.portability.CameraSettings;
@@ -109,7 +109,7 @@ public class PhotoModule
         RemoteCameraModule,
         CountDownView.OnCountDownStatusListener {
 
-    private static final String PHOTO_MODULE_STRING_ID = "PhotoModule";
+    public static final String PHOTO_MODULE_STRING_ID = "PhotoModule";
 
     private static final Log.Tag TAG = new Log.Tag(PHOTO_MODULE_STRING_ID);
 
@@ -150,7 +150,7 @@ public class PhotoModule
     // needed to be updated in mUpdateSet.
     private int mUpdateSet;
 
-    private int mZoomValue; // The current zoom value.
+    private float mZoomValue; // The current zoom ratio.
     private int mTimerDuration;
     /** Set when a volume button is clicked to take photo */
     private boolean mVolumeButtonClickedFlag = false;
@@ -249,7 +249,7 @@ public class PhotoModule
     private FocusOverlayManager mFocusManager;
 
     private final int mGcamModeIndex;
-    private final CountdownSoundPlayer mCountdownSoundPlayer = new CountdownSoundPlayer();
+    private SoundPlayer mCountdownSoundPlayer;
 
     private CameraCapabilities.SceneMode mSceneMode;
 
@@ -387,13 +387,16 @@ public class PhotoModule
             // in the new module.  The new module will set the enabled/disabled
             // of this button when the module's preferred camera becomes available.
             ButtonManager buttonManager = mActivity.getButtonManager();
-            buttonManager.disableButton(ButtonManager.BUTTON_HDR_PLUS);
+
+            buttonManager.disableButtonClick(ButtonManager.BUTTON_HDR_PLUS);
 
             mAppController.getCameraAppUI().freezeScreenUntilPreviewReady();
 
             // Do not post this to avoid this module switch getting interleaved with
             // other button callbacks.
             mActivity.onModeSelected(mGcamModeIndex);
+
+            buttonManager.enableButtonClick(ButtonManager.BUTTON_HDR_PLUS);
         }
     }
 
@@ -447,6 +450,7 @@ public class PhotoModule
         mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false);
         mSensorManager = (SensorManager) (mActivity.getSystemService(Context.SENSOR_SERVICE));
         mUI.setCountdownFinishedListener(this);
+        mCountdownSoundPlayer = new SoundPlayer(mAppController.getAndroidContext());
 
         // TODO: Make this a part of app controller API.
         View cancelButton = mActivity.findViewById(R.id.shutter_cancel_button);
@@ -481,6 +485,7 @@ public class PhotoModule
 
     private void onPreviewStarted() {
         mAppController.onPreviewStarted();
+        mAppController.setShutterEnabled(true);
         setCameraState(IDLE);
         startFaceDetection();
         settingsFirstRun();
@@ -523,7 +528,14 @@ public class PhotoModule
             }, createAspectRatioDialogCallback());
         } else {
             // App upgrade. Only show aspect ratio selection.
-            mUI.showAspectRatioDialog(createAspectRatioDialogCallback());
+            boolean wasShown = mUI.showAspectRatioDialog(createAspectRatioDialogCallback());
+            if (!wasShown) {
+                // If the dialog was not shown, set this flag to true so that we
+                // never have to check for it again. It means that we don't need
+                // to show the dialog on this device.
+                mActivity.getSettingsManager().set(SettingsManager.SCOPE_GLOBAL,
+                        Keys.KEY_USER_SELECTED_ASPECT_RATIO, true);
+            }
         }
     }
 
@@ -650,8 +662,9 @@ public class PhotoModule
         Log.i(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
         closeCamera();
         mCameraId = mPendingSwitchCameraId;
+
         settingsManager.set(mAppController.getModuleScope(), Keys.KEY_CAMERA_ID, mCameraId);
-        mActivity.getCameraProvider().requestCamera(mCameraId);
+        requestCameraOpen();
         mUI.clearFaces();
         if (mFocusManager != null) {
             mFocusManager.removeMessages();
@@ -663,6 +676,16 @@ public class PhotoModule
         // onFrameAvailable from the old camera may already exist.
     }
 
+    /**
+     * Uses the {@link CameraProvider} to open the currently-selected camera
+     * device, using {@link GservicesHelper} to choose between API-1 and API-2.
+     */
+    private void requestCameraOpen() {
+        Log.v(TAG, "requestCameraOpen");
+        mActivity.getCameraProvider().requestCamera(mCameraId,
+                GservicesHelper.useCamera2ApiThroughPortabilityLayer(mActivity));
+    }
+
     private final ButtonManager.ButtonCallback mCameraCallback =
             new ButtonManager.ButtonCallback() {
                 @Override
@@ -701,7 +724,7 @@ public class PhotoModule
                 @Override
                 public void onStateChanged(int state) {
                     SettingsManager settingsManager = mActivity.getSettingsManager();
-                    if (GcamHelper.hasGcamCapture()) {
+                    if (GcamHelper.hasGcamAsSeparateModule()) {
                         // Set the camera setting to default backfacing.
                         settingsManager.setToDefault(mAppController.getModuleScope(),
                                                      Keys.KEY_CAMERA_ID);
@@ -750,7 +773,7 @@ public class PhotoModule
         // PhotoModule should hard reset HDR+ to off,
         // and HDR to off if HDR+ is supported.
         settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_HDR_PLUS, false);
-        if (GcamHelper.hasGcamCapture()) {
+        if (GcamHelper.hasGcamAsSeparateModule()) {
             settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_HDR, false);
         }
     }
@@ -978,6 +1001,18 @@ public class PhotoModule
         int xOffset = (originalWidth - newWidth)/2;
         int yOffset = (originalHeight - newHeight)/2;
 
+        // For some reason L needs this to work.
+        // This code is only run on the Nexus 5.
+        // TODO: Determine why this is needed.
+        if (Build.VERSION.SDK_INT >= 21 || Build.VERSION.CODENAME.equals("L")) {
+            Log.v(TAG,"xOffset = " + xOffset);
+            Log.v(TAG,"yOffset = " + yOffset);
+            xOffset *= 2;
+            yOffset = 0;
+            Log.v(TAG,"new xOffset = " + xOffset);
+            Log.v(TAG,"new yOffset = " + yOffset);
+        }
+
         if (xOffset < 0 || yOffset < 0) {
             return dataBundle;
         }
@@ -1071,15 +1106,10 @@ public class PhotoModule
 
             int orientation = Exif.getOrientation(exif);
 
-            float zoomValue = 0f;
+            float zoomValue = 1.0f;
             if (mCameraCapabilities.supports(CameraCapabilities.Feature.ZOOM)) {
-                int zoomIndex = mCameraSettings.getCurrentZoomIndex();
-                List<Integer> zoomRatios = mCameraCapabilities.getZoomRatioList();
-                if (zoomRatios != null && zoomIndex < zoomRatios.size()) {
-                    zoomValue = 0.01f * zoomRatios.get(zoomIndex);
-                }
+                zoomValue = mCameraSettings.getCurrentZoomRatio();
             }
-
             boolean hdrOn = CameraCapabilities.SceneMode.HDR == mSceneMode;
             String flashSetting =
                     mActivity.getSettingsManager().getString(mAppController.getCameraScope(),
@@ -1272,21 +1302,18 @@ public class PhotoModule
             animateAfterShutter();
         }
 
-        // Set rotation and gps data.
-        int orientation;
-
-        if (mActivity.isAutoRotateScreen()) {
-            orientation = mDisplayRotation;
-        } else {
-            orientation = mOrientation;
-        }
-        Characteristics info =
-                mActivity.getCameraProvider().getCharacteristics(mCameraId);
-        mJpegRotation = info.getJpegOrientation(orientation);
         Location loc = mActivity.getLocationManager().getCurrentLocation();
         CameraUtil.setGpsParameters(mCameraSettings, loc);
         mCameraDevice.applySettings(mCameraSettings);
 
+        // Set JPEG orientation. Even if screen UI is locked in portrait, camera orientation should
+        // still match device orientation (e.g., users should always get landscape photos while
+        // capturing by putting device in landscape.)
+        int orientation = mActivity.isAutoRotateScreen() ? mDisplayRotation : mOrientation;
+        Characteristics info = mActivity.getCameraProvider().getCharacteristics(mCameraId);
+        mJpegRotation = info.getJpegOrientation(orientation);
+        mCameraDevice.setJpegOrientation(mJpegRotation);
+
         // We don't want user to press the button again while taking a
         // multi-second HDR photo.
         mAppController.setShutterEnabled(false);
@@ -1328,17 +1355,19 @@ public class PhotoModule
 
     @Override
     public void onOrientationChanged(int orientation) {
-        // We keep the last known orientation. So if the user first orient
-        // the camera then point the camera to floor or sky, we still have
-        // the correct orientation.
         if (orientation == OrientationEventListener.ORIENTATION_UNKNOWN) {
             return;
         }
-        mOrientation = CameraUtil.roundOrientation(orientation, mOrientation);
+
+        // TODO: Document orientation compute logic and unify them in OrientationManagerImpl.
+        // b/17443789
+        // Flip to counter-clockwise orientation.
+        mOrientation = (360 - orientation) % 360;
     }
 
     @Override
     public void onCameraAvailable(CameraProxy cameraProxy) {
+        Log.v(TAG, "onCameraAvailable");
         if (mPaused) {
             return;
         }
@@ -1347,7 +1376,7 @@ public class PhotoModule
         initializeCapabilities();
 
         // Reset zoom value index.
-        mZoomValue = 0;
+        mZoomValue = 1.0f;
         if (mFocusManager == null) {
             initializeFocusManager();
         }
@@ -1403,9 +1432,11 @@ public class PhotoModule
                     outputStream.write(data);
                     outputStream.close();
 
+                    Log.v(TAG, "saved result to URI: " + mSaveUri);
                     mActivity.setResultEx(Activity.RESULT_OK);
                     mActivity.finish();
                 } catch (IOException ex) {
+                    Log.w(TAG, "exception saving result to URI: " + mSaveUri, ex);
                     // ignore exception
                 } finally {
                     CameraUtil.closeSilently(outputStream);
@@ -1415,6 +1446,7 @@ public class PhotoModule
                 int orientation = Exif.getOrientation(exif);
                 Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024);
                 bitmap = CameraUtil.rotate(bitmap, orientation);
+                Log.v(TAG, "inlined bitmap into capture intent result");
                 mActivity.setResultEx(Activity.RESULT_OK,
                         new Intent("inline-data").putExtra("data", bitmap));
                 mActivity.finish();
@@ -1430,11 +1462,14 @@ public class PhotoModule
                 tempStream.write(data);
                 tempStream.close();
                 tempUri = Uri.fromFile(path);
+                Log.v(TAG, "wrote temp file for cropping to: " + sTempCropFilename);
             } catch (FileNotFoundException ex) {
+                Log.w(TAG, "error writing temp cropping file to: " + sTempCropFilename, ex);
                 mActivity.setResultEx(Activity.RESULT_CANCELED);
                 mActivity.finish();
                 return;
             } catch (IOException ex) {
+                Log.w(TAG, "error writing temp cropping file to: " + sTempCropFilename, ex);
                 mActivity.setResultEx(Activity.RESULT_CANCELED);
                 mActivity.finish();
                 return;
@@ -1447,6 +1482,7 @@ public class PhotoModule
                 newExtras.putString("circleCrop", "true");
             }
             if (mSaveUri != null) {
+                Log.v(TAG, "setting output of cropped file to: " + mSaveUri);
                 newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri);
             } else {
                 newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true);
@@ -1461,7 +1497,7 @@ public class PhotoModule
 
             cropIntent.setData(tempUri);
             cropIntent.putExtras(newExtras);
-
+            Log.v(TAG, "starting CROP intent for capture");
             mActivity.startActivityForResult(cropIntent, REQUEST_CROP);
         }
     }
@@ -1530,7 +1566,11 @@ public class PhotoModule
 
     @Override
     public void onRemainingSecondsChanged(int remainingSeconds) {
-        mCountdownSoundPlayer.onRemainingSecondsChanged(remainingSeconds);
+        if (remainingSeconds == 1) {
+            mCountdownSoundPlayer.play(R.raw.beep_twice, 0.6f);
+        } else if (remainingSeconds == 2 || remainingSeconds == 3) {
+            mCountdownSoundPlayer.play(R.raw.beep_once, 0.6f);
+        }
     }
 
     @Override
@@ -1553,7 +1593,8 @@ public class PhotoModule
         }
         Log.v(TAG, "Executing onResumeTasks.");
 
-        mCountdownSoundPlayer.loadSounds();
+        mCountdownSoundPlayer.loadSound(R.raw.beep_once);
+        mCountdownSoundPlayer.loadSound(R.raw.beep_twice);
         if (mFocusManager != null) {
             // If camera is not open when resume is called, focus manager will
             // not be initialized yet, in which case it will start listening to
@@ -1567,10 +1608,10 @@ public class PhotoModule
             // No camera provider, the Activity is destroyed already.
             return;
         }
-        camProvider.requestCamera(mCameraId);
+        requestCameraOpen();
 
         mJpegPictureCallbackTime = 0;
-        mZoomValue = 0;
+        mZoomValue = 1.0f;
 
         mOnResumeTime = SystemClock.uptimeMillis();
         checkDisplayRotation();
@@ -1925,10 +1966,14 @@ public class PhotoModule
         mCameraDevice.setPreviewTexture(mActivity.getCameraAppUI().getSurfaceTexture());
 
         Log.i(TAG, "startPreview");
-        mCameraDevice.startPreview();
+        mCameraDevice.startPreviewWithCallback(mHandler, new CameraStartPreviewCallback() {
+                @Override
+                public void onPreviewStarted() {
+                    mFocusManager.onPreviewStarted();
+                    PhotoModule.this.onPreviewStarted();
+                }
+        });
 
-        mFocusManager.onPreviewStarted();
-        onPreviewStarted();
         SessionStatsCollector.instance().previewActive(true);
         if (mSnapshotOnIdle) {
             mHandler.post(mDoSnapRunnable);
@@ -1996,7 +2041,7 @@ public class PhotoModule
     private void updateCameraParametersZoom() {
         // Set zoom.
         if (mCameraCapabilities.supports(CameraCapabilities.Feature.ZOOM)) {
-            mCameraSettings.setZoomIndex(mZoomValue);
+            mCameraSettings.setZoomRatio(mZoomValue);
         }
     }
 
@@ -2091,6 +2136,7 @@ public class PhotoModule
                 (double) size.width() / size.height());
         Size original = mCameraSettings.getCurrentPreviewSize();
         if (!optimalSize.equals(original)) {
+            Log.v(TAG, "setting preview size");
             mCameraSettings.setPreviewSize(optimalSize);
 
             // Zoom related settings will be changed for different preview
@@ -2105,10 +2151,11 @@ public class PhotoModule
         }
 
         if (optimalSize.width() != 0 && optimalSize.height() != 0) {
+            Log.v(TAG, "updating aspect ratio");
             mUI.updatePreviewAspectRatio((float) optimalSize.width()
                     / (float) optimalSize.height());
         }
-        Log.i(TAG, "Preview size is " + optimalSize);
+        Log.d(TAG, "Preview size is " + optimalSize);
     }
 
     private void updateParametersPictureQuality() {
@@ -2286,25 +2333,19 @@ public class PhotoModule
                 mCameraCapabilities.supports(CameraCapabilities.FocusMode.CONTINUOUS_PICTURE);
     }
 
-    // TODO: Remove this
     @Override
-    public int onZoomChanged(int index) {
+    public void onZoomChanged(float ratio) {
         // Not useful to change zoom value when the activity is paused.
         if (mPaused) {
-            return index;
+            return;
         }
-        mZoomValue = index;
+        mZoomValue = ratio;
         if (mCameraSettings == null || mCameraDevice == null) {
-            return index;
+            return;
         }
         // Set zoom parameters asynchronously
         mCameraSettings.setZoomRatio(mZoomValue);
         mCameraDevice.applySettings(mCameraSettings);
-        CameraSettings settings = mCameraDevice.getSettings();
-        if (settings != null) {
-            return settings.getCurrentZoomIndex();
-        }
-        return index;
     }
 
     @Override
@@ -2380,42 +2421,4 @@ public class PhotoModule
             }
         });
     }
-
-    /**
-     * This class manages the loading/releasing/playing of the sounds needed for
-     * countdown timer.
-     */
-    private class CountdownSoundPlayer {
-        private SoundPool mSoundPool;
-        private int mBeepOnce;
-        private int mBeepTwice;
-
-        void loadSounds() {
-            // Load the beeps.
-            if (mSoundPool == null) {
-                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
-                mBeepOnce = mSoundPool.load(mAppController.getAndroidContext(), R.raw.beep_once, 1);
-                mBeepTwice = mSoundPool.load(mAppController.getAndroidContext(), R.raw.beep_twice, 1);
-            }
-        }
-
-        void onRemainingSecondsChanged(int newVal) {
-            if (mSoundPool == null) {
-                Log.e(TAG, "Cannot play sound - they have not been loaded.");
-                return;
-            }
-            if (newVal == 1) {
-                mSoundPool.play(mBeepTwice, 1.0f, 1.0f, 0, 0, 1.0f);
-            } else if (newVal == 2 || newVal == 3) {
-                mSoundPool.play(mBeepOnce, 1.0f, 1.0f, 0, 0, 1.0f);
-            }
-        }
-
-        void release() {
-            if (mSoundPool != null) {
-                mSoundPool.release();
-                mSoundPool = null;
-            }
-        }
-    }
 }