Merge "Import revised translations.  DO NOT MERGE" into ics-mr1
diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java
index 38a6d48..ea281a9 100644
--- a/src/com/android/camera/Storage.java
+++ b/src/com/android/camera/Storage.java
@@ -52,7 +52,7 @@
     public static Uri addImage(ContentResolver resolver, String title, long date,
                 Location location, int orientation, byte[] jpeg, int width, int height) {
         // Save the image.
-        String path = DIRECTORY + '/' + title + ".jpg";
+        String path = generateFilepath(title);
         FileOutputStream out = null;
         try {
             out = new FileOutputStream(path);
@@ -98,6 +98,10 @@
         return uri;
     }
 
+    public static String generateFilepath(String title) {
+        return DIRECTORY + '/' + title + ".jpg";
+    }
+
     public static long getAvailableSpace() {
         String state = Environment.getExternalStorageState();
         Log.d(TAG, "External storage state=" + state);
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index ba8a4f7..d6ebb0a 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -350,6 +350,12 @@
         return result;
     }
 
+    public static int getCameraOrientation(int cameraId) {
+        Camera.CameraInfo info = new Camera.CameraInfo();
+        Camera.getCameraInfo(cameraId, info);
+        return info.orientation;
+    }
+
     public static int roundOrientation(int orientation, int orientationHistory) {
         boolean changeOrientation = false;
         if (orientationHistory == OrientationEventListener.ORIENTATION_UNKNOWN) {
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
index 1e90544..80a9a4c 100755
--- a/src/com/android/camera/VideoCamera.java
+++ b/src/com/android/camera/VideoCamera.java
@@ -192,6 +192,7 @@
     private String mPrefVideoEffectDefault;
     private boolean mResetEffect = true;
     public static final String RESET_EFFECT_EXTRA = "reset_effect";
+    public static final String BACKGROUND_URI_GALLERY_EXTRA = "background_uri_gallery";
 
     private boolean mMediaRecorderRecording = false;
     private long mRecordingStartTime;
@@ -371,6 +372,9 @@
         // Do not reset the effect if users are switching between back and front
         // cameras.
         mResetEffect = getIntent().getBooleanExtra(RESET_EFFECT_EXTRA, true);
+        // If background replacement was on when the camera was switched, the
+        // background uri will be sent via the intent.
+        mEffectUriFromGallery = getIntent().getStringExtra(BACKGROUND_URI_GALLERY_EXTRA);
         resetEffect();
 
         /*
@@ -2112,14 +2116,19 @@
                 // Restart the activity to have a crossfade animation.
                 // TODO: Use SurfaceTexture to implement a better and faster
                 // animation.
+                Intent intent;
                 if (mIsVideoCaptureIntent) {
                     // If the intent is video capture, stay in video capture mode.
-                    Intent intent = getIntent();
-                    intent.putExtra(RESET_EFFECT_EXTRA, false);
-                    MenuHelper.gotoVideoMode(this, intent);
+                    intent = getIntent();
                 } else {
-                    MenuHelper.gotoVideoMode(this, false);
+                    intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
                 }
+                // To maintain the same background in background replacer, we
+                // need to send the background video uri via the Intent (apart
+                // from the condition that the effects should not be reset).
+                intent.putExtra(BACKGROUND_URI_GALLERY_EXTRA, mEffectUriFromGallery);
+                intent.putExtra(RESET_EFFECT_EXTRA, false);
+                MenuHelper.gotoVideoMode(this, intent);
                 finish();
             } else {
                 readVideoPreferences();
diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java
index e4c8d98..67f187b 100755
--- a/src/com/android/camera/panorama/PanoramaActivity.java
+++ b/src/com/android/camera/panorama/PanoramaActivity.java
@@ -52,6 +52,7 @@
 import android.hardware.Camera.Sound;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
+import android.media.ExifInterface;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -70,6 +71,7 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
 import java.util.List;
 
 /**
@@ -172,6 +174,8 @@
     // The value could be 0, 90, 180, 270 for the 4 different orientations measured in clockwise
     // respectively.
     private int mDeviceOrientation;
+    private int mDeviceOrientationAtCapture;
+    private int mCameraOrientation;
     private int mOrientationCompensation;
 
     private RotateDialogController mRotateDialog;
@@ -338,7 +342,9 @@
 
     private void openCamera() {
         try {
-            mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId());
+            int backCameraId = CameraHolder.instance().getBackCameraId();
+            mCameraDevice = Util.openCamera(this, backCameraId);
+            mCameraOrientation = Util.getCameraOrientation(backCameraId);
         } catch (CameraHardwareException e) {
             Util.showErrorAndFinish(this, R.string.cannot_connect_camera);
             return;
@@ -568,6 +574,7 @@
         mPanoProgressBar.setIndicatorWidth(20);
         mPanoProgressBar.setMaxProgress(DEFAULT_SWEEP_ANGLE);
         mPanoProgressBar.setVisibility(View.VISIBLE);
+        mDeviceOrientationAtCapture = mDeviceOrientation;
         keepScreenOn();
     }
 
@@ -799,7 +806,13 @@
                 } else if (!jpeg.isValid) {  // Error when generating mosaic.
                     mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR);
                 } else {
-                    int orientation = Exif.getOrientation(jpeg.data);
+                    // The panorama image returned from the library is orientated based on the
+                    // natural orientation of a camera. We need to set an orientation for the image
+                    // in its EXIF header, so the image can be displayed correctly.
+                    // The orientation is calculated from compensating the
+                    // device orientation at capture and the camera orientation respective to
+                    // the natural orientation of the device.
+                    int orientation = (mDeviceOrientationAtCapture + mCameraOrientation) % 360;
                     Uri uri = savePanorama(jpeg.data, jpeg.width, jpeg.height, orientation);
                     if (uri != null) {
                         // Create a thumbnail whose width or height is equal or bigger
@@ -812,6 +825,7 @@
                                 Math.max(widthRatio, heightRatio));
                         mThumbnail = Thumbnail.createThumbnail(
                                 jpeg.data, orientation, inSampleSize, uri);
+                        Util.broadcastNewPicture(PanoramaActivity.this, uri);
                     }
                     mMainHandler.sendMessage(
                             mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL));
@@ -889,14 +903,42 @@
 
     private Uri savePanorama(byte[] jpegData, int width, int height, int orientation) {
         if (jpegData != null) {
-            String imagePath = PanoUtil.createName(
+            String filename = PanoUtil.createName(
                     getResources().getString(R.string.pano_file_name_format), mTimeTaken);
-            return Storage.addImage(getContentResolver(), imagePath, mTimeTaken, null,
+            Uri uri = Storage.addImage(getContentResolver(), filename, mTimeTaken, null,
                     orientation, jpegData, width, height);
+            if (uri != null && orientation != 0) {
+                String filepath = Storage.generateFilepath(filename);
+                try {
+                    // Save the orientation in EXIF.
+                    ExifInterface exif = new ExifInterface(filepath);
+                    exif.setAttribute(ExifInterface.TAG_ORIENTATION,
+                            getExifOrientation(orientation));
+                    exif.saveAttributes();
+                } catch (IOException e) {
+                    Log.e(TAG, "cannot set exif data: " + filepath);
+                }
+            }
+            return uri;
         }
         return null;
     }
 
+    private static String getExifOrientation(int orientation) {
+        switch (orientation) {
+            case 0:
+                return String.valueOf(ExifInterface.ORIENTATION_NORMAL);
+            case 90:
+                return String.valueOf(ExifInterface.ORIENTATION_ROTATE_90);
+            case 180:
+                return String.valueOf(ExifInterface.ORIENTATION_ROTATE_180);
+            case 270:
+                return String.valueOf(ExifInterface.ORIENTATION_ROTATE_270);
+            default:
+                throw new AssertionError("invalid: " + orientation);
+        }
+    }
+
     private void clearMosaicFrameProcessorIfNeeded() {
         if (!mPausing || mThreadRunning) return;
         mMosaicFrameProcessor.clear();
diff --git a/src/com/android/camera/ui/IndicatorControlBar.java b/src/com/android/camera/ui/IndicatorControlBar.java
index 197c594..615a5ba 100644
--- a/src/com/android/camera/ui/IndicatorControlBar.java
+++ b/src/com/android/camera/ui/IndicatorControlBar.java
@@ -57,7 +57,9 @@
 
         // Add CameraPicker control.
         initializeCameraPicker();
-        mCameraPicker.setBackgroundResource(R.drawable.bg_pressed);
+        if (mCameraPicker != null) {
+            mCameraPicker.setBackgroundResource(R.drawable.bg_pressed);
+        }
 
         // Add the ZoomControl if supported.
         if (zoomSupported) {
diff --git a/src/com/android/camera/ui/IndicatorControlWheel.java b/src/com/android/camera/ui/IndicatorControlWheel.java
index 90d8ba8..0948346 100644
--- a/src/com/android/camera/ui/IndicatorControlWheel.java
+++ b/src/com/android/camera/ui/IndicatorControlWheel.java
@@ -204,32 +204,36 @@
         if (mInAnimation) return -1;
         int count = getChildCountByLevel(mCurrentLevel);
         if (count == 0) return -1;
-        int startIndex = 0;
         int sectors = count - 1;
+        int startIndex = (mCurrentLevel == 0) ? 0 : mSecondLevelStartIndex;
+        int endIndex;
+        if (mCurrentLevel == 0) {
+            // Skip the first component if it is zoom control, as we will
+            // deal with it specifically.
+            if (mZoomControl != null) startIndex++;
+            endIndex = mSecondLevelStartIndex - 1;
+        } else {
+            endIndex = getChildCount() - 1;
+        }
         // Check which indicator is touched.
-        if ((delta >= (mStartVisibleRadians[mCurrentLevel] - HIGHLIGHT_RADIANS / 2)) &&
-            (delta <= (mEndVisibleRadians[mCurrentLevel] + HIGHLIGHT_RADIANS / 2))) {
+        double halfTouchSectorRadians = mTouchSectorRadians[mCurrentLevel];
+        if ((delta >= (mChildRadians[startIndex] - halfTouchSectorRadians)) &&
+                (delta <= (mChildRadians[endIndex] + halfTouchSectorRadians))) {
             int index = 0;
-            if (mCurrentLevel == 0) {
-                // Skip the first component if it is zoom control, as we will
-                // deal with it specifically.
-                if (mZoomControl != null) startIndex++;
-            } else {
-                startIndex = mSecondLevelStartIndex;
-                index = (int) ((delta - mStartVisibleRadians[mCurrentLevel])
+            if (mCurrentLevel == 1) {
+                index = (int) ((delta - mChildRadians[startIndex])
                         / mSectorRadians[mCurrentLevel]);
                 // greater than the center of ending indicator
                 if (index > sectors) return (startIndex + sectors);
                 // less than the center of starting indicator
                 if (index < 0) return startIndex;
             }
-
             if (delta <= (mChildRadians[startIndex + index]
-                    + mTouchSectorRadians[mCurrentLevel] / 2)) {
+                    + halfTouchSectorRadians)) {
                 return (startIndex + index);
             }
             if (delta >= (mChildRadians[startIndex + index + 1]
-                    - mTouchSectorRadians[mCurrentLevel] / 2)) {
+                    - halfTouchSectorRadians)) {
                 return (startIndex + index + 1);
             }