Merge "bugfix 5370554 camcorder preview background is inconsistent"
diff --git a/res/raw/backdropper.graph b/res/raw/backdropper.graph
index e3fe877..25c86e6 100644
--- a/res/raw/backdropper.graph
+++ b/res/raw/backdropper.graph
@@ -35,6 +35,8 @@
 @external previewWidth;
 @external previewHeight;
 
+@external orientation;
+
 @external learningDoneListener;
 
 // Filters ---------------------------------------------------
@@ -52,6 +54,7 @@
   sourceUrl = "no_file_specified";
   waitForNewFrame = false;
   sourceIsUrl = true;
+  orientation = $orientation;
 }
 
 // Background replacer
diff --git a/res/raw/goofy_face.graph b/res/raw/goofy_face.graph
index e346322..430c811 100644
--- a/res/raw/goofy_face.graph
+++ b/res/raw/goofy_face.graph
@@ -37,6 +37,10 @@
 @external previewWidth;
 @external previewHeight;
 
+// Not used by this graph, but simplifies higher-level
+// graph initialization code.
+@external orientation;
+
 // Filters ---------------------------------------------------
 
 // Camera input
diff --git a/res/xml/video_preferences.xml b/res/xml/video_preferences.xml
index 700c843..e158139 100644
--- a/res/xml/video_preferences.xml
+++ b/res/xml/video_preferences.xml
@@ -62,4 +62,12 @@
             camera:largeIcons="@array/video_effect_icons"
             camera:entries="@array/pref_video_effect_entries"
             camera:entryValues="@array/pref_video_effect_entryvalues" />
+    <RecordLocationPreference
+            camera:key="pref_camera_recordlocation_key"
+            camera:defaultValue="@string/pref_camera_recordlocation_default"
+            camera:title="@string/pref_camera_recordlocation_title"
+            camera:icons="@array/camera_recordlocation_icons"
+            camera:largeIcons="@array/camera_recordlocation_largeicons"
+            camera:entries="@array/pref_camera_recordlocation_entries"
+            camera:entryValues="@array/pref_camera_recordlocation_entryvalues" />
 </PreferenceGroup>
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index 10f0b80..74a1b37 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -941,12 +941,12 @@
         final String[] SETTING_KEYS = {
                 CameraSettings.KEY_FLASH_MODE,
                 CameraSettings.KEY_WHITE_BALANCE,
+                CameraSettings.KEY_EXPOSURE,
                 CameraSettings.KEY_SCENE_MODE};
         final String[] OTHER_SETTING_KEYS = {
                 CameraSettings.KEY_RECORD_LOCATION,
-                CameraSettings.KEY_FOCUS_MODE,
-                CameraSettings.KEY_EXPOSURE,
-                CameraSettings.KEY_PICTURE_SIZE};
+                CameraSettings.KEY_PICTURE_SIZE,
+                CameraSettings.KEY_FOCUS_MODE};
 
         CameraPicker.setImageResourceId(R.drawable.ic_switch_photo_facing_holo_light);
         mIndicatorControlContainer.initialize(this, mPreferenceGroup,
diff --git a/src/com/android/camera/EffectsRecorder.java b/src/com/android/camera/EffectsRecorder.java
index 301f2a2..f177387 100644
--- a/src/com/android/camera/EffectsRecorder.java
+++ b/src/com/android/camera/EffectsRecorder.java
@@ -300,7 +300,8 @@
             mGraphEnv.addReferences(
                     "previewSurface", mPreviewSurfaceHolder.getSurface(),
                     "previewWidth", mPreviewWidth,
-                    "previewHeight", mPreviewHeight);
+                    "previewHeight", mPreviewHeight,
+                    "orientation", mOrientationHint);
             if (mState == STATE_PREVIEW) {
                 // Switching effects while running. Inform video camera.
                 sendMessage(mCurrentEffect, EFFECT_MSG_SWITCHING_EFFECT);
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index c5bc79d..61a55dd 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -115,8 +115,8 @@
     public static Bitmap rotateAndMirror(Bitmap b, int degrees, boolean mirror) {
         if ((degrees != 0 || mirror) && b != null) {
             Matrix m = new Matrix();
-            m.setRotate(degrees,
-                    (float) b.getWidth() / 2, (float) b.getHeight() / 2);
+            // Mirror first.
+            // horizontal flip + rotation = -rotation + horizontal flip
             if (mirror) {
                 m.postScale(-1, 1);
                 degrees = (degrees + 360) % 360;
@@ -128,6 +128,11 @@
                     throw new IllegalArgumentException("Invalid degrees=" + degrees);
                 }
             }
+            if (degrees != 0) {
+                // clockwise
+                m.postRotate(degrees,
+                        (float) b.getWidth() / 2, (float) b.getHeight() / 2);
+            }
 
             try {
                 Bitmap b2 = Bitmap.createBitmap(
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
index 81ce3a9..b75fbed 100644
--- a/src/com/android/camera/VideoCamera.java
+++ b/src/com/android/camera/VideoCamera.java
@@ -235,7 +235,8 @@
     // The orientation compensation for icons and thumbnails. Ex: if the value
     // is 90, the UI components should be rotated 90 degrees counter-clockwise.
     private int mOrientationCompensation = 0;
-    private int mOrientationHint; // the orientation hint for video playback
+    // The orientation compenstaion when we start recording.
+    private int mOrientationCompensationAtRecordStart;
 
     private static final int ZOOM_STOPPED = 0;
     private static final int ZOOM_START = 1;
@@ -465,11 +466,12 @@
 
         final String[] SETTING_KEYS = {
                     CameraSettings.KEY_VIDEOCAMERA_FLASH_MODE,
-                    CameraSettings.KEY_VIDEO_EFFECT,
                     CameraSettings.KEY_WHITE_BALANCE,
+                    CameraSettings.KEY_VIDEO_EFFECT,
+                    CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL,
                     CameraSettings.KEY_VIDEO_QUALITY};
         final String[] OTHER_SETTING_KEYS = {
-                    CameraSettings.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL};
+                    CameraSettings.KEY_RECORD_LOCATION};
 
         CameraPicker.setImageResourceId(R.drawable.ic_switch_video_facing_holo_light);
         mIndicatorControlContainer.initialize(this, mPreferenceGroup,
@@ -511,7 +513,7 @@
                 mOrientationCompensation = orientationCompensation;
                 if (effectsActive()) {
                     CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
-                    int rotation = (info.orientation + mOrientation) % 360;;
+                    int rotation = (info.orientation + mOrientation) % 360;
                     mEffectsRecorder.setOrientationHint(rotation);
                 }
                 // Do not rotate the icons during recording because the video
@@ -1137,6 +1139,13 @@
             mMediaRecorder.setCaptureRate((1000 / (double) mTimeBetweenTimeLapseFrameCaptureMs));
         }
 
+        Location loc = mLocationManager.getCurrentLocation();
+        if (loc != null) {
+            mMediaRecorder.setLocation((float) loc.getLatitude(),
+                    (float) loc.getLongitude());
+        }
+
+
         // Set output file.
         // Try Uri in the intent first. If it doesn't exist, use our own
         // instead.
@@ -1169,6 +1178,9 @@
 
         // See android.hardware.Camera.Parameters.setRotation for
         // documentation.
+        // Note that mOrientation here is the device orientation, which is the opposite of
+        // what activity.getWindowManager().getDefaultDisplay().getRotation() would return,
+        // which is the orientation the graphics need to rotate in order to render correctly.
         int rotation = 0;
         if (mOrientation != OrientationEventListener.ORIENTATION_UNKNOWN) {
             CameraInfo info = CameraHolder.instance().getCameraInfo()[mCameraId];
@@ -1179,7 +1191,7 @@
             }
         }
         mMediaRecorder.setOrientationHint(rotation);
-        mOrientationHint = rotation;
+        mOrientationCompensationAtRecordStart = mOrientationCompensation;
 
         try {
             mMediaRecorder.prepare();
@@ -1214,7 +1226,7 @@
             rotation = (info.orientation + mOrientation) % 360;
         }
         mEffectsRecorder.setOrientationHint(rotation);
-        mOrientationHint = rotation;
+        mOrientationCompensationAtRecordStart = mOrientationCompensation;
 
         mEffectsRecorder.setPreviewDisplay(
                 mSurfaceHolder,
@@ -1546,13 +1558,11 @@
                     mPreviewFrameLayout.getWidth());
             if (bitmap != null) {
                 // MetadataRetriever already rotates the thumbnail. We should rotate
-                // it back (and mirror if it is front-facing camera).
+                // it to match the UI orientation (and mirror if it is front-facing camera).
                 CameraInfo[] info = CameraHolder.instance().getCameraInfo();
-                if (info[mCameraId].facing == CameraInfo.CAMERA_FACING_BACK) {
-                    bitmap = Util.rotateAndMirror(bitmap, -mOrientationHint, false);
-                } else {
-                    bitmap = Util.rotateAndMirror(bitmap, -mOrientationHint, true);
-                }
+                boolean mirror = (info[mCameraId].facing == CameraInfo.CAMERA_FACING_FRONT);
+                bitmap = Util.rotateAndMirror(bitmap, -mOrientationCompensationAtRecordStart,
+                        mirror);
                 mReviewImage.setImageBitmap(bitmap);
                 mReviewImage.setVisibility(View.VISIBLE);
             }
diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java
index a1605de..09df1e0 100755
--- a/src/com/android/camera/panorama/PanoramaActivity.java
+++ b/src/com/android/camera/panorama/PanoramaActivity.java
@@ -38,6 +38,7 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.ProgressDialog;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.Resources;
@@ -71,6 +72,7 @@
 import android.widget.TextView;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.util.List;
 
 /**
@@ -147,9 +149,6 @@
     private Thumbnail mThumbnail;
     private SharePopup mSharePopup;
 
-    private AnimatorSet mThumbnailViewAndModePickerOut;
-    private AnimatorSet mThumbnailViewAndModePickerIn;
-
     private int mPreviewWidth;
     private int mPreviewHeight;
     private Camera mCameraDevice;
@@ -271,9 +270,8 @@
                         onBackgroundThreadFinished();
                         // Set the thumbnail bitmap here because mThumbnailView must be accessed
                         // from the UI thread.
-                        if (mThumbnail != null) {
-                            mThumbnailView.setBitmap(mThumbnail.getBitmap());
-                        }
+                        updateThumbnailButton();
+
                         // Share popup may still have the reference to the old thumbnail. Clear it.
                         mSharePopup = null;
                         resetToPreview();
@@ -309,6 +307,12 @@
                 });
     }
 
+    @Override
+    public void onStart() {
+        super.onStart();
+        updateThumbnailButton();
+    }
+
     private void setupCamera() {
         openCamera();
         Parameters parameters = mCameraDevice.getParameters();
@@ -526,30 +530,6 @@
         mCaptureIndicator.setVisibility(View.VISIBLE);
         showDirectionIndicators(PanoProgressBar.DIRECTION_NONE);
 
-        // XML-style animations can not be used here. The Y position has to be calculated runtime.
-        float ystart = mThumbnailView.getY();
-        ValueAnimator va1 = ObjectAnimator.ofFloat(
-                mThumbnailView, "y", ystart, -mThumbnailView.getHeight());
-        ValueAnimator va1Reverse = ObjectAnimator.ofFloat(
-                mThumbnailView, "y", -mThumbnailView.getHeight(), ystart);
-        ystart = mModePicker.getY();
-        float height = mCaptureLayout.getHeight();
-        ValueAnimator va2 = ObjectAnimator.ofFloat(
-                mModePicker, "y", ystart, height + 1);
-        ValueAnimator va2Reverse = ObjectAnimator.ofFloat(
-                mModePicker, "y", height + 1, ystart);
-        LinearInterpolator li = new LinearInterpolator();
-        mThumbnailViewAndModePickerOut = new AnimatorSet();
-        mThumbnailViewAndModePickerOut.play(va1).with(va2);
-        mThumbnailViewAndModePickerOut.setDuration(500);
-        mThumbnailViewAndModePickerOut.setInterpolator(li);
-        mThumbnailViewAndModePickerIn = new AnimatorSet();
-        mThumbnailViewAndModePickerIn.play(va1Reverse).with(va2Reverse);
-        mThumbnailViewAndModePickerIn.setDuration(500);
-        mThumbnailViewAndModePickerIn.setInterpolator(li);
-
-        mThumbnailViewAndModePickerOut.start();
-
         mCompassValueXStart = mCompassValueXStartBuffer;
         mCompassValueYStart = mCompassValueYStartBuffer;
         mMinAngleX = 0;
@@ -571,6 +551,8 @@
             }
         });
 
+        if (mModePicker != null) mModePicker.setEnabled(false);
+
         mPanoProgressBar.reset();
         // TODO: calculate the indicator width according to different devices to reflect the actual
         // angle of view of the camera device.
@@ -609,7 +591,8 @@
                 }
             });
         }
-        mThumbnailViewAndModePickerIn.start();
+        // do we have to wait for the thread to complete before enabling this?
+        if (mModePicker != null) mModePicker.setEnabled(true);
     }
 
     private void showTooFastIndication() {
@@ -749,6 +732,19 @@
         t.start();
     }
 
+    private void updateThumbnailButton() {
+        // Update last image if URI is invalid and the storage is ready.
+        ContentResolver contentResolver = getContentResolver();
+        if ((mThumbnail == null || !Util.isUriValid(mThumbnail.getUri(), contentResolver))) {
+            mThumbnail = Thumbnail.getLastThumbnail(contentResolver);
+        }
+        if (mThumbnail != null) {
+            mThumbnailView.setBitmap(mThumbnail.getBitmap());
+        } else {
+            mThumbnailView.setBitmap(null);
+        }
+    }
+
     public void saveHighResMosaic() {
         runBackgroundThread(new Thread() {
             @Override
@@ -884,6 +880,7 @@
             stopCapture(true);
             reset();
         }
+        if (mSharePopup != null) mSharePopup.dismiss();
         releaseCamera();
         mMosaicView.onPause();
         clearMosaicFrameProcessorIfNeeded();
diff --git a/src/com/android/camera/ui/SecondLevelIndicatorControlBar.java b/src/com/android/camera/ui/SecondLevelIndicatorControlBar.java
index f3e5247..8fce8a7 100644
--- a/src/com/android/camera/ui/SecondLevelIndicatorControlBar.java
+++ b/src/com/android/camera/ui/SecondLevelIndicatorControlBar.java
@@ -34,7 +34,7 @@
 public class SecondLevelIndicatorControlBar extends IndicatorControl implements
         View.OnClickListener, AbstractIndicatorButton.IndicatorChangeListener {
     private static final String TAG = "SecondLevelIndicatorControlBar";
-    private static int ICON_SPACING = Util.dpToPixel(24);
+    private static int ICON_SPACING = Util.dpToPixel(16);
     private ImageView mCloseIcon;
     private View mDivider; // the divider line
     private View mIndicatorHighlight; // the side highlight bar