Merge "Reset ongoing animation when opening menu" into gb-ub-photos-bryce
diff --git a/res/drawable-hdpi/ic_localadjust_add.png b/res/drawable-hdpi/ic_localadjust_add.png
new file mode 100644
index 0000000..4e0dc2b
--- /dev/null
+++ b/res/drawable-hdpi/ic_localadjust_add.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_localadjust_delete.png b/res/drawable-hdpi/ic_localadjust_delete.png
new file mode 100644
index 0000000..521541f
--- /dev/null
+++ b/res/drawable-hdpi/ic_localadjust_delete.png
Binary files differ
diff --git a/res/drawable-hdpi/localadjust_defocused.png b/res/drawable-hdpi/localadjust_defocused.png
new file mode 100644
index 0000000..20677a0
--- /dev/null
+++ b/res/drawable-hdpi/localadjust_defocused.png
Binary files differ
diff --git a/res/drawable-hdpi/localadjust_focused.png b/res/drawable-hdpi/localadjust_focused.png
new file mode 100644
index 0000000..5f6b856
--- /dev/null
+++ b/res/drawable-hdpi/localadjust_focused.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_localadjust_add.png b/res/drawable-mdpi/ic_localadjust_add.png
new file mode 100644
index 0000000..9465734
--- /dev/null
+++ b/res/drawable-mdpi/ic_localadjust_add.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_localadjust_delete.png b/res/drawable-mdpi/ic_localadjust_delete.png
new file mode 100644
index 0000000..b6221e6
--- /dev/null
+++ b/res/drawable-mdpi/ic_localadjust_delete.png
Binary files differ
diff --git a/res/drawable-mdpi/localadjust_defocused.png b/res/drawable-mdpi/localadjust_defocused.png
new file mode 100644
index 0000000..7abcbba
--- /dev/null
+++ b/res/drawable-mdpi/localadjust_defocused.png
Binary files differ
diff --git a/res/drawable-mdpi/localadjust_focused.png b/res/drawable-mdpi/localadjust_focused.png
new file mode 100644
index 0000000..d2a9925
--- /dev/null
+++ b/res/drawable-mdpi/localadjust_focused.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_localadjust_add.png b/res/drawable-xhdpi/ic_localadjust_add.png
new file mode 100644
index 0000000..ca7b654
--- /dev/null
+++ b/res/drawable-xhdpi/ic_localadjust_add.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_localadjust_delete.png b/res/drawable-xhdpi/ic_localadjust_delete.png
new file mode 100644
index 0000000..9dfb392
--- /dev/null
+++ b/res/drawable-xhdpi/ic_localadjust_delete.png
Binary files differ
diff --git a/res/drawable-xhdpi/localadjust_defocused.png b/res/drawable-xhdpi/localadjust_defocused.png
new file mode 100644
index 0000000..8ece122
--- /dev/null
+++ b/res/drawable-xhdpi/localadjust_defocused.png
Binary files differ
diff --git a/res/drawable-xhdpi/localadjust_focused.png b/res/drawable-xhdpi/localadjust_focused.png
new file mode 100644
index 0000000..76aef60
--- /dev/null
+++ b/res/drawable-xhdpi/localadjust_focused.png
Binary files differ
diff --git a/res/drawable/filtershow_addpoint.png b/res/drawable/filtershow_addpoint.png
index 483d8ee..5abfc74 100644
--- a/res/drawable/filtershow_addpoint.png
+++ b/res/drawable/filtershow_addpoint.png
Binary files differ
diff --git a/res/layout/filtershow_control_action_slider.xml b/res/layout/filtershow_control_action_slider.xml
index 734d750..a3ef3ed 100644
--- a/res/layout/filtershow_control_action_slider.xml
+++ b/res/layout/filtershow_control_action_slider.xml
@@ -22,7 +22,7 @@
     android:orientation="horizontal" >
 
     <ImageButton
-        android:id="@+id/actionButton"
+        android:id="@+id/leftActionButton"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="left|center_vertical"
@@ -39,5 +39,17 @@
         android:layout_gravity="center_vertical"
         android:layout_weight="1"
         style="@style/FilterShowSlider" />
+
+    <ImageButton
+        android:id="@+id/rightActionButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="left|center_vertical"
+        android:scaleType="centerInside"
+        android:layout_weight="0"
+        android:background="@drawable/filtershow_button_background"
+        android:src="@drawable/ic_menu_trash_holo_light"
+        android:paddingBottom="8dp"  />
+
 </LinearLayout>
 
diff --git a/res/values-en-rGB/filtershow_strings.xml b/res/values-en-rGB/filtershow_strings.xml
index 1abf1b2..19c4ac2 100644
--- a/res/values-en-rGB/filtershow_strings.xml
+++ b/res/values-en-rGB/filtershow_strings.xml
@@ -21,16 +21,13 @@
     <!-- no translation found for original_picture_text (3076213290079909698) -->
     <skip />
     <string name="setting_wallpaper" msgid="4679087092300036632">"Setting wallpaper"</string>
-    <!-- no translation found for download_failure (5923323939788582895) -->
-    <skip />
+    <string name="download_failure" msgid="5923323939788582895">"Could not download photo. Network unavailable."</string>
     <string name="original" msgid="3524493791230430897">"Original"</string>
     <string name="borders" msgid="2067345080568684614">"Borders"</string>
     <string name="filtershow_undo" msgid="6781743189243585101">"Undo"</string>
     <string name="filtershow_redo" msgid="4219489910543059747">"Redo"</string>
-    <!-- no translation found for show_imagestate_panel (281932769701043015) -->
-    <skip />
-    <!-- no translation found for hide_imagestate_panel (7207643485811695257) -->
-    <skip />
+    <string name="show_imagestate_panel" msgid="281932769701043015">"Show Applied Effects"</string>
+    <string name="hide_imagestate_panel" msgid="7207643485811695257">"Hide Applied Effects"</string>
     <string name="menu_settings" msgid="6428291655769260831">"Settings"</string>
     <string name="unsaved" msgid="8704442449002374375">"There are unsaved changes to this image."</string>
     <string name="save_before_exit" msgid="2680660633675916712">"Do you want to save before exiting?"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index a2d002a..2a871e5 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -235,8 +235,7 @@
     <string name="pref_camera_id_entry_back" msgid="5142699735103692485">"Back"</string>
     <string name="pref_camera_id_entry_front" msgid="5668958706828733669">"Front"</string>
     <string name="pref_camera_recordlocation_title" msgid="371208839215448917">"Store location"</string>
-    <!-- no translation found for pref_camera_location_label (2254270920298609161) -->
-    <skip />
+    <string name="pref_camera_location_label" msgid="2254270920298609161">"LOCATION"</string>
     <string name="pref_camera_timer_title" msgid="3105232208281893389">"Countdown timer"</string>
   <plurals name="pref_camera_timer_entry">
     <item quantity="one" msgid="1654523400981245448">"1 second"</item>
@@ -296,31 +295,23 @@
     <string name="pref_camera_scenemode_entry_night" msgid="7606898503102476329">"Night"</string>
     <string name="pref_camera_scenemode_entry_sunset" msgid="181661154611507212">"Sunset"</string>
     <string name="pref_camera_scenemode_entry_party" msgid="907053529286788253">"Party"</string>
-    <!-- no translation found for pref_camera_scenemode_label_auto (4475096836397300237) -->
-    <skip />
+    <string name="pref_camera_scenemode_label_auto" msgid="4475096836397300237">"NONE"</string>
     <string name="pref_camera_scenemode_label_action" msgid="964748409622151496">"ACTION"</string>
     <string name="pref_camera_scenemode_label_night" msgid="1269871886845854574">"NIGHT"</string>
     <string name="pref_camera_scenemode_label_sunset" msgid="2802732082948866877">"SUNSET"</string>
     <string name="pref_camera_scenemode_label_party" msgid="1409459091844374828">"PARTY"</string>
-    <!-- no translation found for pref_camera_countdown_label (7592784692450586126) -->
-    <skip />
-    <!-- no translation found for pref_camera_countdown_label_off (4987856883590176585) -->
-    <skip />
-    <!-- no translation found for pref_camera_countdown_label_one (1101814103087928898) -->
-    <skip />
-    <!-- no translation found for pref_camera_countdown_label_three (1047399297342955649) -->
-    <skip />
-    <!-- no translation found for pref_camera_countdown_label_ten (6274681535347260279) -->
-    <skip />
-    <!-- no translation found for pref_camera_countdown_label_fifteen (4544824246687597089) -->
-    <skip />
+    <string name="pref_camera_countdown_label" msgid="7592784692450586126">"COUNTDOWN TIMER"</string>
+    <string name="pref_camera_countdown_label_off" msgid="4987856883590176585">"TIMER OFF"</string>
+    <string name="pref_camera_countdown_label_one" msgid="1101814103087928898">"1 SECOND"</string>
+    <string name="pref_camera_countdown_label_three" msgid="1047399297342955649">"3 SECONDS"</string>
+    <string name="pref_camera_countdown_label_ten" msgid="6274681535347260279">"10 SECONDS"</string>
+    <string name="pref_camera_countdown_label_fifteen" msgid="4544824246687597089">"15 SECONDS"</string>
     <string name="not_selectable_in_scene_mode" msgid="2970291701448555126">"Not selectable in scene mode."</string>
     <string name="pref_exposure_title" msgid="1229093066434614811">"Exposure"</string>
     <string name="pref_exposure_label" msgid="552624394642497940">"EXPOSURE"</string>
     <!-- no translation found for pref_camera_hdr_default (1336869406134365882) -->
     <skip />
-    <!-- no translation found for pref_camera_hdr_label (7217211253357027510) -->
-    <skip />
+    <string name="pref_camera_hdr_label" msgid="7217211253357027510">"HDR"</string>
     <string name="pref_camera_id_label_back" msgid="8745553500400332333">"FRONT CAMERA"</string>
     <string name="pref_camera_id_label_front" msgid="8699439330056996709">"BACK CAMERA"</string>
     <string name="dialog_ok" msgid="6263301364153382152">"OK"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 0f26eaf..1e7f1a5 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -278,7 +278,7 @@
     <string name="pref_camera_flashmode_label_on" msgid="7347504762794840140">"FLASH ACTIVADO"</string>
     <string name="pref_camera_flashmode_label_off" msgid="3541596735596053416">"FLASH DESACTIVADO"</string>
     <string name="pref_camera_whitebalance_title" msgid="677420930596673340">"Balance blancos"</string>
-    <string name="pref_camera_whitebalance_label" msgid="7467403405883190920">"EQUILIBRIO DE BLANCOS"</string>
+    <string name="pref_camera_whitebalance_label" msgid="7467403405883190920">"BALANCE DE BLANCOS"</string>
     <string name="pref_camera_whitebalance_entry_auto" msgid="6580665476983469293">"Automático"</string>
     <string name="pref_camera_whitebalance_entry_incandescent" msgid="8856667786449549938">"Incandescente"</string>
     <string name="pref_camera_whitebalance_entry_daylight" msgid="2534757270149561027">"Luz del día"</string>
@@ -286,7 +286,7 @@
     <string name="pref_camera_whitebalance_entry_cloudy" msgid="3531996716997959326">"Nublado"</string>
     <string name="pref_camera_whitebalance_label_auto" msgid="1479694362310491429">"AUTOMÁTICO"</string>
     <string name="pref_camera_whitebalance_label_incandescent" msgid="7427628260209908900">"INCANDESCENTE"</string>
-    <string name="pref_camera_whitebalance_label_daylight" msgid="1859710806141461399">"LUZ DEL DÍA"</string>
+    <string name="pref_camera_whitebalance_label_daylight" msgid="1859710806141461399">"LUZ NATURAL"</string>
     <string name="pref_camera_whitebalance_label_fluorescent" msgid="5173251749161337707">"FLUORESCENTE"</string>
     <string name="pref_camera_whitebalance_label_cloudy" msgid="8230173517179285320">"NUBLADO"</string>
     <string name="pref_camera_scenemode_title" msgid="1420535844292504016">"Modo de preselección de escenas"</string>
@@ -376,7 +376,7 @@
     <string name="accessibility_play_video" msgid="7596298365794810207">"Reproducir video"</string>
     <string name="accessibility_pause_video" msgid="6526344477133046653">"Pausar video"</string>
     <string name="accessibility_reload_video" msgid="3250335917598607232">"Volver a cargar video"</string>
-    <string name="accessibility_time_bar" msgid="1414029843602604531">"Barra de tiempo del Reproductor de Google Video"</string>
+    <string name="accessibility_time_bar" msgid="1414029843602604531">"Barra de tiempo del reproductor de video"</string>
     <string name="capital_on" msgid="5491353494964003567">"ACTIVADO"</string>
     <string name="capital_off" msgid="7231052688467970897">"DESACTIVADO"</string>
     <string name="pref_video_time_lapse_frame_interval_off" msgid="3490489191038309496">"Apagado"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index a0e121c..f06e397 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -321,7 +321,7 @@
     <skip />
     <!-- no translation found for pref_camera_hdr_label (7217211253357027510) -->
     <skip />
-    <string name="pref_camera_id_label_back" msgid="8745553500400332333">"CÁMARA DELANTERA"</string>
+    <string name="pref_camera_id_label_back" msgid="8745553500400332333">"CÁMARA FRONTAL"</string>
     <string name="pref_camera_id_label_front" msgid="8699439330056996709">"CÁMARA TRASERA"</string>
     <string name="dialog_ok" msgid="6263301364153382152">"Aceptar"</string>
     <string name="spaceIsLow_content" product="nosdcard" msgid="4401325203349203177">"No queda espacio en el almacenamiento USB. Cambia la configuración de calidad o elimina algunas imágenes u otros archivos."</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 34c91e8..62289c3 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -267,7 +267,7 @@
     <string name="pref_camera_focusmode_entry_infinity" msgid="3413922419264967552">"بی نهایت"</string>
     <string name="pref_camera_focusmode_entry_macro" msgid="4424489110551866161">"ماکرو"</string>
     <string name="pref_camera_focusmode_label_auto" msgid="8547956917516317183">"خودکار"</string>
-    <string name="pref_camera_focusmode_label_infinity" msgid="4272904160062531778">"نامحدود"</string>
+    <string name="pref_camera_focusmode_label_infinity" msgid="4272904160062531778">"بی‌نهایت"</string>
     <string name="pref_camera_focusmode_label_macro" msgid="8749317592620908054">"ماکرو"</string>
     <string name="pref_camera_flashmode_title" msgid="2287362477238791017">"حالت فلاش"</string>
     <string name="pref_camera_flashmode_label" msgid="7546741624882856171">"حالت فلاش"</string>
@@ -275,7 +275,7 @@
     <string name="pref_camera_flashmode_entry_on" msgid="5330043918845197616">"روشن"</string>
     <string name="pref_camera_flashmode_entry_off" msgid="867242186958805761">"خاموش"</string>
     <string name="pref_camera_flashmode_label_auto" msgid="8854671890619026197">"فلاش خودکار"</string>
-    <string name="pref_camera_flashmode_label_on" msgid="7347504762794840140">"فلش روشن"</string>
+    <string name="pref_camera_flashmode_label_on" msgid="7347504762794840140">"فلاش روشن"</string>
     <string name="pref_camera_flashmode_label_off" msgid="3541596735596053416">"فلاش خاموش"</string>
     <string name="pref_camera_whitebalance_title" msgid="677420930596673340">"توازن سفیدی"</string>
     <string name="pref_camera_whitebalance_label" msgid="7467403405883190920">"توازن سفیدی"</string>
@@ -300,7 +300,7 @@
     <skip />
     <string name="pref_camera_scenemode_label_action" msgid="964748409622151496">"عملکرد"</string>
     <string name="pref_camera_scenemode_label_night" msgid="1269871886845854574">"شب"</string>
-    <string name="pref_camera_scenemode_label_sunset" msgid="2802732082948866877">"غروب آفتاب"</string>
+    <string name="pref_camera_scenemode_label_sunset" msgid="2802732082948866877">"غروب"</string>
     <string name="pref_camera_scenemode_label_party" msgid="1409459091844374828">"مهمانی"</string>
     <!-- no translation found for pref_camera_countdown_label (7592784692450586126) -->
     <skip />
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index bee5f22..1497bc4 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -38,7 +38,7 @@
     <string name="saving_image" msgid="7270334453636349407">"चित्र सहेज रहा है…"</string>
     <string name="filtershow_saving_image" msgid="6659463980581993016">"चित्र <xliff:g id="ALBUM_NAME">%1$s</xliff:g> में सहेजा जा रहा है …"</string>
     <string name="save_error" msgid="6857408774183654970">"काट-छांट की गई चित्र को नहीं सहेज सका."</string>
-    <string name="crop_label" msgid="521114301871349328">"चित्र काटें"</string>
+    <string name="crop_label" msgid="521114301871349328">"चित्र काट-छांट करें"</string>
     <string name="trim_label" msgid="274203231381209979">"वीडियो ट्रिम करें"</string>
     <string name="select_image" msgid="7841406150484742140">"फ़ोटो को चुनें"</string>
     <string name="select_video" msgid="4859510992798615076">"वीडियो को चुनें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 1af22a9..543f7c2 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -285,7 +285,7 @@
     <string name="pref_camera_whitebalance_entry_fluorescent" msgid="2435332872847454032">"Fluorescentno"</string>
     <string name="pref_camera_whitebalance_entry_cloudy" msgid="3531996716997959326">"Oblačno"</string>
     <string name="pref_camera_whitebalance_label_auto" msgid="1479694362310491429">"AUTOMATSKI"</string>
-    <string name="pref_camera_whitebalance_label_incandescent" msgid="7427628260209908900">"USIJANO"</string>
+    <string name="pref_camera_whitebalance_label_incandescent" msgid="7427628260209908900">"SVJETLOST ŽARULJE"</string>
     <string name="pref_camera_whitebalance_label_daylight" msgid="1859710806141461399">"DNEVNO SVJETLO"</string>
     <string name="pref_camera_whitebalance_label_fluorescent" msgid="5173251749161337707">"FLUORESCENTNO"</string>
     <string name="pref_camera_whitebalance_label_cloudy" msgid="8230173517179285320">"OBLAČNO"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index b9d82b9..79da154 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -299,7 +299,7 @@
     <!-- no translation found for pref_camera_scenemode_label_auto (4475096836397300237) -->
     <skip />
     <string name="pref_camera_scenemode_label_action" msgid="964748409622151496">"动作"</string>
-    <string name="pref_camera_scenemode_label_night" msgid="1269871886845854574">"晚上"</string>
+    <string name="pref_camera_scenemode_label_night" msgid="1269871886845854574">"夜晚"</string>
     <string name="pref_camera_scenemode_label_sunset" msgid="2802732082948866877">"日落"</string>
     <string name="pref_camera_scenemode_label_party" msgid="1409459091844374828">"聚会"</string>
     <!-- no translation found for pref_camera_countdown_label (7592784692450586126) -->
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index b5f41d3..1b3f573 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -425,7 +425,7 @@
     <string name="time_lapse_interval_set" msgid="2486386210951700943">"完成"</string>
     <string name="set_time_interval" msgid="2970567717633813771">"設定時間間隔"</string>
     <string name="set_time_interval_help" msgid="6665849510484821483">"延時攝影功能已關閉,請開啟以設定時間間格。"</string>
-    <string name="set_timer_help" msgid="5007708849404589472">"倒數計時器目前為關閉狀態,開啓即可在拍照前倒數計時。"</string>
+    <string name="set_timer_help" msgid="5007708849404589472">"倒數計時器目前為關閉狀態,開啟即可在拍照前倒數計時。"</string>
     <string name="set_duration" msgid="5578035312407161304">"設定倒數時間 (以秒為單位)"</string>
     <string name="count_down_title_text" msgid="4976386810910453266">"拍照倒數計時中"</string>
     <string name="remember_location_title" msgid="9060472929006917810">"記錄拍攝地點?"</string>
diff --git a/src/com/android/camera/PanoramaModule.java b/src/com/android/camera/PanoramaModule.java
index c83bf82..007ea7a 100644
--- a/src/com/android/camera/PanoramaModule.java
+++ b/src/com/android/camera/PanoramaModule.java
@@ -35,6 +35,7 @@
 import android.graphics.drawable.Drawable;
 import android.hardware.Camera.Parameters;
 import android.hardware.Camera.Size;
+import android.location.Location;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -176,6 +177,9 @@
     private boolean mPaused;
     private boolean mIsCreatingRenderer;
 
+    private LocationManager mLocationManager;
+    private ComboPreferences mPreferences;
+
     private class MosaicJpeg {
         public MosaicJpeg(byte[] data, int width, int height) {
             this.data = data;
@@ -279,6 +283,10 @@
 
         mGLRootView = (GLRootView) mActivity.getGLRoot();
 
+        mPreferences = new ComboPreferences(mActivity);
+        CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal());
+        mLocationManager = new LocationManager(mActivity, null);
+
         mMainHandler = new Handler() {
             @Override
             public void handleMessage(Message msg) {
@@ -902,6 +910,7 @@
                     mActivity.getResources().getString(R.string.pano_file_name_format), mTimeTaken);
             String filepath = Storage.generateFilepath(filename);
 
+            Location loc = mLocationManager.getCurrentLocation();
             ExifInterface exif = new ExifInterface();
             try {
                 exif.readExif(jpegData);
@@ -910,19 +919,27 @@
                         TimeZone.getDefault());
                 exif.setTag(exif.buildTag(ExifInterface.TAG_ORIENTATION,
                         ExifInterface.getOrientationValueForRotation(orientation)));
+                writeLocation(loc, exif);
                 exif.writeExif(jpegData, filepath);
             } catch (IOException e) {
                 Log.e(TAG, "Cannot set exif for " + filepath, e);
                 Storage.writeFile(filepath, jpegData);
             }
-
             int jpegLength = (int) (new File(filepath).length());
             return Storage.addImage(mContentResolver, filename, mTimeTaken,
-                    null, orientation, jpegLength, filepath, width, height);
+                    loc, orientation, jpegLength, filepath, width, height);
         }
         return null;
     }
 
+    private static void writeLocation(Location location, ExifInterface exif) {
+        if (location == null) {
+            return;
+        }
+        exif.addGpsTags(location.getLatitude(), location.getLongitude());
+        exif.setTag(exif.buildTag(ExifInterface.TAG_GPS_PROCESSING_METHOD, location.getProvider()));
+    }
+
     private void clearMosaicFrameProcessorIfNeeded() {
         if (!mPaused || mThreadRunning) return;
         // Only clear the processor if it is initialized by this activity
@@ -943,6 +960,7 @@
     @Override
     public void onPauseBeforeSuper() {
         mPaused = true;
+        if (mLocationManager != null) mLocationManager.recordLocation(false);
     }
 
     @Override
@@ -1059,6 +1077,11 @@
         }
         keepScreenOnAwhile();
 
+        // Initialize location service.
+        boolean recordLocation = RecordLocationPreference.get(mPreferences,
+                mContentResolver);
+        mLocationManager.recordLocation(recordLocation);
+
         // Dismiss open menu if exists.
         PopupManager.getInstance(mActivity).notifyShowPopup(null);
         mRootView.requestLayout();
diff --git a/src/com/android/gallery3d/filtershow/controller/ActionSlider.java b/src/com/android/gallery3d/filtershow/controller/ActionSlider.java
index 6ed2467..f80a1ca 100644
--- a/src/com/android/gallery3d/filtershow/controller/ActionSlider.java
+++ b/src/com/android/gallery3d/filtershow/controller/ActionSlider.java
@@ -27,7 +27,8 @@
 
 public class ActionSlider extends TitledSlider {
     private static final String LOGTAG = "ActionSlider";
-    ImageButton mActionButton;
+    ImageButton mLeftButton;
+    ImageButton mRightButton;
     public ActionSlider() {
         mLayoutID = R.layout.filtershow_control_action_slider;
     }
@@ -35,22 +36,36 @@
     @Override
     public void setUp(ViewGroup container, Parameter parameter, Editor editor) {
         super.setUp(container, parameter, editor);
-        mActionButton = (ImageButton) mTopView.findViewById(R.id.actionButton);
-        mActionButton.setOnClickListener(new OnClickListener() {
+        mLeftButton = (ImageButton) mTopView.findViewById(R.id.leftActionButton);
+        mLeftButton.setOnClickListener(new OnClickListener() {
 
             @Override
             public void onClick(View v) {
-                ((ParameterActionAndInt) mParameter).fireAction();
+                ((ParameterActionAndInt) mParameter).fireLeftAction();
             }
         });
+
+        mRightButton = (ImageButton) mTopView.findViewById(R.id.rightActionButton);
+        mRightButton.setOnClickListener(new OnClickListener() {
+
+                @Override
+            public void onClick(View v) {
+                ((ParameterActionAndInt) mParameter).fireRightAction();
+            }
+        });
+        updateUI();
     }
 
     @Override
     public void updateUI() {
         super.updateUI();
-        if (mActionButton != null) {
-            int iconId = ((ParameterActionAndInt) mParameter).getActionIcon();
-            mActionButton.setImageResource(iconId);
+        if (mLeftButton != null) {
+            int iconId = ((ParameterActionAndInt) mParameter).getLeftIcon();
+            mLeftButton.setImageResource(iconId);
+        }
+        if (mRightButton != null) {
+            int iconId = ((ParameterActionAndInt) mParameter).getRightIcon();
+            mRightButton.setImageResource(iconId);
         }
     }
 }
diff --git a/src/com/android/gallery3d/filtershow/controller/BasicParameterStyle.java b/src/com/android/gallery3d/filtershow/controller/BasicParameterStyle.java
index 633e41f..072edd7 100644
--- a/src/com/android/gallery3d/filtershow/controller/BasicParameterStyle.java
+++ b/src/com/android/gallery3d/filtershow/controller/BasicParameterStyle.java
@@ -92,8 +92,6 @@
 
     @Override
     public void getIcon(int index, RenderingRequestCaller caller) {
-        Log.v(LOGTAG, "############ " + ID + " getIcon " + index);
-
         mEditor.computeIcon(index, caller);
     }
 
diff --git a/src/com/android/gallery3d/filtershow/controller/ParameterActionAndInt.java b/src/com/android/gallery3d/filtershow/controller/ParameterActionAndInt.java
index 04567e2..8a05c3a 100644
--- a/src/com/android/gallery3d/filtershow/controller/ParameterActionAndInt.java
+++ b/src/com/android/gallery3d/filtershow/controller/ParameterActionAndInt.java
@@ -19,7 +19,11 @@
 public interface ParameterActionAndInt extends ParameterInteger {
     static String sParameterType = "ParameterActionAndInt";
 
-    public void fireAction();
+    public void fireLeftAction();
 
-    public int getActionIcon();
+    public int getLeftIcon();
+
+    public void fireRightAction();
+
+    public int getRightIcon();
 }
diff --git a/src/com/android/gallery3d/filtershow/editors/Editor.java b/src/com/android/gallery3d/filtershow/editors/Editor.java
index 1e239e6..dc13b3e 100644
--- a/src/com/android/gallery3d/filtershow/editors/Editor.java
+++ b/src/com/android/gallery3d/filtershow/editors/Editor.java
@@ -64,13 +64,7 @@
     }
 
     public String calculateUserMessage(Context context, String effectName, Object parameterValue) {
-        String apply = "";
-        if (mShowParameter == SHOW_VALUE_INT) {
-            apply += " " + effectName + " " + parameterValue;
-        } else {
-            apply += " " + effectName;
-        }
-        return apply;
+        return effectName + " " + parameterValue;
     }
 
     protected Editor(int id) {
@@ -214,7 +208,9 @@
     public void commitLocalRepresentation() {
         ImagePreset preset = MasterImage.getImage().getPreset();
         preset.updateFilterRepresentation(getLocalRepresentation());
-        mPanelController.onNewValue(-1);
+        if (mPanelController != null) {
+            mPanelController.onNewValue(-1);
+        }
     }
 
     /**
diff --git a/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java b/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java
index e49f6cd..33ed143 100644
--- a/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java
+++ b/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java
@@ -198,7 +198,9 @@
     public void commitLocalRepresentation() {
         super.commitLocalRepresentation();
         FilterRepresentation rep = getLocalRepresentation();
-        mPanelController.onNewValue(-1);
+        if (mPanelController != null) {
+            mPanelController.onNewValue(-1);
+        }
     }
 
     @Override
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
index 3511c67..cbcae4b 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
@@ -1,5 +1,7 @@
 package com.android.gallery3d.filtershow.filters;
 
+import android.util.Log;
+
 import com.android.gallery3d.R;
 import com.android.gallery3d.filtershow.ui.Spline;
 
@@ -7,6 +9,8 @@
  * TODO: Insert description here. (generated by hoford)
  */
 public class FilterCurvesRepresentation extends FilterRepresentation {
+    private static final String LOGTAG = "FilterCurvesRepresentation";
+
     private Spline[] mSplines = new Spline[4];
 
     public FilterCurvesRepresentation() {
@@ -20,10 +24,33 @@
         setShowParameterValue(false);
         setShowUtilityPanel(true);
         setSupportsPartialRendering(true);
-        for (int i = 0; i < mSplines.length; i++) {
-            mSplines[i] = new Spline();
-            mSplines[i].reset();
+        reset();
+    }
+
+    @Override
+    public FilterRepresentation clone() throws CloneNotSupportedException {
+        FilterCurvesRepresentation rep = new FilterCurvesRepresentation();
+        rep.useParametersFrom(this);
+        return rep;
+    }
+
+    @Override
+    public void useParametersFrom(FilterRepresentation a) {
+        if (!(a instanceof FilterCurvesRepresentation)) {
+            Log.v(LOGTAG, "cannot use parameters from " + a);
+            return;
         }
+        FilterCurvesRepresentation representation = (FilterCurvesRepresentation) a;
+        Spline[] spline = new Spline[4];
+        for (int i = 0; i < spline.length; i++) {
+            Spline sp = representation.mSplines[i];
+            if (sp != null) {
+                spline[i] = new Spline(sp);
+            } else {
+                spline[i] = new Spline();
+            }
+        }
+        mSplines = spline;
     }
 
     public boolean isNil() {
diff --git a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
index 528746d..be5df0a 100644
--- a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
+++ b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
@@ -26,6 +26,7 @@
 import android.graphics.PorterDuffXfermode;
 import android.os.AsyncTask;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
@@ -157,7 +158,7 @@
     }
 
     private Spline getSpline(int index) {
-        return curves().getSpline(index);
+        return mFilterCurvesRepresentation.getSpline(index);
     }
 
     @Override
@@ -169,8 +170,8 @@
     }
 
     public void resetCurve() {
-        if (curves() != null) {
-            curves().reset();
+        if (mFilterCurvesRepresentation != null) {
+            mFilterCurvesRepresentation.reset();
             updateCachedImage();
         }
     }
diff --git a/src/com/android/gallery3d/filtershow/ui/Spline.java b/src/com/android/gallery3d/filtershow/ui/Spline.java
index 2cfbd80..cadf2fd 100644
--- a/src/com/android/gallery3d/filtershow/ui/Spline.java
+++ b/src/com/android/gallery3d/filtershow/ui/Spline.java
@@ -98,7 +98,7 @@
     }
 
     public boolean isOriginal() {
-        if (this.getNbPoints() > 2) {
+        if (this.getNbPoints() != 2) {
             return false;
         }
         if (mPoints.elementAt(0).x != 0 || mPoints.elementAt(0).y != 1) {
@@ -378,6 +378,9 @@
 
     public void deletePoint(int n) {
         mPoints.remove(n);
+        if (mPoints.size() < 2) {
+            reset();
+        }
         Collections.sort(mPoints);
     }
 
diff --git a/src/com/android/gallery3d/gadget/MediaSetSource.java b/src/com/android/gallery3d/gadget/MediaSetSource.java
index caeff2a..458651c 100644
--- a/src/com/android/gallery3d/gadget/MediaSetSource.java
+++ b/src/com/android/gallery3d/gadget/MediaSetSource.java
@@ -22,93 +22,212 @@
 
 import com.android.gallery3d.common.Utils;
 import com.android.gallery3d.data.ContentListener;
+import com.android.gallery3d.data.DataManager;
 import com.android.gallery3d.data.MediaItem;
 import com.android.gallery3d.data.MediaObject;
 import com.android.gallery3d.data.MediaSet;
+import com.android.gallery3d.data.Path;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 
 public class MediaSetSource implements WidgetSource, ContentListener {
-    private static final int CACHE_SIZE = 32;
-
-    @SuppressWarnings("unused")
     private static final String TAG = "MediaSetSource";
 
-    private MediaSet mSource;
-    private MediaItem mCache[] = new MediaItem[CACHE_SIZE];
-    private int mCacheStart;
-    private int mCacheEnd;
-    private long mSourceVersion = MediaObject.INVALID_DATA_VERSION;
+    private DataManager mDataManager;
+    private Path mAlbumPath;
 
-    private ContentListener mContentListener;
+    private WidgetSource mSource;
 
-    public MediaSetSource(MediaSet source) {
-        mSource = Utils.checkNotNull(source);
-        mSource.addContentListener(this);
-    }
+    private MediaSet mRootSet;
+    private ContentListener mListener;
 
-    @Override
-    public void close() {
-        mSource.removeContentListener(this);
-    }
-
-    private void ensureCacheRange(int index) {
-        if (index >= mCacheStart && index < mCacheEnd) return;
-
-        long token = Binder.clearCallingIdentity();
-        try {
-            mCacheStart = index;
-            ArrayList<MediaItem> items = mSource.getMediaItem(mCacheStart, CACHE_SIZE);
-            mCacheEnd = mCacheStart + items.size();
-            items.toArray(mCache);
-        } finally {
-            Binder.restoreCallingIdentity(token);
+    public MediaSetSource(DataManager manager, String albumPath) {
+        MediaSet mediaSet = (MediaSet) manager.getMediaObject(albumPath);
+        if (mediaSet != null) {
+            mSource = new CheckedMediaSetSource(mediaSet);
+            return;
         }
-    }
 
-    @Override
-    public synchronized Uri getContentUri(int index) {
-        ensureCacheRange(index);
-        if (index < mCacheStart || index >= mCacheEnd) return null;
-        return mCache[index - mCacheStart].getContentUri();
-    }
-
-    @Override
-    public synchronized Bitmap getImage(int index) {
-        ensureCacheRange(index);
-        if (index < mCacheStart || index >= mCacheEnd) return null;
-        return WidgetUtils.createWidgetBitmap(mCache[index - mCacheStart]);
-    }
-
-    @Override
-    public void reload() {
-        long version = mSource.reload();
-        if (mSourceVersion != version) {
-            mSourceVersion = version;
-            mCacheStart = 0;
-            mCacheEnd = 0;
-            Arrays.fill(mCache, null);
-        }
-    }
-
-    @Override
-    public void setContentListener(ContentListener listener) {
-        mContentListener = listener;
+        // Initialize source to an empty source until the album path can be resolved
+        mDataManager = Utils.checkNotNull(manager);
+        mAlbumPath = Path.fromString(albumPath);
+        mSource = new EmptySource();
+        monitorRootPath();
     }
 
     @Override
     public int size() {
-        long token = Binder.clearCallingIdentity();
-        try {
-            return mSource.getMediaItemCount();
-        } finally {
-            Binder.restoreCallingIdentity(token);
+        return mSource.size();
+    }
+
+    @Override
+    public Bitmap getImage(int index) {
+        return mSource.getImage(index);
+    }
+
+    @Override
+    public Uri getContentUri(int index) {
+        return mSource.getContentUri(index);
+    }
+
+    @Override
+    public synchronized void setContentListener(ContentListener listener) {
+        if (mRootSet != null) {
+            mListener = listener;
+        } else {
+            mSource.setContentListener(listener);
         }
     }
 
     @Override
+    public void reload() {
+        mSource.reload();
+    }
+
+    @Override
+    public void close() {
+        mSource.close();
+    }
+
+    @Override
     public void onContentDirty() {
-        if (mContentListener != null) mContentListener.onContentDirty();
+        resolveAlbumPath();
+    }
+
+    private void monitorRootPath() {
+        String rootPath = mDataManager.getTopSetPath(DataManager.INCLUDE_ALL);
+        mRootSet = (MediaSet) mDataManager.getMediaObject(rootPath);
+        mRootSet.addContentListener(this);
+    }
+
+    private synchronized void resolveAlbumPath() {
+        if (mDataManager == null) return;
+        MediaSet mediaSet = (MediaSet) mDataManager.getMediaObject(mAlbumPath);
+        if (mediaSet != null) {
+            // Clear the reference instead of removing the listener
+            // to get around a concurrent modification exception.
+            mRootSet = null;
+
+            mSource = new CheckedMediaSetSource(mediaSet);
+            if (mListener != null) {
+                mListener.onContentDirty();
+                mSource.setContentListener(mListener);
+                mListener = null;
+            }
+            mDataManager = null;
+            mAlbumPath = null;
+        }
+    }
+
+    private static class CheckedMediaSetSource implements WidgetSource, ContentListener {
+        private static final int CACHE_SIZE = 32;
+
+        @SuppressWarnings("unused")
+        private static final String TAG = "CheckedMediaSetSource";
+
+        private MediaSet mSource;
+        private MediaItem mCache[] = new MediaItem[CACHE_SIZE];
+        private int mCacheStart;
+        private int mCacheEnd;
+        private long mSourceVersion = MediaObject.INVALID_DATA_VERSION;
+
+        private ContentListener mContentListener;
+
+        public CheckedMediaSetSource(MediaSet source) {
+            mSource = Utils.checkNotNull(source);
+            mSource.addContentListener(this);
+        }
+
+        @Override
+        public void close() {
+            mSource.removeContentListener(this);
+        }
+
+        private void ensureCacheRange(int index) {
+            if (index >= mCacheStart && index < mCacheEnd) return;
+
+            long token = Binder.clearCallingIdentity();
+            try {
+                mCacheStart = index;
+                ArrayList<MediaItem> items = mSource.getMediaItem(mCacheStart, CACHE_SIZE);
+                mCacheEnd = mCacheStart + items.size();
+                items.toArray(mCache);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public synchronized Uri getContentUri(int index) {
+            ensureCacheRange(index);
+            if (index < mCacheStart || index >= mCacheEnd) return null;
+            return mCache[index - mCacheStart].getContentUri();
+        }
+
+        @Override
+        public synchronized Bitmap getImage(int index) {
+            ensureCacheRange(index);
+            if (index < mCacheStart || index >= mCacheEnd) return null;
+            return WidgetUtils.createWidgetBitmap(mCache[index - mCacheStart]);
+        }
+
+        @Override
+        public void reload() {
+            long version = mSource.reload();
+            if (mSourceVersion != version) {
+                mSourceVersion = version;
+                mCacheStart = 0;
+                mCacheEnd = 0;
+                Arrays.fill(mCache, null);
+            }
+        }
+
+        @Override
+        public void setContentListener(ContentListener listener) {
+            mContentListener = listener;
+        }
+
+        @Override
+        public int size() {
+            long token = Binder.clearCallingIdentity();
+            try {
+                return mSource.getMediaItemCount();
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void onContentDirty() {
+            if (mContentListener != null) mContentListener.onContentDirty();
+        }
+    }
+
+    private static class EmptySource implements WidgetSource {
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public Bitmap getImage(int index) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Uri getContentUri(int index) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void setContentListener(ContentListener listener) {}
+
+        @Override
+        public void reload() {}
+
+        @Override
+        public void close() {}
     }
 }
diff --git a/src/com/android/gallery3d/gadget/WidgetService.java b/src/com/android/gallery3d/gadget/WidgetService.java
index 334b15a..94dd164 100644
--- a/src/com/android/gallery3d/gadget/WidgetService.java
+++ b/src/com/android/gallery3d/gadget/WidgetService.java
@@ -28,9 +28,6 @@
 import com.android.gallery3d.app.GalleryApp;
 import com.android.gallery3d.common.ApiHelper;
 import com.android.gallery3d.data.ContentListener;
-import com.android.gallery3d.data.DataManager;
-import com.android.gallery3d.data.MediaSet;
-import com.android.gallery3d.data.Path;
 
 @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
 public class WidgetService extends RemoteViewsService {
@@ -52,33 +49,6 @@
                 id, type, albumPath);
     }
 
-    private static class EmptySource implements WidgetSource {
-
-        @Override
-        public int size() {
-            return 0;
-        }
-
-        @Override
-        public Bitmap getImage(int index) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public Uri getContentUri(int index) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setContentListener(ContentListener listener) {}
-
-        @Override
-        public void reload() {}
-
-        @Override
-        public void close() {}
-    }
-
     private static class PhotoRVFactory implements
             RemoteViewsService.RemoteViewsFactory, ContentListener {
 
@@ -99,12 +69,7 @@
         @Override
         public void onCreate() {
             if (mType == WidgetDatabaseHelper.TYPE_ALBUM) {
-                Path path = Path.fromString(mAlbumPath);
-                DataManager manager = mApp.getDataManager();
-                MediaSet mediaSet = (MediaSet) manager.getMediaObject(path);
-                mSource = mediaSet == null
-                        ? new EmptySource()
-                        : new MediaSetSource(mediaSet);
+                mSource = new MediaSetSource(mApp.getDataManager(), mAlbumPath);
             } else {
                 mSource = new LocalPhotoSource(mApp.getAndroidContext());
             }