Merge "Catch potential RTE from Camera." into ub-camera-everglades
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 8932a55..8d9d062 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -352,6 +352,5 @@
     <string name="setting_summary_x_megapixels" msgid="6533463462760866830">"%1$s megapikseliä"</string>
     <string name="cling_text_for_refocus_editor_button" msgid="86205552045250053">"Muokkaa linssin sumennusta käytt. kuvaa klikkaamalla tätä."</string>
     <string name="pref_category_advanced" msgid="5921085080077574872">"Lisäasetukset"</string>
-    <!-- no translation found for pref_camera_exposure_compensation (4143245817259719147) -->
-    <skip />
+    <string name="pref_camera_exposure_compensation" msgid="4143245817259719147">"Manuaalinen valotus"</string>
 </resources>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index 2a804a4..0cef96c 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -352,6 +352,5 @@
     <string name="setting_summary_x_megapixels" msgid="6533463462760866830">"%1$s მეგაპიქსელი"</string>
     <string name="cling_text_for_refocus_editor_button" msgid="86205552045250053">"დააწკაპუნეთ აქ დაბინდული ობიექტივის სურათის შესაცვლელად."</string>
     <string name="pref_category_advanced" msgid="5921085080077574872">"გაფართოებული"</string>
-    <!-- no translation found for pref_camera_exposure_compensation (4143245817259719147) -->
-    <skip />
+    <string name="pref_camera_exposure_compensation" msgid="4143245817259719147">"ექსპოზიცია ხელით"</string>
 </resources>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index e890b91..165d8bd 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -352,6 +352,5 @@
     <string name="setting_summary_x_megapixels" msgid="6533463462760866830">"%1$s megapiksel"</string>
     <string name="cling_text_for_refocus_editor_button" msgid="86205552045250053">"Klik di sini untuk mengedit imej kabur lensa."</string>
     <string name="pref_category_advanced" msgid="5921085080077574872">"Lanjutan"</string>
-    <!-- no translation found for pref_camera_exposure_compensation (4143245817259719147) -->
-    <skip />
+    <string name="pref_camera_exposure_compensation" msgid="4143245817259719147">"Dedahan manual"</string>
 </resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 9642736..d9645b6 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -352,6 +352,5 @@
     <string name="setting_summary_x_megapixels" msgid="6533463462760866830">"%1$s megapixeli"</string>
     <string name="cling_text_for_refocus_editor_button" msgid="86205552045250053">"Dați clic aici pentru a edita imaginea cu fundal încețoșat."</string>
     <string name="pref_category_advanced" msgid="5921085080077574872">"Avansat"</string>
-    <!-- no translation found for pref_camera_exposure_compensation (4143245817259719147) -->
-    <skip />
+    <string name="pref_camera_exposure_compensation" msgid="4143245817259719147">"Expunere manuală"</string>
 </resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 2ffba4a..fcea855 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -323,8 +323,8 @@
     <string name="torch_off_desc" msgid="8304675202998742618">"Işık kapalı"</string>
     <string name="camera_id_back_desc" msgid="3566327490758890635">"Arka kamera"</string>
     <string name="camera_id_front_desc" msgid="7497517948130254220">"Ön kamera"</string>
-    <string name="grid_lines_off_desc" msgid="2022385817190451353">"Izgara çizgileri kapalı"</string>
-    <string name="grid_lines_on_desc" msgid="4601540461914364817">"Izgara çizgileri açık"</string>
+    <string name="grid_lines_off_desc" msgid="2022385817190451353">"Kılavuz çizgileri kapalı"</string>
+    <string name="grid_lines_on_desc" msgid="4601540461914364817">"Kılavuz çizgileri açık"</string>
     <string name="more_options_desc" msgid="4628738800610478353">"Diğer Seçenekler"</string>
     <string name="cancel_button_description" msgid="3801167024006905033">"İptal"</string>
     <string name="done_button_description" msgid="1334963435441544592">"Bitti"</string>
diff --git a/res/drawable-hdpi/ic_video_disabled.png b/res_p/drawable-hdpi/ic_video_disabled.png
similarity index 100%
rename from res/drawable-hdpi/ic_video_disabled.png
rename to res_p/drawable-hdpi/ic_video_disabled.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_video_disabled.png b/res_p/drawable-mdpi/ic_video_disabled.png
similarity index 100%
rename from res/drawable-mdpi/ic_video_disabled.png
rename to res_p/drawable-mdpi/ic_video_disabled.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_video_disabled.png b/res_p/drawable-xhdpi/ic_video_disabled.png
similarity index 100%
rename from res/drawable-xhdpi/ic_video_disabled.png
rename to res_p/drawable-xhdpi/ic_video_disabled.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_video_disabled.png b/res_p/drawable-xxhdpi/ic_video_disabled.png
similarity index 100%
rename from res/drawable-xxhdpi/ic_video_disabled.png
rename to res_p/drawable-xxhdpi/ic_video_disabled.png
Binary files differ
diff --git a/src/com/android/camera/ButtonManager.java b/src/com/android/camera/ButtonManager.java
index c467f5a..cd48928 100644
--- a/src/com/android/camera/ButtonManager.java
+++ b/src/com/android/camera/ButtonManager.java
@@ -74,6 +74,10 @@
     private ImageButton mExposureP1;
     private ImageButton mExposureP2;
 
+    private int mMinExposureCompensation;
+    private int mMaxExposureCompensation;
+    private float mExposureCompensationStep;
+
     /** A listener for button enabled and visibility
         state changes. */
     private ButtonStatusListener mListener;
@@ -486,8 +490,12 @@
                         case R.id.exposure_p2:
                             comp = 2;
                     }
-                    // Each integer compensation represent 1/6 of a stop.
-                    cb.setExposure(comp * 6);
+
+                    if (mExposureCompensationStep != 0.0f) {
+                        int compValue =
+                            Math.round(comp / mExposureCompensationStep);
+                        cb.setExposure(compValue);
+                    }
                 }
             };
 
@@ -500,6 +508,25 @@
     }
 
     /**
+     * Set the exposure compensation parameters supported by the current camera mode.
+     * @param min Minimum exposure compensation value.
+     * @param max Maximum exposure compensation value.
+     * @param step Expsoure compensation step value.
+     */
+    public void setExposureCompensationParameters(int min, int max, float step) {
+        mMaxExposureCompensation = max;
+        mMinExposureCompensation = min;
+        mExposureCompensationStep = step;
+
+        mExposureN2.setEnabled(Math.round(min * step) <= -2);
+        mExposureN1.setEnabled(Math.round(min * step) <= -1);
+        mExposureP1.setEnabled(Math.round(max * step) >= 1);
+        mExposureP1.setEnabled(Math.round(max * step) >= 2);
+
+        updateExposureButtons();
+    }
+
+    /**
      * Check if a button is enabled with the given button id..
      */
     public boolean isEnabled(int buttonId) {
@@ -670,7 +697,7 @@
      */
     public void updateExposureButtons() {
         String compString = mSettingsManager.get(SettingsManager.SETTING_EXPOSURE_COMPENSATION_VALUE);
-        int comp = Integer.parseInt(compString);
+        int compValue = Integer.parseInt(compString);
 
         // Reset all button states.
         mExposureN2.setBackground(null);
@@ -684,22 +711,24 @@
         Drawable background = context.getResources()
             .getDrawable(R.drawable.button_background_selected_photo);
 
-        // Each integer compensation represent 1/6 of a stop.
-        switch (comp / 6) {
-            case -2:
-                mExposureN2.setBackground(background);
-                break;
-            case -1:
-                mExposureN1.setBackground(background);
-                break;
-            case 0:
-                mExposure0.setBackground(background);
-                break;
-            case 1:
-                mExposureP1.setBackground(background);
-                break;
-            case 2:
-                mExposureP2.setBackground(background);
+        if (mExposureCompensationStep != 0.0f) {
+            int comp = Math.round(compValue * mExposureCompensationStep);
+            switch (comp) {
+                case -2:
+                    mExposureN2.setBackground(background);
+                    break;
+                case -1:
+                    mExposureN1.setBackground(background);
+                    break;
+                case 0:
+                    mExposure0.setBackground(background);
+                    break;
+                case 1:
+                    mExposureP1.setBackground(background);
+                    break;
+                case 2:
+                    mExposureP2.setBackground(background);
+            }
         }
     }
 
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 7df6341..a9399d7 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -33,6 +33,7 @@
 import android.location.Location;
 import android.media.CameraProfile;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -557,6 +558,9 @@
                 setExposureCompensation(value);
             }
         };
+        bottomBarSpec.minExposureCompensation = mParameters.getMinExposureCompensation();
+        bottomBarSpec.maxExposureCompensation = mParameters.getMaxExposureCompensation();
+        bottomBarSpec.exposureCompensationStep = mParameters.getExposureCompensationStep();
 
         if (isImageCaptureIntent()) {
             bottomBarSpec.showCancel = true;
@@ -839,8 +843,14 @@
                 }
             }
 
-            // Send the taken photo to remote shutter listeners, if any are registered.
-            getServices().getRemoteShutterListener().onPictureTaken(jpegData);
+            // Send the taken photo to remote shutter listeners, if any are
+            // registered.
+            AsyncTask.SERIAL_EXECUTOR.execute(new Runnable() {
+                @Override
+                public void run() {
+                    getServices().getRemoteShutterListener().onPictureTaken(jpegData);
+                }
+            });
 
             // Check this in advance of each shot so we don't add to shutter
             // latency. It's true that someone else could write to the SD card
@@ -945,6 +955,7 @@
             return false;
         }
         mCaptureStartTime = System.currentTimeMillis();
+
         mPostViewPictureCallbackTime = 0;
         mJpegImageData = null;
 
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index 1398085..8721348 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -325,6 +325,9 @@
         // TODO: Need to look at the controller interface to see if we can get
         // rid of passing in the activity directly.
         mAppController = mActivity;
+
+        mActivity.updateStorageSpaceAndHint();
+
         mUI = new VideoUI(mActivity, this,  mActivity.getModuleLayoutRoot());
         mActivity.setPreviewStatusListener(mUI);
 
@@ -1390,6 +1393,10 @@
             // by MediaRecorder.
             mParameters = mCameraDevice.getParameters();
         }
+
+        // Redo storage space calculation so it's accurate for the next video recording.
+        mActivity.updateStorageSpaceAndHint();
+
         return fail;
     }
 
diff --git a/src/com/android/camera/app/CameraAppUI.java b/src/com/android/camera/app/CameraAppUI.java
index 98ed1db..ec089c8 100644
--- a/src/com/android/camera/app/CameraAppUI.java
+++ b/src/com/android/camera/app/CameraAppUI.java
@@ -23,6 +23,7 @@
 import android.graphics.Matrix;
 import android.graphics.RectF;
 import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
 import android.hardware.display.DisplayManager;
 import android.util.CameraPerformanceTracker;
 import android.view.GestureDetector;
@@ -427,9 +428,16 @@
          * when an expsosure button is pressed. This callback can be null.
          */
         public interface ExposureCompensationSetCallback {
-            public abstract void setExposure(int value);
+            public void setExposure(int value);
         }
         public ExposureCompensationSetCallback exposureCompensationSetCallback;
+
+        /**
+         * Exposure compensation parameters.
+         */
+        public int minExposureCompensation;
+        public int maxExposureCompensation;
+        public float exposureCompensationStep;
     }
 
 
@@ -1708,6 +1716,11 @@
             buttonManager.setExposureCompensationCallback(null);
         }
 
+        buttonManager.setExposureCompensationParameters(
+                bottomBarSpec.minExposureCompensation,
+                bottomBarSpec.maxExposureCompensation,
+                bottomBarSpec.exposureCompensationStep);
+
         /** Intent UI */
         if (bottomBarSpec.showCancel) {
             buttonManager.initializePushButton(ButtonManager.BUTTON_CANCEL,
diff --git a/src/com/android/camera/settings/CameraSettingsActivity.java b/src/com/android/camera/settings/CameraSettingsActivity.java
index 71c6c3a..fcff0d8 100644
--- a/src/com/android/camera/settings/CameraSettingsActivity.java
+++ b/src/com/android/camera/settings/CameraSettingsActivity.java
@@ -275,13 +275,17 @@
 
         /**
          * Sets the entries for the given list preference.
-         * 
+         *
          * @param selectedQualities The possible S,M,L entries the user can
          *            choose from.
          * @param preference The preference to set the entries for.
          */
         private void setEntriesForSelection(SelectedPictureSizes selectedSizes,
                 ListPreference preference) {
+            if (selectedSizes == null) {
+                return;
+            }
+
             String[] entries = new String[3];
             entries[0] = getSizeSummaryString(selectedSizes.large);
             entries[1] = getSizeSummaryString(selectedSizes.medium);
@@ -291,13 +295,17 @@
 
         /**
          * Sets the entries for the given list preference.
-         * 
+         *
          * @param selectedQualities The possible S,M,L entries the user can
          *            choose from.
          * @param preference The preference to set the entries for.
          */
         private void setEntriesForSelection(SelectedVideoQualities selectedQualities,
                 ListPreference preference) {
+            if (mVideoQualitiesFront == null) {
+                return;
+            }
+
             String[] entries = new String[3];
             entries[0] = mCamcorderProfileNames[selectedQualities.large];
             entries[1] = mCamcorderProfileNames[selectedQualities.medium];
@@ -307,24 +315,32 @@
 
         /**
          * Sets the summary for the given list preference.
-         * 
+         *
          * @param selectedQualities The selected picture sizes.
          * @param preference The preference for which to set the summary.
          */
         private void setSummaryForSelection(SelectedPictureSizes selectedSizes,
                 ListPreference preference) {
+            if (selectedSizes == null) {
+                return;
+            }
+
             Size selectedSize = selectedSizes.getFromSetting(preference.getValue());
             preference.setSummary(getSizeSummaryString(selectedSize));
         }
 
         /**
          * Sets the summary for the given list preference.
-         * 
+         *
          * @param selectedQualities The selected video qualities.
          * @param preference The preference for which to set the summary.
          */
         private void setSummaryForSelection(SelectedVideoQualities selectedQualities,
                 ListPreference preference) {
+            if (selectedQualities == null) {
+                return;
+            }
+
             int selectedQuality = selectedQualities.getFromSetting(preference.getValue());
             preference.setSummary(mCamcorderProfileNames[selectedQuality]);
         }
@@ -379,7 +395,7 @@
 
         /**
          * Gets the first camera facing the given direction.
-         * 
+         *
          * @param facing Either {@link CameraInfo#CAMERA_FACING_BACK} or
          *            {@link CameraInfo#CAMERA_FACING_FRONT}.
          * @return The ID of the first camera matching the given direction, or