Merge "Release surface texture to fix gray camera preview" into gb-ub-photos-bryce
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 508aefe..3cd30cb 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -88,8 +88,11 @@
</intent-filter>
</activity>
- <activity android:name="com.android.gallery3d.app.Gallery" android:label="@string/app_name"
- android:configChanges="keyboardHidden|orientation|screenSize">
+ <activity android:name="com.android.photos.GalleryActivity"
+ android:label="@string/app_name"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:theme="@style/Theme.Photos.Gallery"
+ android:uiOptions="splitActionBarWhenNarrow">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
@@ -164,17 +167,6 @@
</intent-filter>
</activity>
- <!-- we add this activity-alias for shortcut backward compatibility -->
- <!-- Note: The alias must put after the target activity -->
- <activity-alias android:name="com.cooliris.media.Gallery"
- android:targetActivity="com.android.gallery3d.app.Gallery"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity-alias>
-
<!-- This activity receives USB_DEVICE_ATTACHED intents and allows importing
media from attached MTP devices, like cameras and camera phones -->
<activity android:launchMode="singleInstance"
diff --git a/jni/Android.mk b/jni/Android.mk
index 1843c77..e612486 100644
--- a/jni/Android.mk
+++ b/jni/Android.mk
@@ -32,6 +32,7 @@
filters/contrast.c \
filters/hue.c \
filters/shadows.c \
+ filters/highlight.c \
filters/hsv.c \
filters/vibrance.c \
filters/geometry.c \
diff --git a/jni/filters/contrast.c b/jni/filters/contrast.c
index 6c1b976..b04e936 100644
--- a/jni/filters/contrast.c
+++ b/jni/filters/contrast.c
@@ -27,6 +27,15 @@
return (unsigned char) c;
}
+int clampMax(int c,int max)
+{
+ c &= ~(c >> 31);
+ c -= max;
+ c &= (c >> 31);
+ c += max;
+ return c;
+}
+
void JNIFUNCF(ImageFilterContrast, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat bright)
{
char* destination = 0;
diff --git a/jni/filters/filters.h b/jni/filters/filters.h
index d518b63..14b69cd 100644
--- a/jni/filters/filters.h
+++ b/jni/filters/filters.h
@@ -44,6 +44,7 @@
#define CLAMP(c) (MAX(0, MIN(255, c)))
__inline__ unsigned char clamp(int c);
+__inline__ int clampMax(int c,int max);
extern void rgb2hsv( unsigned char *rgb,int rgbOff,unsigned short *hsv,int hsvOff);
extern void hsv2rgb(unsigned short *hsv,int hsvOff,unsigned char *rgb,int rgbOff);
diff --git a/jni/filters/highlight.c b/jni/filters/highlight.c
new file mode 100644
index 0000000..fe9b88f
--- /dev/null
+++ b/jni/filters/highlight.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <math.h>
+#include "filters.h"
+
+void JNIFUNCF(ImageFilterHighlights, nativeApplyFilter, jobject bitmap,
+ jint width, jint height, jfloatArray luminanceMap){
+ char* destination = 0;
+ AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
+ unsigned char * rgb = (unsigned char * )destination;
+ int i;
+ int len = width * height * 4;
+ jfloat* lum = (*env)->GetFloatArrayElements(env, luminanceMap,0);
+ unsigned short * hsv = (unsigned short *)malloc(3*sizeof(short));
+
+ for (i = 0; i < len; i+=4)
+ {
+ rgb2hsv(rgb,i,hsv,0);
+ int v = clampMax(hsv[0],4080);
+ hsv[0] = (unsigned short) clampMax(lum[((255*v)/4080)]*4080,4080);
+ hsv2rgb(hsv,0, rgb,i);
+ }
+
+ free(hsv);
+ AndroidBitmap_unlockPixels(env, bitmap);
+}
diff --git a/res/layout/photo_set.xml b/res/layout/photo_set.xml
new file mode 100644
index 0000000..2bb97bb
--- /dev/null
+++ b/res/layout/photo_set.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp" >
+
+ <ListView
+ android:id="@id/android:list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:drawSelectorOnTop="true" />
+
+ <TextView
+ android:id="@id/android:empty"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/empty_album" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/res/menu/gallery.xml b/res/menu/gallery.xml
new file mode 100644
index 0000000..dc36787
--- /dev/null
+++ b/res/menu/gallery.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+ <item
+ android:id="@+id/menu_camera"
+ android:icon="@android:drawable/ic_menu_camera"
+ android:showAsAction="ifRoom"
+ android:title="@string/menu_camera"/>
+ <item
+ android:id="@+id/menu_search"
+ android:icon="@android:drawable/ic_menu_search"
+ android:showAsAction="ifRoom"
+ android:title="@string/menu_search"/>
+ <item
+ android:id="@+id/menu_settings"
+ android:icon="@android:drawable/ic_menu_preferences"
+ android:showAsAction="never"
+ android:title="@string/settings"/>
+ <item
+ android:id="@+id/menu_help"
+ android:icon="@android:drawable/ic_menu_help"
+ android:showAsAction="never"
+ android:title="@string/help"/>
+</menu>
\ No newline at end of file
diff --git a/res/values-af/filtershow_strings.xml b/res/values-af/filtershow_strings.xml
index 9f5751e..34e5ebf 100644
--- a/res/values-af/filtershow_strings.xml
+++ b/res/values-af/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Outokleur"</string>
<string name="hue" msgid="6231252147971086030">"Kleur"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Skaduwees"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Kurwes"</string>
<string name="vignette" msgid="934721068851885390">"Vinjet"</string>
<string name="redeye" msgid="4508883127049472069">"Rooi oog"</string>
diff --git a/res/values-am/filtershow_strings.xml b/res/values-am/filtershow_strings.xml
index cf72a53..eb0549d 100644
--- a/res/values-am/filtershow_strings.xml
+++ b/res/values-am/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"ራስ-ቀለም መሙላት"</string>
<string name="hue" msgid="6231252147971086030">"የቀለም ድባብ"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"ጥላዎች"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"ጥምዞች"</string>
<string name="vignette" msgid="934721068851885390">"ቪኜት"</string>
<string name="redeye" msgid="4508883127049472069">"ቀይ አይን"</string>
diff --git a/res/values-ar/filtershow_strings.xml b/res/values-ar/filtershow_strings.xml
index ee1bfca..0310852 100644
--- a/res/values-ar/filtershow_strings.xml
+++ b/res/values-ar/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"لون تلقائي"</string>
<string name="hue" msgid="6231252147971086030">"تدرج اللون"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"ظلال"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"المنحنيات"</string>
<string name="vignette" msgid="934721068851885390">"نقوش صورة نصفية"</string>
<string name="redeye" msgid="4508883127049472069">"العين الحمراء"</string>
diff --git a/res/values-be/filtershow_strings.xml b/res/values-be/filtershow_strings.xml
index 06af904..73d96e0 100644
--- a/res/values-be/filtershow_strings.xml
+++ b/res/values-be/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Aўтаколер"</string>
<string name="hue" msgid="6231252147971086030">"Тон"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Цені"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Пэндзаль"</string>
<string name="vignette" msgid="934721068851885390">"Віньетка"</string>
<string name="redeye" msgid="4508883127049472069">"Чырвонае вока"</string>
diff --git a/res/values-bg/filtershow_strings.xml b/res/values-bg/filtershow_strings.xml
index cc4daae..f6e9cdc 100644
--- a/res/values-bg/filtershow_strings.xml
+++ b/res/values-bg/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Авт. цвят"</string>
<string name="hue" msgid="6231252147971086030">"Нюанс"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Засенчване"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Извивки"</string>
<string name="vignette" msgid="934721068851885390">"Винетиране"</string>
<string name="redeye" msgid="4508883127049472069">"Червени очи"</string>
diff --git a/res/values-ca/filtershow_strings.xml b/res/values-ca/filtershow_strings.xml
index 5f4b8e1..6c291e8 100644
--- a/res/values-ca/filtershow_strings.xml
+++ b/res/values-ca/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autocolor"</string>
<string name="hue" msgid="6231252147971086030">"To de color"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Ombres"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Corbes"</string>
<string name="vignette" msgid="934721068851885390">"Vinyeta"</string>
<string name="redeye" msgid="4508883127049472069">"Ulls vermells"</string>
diff --git a/res/values-cs/filtershow_strings.xml b/res/values-cs/filtershow_strings.xml
index e0c59f5..9b1db5f 100644
--- a/res/values-cs/filtershow_strings.xml
+++ b/res/values-cs/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autom. barva"</string>
<string name="hue" msgid="6231252147971086030">"Odstín"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Stíny"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Křivky"</string>
<string name="vignette" msgid="934721068851885390">"Viněta"</string>
<string name="redeye" msgid="4508883127049472069">"Červené oči"</string>
diff --git a/res/values-da/filtershow_strings.xml b/res/values-da/filtershow_strings.xml
index bc5ed33..58fa4fd 100644
--- a/res/values-da/filtershow_strings.xml
+++ b/res/values-da/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Automatisk farve"</string>
<string name="hue" msgid="6231252147971086030">"Nuance"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Skygger"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Kurver"</string>
<string name="vignette" msgid="934721068851885390">"Vignet"</string>
<string name="redeye" msgid="4508883127049472069">"Røde øjne"</string>
diff --git a/res/values-de/filtershow_strings.xml b/res/values-de/filtershow_strings.xml
index 0c660bc..c6ce09d 100644
--- a/res/values-de/filtershow_strings.xml
+++ b/res/values-de/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autom. Farbe"</string>
<string name="hue" msgid="6231252147971086030">"Farbton"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Schatten"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Kurven"</string>
<string name="vignette" msgid="934721068851885390">"Vignettierung"</string>
<string name="redeye" msgid="4508883127049472069">"Rote Augen"</string>
diff --git a/res/values-el/filtershow_strings.xml b/res/values-el/filtershow_strings.xml
index 40acfdc..0f23e0f 100644
--- a/res/values-el/filtershow_strings.xml
+++ b/res/values-el/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Αυτόματο χρώμα"</string>
<string name="hue" msgid="6231252147971086030">"Απόχρωση"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Σκιές"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Καμπύλες"</string>
<string name="vignette" msgid="934721068851885390">"Βινιετάρισμα"</string>
<string name="redeye" msgid="4508883127049472069">"Κόκκινα μάτια"</string>
diff --git a/res/values-en-rGB/filtershow_strings.xml b/res/values-en-rGB/filtershow_strings.xml
index ad6e4e0..a1fba2f 100644
--- a/res/values-en-rGB/filtershow_strings.xml
+++ b/res/values-en-rGB/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autocolour"</string>
<string name="hue" msgid="6231252147971086030">"Hue"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Shadows"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Curves"</string>
<string name="vignette" msgid="934721068851885390">"Vignette"</string>
<string name="redeye" msgid="4508883127049472069">"Red Eye"</string>
diff --git a/res/values-es-rUS/filtershow_strings.xml b/res/values-es-rUS/filtershow_strings.xml
index e3a9a8e..96c7678 100644
--- a/res/values-es-rUS/filtershow_strings.xml
+++ b/res/values-es-rUS/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Color autom."</string>
<string name="hue" msgid="6231252147971086030">"Tono"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Sombras"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Curvas"</string>
<string name="vignette" msgid="934721068851885390">"Viñeta"</string>
<string name="redeye" msgid="4508883127049472069">"Ojos rojos"</string>
diff --git a/res/values-es/filtershow_strings.xml b/res/values-es/filtershow_strings.xml
index e3820fa..0f0d69e 100644
--- a/res/values-es/filtershow_strings.xml
+++ b/res/values-es/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Color automático"</string>
<string name="hue" msgid="6231252147971086030">"Tonalidad"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Sombras"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Curvar"</string>
<string name="vignette" msgid="934721068851885390">"Viñeta"</string>
<string name="redeye" msgid="4508883127049472069">"Ojos rojos"</string>
diff --git a/res/values-et/filtershow_strings.xml b/res/values-et/filtershow_strings.xml
index d7be6e5..f741463 100644
--- a/res/values-et/filtershow_strings.xml
+++ b/res/values-et/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autom. värvid"</string>
<string name="hue" msgid="6231252147971086030">"Värvitoon"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Varjud"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Kõverad"</string>
<string name="vignette" msgid="934721068851885390">"Vinjett"</string>
<string name="redeye" msgid="4508883127049472069">"Punasilmsus"</string>
diff --git a/res/values-fa/filtershow_strings.xml b/res/values-fa/filtershow_strings.xml
index 3051612..30fb365 100644
--- a/res/values-fa/filtershow_strings.xml
+++ b/res/values-fa/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"رنگ خودکار"</string>
<string name="hue" msgid="6231252147971086030">"رنگمایه"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"سایهها"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"نمودارها"</string>
<string name="vignette" msgid="934721068851885390">"محو لبهها"</string>
<string name="redeye" msgid="4508883127049472069">"قرمزی چشم"</string>
diff --git a/res/values-fi/filtershow_strings.xml b/res/values-fi/filtershow_strings.xml
index 1c9491c..44ca6c3 100644
--- a/res/values-fi/filtershow_strings.xml
+++ b/res/values-fi/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autom. värit"</string>
<string name="hue" msgid="6231252147971086030">"Sävy"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Tummat alueet"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Valotuskäyrät"</string>
<string name="vignette" msgid="934721068851885390">"Vinjetti"</string>
<string name="redeye" msgid="4508883127049472069">"Punasilmäisyys"</string>
diff --git a/res/values-fr/filtershow_strings.xml b/res/values-fr/filtershow_strings.xml
index 868e61a..b6ffb6e 100644
--- a/res/values-fr/filtershow_strings.xml
+++ b/res/values-fr/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Coloration auto"</string>
<string name="hue" msgid="6231252147971086030">"Teinte"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Ombres"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Courbes"</string>
<string name="vignette" msgid="934721068851885390">"Vignetage"</string>
<string name="redeye" msgid="4508883127049472069">"Yeux rouges"</string>
diff --git a/res/values-hi/filtershow_strings.xml b/res/values-hi/filtershow_strings.xml
index 88ac1a4..30d47c8 100644
--- a/res/values-hi/filtershow_strings.xml
+++ b/res/values-hi/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"ऑटोकलर"</string>
<string name="hue" msgid="6231252147971086030">"ह्यू"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"छाया"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"वक्र"</string>
<string name="vignette" msgid="934721068851885390">"विनेट"</string>
<string name="redeye" msgid="4508883127049472069">"रेड आई"</string>
diff --git a/res/values-hr/filtershow_strings.xml b/res/values-hr/filtershow_strings.xml
index ee4b51d..99a3721 100644
--- a/res/values-hr/filtershow_strings.xml
+++ b/res/values-hr/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Automatska boja"</string>
<string name="hue" msgid="6231252147971086030">"Nijansa"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Sjenke"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Krivulje"</string>
<string name="vignette" msgid="934721068851885390">"Vinjeta"</string>
<string name="redeye" msgid="4508883127049472069">"Crvene oči"</string>
diff --git a/res/values-hu/filtershow_strings.xml b/res/values-hu/filtershow_strings.xml
index cb0a78e..f577e0b 100644
--- a/res/values-hu/filtershow_strings.xml
+++ b/res/values-hu/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Automat. szín"</string>
<string name="hue" msgid="6231252147971086030">"Színárnyalat"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Árnyékok"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Görbék"</string>
<string name="vignette" msgid="934721068851885390">"Vignetta"</string>
<string name="redeye" msgid="4508883127049472069">"Vörösszem"</string>
diff --git a/res/values-in/filtershow_strings.xml b/res/values-in/filtershow_strings.xml
index eb30676..39f407f 100644
--- a/res/values-in/filtershow_strings.xml
+++ b/res/values-in/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Warna Otomatis"</string>
<string name="hue" msgid="6231252147971086030">"Rona"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Bayangan"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Kurva"</string>
<string name="vignette" msgid="934721068851885390">"Vinyet"</string>
<string name="redeye" msgid="4508883127049472069">"Mata Merah"</string>
diff --git a/res/values-it/filtershow_strings.xml b/res/values-it/filtershow_strings.xml
index 8de522c..ac4294a 100644
--- a/res/values-it/filtershow_strings.xml
+++ b/res/values-it/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Colore autom."</string>
<string name="hue" msgid="6231252147971086030">"Tonalità"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Ombre"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Curve"</string>
<string name="vignette" msgid="934721068851885390">"Vignetta"</string>
<string name="redeye" msgid="4508883127049472069">"Occhi rossi"</string>
diff --git a/res/values-iw/filtershow_strings.xml b/res/values-iw/filtershow_strings.xml
index 36f7a51..c740611 100644
--- a/res/values-iw/filtershow_strings.xml
+++ b/res/values-iw/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"צבע אוטומטי"</string>
<string name="hue" msgid="6231252147971086030">"גוון"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"צלליות"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"קימורים"</string>
<string name="vignette" msgid="934721068851885390">"עמעום קצוות"</string>
<string name="redeye" msgid="4508883127049472069">"עיניים אדומות"</string>
diff --git a/res/values-ja/filtershow_strings.xml b/res/values-ja/filtershow_strings.xml
index 8ad69e1..289faef 100644
--- a/res/values-ja/filtershow_strings.xml
+++ b/res/values-ja/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"自動色補正"</string>
<string name="hue" msgid="6231252147971086030">"色彩"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"影"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"カーブ"</string>
<string name="vignette" msgid="934721068851885390">"周辺減光"</string>
<string name="redeye" msgid="4508883127049472069">"赤目処理"</string>
diff --git a/res/values-ko/filtershow_strings.xml b/res/values-ko/filtershow_strings.xml
index 9a7005b..b2eb59a 100644
--- a/res/values-ko/filtershow_strings.xml
+++ b/res/values-ko/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"자동 색상"</string>
<string name="hue" msgid="6231252147971086030">"색조"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"그림자"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"곡선"</string>
<string name="vignette" msgid="934721068851885390">"비네트"</string>
<string name="redeye" msgid="4508883127049472069">"적목현상 없애기"</string>
diff --git a/res/values-lt/filtershow_strings.xml b/res/values-lt/filtershow_strings.xml
index 06e6d28..819e668 100644
--- a/res/values-lt/filtershow_strings.xml
+++ b/res/values-lt/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autom. spalva"</string>
<string name="hue" msgid="6231252147971086030">"Atspalvis"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Šešėliai"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Kreivės"</string>
<string name="vignette" msgid="934721068851885390">"Vinjetė"</string>
<string name="redeye" msgid="4508883127049472069">"Raudonos akys"</string>
diff --git a/res/values-lv/filtershow_strings.xml b/res/values-lv/filtershow_strings.xml
index 9ac6f7f..29e1afd 100644
--- a/res/values-lv/filtershow_strings.xml
+++ b/res/values-lv/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Aut. krāsu pal."</string>
<string name="hue" msgid="6231252147971086030">"Nokrāsa"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Ēnas"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Līknes"</string>
<string name="vignette" msgid="934721068851885390">"Vinjete"</string>
<string name="redeye" msgid="4508883127049472069">"Sarkano acu ef."</string>
diff --git a/res/values-ms/filtershow_strings.xml b/res/values-ms/filtershow_strings.xml
index ee7287c..d175a44 100644
--- a/res/values-ms/filtershow_strings.xml
+++ b/res/values-ms/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autowarna"</string>
<string name="hue" msgid="6231252147971086030">"Rona"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Bayang-bayang"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Lengkung"</string>
<string name="vignette" msgid="934721068851885390">"Vignet"</string>
<string name="redeye" msgid="4508883127049472069">"Mata Merah"</string>
diff --git a/res/values-nb/filtershow_strings.xml b/res/values-nb/filtershow_strings.xml
index 3f0f06a..84cee67 100644
--- a/res/values-nb/filtershow_strings.xml
+++ b/res/values-nb/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autofarger"</string>
<string name="hue" msgid="6231252147971086030">"Nyanse"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Skygger"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Kurver"</string>
<string name="vignette" msgid="934721068851885390">"Vignettering"</string>
<string name="redeye" msgid="4508883127049472069">"Røde øyne"</string>
diff --git a/res/values-nl/filtershow_strings.xml b/res/values-nl/filtershow_strings.xml
index 8bbbe3b..1876a4a 100644
--- a/res/values-nl/filtershow_strings.xml
+++ b/res/values-nl/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Auto-kleur"</string>
<string name="hue" msgid="6231252147971086030">"Kleurschakering"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Schaduw"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Curven"</string>
<string name="vignette" msgid="934721068851885390">"Vervloeien"</string>
<string name="redeye" msgid="4508883127049472069">"Rode ogen"</string>
diff --git a/res/values-pl/filtershow_strings.xml b/res/values-pl/filtershow_strings.xml
index 48a45cc..a658e50 100644
--- a/res/values-pl/filtershow_strings.xml
+++ b/res/values-pl/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autokolor"</string>
<string name="hue" msgid="6231252147971086030">"Odcień"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Cienie"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Krzywe"</string>
<string name="vignette" msgid="934721068851885390">"Winietowanie"</string>
<string name="redeye" msgid="4508883127049472069">"Czerwone oczy"</string>
diff --git a/res/values-pt-rPT/filtershow_strings.xml b/res/values-pt-rPT/filtershow_strings.xml
index e94bf45..9dd5bb8 100644
--- a/res/values-pt-rPT/filtershow_strings.xml
+++ b/res/values-pt-rPT/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Cor automática"</string>
<string name="hue" msgid="6231252147971086030">"Tonalidade"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Sombras"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Curvas"</string>
<string name="vignette" msgid="934721068851885390">"Vinheta"</string>
<string name="redeye" msgid="4508883127049472069">"Olhos Vermelhos"</string>
diff --git a/res/values-pt/filtershow_strings.xml b/res/values-pt/filtershow_strings.xml
index 8c80270..3ab7d02 100644
--- a/res/values-pt/filtershow_strings.xml
+++ b/res/values-pt/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Cor automática"</string>
<string name="hue" msgid="6231252147971086030">"Matiz"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Sombras"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Curvas"</string>
<string name="vignette" msgid="934721068851885390">"Vinheta"</string>
<string name="redeye" msgid="4508883127049472069">"Olhos vermelhos"</string>
diff --git a/res/values-ro/filtershow_strings.xml b/res/values-ro/filtershow_strings.xml
index 46be094..688965b 100644
--- a/res/values-ro/filtershow_strings.xml
+++ b/res/values-ro/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Culoare auto."</string>
<string name="hue" msgid="6231252147971086030">"Tonalitate"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Umbre"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Curbe"</string>
<string name="vignette" msgid="934721068851885390">"Vignetare"</string>
<string name="redeye" msgid="4508883127049472069">"Ochi roşii"</string>
diff --git a/res/values-ru/filtershow_strings.xml b/res/values-ru/filtershow_strings.xml
index 42d6db5..cb69521 100644
--- a/res/values-ru/filtershow_strings.xml
+++ b/res/values-ru/filtershow_strings.xml
@@ -45,7 +45,7 @@
<string name="aspect5to7_effect" msgid="5122395569059384741">"5:7"</string>
<string name="aspect7to5_effect" msgid="5780001758108328143">"7:5"</string>
<string name="aspect9to16_effect" msgid="7740468012919660728">"16:9"</string>
- <string name="aspectNone_effect" msgid="6263330561046574134">"Оригинал"</string>
+ <string name="aspectNone_effect" msgid="6263330561046574134">"Вручную"</string>
<!-- no translation found for aspectOriginal_effect (5678516555493036594) -->
<skip />
<string name="Fixed" msgid="8017376448916924565">"Постоянное"</string>
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Авторежим"</string>
<string name="hue" msgid="6231252147971086030">"Оттенок"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Тени"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Кривые"</string>
<string name="vignette" msgid="934721068851885390">"Виньет-ние"</string>
<string name="redeye" msgid="4508883127049472069">"Красные глаза"</string>
diff --git a/res/values-sk/filtershow_strings.xml b/res/values-sk/filtershow_strings.xml
index a49bd3c..3d57b44 100644
--- a/res/values-sk/filtershow_strings.xml
+++ b/res/values-sk/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autom. farba"</string>
<string name="hue" msgid="6231252147971086030">"Odtieň"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Tiene"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Krivky"</string>
<string name="vignette" msgid="934721068851885390">"Vineta"</string>
<string name="redeye" msgid="4508883127049472069">"Červené oči"</string>
diff --git a/res/values-sl/filtershow_strings.xml b/res/values-sl/filtershow_strings.xml
index e0539e3..dbf2e4b 100644
--- a/res/values-sl/filtershow_strings.xml
+++ b/res/values-sl/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Samodej. barva"</string>
<string name="hue" msgid="6231252147971086030">"Odtenek"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Sence"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Krivulje"</string>
<string name="vignette" msgid="934721068851885390">"Vinjeta"</string>
<string name="redeye" msgid="4508883127049472069">"Rdeče oči"</string>
diff --git a/res/values-sr/filtershow_strings.xml b/res/values-sr/filtershow_strings.xml
index d5837d9..af002bf 100644
--- a/res/values-sr/filtershow_strings.xml
+++ b/res/values-sr/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Аутоматска боја"</string>
<string name="hue" msgid="6231252147971086030">"Нијанса"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Сенке"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Криве"</string>
<string name="vignette" msgid="934721068851885390">"Вињета"</string>
<string name="redeye" msgid="4508883127049472069">"Црвене очи"</string>
diff --git a/res/values-sv/filtershow_strings.xml b/res/values-sv/filtershow_strings.xml
index f43c7d2..12057c3 100644
--- a/res/values-sv/filtershow_strings.xml
+++ b/res/values-sv/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autofärg"</string>
<string name="hue" msgid="6231252147971086030">"Nyans"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Skuggor"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Kurvor"</string>
<string name="vignette" msgid="934721068851885390">"Vignette"</string>
<string name="redeye" msgid="4508883127049472069">"Röda ögon"</string>
diff --git a/res/values-sw/filtershow_strings.xml b/res/values-sw/filtershow_strings.xml
index 9f26a05..9b5f243 100644
--- a/res/values-sw/filtershow_strings.xml
+++ b/res/values-sw/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Rangi otomatiki"</string>
<string name="hue" msgid="6231252147971086030">"Rangi"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Vivuli"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Pindo"</string>
<string name="vignette" msgid="934721068851885390">"Vignete"</string>
<string name="redeye" msgid="4508883127049472069">"Jicho Jekundu"</string>
diff --git a/res/values-th/filtershow_strings.xml b/res/values-th/filtershow_strings.xml
index 1f86b14..f508315 100644
--- a/res/values-th/filtershow_strings.xml
+++ b/res/values-th/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"ให้สีอัตโนมัติ"</string>
<string name="hue" msgid="6231252147971086030">"สี"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"เงา"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"เส้นโค้ง"</string>
<string name="vignette" msgid="934721068851885390">"วิกเน็ตต์"</string>
<string name="redeye" msgid="4508883127049472069">"ตาแดง"</string>
diff --git a/res/values-tl/filtershow_strings.xml b/res/values-tl/filtershow_strings.xml
index 8ea767a..fee5bfe 100644
--- a/res/values-tl/filtershow_strings.xml
+++ b/res/values-tl/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Autocolor"</string>
<string name="hue" msgid="6231252147971086030">"Hue"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Mga Shadow"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Mga Kurba"</string>
<string name="vignette" msgid="934721068851885390">"Vignette"</string>
<string name="redeye" msgid="4508883127049472069">"Red Eye"</string>
diff --git a/res/values-tr/filtershow_strings.xml b/res/values-tr/filtershow_strings.xml
index cdc8189..d9808ae 100644
--- a/res/values-tr/filtershow_strings.xml
+++ b/res/values-tr/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Otomatik Renk"</string>
<string name="hue" msgid="6231252147971086030">"Hue"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Gölgeler"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Eğriler"</string>
<string name="vignette" msgid="934721068851885390">"Vinyet"</string>
<string name="redeye" msgid="4508883127049472069">"Kırmızı Göz"</string>
diff --git a/res/values-uk/filtershow_strings.xml b/res/values-uk/filtershow_strings.xml
index a05ef93..e2f4d92 100644
--- a/res/values-uk/filtershow_strings.xml
+++ b/res/values-uk/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Автоколір"</string>
<string name="hue" msgid="6231252147971086030">"Тон"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Тіні"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Криві"</string>
<string name="vignette" msgid="934721068851885390">"Віньєтка"</string>
<string name="redeye" msgid="4508883127049472069">"Червоні очі"</string>
diff --git a/res/values-v14/styles.xml b/res/values-v14/styles.xml
index 18f3440..18610cb 100644
--- a/res/values-v14/styles.xml
+++ b/res/values-v14/styles.xml
@@ -22,4 +22,6 @@
<style name="ActionBarTwoLineItem">
<item name="android:background">?android:attr/activatedBackgroundIndicator</item>
</style>
+ <style name="Theme.Photos.Gallery" parent="android:Theme.Holo.Light">
+ </style>
</resources>
diff --git a/res/values-vi/filtershow_strings.xml b/res/values-vi/filtershow_strings.xml
index 0f4c9d3..7e2d56b 100644
--- a/res/values-vi/filtershow_strings.xml
+++ b/res/values-vi/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"Màu tự động"</string>
<string name="hue" msgid="6231252147971086030">"Màu sắc"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Bóng"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Đồ thị màu"</string>
<string name="vignette" msgid="934721068851885390">"Làm mờ nét ảnh"</string>
<string name="redeye" msgid="4508883127049472069">"Mắt đỏ"</string>
diff --git a/res/values-zh-rCN/filtershow_strings.xml b/res/values-zh-rCN/filtershow_strings.xml
index 8876ce8..958f009 100644
--- a/res/values-zh-rCN/filtershow_strings.xml
+++ b/res/values-zh-rCN/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"自动调整色彩"</string>
<string name="hue" msgid="6231252147971086030">"色调"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"阴影"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"曲线"</string>
<string name="vignette" msgid="934721068851885390">"晕影"</string>
<string name="redeye" msgid="4508883127049472069">"红眼"</string>
diff --git a/res/values-zh-rTW/filtershow_strings.xml b/res/values-zh-rTW/filtershow_strings.xml
index 8f205fb..eb4526c 100644
--- a/res/values-zh-rTW/filtershow_strings.xml
+++ b/res/values-zh-rTW/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"自動色彩校正"</string>
<string name="hue" msgid="6231252147971086030">"色調"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"陰影"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"曲線"</string>
<string name="vignette" msgid="934721068851885390">"暈影"</string>
<string name="redeye" msgid="4508883127049472069">"紅眼"</string>
diff --git a/res/values-zu/filtershow_strings.xml b/res/values-zu/filtershow_strings.xml
index 5798c10..5439804 100644
--- a/res/values-zu/filtershow_strings.xml
+++ b/res/values-zu/filtershow_strings.xml
@@ -59,6 +59,8 @@
<string name="wbalance" msgid="6346581563387083613">"I-Autocolor"</string>
<string name="hue" msgid="6231252147971086030">"I-Hue"</string>
<string name="shadow_recovery" msgid="3928572915300287152">"Izithunzi"</string>
+ <!-- no translation found for highlight_recovery (8262208470735204243) -->
+ <skip />
<string name="curvesRGB" msgid="915010781090477550">"Ukugobeka"</string>
<string name="vignette" msgid="934721068851885390">"I-Vignette"</string>
<string name="redeye" msgid="4508883127049472069">"Iso elibomvu"</string>
diff --git a/res/values/filtershow_ids.xml b/res/values/filtershow_ids.xml
index ba31834..28e7816 100644
--- a/res/values/filtershow_ids.xml
+++ b/res/values/filtershow_ids.xml
@@ -28,6 +28,7 @@
<item type="id" name="hueButton" />
<item type="id" name="exposureButton" />
<item type="id" name="shadowRecoveryButton" />
+ <item type="id" name="highlightRecoveryButton" />
<item type="id" name="sharpenButton" />
<item type="id" name="curvesButtonRGB" />
<item type="id" name="negativeButton" />
diff --git a/res/values/filtershow_strings.xml b/res/values/filtershow_strings.xml
index 66fb390..3e9e355 100644
--- a/res/values/filtershow_strings.xml
+++ b/res/values/filtershow_strings.xml
@@ -23,6 +23,8 @@
<string name="cannot_load_image">Cannot load the image!</string>
<!-- String displayed when showing the original image [CHAR LIMIT=NONE] -->
<string name="original_picture_text">@string/original</string>
+ <!-- String displayed when setting the homepage wallpaper in the background [CHAR LIMIT=NONE] -->
+ <string name="setting_wallpaper">Setting wallpaper</string>
<!-- generic strings -->
@@ -115,6 +117,8 @@
<string name="hue">Hue</string>
<!-- Label for the image shadow recovery (lightens/darkens shadows) filter button [CHAR LIMIT=10] -->
<string name="shadow_recovery">Shadows</string>
+ <!-- Label for the image highlights recovery (lightens/darkens bright regions) filter button [CHAR LIMIT=15] -->
+ <string name="highlight_recovery">Highlights</string>
<!-- Label for the image curves filter button [CHAR LIMIT=10] -->
<string name="curvesRGB">Curves</string>
<!-- Label for the image vignette filter (darkens photo around edges) button [CHAR LIMIT=10] -->
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fae3466..263b8b1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1002,4 +1002,12 @@
<!-- Positive answer for first run dialog asking if the user wants to remember photo locations [CHAR LIMIT = 20] -->
<string name="remember_location_yes">Yes</string>
+ <!-- Menu item to launch the camera app [CHAR LIMIT=25] -->
+ <string name="menu_camera">Camera</string>
+ <!-- Menu item to search for photos [CHAR LIMIT=25] -->
+ <string name="menu_search">Search</string>
+ <!-- Title for the all photos tab [CHAR LIMIT=25] -->
+ <string name="tab_photos">Photos</string>
+ <!-- Title for the albums tab [CHAR LIMIT=25] -->
+ <string name="tab_albums">Albums</string>
</resources>
diff --git a/src/android/util/Pools.java b/src/android/util/Pools.java
new file mode 100644
index 0000000..40bab1e
--- /dev/null
+++ b/src/android/util/Pools.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ * Helper class for crating pools of objects. An example use looks like this:
+ * <pre>
+ * public class MyPooledClass {
+ *
+ * private static final SynchronizedPool<MyPooledClass> sPool =
+ * new SynchronizedPool<MyPooledClass>(10);
+ *
+ * public static MyPooledClass obtain() {
+ * MyPooledClass instance = sPool.acquire();
+ * return (instance != null) ? instance : new MyPooledClass();
+ * }
+ *
+ * public void recycle() {
+ * // Clear state if needed.
+ * sPool.release(this);
+ * }
+ *
+ * . . .
+ * }
+ * </pre>
+ *
+ * @hide
+ */
+public final class Pools {
+
+ /**
+ * Interface for managing a pool of objects.
+ *
+ * @param <T> The pooled type.
+ */
+ public static interface Pool<T> {
+
+ /**
+ * @return An instance from the pool if such, null otherwise.
+ */
+ public T acquire();
+
+ /**
+ * Release an instance to the pool.
+ *
+ * @param instance The instance to release.
+ * @return Whether the instance was put in the pool.
+ *
+ * @throws IllegalStateException If the instance is already in the pool.
+ */
+ public boolean release(T instance);
+ }
+
+ private Pools() {
+ /* do nothing - hiding constructor */
+ }
+
+ /**
+ * Simple (non-synchronized) pool of objects.
+ *
+ * @param <T> The pooled type.
+ */
+ public static class SimplePool<T> implements Pool<T> {
+ private final Object[] mPool;
+
+ private int mPoolSize;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param maxPoolSize The max pool size.
+ *
+ * @throws IllegalArgumentException If the max pool size is less than zero.
+ */
+ public SimplePool(int maxPoolSize) {
+ if (maxPoolSize <= 0) {
+ throw new IllegalArgumentException("The max pool size must be > 0");
+ }
+ mPool = new Object[maxPoolSize];
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T acquire() {
+ if (mPoolSize > 0) {
+ final int lastPooledIndex = mPoolSize - 1;
+ T instance = (T) mPool[lastPooledIndex];
+ mPool[lastPooledIndex] = null;
+ mPoolSize--;
+ return instance;
+ }
+ return null;
+ }
+
+ @Override
+ public boolean release(T instance) {
+ if (isInPool(instance)) {
+ throw new IllegalStateException("Already in the pool!");
+ }
+ if (mPoolSize < mPool.length) {
+ mPool[mPoolSize] = instance;
+ mPoolSize++;
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isInPool(T instance) {
+ for (int i = 0; i < mPoolSize; i++) {
+ if (mPool[i] == instance) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Synchronized) pool of objects.
+ *
+ * @param <T> The pooled type.
+ */
+ public static class SynchronizedPool<T> extends SimplePool<T> {
+ private final Object mLock = new Object();
+
+ /**
+ * Creates a new instance.
+ *
+ * @param maxPoolSize The max pool size.
+ *
+ * @throws IllegalArgumentException If the max pool size is less than zero.
+ */
+ public SynchronizedPool(int maxPoolSize) {
+ super(maxPoolSize);
+ }
+
+ @Override
+ public T acquire() {
+ synchronized (mLock) {
+ return super.acquire();
+ }
+ }
+
+ @Override
+ public boolean release(T element) {
+ synchronized (mLock) {
+ return super.release(element);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/camera/CaptureAnimManager.java b/src/com/android/camera/CaptureAnimManager.java
index 4643c37..ec38290 100644
--- a/src/com/android/camera/CaptureAnimManager.java
+++ b/src/com/android/camera/CaptureAnimManager.java
@@ -33,9 +33,9 @@
// times mark endpoint of animation phase
private static final int TIME_FLASH = 200;
private static final int TIME_HOLD = 400;
- private static final int TIME_SLIDE = 700;
- private static final int TIME_HOLD2 = 1000;
- private static final int TIME_SLIDE2 = 1200;
+ private static final int TIME_SLIDE = 800;
+ private static final int TIME_HOLD2 = 3300;
+ private static final int TIME_SLIDE2 = 4100;
private static final int ANIM_BOTH = 0;
private static final int ANIM_FLASH = 1;
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index 4d01bc3..245ef59 100644
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -2216,7 +2216,6 @@
initializeMiscControls();
showTimeLapseUI(mCaptureTimeLapse);
initializeVideoSnapshot();
- resizeForPreviewAspectRatio();
// from onResume()
showVideoSnapshotUI(false);
@@ -2279,6 +2278,7 @@
}
private void updateOnScreenIndicators() {
+ if (mParameters == null) return;
updateFlashOnScreenIndicator(mParameters.getFlashMode());
}
@@ -2436,7 +2436,7 @@
}
private void initializeZoom() {
- if (!mParameters.isZoomSupported()) return;
+ if (mParameters == null || !mParameters.isZoomSupported()) return;
mZoomMax = mParameters.getMaxZoom();
mZoomRatios = mParameters.getZoomRatios();
// Currently we use immediate zoom for fast zooming to get better UX and
@@ -2448,6 +2448,7 @@
}
private void initializeVideoSnapshot() {
+ if (mParameters == null) return;
if (Util.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) {
mActivity.setSingleTapUpListener(mPreviewFrameLayout);
// Show the tap to focus toast if this is the first start.
@@ -2462,6 +2463,7 @@
}
void showVideoSnapshotUI(boolean enabled) {
+ if (mParameters == null) return;
if (Util.isVideoSnapshotSupported(mParameters) && !mIsVideoCaptureIntent) {
if (ApiHelper.HAS_SURFACE_TEXTURE && enabled) {
((CameraScreenNail) mActivity.mCameraScreenNail).animateCapture(mDisplayRotation);
diff --git a/src/com/android/gallery3d/app/AbstractGalleryActivity.java b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
index c9cce81..d960942 100644
--- a/src/com/android/gallery3d/app/AbstractGalleryActivity.java
+++ b/src/com/android/gallery3d/app/AbstractGalleryActivity.java
@@ -38,9 +38,9 @@
import com.android.gallery3d.R;
import com.android.gallery3d.common.ApiHelper;
-import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.DataManager;
import com.android.gallery3d.data.MediaItem;
+import com.android.photos.data.GalleryBitmapPool;
import com.android.gallery3d.ui.GLRoot;
import com.android.gallery3d.ui.GLRootView;
import com.android.gallery3d.util.LightCycleHelper.PanoramaViewHelper;
@@ -222,16 +222,10 @@
} finally {
mGLRootView.unlockRenderThread();
}
- clearBitmapPool(MediaItem.getMicroThumbPool());
- clearBitmapPool(MediaItem.getThumbPool());
-
+ GalleryBitmapPool.getInstance().clear();
MediaItem.getBytesBufferPool().clear();
}
- private static void clearBitmapPool(BitmapPool pool) {
- if (pool != null) pool.clear();
- }
-
@Override
protected void onDestroy() {
super.onDestroy();
diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java
index faff146..d409315 100644
--- a/src/com/android/gallery3d/app/PhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java
@@ -23,7 +23,6 @@
import com.android.gallery3d.common.BitmapUtils;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.ContentListener;
import com.android.gallery3d.data.LocalMediaItem;
import com.android.gallery3d.data.MediaItem;
@@ -550,8 +549,8 @@
}
@Override
- public Bitmap getTile(int level, int x, int y, int tileSize, BitmapPool pool) {
- return mTileProvider.getTile(level, x, y, tileSize, pool);
+ public Bitmap getTile(int level, int x, int y, int tileSize) {
+ return mTileProvider.getTile(level, x, y, tileSize);
}
@Override
diff --git a/src/com/android/gallery3d/data/BitmapPool.java b/src/com/android/gallery3d/data/BitmapPool.java
deleted file mode 100644
index 5bc6d67..0000000
--- a/src/com/android/gallery3d/data/BitmapPool.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.gallery3d.data;
-
-import android.graphics.Bitmap;
-
-import com.android.gallery3d.common.Utils;
-
-import java.util.ArrayList;
-
-public class BitmapPool {
- @SuppressWarnings("unused")
- private static final String TAG = "BitmapPool";
-
- private final ArrayList<Bitmap> mPool;
- private final int mPoolLimit;
-
- // mOneSize is true if the pool can only cache Bitmap with one size.
- private final boolean mOneSize;
- private final int mWidth, mHeight; // only used if mOneSize is true
-
- // Construct a BitmapPool which caches bitmap with the specified size.
- public BitmapPool(int width, int height, int poolLimit) {
- mWidth = width;
- mHeight = height;
- mPoolLimit = poolLimit;
- mPool = new ArrayList<Bitmap>(poolLimit);
- mOneSize = true;
- }
-
- // Construct a BitmapPool which caches bitmap with any size;
- public BitmapPool(int poolLimit) {
- mWidth = -1;
- mHeight = -1;
- mPoolLimit = poolLimit;
- mPool = new ArrayList<Bitmap>(poolLimit);
- mOneSize = false;
- }
-
- // Get a Bitmap from the pool.
- public synchronized Bitmap getBitmap() {
- Utils.assertTrue(mOneSize);
- int size = mPool.size();
- return size > 0 ? mPool.remove(size - 1) : null;
- }
-
- // Get a Bitmap from the pool with the specified size.
- public synchronized Bitmap getBitmap(int width, int height) {
- Utils.assertTrue(!mOneSize);
- for (int i = mPool.size() - 1; i >= 0; i--) {
- Bitmap b = mPool.get(i);
- if (b.getWidth() == width && b.getHeight() == height) {
- return mPool.remove(i);
- }
- }
- return null;
- }
-
- // Put a Bitmap into the pool, if the Bitmap has a proper size. Otherwise
- // the Bitmap will be recycled. If the pool is full, an old Bitmap will be
- // recycled.
- public void recycle(Bitmap bitmap) {
- if (bitmap == null) return;
- if (mOneSize && ((bitmap.getWidth() != mWidth) ||
- (bitmap.getHeight() != mHeight))) {
- bitmap.recycle();
- return;
- }
- synchronized (this) {
- if (mPool.size() >= mPoolLimit) mPool.remove(0);
- mPool.add(bitmap);
- }
- }
-
- public synchronized void clear() {
- mPool.clear();
- }
-
- public boolean isOneSize() {
- return mOneSize;
- }
-}
diff --git a/src/com/android/gallery3d/data/DataManager.java b/src/com/android/gallery3d/data/DataManager.java
index 8fcf400..38865e9 100644
--- a/src/com/android/gallery3d/data/DataManager.java
+++ b/src/com/android/gallery3d/data/DataManager.java
@@ -16,13 +16,13 @@
package com.android.gallery3d.data;
+import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import com.android.gallery3d.app.GalleryApp;
import com.android.gallery3d.app.StitchingChangeListener;
-import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback;
import com.android.gallery3d.data.MediaSet.ItemConsumer;
@@ -65,6 +65,11 @@
// to prevent concurrency issue.
public static final Object LOCK = new Object();
+ public static DataManager from(Context context) {
+ GalleryApp app = (GalleryApp) context.getApplicationContext();
+ return app.getDataManager();
+ }
+
private static final String TAG = "DataManager";
// This is the path for the media set seen by the user at top level.
diff --git a/src/com/android/gallery3d/data/DecodeUtils.java b/src/com/android/gallery3d/data/DecodeUtils.java
index 4d3c996..fa70915 100644
--- a/src/com/android/gallery3d/data/DecodeUtils.java
+++ b/src/com/android/gallery3d/data/DecodeUtils.java
@@ -28,6 +28,7 @@
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.common.BitmapUtils;
import com.android.gallery3d.common.Utils;
+import com.android.photos.data.GalleryBitmapPool;
import com.android.gallery3d.ui.Log;
import com.android.gallery3d.util.ThreadPool.CancelListener;
import com.android.gallery3d.util.ThreadPool.JobContext;
@@ -246,21 +247,17 @@
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public static Bitmap decode(JobContext jc, byte[] data, int offset,
- int length, BitmapFactory.Options options, BitmapPool pool) {
- if (pool == null) {
- return decode(jc, data, offset, length, options);
- }
-
+ public static Bitmap decodeUsingPool(JobContext jc, byte[] data, int offset,
+ int length, BitmapFactory.Options options) {
if (options == null) options = new BitmapFactory.Options();
if (options.inSampleSize < 1) options.inSampleSize = 1;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inBitmap = (options.inSampleSize == 1)
- ? findCachedBitmap(pool, jc, data, offset, length, options) : null;
+ ? findCachedBitmap(jc, data, offset, length, options) : null;
try {
Bitmap bitmap = decode(jc, data, offset, length, options);
if (options.inBitmap != null && options.inBitmap != bitmap) {
- pool.recycle(options.inBitmap);
+ GalleryBitmapPool.getInstance().put(options.inBitmap);
options.inBitmap = null;
}
return bitmap;
@@ -268,7 +265,7 @@
if (options.inBitmap == null) throw e;
Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
- pool.recycle(options.inBitmap);
+ GalleryBitmapPool.getInstance().put(options.inBitmap);
options.inBitmap = null;
return decode(jc, data, offset, length, options);
}
@@ -277,21 +274,17 @@
// This is the same as the method above except the source data comes
// from a file descriptor instead of a byte array.
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public static Bitmap decode(JobContext jc,
- FileDescriptor fileDescriptor, Options options, BitmapPool pool) {
- if (pool == null) {
- return decode(jc, fileDescriptor, options);
- }
-
+ public static Bitmap decodeUsingPool(JobContext jc,
+ FileDescriptor fileDescriptor, Options options) {
if (options == null) options = new BitmapFactory.Options();
if (options.inSampleSize < 1) options.inSampleSize = 1;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inBitmap = (options.inSampleSize == 1)
- ? findCachedBitmap(pool, jc, fileDescriptor, options) : null;
+ ? findCachedBitmap(jc, fileDescriptor, options) : null;
try {
Bitmap bitmap = DecodeUtils.decode(jc, fileDescriptor, options);
if (options.inBitmap != null && options.inBitmap != bitmap) {
- pool.recycle(options.inBitmap);
+ GalleryBitmapPool.getInstance().put(options.inBitmap);
options.inBitmap = null;
}
return bitmap;
@@ -299,23 +292,21 @@
if (options.inBitmap == null) throw e;
Log.w(TAG, "decode fail with a given bitmap, try decode to a new bitmap");
- pool.recycle(options.inBitmap);
+ GalleryBitmapPool.getInstance().put(options.inBitmap);
options.inBitmap = null;
return decode(jc, fileDescriptor, options);
}
}
- private static Bitmap findCachedBitmap(BitmapPool pool, JobContext jc,
- byte[] data, int offset, int length, Options options) {
- if (pool.isOneSize()) return pool.getBitmap();
+ private static Bitmap findCachedBitmap(JobContext jc, byte[] data,
+ int offset, int length, Options options) {
decodeBounds(jc, data, offset, length, options);
- return pool.getBitmap(options.outWidth, options.outHeight);
+ return GalleryBitmapPool.getInstance().get(options.outWidth, options.outHeight);
}
- private static Bitmap findCachedBitmap(BitmapPool pool, JobContext jc,
- FileDescriptor fileDescriptor, Options options) {
- if (pool.isOneSize()) return pool.getBitmap();
+ private static Bitmap findCachedBitmap(JobContext jc, FileDescriptor fileDescriptor,
+ Options options) {
decodeBounds(jc, fileDescriptor, options);
- return pool.getBitmap(options.outWidth, options.outHeight);
+ return GalleryBitmapPool.getInstance().get(options.outWidth, options.outHeight);
}
}
diff --git a/src/com/android/gallery3d/data/ImageCacheRequest.java b/src/com/android/gallery3d/data/ImageCacheRequest.java
index 3f937e3..4756149 100644
--- a/src/com/android/gallery3d/data/ImageCacheRequest.java
+++ b/src/com/android/gallery3d/data/ImageCacheRequest.java
@@ -60,13 +60,11 @@
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap;
if (mType == MediaItem.TYPE_MICROTHUMBNAIL) {
- bitmap = DecodeUtils.decode(jc,
- buffer.data, buffer.offset, buffer.length, options,
- MediaItem.getMicroThumbPool());
+ bitmap = DecodeUtils.decodeUsingPool(jc,
+ buffer.data, buffer.offset, buffer.length, options);
} else {
- bitmap = DecodeUtils.decode(jc,
- buffer.data, buffer.offset, buffer.length, options,
- MediaItem.getThumbPool());
+ bitmap = DecodeUtils.decodeUsingPool(jc,
+ buffer.data, buffer.offset, buffer.length, options);
}
if (bitmap == null && !jc.isCancelled()) {
Log.w(TAG, "decode cached failed " + debugTag());
diff --git a/src/com/android/gallery3d/data/MediaItem.java b/src/com/android/gallery3d/data/MediaItem.java
index 19084d4..59ea865 100644
--- a/src/com/android/gallery3d/data/MediaItem.java
+++ b/src/com/android/gallery3d/data/MediaItem.java
@@ -42,15 +42,10 @@
private static final int BYTESBUFFER_SIZE = 200 * 1024;
private static int sMicrothumbnailTargetSize = 200;
- private static BitmapPool sMicroThumbPool;
private static final BytesBufferPool sMicroThumbBufferPool =
new BytesBufferPool(BYTESBUFFE_POOL_SIZE, BYTESBUFFER_SIZE);
private static int sThumbnailTargetSize = 640;
- private static final BitmapPool sThumbPool =
- ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_FACTORY
- ? new BitmapPool(4)
- : null;
// TODO: fix default value for latlng and change this.
public static final double INVALID_LATLNG = 0f;
@@ -126,33 +121,14 @@
}
}
- public static BitmapPool getMicroThumbPool() {
- if (ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_FACTORY && sMicroThumbPool == null) {
- initializeMicroThumbPool();
- }
- return sMicroThumbPool;
- }
-
- public static BitmapPool getThumbPool() {
- return sThumbPool;
- }
-
public static BytesBufferPool getBytesBufferPool() {
return sMicroThumbBufferPool;
}
- private static void initializeMicroThumbPool() {
- sMicroThumbPool =
- ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_FACTORY
- ? new BitmapPool(sMicrothumbnailTargetSize, sMicrothumbnailTargetSize, 16)
- : null;
- }
-
public static void setThumbnailSizes(int size, int microSize) {
sThumbnailTargetSize = size;
if (sMicrothumbnailTargetSize != microSize) {
sMicrothumbnailTargetSize = microSize;
- initializeMicroThumbPool();
}
}
}
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index f7147ea..fd30ac0 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -71,6 +71,7 @@
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.presets.ImagePreset;
import com.android.gallery3d.filtershow.provider.SharedImageProvider;
+import com.android.gallery3d.filtershow.tools.BitmapTask;
import com.android.gallery3d.filtershow.tools.SaveCopyTask;
import com.android.gallery3d.filtershow.ui.FilterIconButton;
import com.android.gallery3d.filtershow.ui.FramedTextButton;
@@ -151,6 +152,7 @@
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ImageFilter.setActivityForMemoryToasts(this);
setResources();
Resources res = getResources();
@@ -519,6 +521,9 @@
if (mLoadBitmapTask != null) {
mLoadBitmapTask.cancel(false);
}
+ MasterImage.reset();
+ FilteringPipeline.reset();
+ ImageFilter.resetStatics();
super.onDestroy();
}
@@ -814,7 +819,6 @@
}
public void hideImageViews() {
- mImageShow.setShowControls(false); // reset
for (View view : mImageViews) {
view.setVisibility(View.GONE);
}
@@ -1090,11 +1094,7 @@
mCropExtras.getOutputFormat(), this);
}
if (mSaveAsWallpaper) {
- try {
- WallpaperManager.getInstance(this).setBitmap(filtered);
- } catch (IOException e) {
- Log.w(LOGTAG, "fail to set wall paper", e);
- }
+ setWallpaperInBackground(filtered);
}
if (mReturnAsExtra) {
if (filtered != null) {
@@ -1117,6 +1117,28 @@
}
}
+ void setWallpaperInBackground(final Bitmap bmap) {
+ Toast.makeText(this, R.string.setting_wallpaper, Toast.LENGTH_LONG).show();
+ BitmapTask.Callbacks<FilterShowActivity> cb = new BitmapTask.Callbacks<FilterShowActivity>() {
+ @Override
+ public void onComplete(Bitmap result) {}
+
+ @Override
+ public void onCancel() {}
+
+ @Override
+ public Bitmap onExecute(FilterShowActivity param) {
+ try {
+ WallpaperManager.getInstance(param).setBitmap(bmap);
+ } catch (IOException e) {
+ Log.w(LOGTAG, "fail to set wall paper", e);
+ }
+ return null;
+ }
+ };
+ (new BitmapTask<FilterShowActivity>(cb)).execute(this);
+ }
+
public void done() {
if (mOutputted) {
hideSavingProgress();
diff --git a/src/com/android/gallery3d/filtershow/PanelController.java b/src/com/android/gallery3d/filtershow/PanelController.java
index 18a9585..5bda246 100644
--- a/src/com/android/gallery3d/filtershow/PanelController.java
+++ b/src/com/android/gallery3d/filtershow/PanelController.java
@@ -375,18 +375,20 @@
ImageShow image = null;
mActivity.hideImageViews();
for (View view : mImageViews) {
+ image = (ImageShow) view;
if (view.getId() == id) {
view.setVisibility(View.VISIBLE);
- image = (ImageShow) view;
+ image.select();
} else {
view.setVisibility(View.GONE);
+ image.unselect();
}
}
return image;
}
public void showDefaultImageView() {
- showImageView(R.id.imageShow).setShowControls(false);
+ showImageView(R.id.imageShow);
MasterImage.getImage().setCurrentFilter(null);
MasterImage.getImage().setCurrentFilterRepresentation(null);
}
@@ -498,7 +500,7 @@
}
mUtilityPanel.hideAccessoryViews();
- if (view instanceof FilterIconButton) {
+ if (view instanceof FilterIconButton && view.getId() != R.id.applyEffect) {
mCurrentEditor = null;
FilterIconButton component = (FilterIconButton) view;
FilterRepresentation representation = component.getFilterRepresentation();
@@ -515,7 +517,6 @@
mCurrentImage = showImageView(representation.getEditorId());
}
}
- mCurrentImage.setShowControls(representation.showEditingControls());
mUtilityPanel.setShowParameter(representation.showParameterValue());
mCurrentImage.select();
@@ -533,7 +534,7 @@
switch (view.getId()) {
case R.id.tinyplanetButton: {
- mCurrentImage = showImageView(R.id.imageTinyPlanet).setShowControls(true);
+ mCurrentImage = showImageView(R.id.imageTinyPlanet);
String ename = mCurrentImage.getContext().getString(R.string.tinyplanet);
mUtilityPanel.setEffectName(ename);
if (!mDisableFilterButtons) {
@@ -556,8 +557,8 @@
if (mCurrentImage instanceof ImageCrop && mUtilityPanel.firstTimeCropDisplayed) {
((ImageCrop) mCurrentImage).clear();
mUtilityPanel.firstTimeCropDisplayed = false;
+ ((ImageCrop) mCurrentImage).setFixedAspect(mFixedAspect);
}
- ((ImageCrop) mCurrentImage).setFixedAspect(mFixedAspect);
break;
}
case R.id.rotateButton: {
diff --git a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
index 419abe8..0af4063 100644
--- a/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
+++ b/src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
@@ -31,7 +31,7 @@
public class FilteringPipeline implements Handler.Callback {
- private final static FilteringPipeline gPipeline = new FilteringPipeline();
+ private static FilteringPipeline sPipeline;
private static final String LOGTAG = "FilteringPipeline";
private ImagePreset mPreviousGeometryPreset = null;
private ImagePreset mPreviousFiltersPreset = null;
@@ -48,6 +48,7 @@
private final static int NEW_RENDERING_REQUEST = 1;
private final static int COMPUTE_PRESET = 2;
private final static int COMPUTE_RENDERING_REQUEST = 3;
+ private final static int COMPUTE_PARTIAL_RENDERING_REQUEST = 4;
private Handler mProcessingHandler = null;
private final Handler mUIHandler = new Handler() {
@@ -81,7 +82,13 @@
mUIHandler.sendMessage(uimsg);
break;
}
- case COMPUTE_RENDERING_REQUEST: {
+ case COMPUTE_RENDERING_REQUEST:
+ case COMPUTE_PARTIAL_RENDERING_REQUEST: {
+ if (msg.what == COMPUTE_PARTIAL_RENDERING_REQUEST) {
+ if (mProcessingHandler.hasMessages(COMPUTE_PARTIAL_RENDERING_REQUEST)) {
+ return false;
+ }
+ }
RenderingRequest request = (RenderingRequest) msg.obj;
render(request);
Message uimsg = mUIHandler.obtainMessage(NEW_RENDERING_REQUEST);
@@ -95,6 +102,7 @@
private static float RESIZE_FACTOR = 0.8f;
private static float MAX_PROCESS_TIME = 100; // in ms
+ private static long HIRES_DELAY = 100; // in ms
private float mResizeFactor = 1.0f;
private long mResizeTime = 0;
@@ -109,7 +117,10 @@
}
public static FilteringPipeline getPipeline() {
- return gPipeline;
+ if (sPipeline == null) {
+ sPipeline = new FilteringPipeline();
+ }
+ return sPipeline;
}
public synchronized void setOriginal(Bitmap bitmap) {
@@ -165,9 +176,17 @@
if (mOriginalAllocation == null) {
return;
}
- Message msg = mProcessingHandler.obtainMessage(COMPUTE_RENDERING_REQUEST);
+ int type = COMPUTE_RENDERING_REQUEST;
+ if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+ type = COMPUTE_PARTIAL_RENDERING_REQUEST;
+ }
+ Message msg = mProcessingHandler.obtainMessage(type);
msg.obj = request;
- mProcessingHandler.sendMessage(msg);
+ if (type == COMPUTE_PARTIAL_RENDERING_REQUEST) {
+ mProcessingHandler.sendMessageDelayed(msg, HIRES_DELAY);
+ } else {
+ mProcessingHandler.sendMessage(msg);
+ }
}
public synchronized void updatePreviewBuffer() {
@@ -210,11 +229,15 @@
if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
return "GEOMETRY_RENDERING";
}
+ if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+ return "PARTIAL_RENDERING";
+ }
return "UNKNOWN TYPE!";
}
private void render(RenderingRequest request) {
- if (request.getBitmap() == null
+ if ((request.getType() != RenderingRequest.PARTIAL_RENDERING
+ && request.getBitmap() == null)
|| request.getImagePreset() == null) {
return;
}
@@ -225,11 +248,21 @@
Bitmap bitmap = request.getBitmap();
ImagePreset preset = request.getImagePreset();
setPresetParameters(preset);
+
+ if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+ bitmap = MasterImage.getImage().getImageLoader().getScaleOneImageForPreset(null, preset, request.getBounds(), request.getDestination(), false);
+ if (bitmap == null) {
+ return;
+ }
+ bitmap = preset.applyGeometry(bitmap);
+ }
+
if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
FiltersManager.getManager().resetBitmapsRS();
}
- if (request.getType() != RenderingRequest.ICON_RENDERING) {
+ if (request.getType() != RenderingRequest.ICON_RENDERING
+ && request.getType() != RenderingRequest.PARTIAL_RENDERING) {
updateOriginalAllocation(preset);
}
if (DEBUG) {
@@ -243,9 +276,11 @@
} else if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
mFiltersOnlyOriginalAllocation.copyTo(bitmap);
}
+
if (request.getType() == RenderingRequest.FULL_RENDERING
|| request.getType() == RenderingRequest.FILTERS_RENDERING
- || request.getType() == RenderingRequest.ICON_RENDERING) {
+ || request.getType() == RenderingRequest.ICON_RENDERING
+ || request.getType() == RenderingRequest.PARTIAL_RENDERING) {
Bitmap bmp = preset.apply(bitmap);
request.setBitmap(bmp);
}
@@ -305,4 +340,8 @@
public float getPreviewScaleFactor() {
return mPreviewScaleFactor;
}
+
+ public static void reset() {
+ sPipeline = null;
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
index 698992a..b502a2f 100644
--- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
+++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java
@@ -62,6 +62,8 @@
import java.util.Vector;
import java.util.concurrent.locks.ReentrantLock;
+
+// TODO: this class has waaaay to much bitmap copying. Cleanup.
public class ImageLoader {
private static final String LOGTAG = "ImageLoader";
@@ -91,6 +93,7 @@
public static final int ORI_TRANSPOSE = ExifInterface.ORIENTATION_TRANSPOSE;
public static final int ORI_TRANSVERSE = ExifInterface.ORIENTATION_TRANSVERSE;
+ private static final int BITMAP_LOAD_BACKOUT_ATTEMPTS = 5;
private Context mContext = null;
private Uri mUri = null;
@@ -264,12 +267,12 @@
bitmap.getHeight(), matrix, true);
}
- private Bitmap loadRegionBitmap(Uri uri, Rect bounds) {
+ private Bitmap loadRegionBitmap(Uri uri, BitmapFactory.Options options, Rect bounds) {
InputStream is = null;
try {
is = mContext.getContentResolver().openInputStream(uri);
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
- return decoder.decodeRegion(bounds, null);
+ return decoder.decodeRegion(bounds, options);
} catch (FileNotFoundException e) {
Log.e(LOGTAG, "FileNotFoundException: " + uri);
} catch (Exception e) {
@@ -369,21 +372,36 @@
// FIXME: this currently does the loading + filtering on the UI thread --
// need to move this to a background thread.
public Bitmap getScaleOneImageForPreset(ImageShow caller, ImagePreset imagePreset, Rect bounds,
- boolean force) {
+ Rect destination, boolean force) {
mLoadingLock.lock();
Bitmap bmp = mZoomCache.getImage(imagePreset, bounds);
if (force || bmp == null) {
- bmp = loadRegionBitmap(mUri, bounds);
+ BitmapFactory.Options options = null;
+ if (destination != null) {
+ options = new BitmapFactory.Options();
+ if (bounds.width() > destination.width()) {
+ int sampleSize = 1;
+ int w = bounds.width();
+ while (w > destination.width()) {
+ sampleSize *= 2;
+ w /= sampleSize;
+ }
+ options.inSampleSize = sampleSize;
+ }
+ }
+ bmp = loadRegionBitmap(mUri, options, bounds);
+ if (destination != null) {
+ mLoadingLock.unlock();
+ return bmp;
+ }
if (bmp != null) {
- // TODO: this workaround for RS might not be needed ultimately
- Bitmap bmp2 = bmp.copy(Bitmap.Config.ARGB_8888, true);
float scaleFactor = imagePreset.getScaleFactor();
imagePreset.setScaleFactor(1.0f);
- bmp2 = imagePreset.apply(bmp2);
+ bmp = imagePreset.apply(bmp);
imagePreset.setScaleFactor(scaleFactor);
- mZoomCache.setImage(imagePreset, bounds, bmp2);
+ mZoomCache.setImage(imagePreset, bounds, bmp);
mLoadingLock.unlock();
- return bmp2;
+ return bmp;
}
}
mLoadingLock.unlock();
@@ -406,22 +424,16 @@
public static Bitmap loadMutableBitmap(Context context, Uri sourceUri) {
BitmapFactory.Options options = new BitmapFactory.Options();
+ return loadMutableBitmap(context, sourceUri, options);
+ }
+
+ public static Bitmap loadMutableBitmap(Context context, Uri sourceUri,
+ BitmapFactory.Options options) {
// TODO: on <3.x we need a copy of the bitmap (inMutable doesn't
// exist)
options.inMutable = true;
- InputStream is = null;
- Bitmap bitmap = null;
- try {
- is = context.getContentResolver().openInputStream(sourceUri);
- bitmap = BitmapFactory.decodeStream(is, null, options);
- } catch (FileNotFoundException e) {
- Log.w(LOGTAG, "could not load bitmap ", e);
- is = null;
- bitmap = null;
- } finally {
- Utils.closeSilently(is);
- }
+ Bitmap bitmap = decodeUriWithBackouts(context, sourceUri, options);
if (bitmap == null) {
return null;
}
@@ -430,6 +442,81 @@
return bitmap;
}
+ public static Bitmap decodeUriWithBackouts(Context context, Uri sourceUri,
+ BitmapFactory.Options options) {
+ boolean noBitmap = true;
+ int num_tries = 0;
+ InputStream is = getInputStream(context, sourceUri);
+
+ if (options.inSampleSize < 1) {
+ options.inSampleSize = 1;
+ }
+ // Stopgap fix for low-memory devices.
+ Bitmap bmap = null;
+ while (noBitmap) {
+ if (is == null) {
+ return null;
+ }
+ try {
+ // Try to decode, downsample if low-memory.
+ bmap = BitmapFactory.decodeStream(is, null, options);
+ noBitmap = false;
+ } catch (java.lang.OutOfMemoryError e) {
+ // Try 5 times before failing for good.
+ if (++num_tries >= BITMAP_LOAD_BACKOUT_ATTEMPTS) {
+ throw e;
+ }
+ is = null;
+ bmap = null;
+ System.gc();
+ is = getInputStream(context, sourceUri);
+ options.inSampleSize *= 2;
+ }
+ }
+ Utils.closeSilently(is);
+ return bmap;
+ }
+
+ private static InputStream getInputStream(Context context, Uri sourceUri) {
+ InputStream is = null;
+ try {
+ is = context.getContentResolver().openInputStream(sourceUri);
+ } catch (FileNotFoundException e) {
+ Log.w(LOGTAG, "could not load bitmap ", e);
+ Utils.closeSilently(is);
+ is = null;
+ }
+ return is;
+ }
+
+ public static Bitmap decodeResourceWithBackouts(Resources res, BitmapFactory.Options options,
+ int id) {
+ boolean noBitmap = true;
+ int num_tries = 0;
+ if (options.inSampleSize < 1) {
+ options.inSampleSize = 1;
+ }
+ // Stopgap fix for low-memory devices.
+ Bitmap bmap = null;
+ while (noBitmap) {
+ try {
+ // Try to decode, downsample if low-memory.
+ bmap = BitmapFactory.decodeResource(
+ res, id, options);
+ noBitmap = false;
+ } catch (java.lang.OutOfMemoryError e) {
+ // Try 5 times before failing for good.
+ if (++num_tries >= BITMAP_LOAD_BACKOUT_ATTEMPTS) {
+ throw e;
+ }
+ bmap = null;
+ System.gc();
+ options.inSampleSize *= 2;
+ }
+ }
+ return bmap;
+ }
+
public void returnFilteredResult(ImagePreset preset,
final FilterShowActivity filterShowActivity) {
preset.setQuality(ImagePreset.QUALITY_FINAL);
@@ -451,13 +538,36 @@
if (param == null || mUri == null) {
return null;
}
- Bitmap bitmap = loadMutableBitmap(mContext, mUri);
- if (bitmap == null) {
- Log.w(LOGTAG, "Failed to save image!");
- return null;
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ boolean noBitmap = true;
+ int num_tries = 0;
+ if (options.inSampleSize < 1) {
+ options.inSampleSize = 1;
}
- bitmap = param.applyGeometry(bitmap);
- return param.apply(bitmap);
+ Bitmap bitmap = null;
+ // Stopgap fix for low-memory devices.
+ while (noBitmap) {
+ try {
+ // Try to do bitmap operations, downsample if low-memory
+ bitmap = loadMutableBitmap(mContext, mUri, options);
+ if (bitmap == null) {
+ Log.w(LOGTAG, "Failed to save image!");
+ return null;
+ }
+ bitmap = param.applyGeometry(bitmap);
+ bitmap = param.apply(bitmap);
+ noBitmap = false;
+ } catch (java.lang.OutOfMemoryError e) {
+ // Try 5 times before failing for good.
+ if (++num_tries >= 5) {
+ throw e;
+ }
+ bitmap = null;
+ System.gc();
+ options.inSampleSize *= 2;
+ }
+ }
+ return bitmap;
}
};
diff --git a/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java b/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java
index 1e9f6b8..3ec74e2 100644
--- a/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java
+++ b/src/com/android/gallery3d/filtershow/cache/RenderingRequest.java
@@ -17,6 +17,7 @@
package com.android.gallery3d.filtershow.cache;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import com.android.gallery3d.app.Log;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.presets.ImagePreset;
@@ -27,29 +28,46 @@
private Bitmap mBitmap = null;
private ImagePreset mImagePreset = null;
private RenderingRequestCaller mCaller = null;
+ private Rect mBounds = null;
+ private Rect mDestination = null;
private int mType = FULL_RENDERING;
- public static int FULL_RENDERING = 0;
- public static int FILTERS_RENDERING = 1;
- public static int GEOMETRY_RENDERING = 2;
- public static int ICON_RENDERING = 3;
+ public static final int FULL_RENDERING = 0;
+ public static final int FILTERS_RENDERING = 1;
+ public static final int GEOMETRY_RENDERING = 2;
+ public static final int ICON_RENDERING = 3;
+ public static final int PARTIAL_RENDERING = 4;
private static final Bitmap.Config mConfig = Bitmap.Config.ARGB_8888;
+ public static void post(Bitmap source, ImagePreset preset, int type, RenderingRequestCaller caller) {
+ RenderingRequest.post(source, preset, type, caller, null, null);
+ }
+
public static void post(Bitmap source, ImagePreset preset, int type,
- RenderingRequestCaller caller) {
- if (source == null || preset == null || caller == null) {
+ RenderingRequestCaller caller, Rect bounds, Rect destination) {
+ if ((type != PARTIAL_RENDERING && source == null) || preset == null || caller == null) {
Log.v(LOGTAG, "something null: source: " + source + " or preset: " + preset + " or caller: " + caller);
return;
}
RenderingRequest request = new RenderingRequest();
Bitmap bitmap = null;
- if (type == FULL_RENDERING || type == GEOMETRY_RENDERING || type == ICON_RENDERING) {
+ if (type == FULL_RENDERING
+ || type == GEOMETRY_RENDERING
+ || type == ICON_RENDERING) {
bitmap = preset.applyGeometry(source);
- } else {
+ } else if (type != PARTIAL_RENDERING) {
bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), mConfig);
}
+
request.setBitmap(bitmap);
ImagePreset passedPreset = new ImagePreset(preset);
passedPreset.setImageLoader(MasterImage.getImage().getImageLoader());
+
+ if (type == PARTIAL_RENDERING) {
+ request.setBounds(bounds);
+ request.setDestination(destination);
+ passedPreset.setPartialRendering(true, bounds);
+ }
+
request.setImagePreset(passedPreset);
request.setType(type);
request.setCaller(caller);
@@ -103,4 +121,20 @@
public void setCaller(RenderingRequestCaller caller) {
mCaller = caller;
}
+
+ public Rect getBounds() {
+ return mBounds;
+ }
+
+ public void setBounds(Rect bounds) {
+ mBounds = bounds;
+ }
+
+ public Rect getDestination() {
+ return mDestination;
+ }
+
+ public void setDestination(Rect destination) {
+ mDestination = destination;
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
index 43660d6..377bd2b 100644
--- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
+++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
@@ -42,6 +42,7 @@
filters.add(new ImageFilterVignette());
filters.add(new ImageFilterContrast());
filters.add(new ImageFilterShadows());
+ filters.add(new ImageFilterHighlights());
filters.add(new ImageFilterVibrance());
filters.add(new ImageFilterSharpen());
filters.add(new ImageFilterCurves());
@@ -89,6 +90,7 @@
representations.add(getRepresentation(ImageFilterVignette.class));
representations.add(getRepresentation(ImageFilterContrast.class));
representations.add(getRepresentation(ImageFilterShadows.class));
+ representations.add(getRepresentation(ImageFilterHighlights.class));
representations.add(getRepresentation(ImageFilterVibrance.class));
representations.add(getRepresentation(ImageFilterSharpen.class));
representations.add(getRepresentation(ImageFilterCurves.class));
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
index 6c83170..3511c67 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
@@ -19,6 +19,7 @@
setShowEditingControls(false);
setShowParameterValue(false);
setShowUtilityPanel(true);
+ setSupportsPartialRendering(true);
for (int i = 0; i < mSplines.length; i++) {
mSplines[i] = new Spline();
mSplines[i].reset();
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java
index e41f0a6..8b8504b 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java
@@ -150,6 +150,10 @@
mCurrent = null;
}
+ public void clearCurrentSection() {
+ mCurrent = null;
+ }
+
public void clear() {
mCurrent = null;
mDrawing.clear();
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java
index 859bf32..d4128dc 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java
@@ -37,6 +37,7 @@
setShowEditingControls(false);
setShowParameterValue(false);
setShowUtilityPanel(false);
+ setSupportsPartialRendering(true);
}
public String toString() {
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
index 513cdcd..83f2a1b 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
@@ -25,6 +25,7 @@
private String mName;
private int mPriority = TYPE_NORMAL;
private Class mFilterClass;
+ private boolean mSupportsPartialRendering = false;
private int mTextId = 0;
private int mEditorId = BasicEditor.ID;
private int mButtonId = 0;
@@ -52,6 +53,7 @@
representation.setName(getName());
representation.setPriority(getPriority());
representation.setFilterClass(getFilterClass());
+ representation.setSupportsPartialRendering(supportsPartialRendering());
representation.setTextId(getTextId());
representation.setEditorId(getEditorId());
representation.setButtonId(getButtonId());
@@ -70,6 +72,7 @@
if (representation.mFilterClass == representation.mFilterClass
&& representation.mName.equalsIgnoreCase(mName)
&& representation.mPriority == mPriority
+ && representation.mSupportsPartialRendering == mSupportsPartialRendering
&& representation.mTextId == mTextId
&& representation.mEditorId == mEditorId
&& representation.mButtonId == mButtonId
@@ -106,6 +109,14 @@
return false;
}
+ public boolean supportsPartialRendering() {
+ return mSupportsPartialRendering;
+ }
+
+ public void setSupportsPartialRendering(boolean value) {
+ mSupportsPartialRendering = value;
+ }
+
public void useParametersFrom(FilterRepresentation a) {
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
index 614c6a0..1b7a367 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java
@@ -18,8 +18,10 @@
import android.graphics.Bitmap;
import android.graphics.Matrix;
+import android.widget.Toast;
import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.editors.BasicEditor;
import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
import com.android.gallery3d.filtershow.presets.ImagePreset;
@@ -31,6 +33,30 @@
protected String mName = "Original";
private final String LOGTAG = "ImageFilter";
+ // TODO: Temporary, for dogfood note memory issues with toasts for better
+ // feedback. Remove this when filters actually work in low memory
+ // situations.
+ private static FilterShowActivity sActivity = null;
+
+ public static void setActivityForMemoryToasts(FilterShowActivity activity) {
+ sActivity = activity;
+ }
+
+ public static void resetStatics() {
+ sActivity = null;
+ }
+
+ public void displayLowMemoryToast() {
+ if (sActivity != null) {
+ sActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ Toast.makeText(sActivity, "Memory too low for filter " + getName() +
+ ", please file a bug report", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+ }
+
public void setName(String name) {
mName = name;
}
@@ -45,8 +71,8 @@
}
/**
- * Called on small bitmaps to create button icons for each filter.
- * Override this to provide filter-specific button icons.
+ * Called on small bitmaps to create button icons for each filter. Override
+ * this to provide filter-specific button icons.
*/
public Bitmap iconApply(Bitmap bitmap, float scaleFactor, int quality) {
return apply(bitmap, scaleFactor, quality);
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
index c92ac01..a4626cd 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
@@ -36,6 +36,7 @@
representation.setMinimum(-180);
representation.setTextId(R.string.bwfilter);
representation.setButtonId(R.id.bwfilterButton);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
index 2f94e3d..2097f0d 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
@@ -37,6 +37,7 @@
representation.setMinimum(-100);
representation.setMaximum(100);
representation.setDefaultValue(0);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
index 55c7095..46a9a29 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
@@ -32,6 +32,7 @@
representation.setFilterClass(ImageFilterEdge.class);
representation.setTextId(R.string.edge);
representation.setButtonId(R.id.edgeButton);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
index 7a8df71..b0b0b2d 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
@@ -36,6 +36,7 @@
representation.setMinimum(-100);
representation.setMaximum(100);
representation.setDefaultValue(0);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java
new file mode 100644
index 0000000..12f032d
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import com.android.gallery3d.R;
+
+import android.graphics.Bitmap;
+import android.util.Log;
+
+public class ImageFilterHighlights extends SimpleImageFilter {
+ private static final String LOGTAG = "ImageFilterVignette";
+
+ public ImageFilterHighlights() {
+ mName = "Highlights";
+ }
+
+ SplineMath mSpline = new SplineMath(5);
+ double[] mHighlightCurve = { 0.0, 0.32, 0.418, 0.476, 0.642 };
+
+ public FilterRepresentation getDefaultRepresentation() {
+ FilterBasicRepresentation representation =
+ (FilterBasicRepresentation) super.getDefaultRepresentation();
+ representation.setName("Shadows");
+ representation.setFilterClass(ImageFilterHighlights.class);
+ representation.setTextId(R.string.highlight_recovery);
+ representation.setButtonId(R.id.highlightRecoveryButton);
+ representation.setMinimum(-100);
+ representation.setMaximum(100);
+ representation.setDefaultValue(0);
+ representation.setSupportsPartialRendering(true);
+ return representation;
+ }
+
+ native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float[] luminanceMap);
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
+ if (getParameters() == null) {
+ return bitmap;
+ }
+ float p = getParameters().getValue();
+ double t = p/100.;
+ for (int i = 0; i < 5; i++) {
+ double x = i / 4.;
+ double y = mHighlightCurve[i] *t+x*(1-t);
+ mSpline.setPoint(i, x, y);
+ }
+
+ float[][] curve = mSpline.calculatetCurve(256);
+ float[] luminanceMap = new float[curve.length];
+ for (int i = 0; i < luminanceMap.length; i++) {
+ luminanceMap[i] = curve[i][1];
+ }
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+
+ nativeApplyFilter(bitmap, w, h, luminanceMap);
+ return bitmap;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
index 8c484c7..b1f9f73 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
@@ -39,6 +39,7 @@
representation.setTextId(R.string.hue);
representation.setButtonId(R.id.hueButton);
representation.setEditorId(BasicEditor.ID);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java
index f48bd04..6f785ef 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java
@@ -45,6 +45,7 @@
representation.setPreviewValue(4);
representation.setTextId(R.string.kmeans);
representation.setButtonId(R.id.kmeansButton);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java
index 841c5c9..c256686 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java
@@ -19,6 +19,7 @@
representation.setShowEditingControls(false);
representation.setShowParameterValue(false);
representation.setEditorId(ImageOnlyEditor.ID);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java
index d529790..a3467ed 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java
@@ -43,9 +43,11 @@
|| (bitmap.getHeight() != sOldBitmap.getHeight())) {
if (mInPixelsAllocation != null) {
mInPixelsAllocation.destroy();
+ mInPixelsAllocation = null;
}
if (mOutPixelsAllocation != null) {
mOutPixelsAllocation.destroy();
+ mOutPixelsAllocation = null;
}
Bitmap bitmapBuffer = bitmap.copy(mBitmapConfig, true);
mOutPixelsAllocation = Allocation.createFromBitmap(mRS, bitmapBuffer,
@@ -87,6 +89,11 @@
Log.e(LOGTAG, "Illegal argument? " + e);
} catch (android.renderscript.RSRuntimeException e) {
Log.e(LOGTAG, "RS runtime exception ? " + e);
+ } catch (java.lang.OutOfMemoryError e) {
+ // Many of the renderscript filters allocated large (>16Mb resources) in order to apply.
+ System.gc();
+ displayLowMemoryToast();
+ Log.e(LOGTAG, "not enough memory for filter " + getName(), e);
}
return bitmap;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
index 6cd8332..0febe49 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
@@ -37,6 +37,7 @@
representation.setMinimum(-100);
representation.setMaximum(100);
representation.setDefaultValue(0);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
index e178239..fd67ee8 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
@@ -37,6 +37,7 @@
representation.setMinimum(-100);
representation.setMaximum(100);
representation.setDefaultValue(0);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
index 9c99d57..8afa474 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
@@ -37,7 +37,8 @@
representation.setTextId(R.string.sharpness);
representation.setButtonId(R.id.sharpenButton);
representation.setOverlayId(R.drawable.filtershow_button_colors_sharpen);
- representation.setEditorId(R.id.imageZoom);
+ representation.setEditorId(R.id.imageShow);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
index a57af71..ea315d3 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
@@ -36,6 +36,7 @@
representation.setMinimum(-100);
representation.setMaximum(100);
representation.setDefaultValue(0);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
index 2f48523..c4c293a 100644
--- a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
@@ -37,6 +37,7 @@
representation.setShowEditingControls(false);
representation.setShowParameterValue(false);
representation.setEditorId(ImageOnlyEditor.ID);
+ representation.setSupportsPartialRendering(true);
return representation;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/SplineMath.java b/src/com/android/gallery3d/filtershow/filters/SplineMath.java
new file mode 100644
index 0000000..5b12d0a
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/SplineMath.java
@@ -0,0 +1,166 @@
+package com.android.gallery3d.filtershow.filters;
+
+
+public class SplineMath {
+ double[][] mPoints = new double[6][2];
+ double[] mDerivatives;
+ SplineMath(int n) {
+ mPoints = new double[n][2];
+ }
+
+ public void setPoint(int index, double x, double y) {
+ mPoints[index][0] = x;
+ mPoints[index][1] = y;
+ mDerivatives = null;
+ }
+
+ public float[][] calculatetCurve(int n) {
+ float[][] curve = new float[n][2];
+ double[][] points = new double[mPoints.length][2];
+ for (int i = 0; i < mPoints.length; i++) {
+
+ points[i][0] = mPoints[i][0];
+ points[i][1] = mPoints[i][1];
+
+ }
+ double[] derivatives = solveSystem(points);
+ float start = (float) points[0][0];
+ float end = (float) (points[points.length - 1][0]);
+
+ curve[0][0] = (float) (points[0][0]);
+ curve[0][1] = (float) (points[0][1]);
+ int last = curve.length - 1;
+ curve[last][0] = (float) (points[points.length - 1][0]);
+ curve[last][1] = (float) (points[points.length - 1][1]);
+
+ for (int i = 0; i < curve.length; i++) {
+
+ double[] cur = null;
+ double[] next = null;
+ double x = start + i * (end - start) / (curve.length - 1);
+ int pivot = 0;
+ for (int j = 0; j < points.length - 1; j++) {
+ if (x >= points[j][0] && x <= points[j + 1][0]) {
+ pivot = j;
+ }
+ }
+ cur = points[pivot];
+ next = points[pivot + 1];
+ if (x <= next[0]) {
+ double x1 = cur[0];
+ double x2 = next[0];
+ double y1 = cur[1];
+ double y2 = next[1];
+
+ // Use the second derivatives to apply the cubic spline
+ // equation:
+ double delta = (x2 - x1);
+ double delta2 = delta * delta;
+ double b = (x - x1) / delta;
+ double a = 1 - b;
+ double ta = a * y1;
+ double tb = b * y2;
+ double tc = (a * a * a - a) * derivatives[pivot];
+ double td = (b * b * b - b) * derivatives[pivot + 1];
+ double y = ta + tb + (delta2 / 6) * (tc + td);
+
+ curve[i][0] = (float) (x);
+ curve[i][1] = (float) (y);
+ } else {
+ curve[i][0] = (float) (next[0]);
+ curve[i][1] = (float) (next[1]);
+ }
+ }
+ return curve;
+ }
+
+ public double getValue(double x) {
+ double[] cur = null;
+ double[] next = null;
+ if (mDerivatives == null)
+ mDerivatives = solveSystem(mPoints);
+ int pivot = 0;
+ for (int j = 0; j < mPoints.length - 1; j++) {
+ pivot = j;
+ if (x <= mPoints[j][0]) {
+ break;
+ }
+ }
+ cur = mPoints[pivot];
+ next = mPoints[pivot + 1];
+ double x1 = cur[0];
+ double x2 = next[0];
+ double y1 = cur[1];
+ double y2 = next[1];
+
+ // Use the second derivatives to apply the cubic spline
+ // equation:
+ double delta = (x2 - x1);
+ double delta2 = delta * delta;
+ double b = (x - x1) / delta;
+ double a = 1 - b;
+ double ta = a * y1;
+ double tb = b * y2;
+ double tc = (a * a * a - a) * mDerivatives[pivot];
+ double td = (b * b * b - b) * mDerivatives[pivot + 1];
+ double y = ta + tb + (delta2 / 6) * (tc + td);
+
+ return y;
+
+ }
+
+ double[] solveSystem(double[][] points) {
+ int n = points.length;
+ double[][] system = new double[n][3];
+ double[] result = new double[n]; // d
+ double[] solution = new double[n]; // returned coefficients
+ system[0][1] = 1;
+ system[n - 1][1] = 1;
+ double d6 = 1.0 / 6.0;
+ double d3 = 1.0 / 3.0;
+
+ // let's create a tridiagonal matrix representing the
+ // system, and apply the TDMA algorithm to solve it
+ // (see http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm)
+ for (int i = 1; i < n - 1; i++) {
+ double deltaPrevX = points[i][0] - points[i - 1][0];
+ double deltaX = points[i + 1][0] - points[i - 1][0];
+ double deltaNextX = points[i + 1][0] - points[i][0];
+ double deltaNextY = points[i + 1][1] - points[i][1];
+ double deltaPrevY = points[i][1] - points[i - 1][1];
+ system[i][0] = d6 * deltaPrevX; // a_i
+ system[i][1] = d3 * deltaX; // b_i
+ system[i][2] = d6 * deltaNextX; // c_i
+ result[i] = (deltaNextY / deltaNextX) - (deltaPrevY / deltaPrevX); // d_i
+ }
+
+ // Forward sweep
+ for (int i = 1; i < n; i++) {
+ // m = a_i/b_i-1
+ double m = system[i][0] / system[i - 1][1];
+ // b_i = b_i - m(c_i-1)
+ system[i][1] = system[i][1] - m * system[i - 1][2];
+ // d_i = d_i - m(d_i-1)
+ result[i] = result[i] - m * result[i - 1];
+ }
+
+ // Back substitution
+ solution[n - 1] = result[n - 1] / system[n - 1][1];
+ for (int i = n - 2; i >= 0; --i) {
+ solution[i] = (result[i] - system[i][2] * solution[i + 1]) / system[i][1];
+ }
+ return solution;
+ }
+
+ public static void main(String[] args) {
+ SplineMath s = new SplineMath(10);
+ for (int i = 0; i < 10; i++) {
+ s.setPoint(i, i, i);
+ }
+ float[][] curve = s.calculatetCurve(40);
+
+ for (int j = 0; j < curve.length; j++) {
+ System.out.println(curve[j][0] + "," + curve[j][1]);
+ }
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java
index c46baf5..479652c 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageDraw.java
@@ -27,11 +27,13 @@
public ImageDraw(Context context, AttributeSet attrs) {
super(context, attrs);
resetParameter();
+ super.setOriginalDisabled(true);
}
public ImageDraw(Context context) {
super(context);
resetParameter();
+ super.setOriginalDisabled(true);
}
public void setEditor(EditorDraw editorDraw) {
@@ -82,27 +84,32 @@
float[] mTmpPoint = new float[2]; // so we do not malloc
@Override
public boolean onTouchEvent(MotionEvent event) {
- super.onTouchEvent(event);
-
- if (event.getPointerCount() != 1) {
- return true;
+ boolean ret = super.onTouchEvent(event);
+ if (event.getPointerCount() > 1) {
+ if (mFRep.getCurrentDrawing() != null) {
+ mFRep.clearCurrentSection();
+ mEditorDraw.commitLocalRepresentation();
+ }
+ return ret;
}
-
- if (didFinishScalingOperation()) {
- return true;
+ if (event.getAction() != MotionEvent.ACTION_DOWN) {
+ if (mFRep.getCurrentDrawing() == null) {
+ return ret;
+ }
}
ImageFilterDraw filter = (ImageFilterDraw) getCurrentFilter();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ calcScreenMapping();
mTmpPoint[0] = event.getX();
mTmpPoint[1] = event.getY();
mToOrig.mapPoints(mTmpPoint);
mFRep.startNewSection(mType, mCurrentColor, mCurrentSize, mTmpPoint[0], mTmpPoint[1]);
-
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
+
int historySize = event.getHistorySize();
final int pointerCount = event.getPointerCount();
for (int h = 0; h < historySize; h++) {
@@ -127,19 +134,10 @@
return true;
}
- Matrix mRotateToScreen;
- Matrix mToScreen;
- Matrix mToOrig = new Matrix();
+ Matrix mRotateToScreen = new Matrix();
+ Matrix mToOrig;
private void calcScreenMapping() {
-
- GeometryMetadata geo = getImagePreset().mGeoData;
- mToScreen = geo.getOriginalToScreen(false,
- mImageLoader.getOriginalBounds().width(),
- mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
- mRotateToScreen = geo.getOriginalToScreen(true,
- mImageLoader.getOriginalBounds().width(),
- mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
- mRotateToScreen.invert(mToOrig);
+ mToOrig = getScreenToImageMatrix(true);
mToOrig.invert(mRotateToScreen);
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 7922398..39e0cc8 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -26,23 +26,19 @@
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.OnGestureListener;
import android.widget.LinearLayout;
-import android.widget.SeekBar;
-import android.widget.SeekBar.OnSeekBarChangeListener;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.PanelController;
import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.cache.RenderingRequestCaller;
import com.android.gallery3d.filtershow.filters.ImageFilter;
import com.android.gallery3d.filtershow.presets.ImagePreset;
-import com.android.gallery3d.filtershow.ui.SliderListener;
import java.io.File;
public class ImageShow extends View implements OnGestureListener,
ScaleGestureDetector.OnScaleGestureListener,
- OnDoubleTapListener,
- SliderListener,
- OnSeekBarChangeListener {
+ OnDoubleTapListener {
private static final String LOGTAG = "ImageShow";
@@ -61,7 +57,7 @@
private ScaleGestureDetector mScaleGestureDetector = null;
protected Rect mImageBounds = new Rect();
-
+ private boolean mOriginalDisabled = false;
private boolean mTouchShowOriginal = false;
private long mTouchShowOriginalDate = 0;
private final long mTouchShowOriginalDelayMin = 200; // 200ms
@@ -82,16 +78,10 @@
return new GeometryMetadata(getImagePreset().mGeoData);
}
- public void setGeometry(GeometryMetadata d) {
- getImagePreset().mGeoData.set(d);
- }
-
- private boolean mShowControls = false;
private String mToast = null;
private boolean mShowToast = false;
private boolean mImportantToast = false;
- private SeekBar mSeekBar = null;
private PanelController mController = null;
private FilterShowActivity mActivity = null;
@@ -131,30 +121,9 @@
private final Handler mHandler = new Handler();
public void select() {
- if (mSeekBar != null) {
- mSeekBar.setOnSeekBarChangeListener(this);
- }
- }
-
- private int parameterToUI(int parameter, int minp, int maxp, int uimax) {
- return (uimax * (parameter - minp)) / (maxp - minp);
- }
-
- private int uiToParameter(int ui, int minp, int maxp, int uimax) {
- return ((maxp - minp) * ui) / uimax + minp;
- }
-
- public void updateSeekBar(int parameter, int minp, int maxp) {
- if (mSeekBar == null) {
- return;
- }
- int seekMax = mSeekBar.getMax();
- int progress = parameterToUI(parameter, minp, maxp, seekMax);
- mSeekBar.setProgress(progress);
}
public void unselect() {
-
}
public boolean hasModifications() {
@@ -176,7 +145,6 @@
return mController;
}
- @Override
public void onNewValue(int parameter) {
if (getImagePreset() != null) {
getImagePreset().fillImageStateAdapter(MasterImage.getImage().getState());
@@ -192,17 +160,6 @@
return mTouch;
}
- @Override
- public void onTouchDown(float x, float y) {
- mTouch.x = (int) x;
- mTouch.y = (int) y;
- invalidate();
- }
-
- @Override
- public void onTouchUp() {
- }
-
public ImageShow(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -231,10 +188,6 @@
setMeasuredDimension(parentWidth, parentHeight);
}
- public void setSeekBar(SeekBar seekBar) {
- mSeekBar = seekBar;
- }
-
public ImageFilter getCurrentFilter() {
return MasterImage.getImage().getCurrentFilter();
}
@@ -277,6 +230,10 @@
*/
protected Matrix getImageToScreenMatrix(boolean reflectRotation) {
GeometryMetadata geo = getImagePreset().mGeoData;
+ if (geo == null || mImageLoader == null
+ || mImageLoader.getOriginalBounds() == null) {
+ return new Matrix();
+ }
Matrix m = geo.getOriginalToScreen(reflectRotation,
mImageLoader.getOriginalBounds().width(),
mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
@@ -339,7 +296,7 @@
@Override
public void onDraw(Canvas canvas) {
-
+ MasterImage.getImage().setImageShowSize(getWidth(), getHeight());
canvas.save();
// TODO: center scale on gesture
float cx = canvas.getWidth()/2.0f;
@@ -363,6 +320,12 @@
1.5f * mTextPadding, mPaint);
}
+ Bitmap partialPreview = MasterImage.getImage().getPartialImage();
+ if (partialPreview != null) {
+ Rect src = new Rect(0, 0, partialPreview.getWidth(), partialPreview.getHeight());
+ Rect dest = new Rect(0, 0, getWidth(), getHeight());
+ canvas.drawBitmap(partialPreview, src, dest, mPaint);
+ }
drawToast(canvas);
}
@@ -476,28 +439,6 @@
}
}
- public ImageShow setShowControls(boolean value) {
- mShowControls = value;
- if (mShowControls) {
- if (mSeekBar != null) {
- mSeekBar.setVisibility(View.VISIBLE);
- }
- } else {
- if (mSeekBar != null) {
- mSeekBar.setVisibility(View.INVISIBLE);
- }
- }
- return this;
- }
-
- public boolean showControls() {
- return mShowControls;
- }
-
- public boolean showHires() {
- return true;
- }
-
public boolean showTitle() {
return false;
}
@@ -574,6 +515,14 @@
return mScaleGestureDetector.isInProgress();
}
+ protected boolean isOriginalDisabled() {
+ return mOriginalDisabled;
+ }
+
+ protected void setOriginalDisabled(boolean originalDisabled) {
+ mOriginalDisabled = originalDisabled;
+ }
+
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
@@ -609,8 +558,9 @@
Point translation = MasterImage.getImage().getTranslation();
translation.x = (int) (originalTranslation.x + translateX);
translation.y = (int) (originalTranslation.y + translateY);
+ MasterImage.getImage().setTranslation(translation);
}
- } else if (!mActivity.isShowingHistoryPanel()
+ } else if (!mOriginalDisabled && !mActivity.isShowingHistoryPanel()
&& (System.currentTimeMillis() - mTouchShowOriginalDate
> mTouchShowOriginalDelayMin)
&& event.getPointerCount() == 1) {
@@ -638,48 +588,6 @@
invalidate();
}
- public float getImageRotation() {
- return getImagePreset().mGeoData.getRotation();
- }
-
- public float getImageRotationZoomFactor() {
- return getImagePreset().mGeoData.getScaleFactor();
- }
-
- public void setImageRotation(float r) {
- getImagePreset().mGeoData.setRotation(r);
- }
-
- public void setImageRotationZoomFactor(float f) {
- getImagePreset().mGeoData.setScaleFactor(f);
- }
-
- public void setImageRotation(float imageRotation,
- float imageRotationZoomFactor) {
- float r = getImageRotation();
- if (imageRotation != r) {
- invalidate();
- }
- setImageRotation(imageRotation);
- setImageRotationZoomFactor(imageRotationZoomFactor);
- }
-
- @Override
- public void onProgressChanged(SeekBar arg0, int progress, boolean arg2) {
- int parameter = progress;
- onNewValue(parameter);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar arg0) {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar arg0) {
- // TODO Auto-generated method stub
- }
-
@Override
public boolean onDoubleTap(MotionEvent arg0) {
// TODO Auto-generated method stub
@@ -706,6 +614,9 @@
@Override
public boolean onFling(MotionEvent startEvent, MotionEvent endEvent, float arg2, float arg3) {
+ if (mActivity == null) {
+ return false;
+ }
if ((!mActivity.isShowingHistoryPanel() && startEvent.getX() > endEvent.getX())
|| (mActivity.isShowingHistoryPanel() && endEvent.getX() > startEvent.getX())) {
if (!mTouchShowOriginal
@@ -783,4 +694,5 @@
}
return false;
}
+
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java b/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java
index 729ac7f..a51d102 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageVignette.java
@@ -20,6 +20,7 @@
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import com.android.gallery3d.filtershow.editors.EditorVignette;
@@ -48,16 +49,28 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
int mask = event.getActionMasked();
- if (MotionEvent.ACTION_UP == mask) {
- mActiveHandle = -1;
- }
- if (MotionEvent.ACTION_DOWN == mask && event.getPointerCount() == 1) {
- mActiveHandle = mElipse.getCloseHandle(event.getX(), event.getY());
- }
- if (mActiveHandle == -1 || event.getPointerCount() > 1) {
- mActiveHandle = -1;
-
- return super.onTouchEvent(event);
+ if (mActiveHandle == -1) {
+ if (MotionEvent.ACTION_DOWN != mask) {
+ return super.onTouchEvent(event);
+ }
+ if (event.getPointerCount() == 1) {
+ mActiveHandle = mElipse.getCloseHandle(event.getX(), event.getY());
+ }
+ if (mActiveHandle == -1) {
+ return super.onTouchEvent(event);
+ }
+ } else {
+ switch (mask) {
+ case MotionEvent.ACTION_UP:
+ mActiveHandle = -1;
+ break;
+ case MotionEvent.ACTION_DOWN:
+ if (event.getPointerCount() == 1) {
+ Log.v(LOGTAG, "################### ACTION_DOWN odd " + mActiveHandle
+ + " touches=1");
+ }
+ break;
+ }
}
float x = event.getX();
float y = event.getY();
@@ -121,9 +134,7 @@
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
- if (mElipse.isUndefined()) {
- setRepresentation(mVignetteRep);
- }
+ setRepresentation(mVignetteRep);
mElipse.draw(canvas);
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java b/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
index 263a5b5..eb568c3 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
@@ -49,9 +49,7 @@
mTouchDown = false;
}
- @Override
public void onTouchDown(float x, float y) {
- super.onTouchDown(x, y);
if (mZoomedIn || mTouchDown) {
return;
}
@@ -81,7 +79,6 @@
invalidate();
}
- @Override
public void onTouchUp() {
mTouchDown = false;
}
@@ -93,7 +90,7 @@
Bitmap filteredImage = null;
if ((mZoomedIn || mTouchDown) && mImageLoader != null) {
filteredImage = mImageLoader.getScaleOneImageForPreset(this, getImagePreset(),
- mZoomBounds, false);
+ mZoomBounds, null, false);
} else {
filteredImage = getFilteredImage();
}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
index 905d2c3..9eafe22 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
@@ -16,9 +16,7 @@
package com.android.gallery3d.filtershow.imageshow;
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.RectF;
+import android.graphics.*;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.HistoryAdapter;
@@ -45,6 +43,7 @@
private Bitmap mGeometryOnlyBitmap = null;
private Bitmap mFiltersOnlyBitmap = null;
+ private Bitmap mPartialBitmap = null;
private ImageLoader mLoader = null;
private HistoryAdapter mHistory = null;
@@ -62,6 +61,8 @@
private Point mTranslation = new Point();
private Point mOriginalTranslation = new Point();
+ private Point mImageShowSize = new Point();
+
private MasterImage() {
}
@@ -193,6 +194,10 @@
return mGeometryOnlyBitmap;
}
+ public Bitmap getPartialImage() {
+ return mPartialBitmap;
+ }
+
public void notifyObservers() {
for (ImageShow observer : mObservers) {
observer.invalidate();
@@ -221,6 +226,7 @@
}
}
invalidatePreview();
+ needsUpdateFullResPreview();
mActivity.enableSave(hasModifications());
}
@@ -237,11 +243,67 @@
updatePresets(false);
}
+ public void invalidatePartialPreview() {
+ if (mPartialBitmap != null) {
+ mPartialBitmap = null;
+ notifyObservers();
+ }
+ }
+
public void invalidatePreview() {
mFilteredPreview.invalidate();
+ invalidatePartialPreview();
+ needsUpdateFullResPreview();
FilteringPipeline.getPipeline().updatePreviewBuffer();
}
+ public void setImageShowSize(int w, int h) {
+ if (mImageShowSize.x != w || mImageShowSize.y != h) {
+ mImageShowSize.set(w, h);
+ needsUpdateFullResPreview();
+ }
+ }
+
+ private Matrix getImageToScreenMatrix(boolean reflectRotation) {
+ GeometryMetadata geo = mPreset.mGeoData;
+ if (geo == null || mLoader == null
+ || mLoader.getOriginalBounds() == null
+ || mImageShowSize.x == 0) {
+ return new Matrix();
+ }
+ Matrix m = geo.getOriginalToScreen(reflectRotation,
+ mLoader.getOriginalBounds().width(),
+ mLoader.getOriginalBounds().height(), mImageShowSize.x, mImageShowSize.y);
+ Point translate = getTranslation();
+ float scaleFactor = getScaleFactor();
+ m.postTranslate(translate.x, translate.y);
+ m.postScale(scaleFactor, scaleFactor, mImageShowSize.x/2.0f, mImageShowSize.y/2.0f);
+ return m;
+ }
+
+ private Matrix getScreenToImageMatrix(boolean reflectRotation) {
+ Matrix m = getImageToScreenMatrix(reflectRotation);
+ Matrix invert = new Matrix();
+ m.invert(invert);
+ return invert;
+ }
+
+ public void needsUpdateFullResPreview() {
+ if (!mPreset.canDoPartialRendering()) {
+ invalidatePartialPreview();
+ return;
+ }
+ Matrix m = getScreenToImageMatrix(true);
+ RectF r = new RectF(0, 0, mImageShowSize.x, mImageShowSize.y);
+ RectF dest = new RectF();
+ m.mapRect(dest, r);
+ Rect bounds = new Rect();
+ dest.roundOut(bounds);
+ RenderingRequest.post(null, mPreset, RenderingRequest.PARTIAL_RENDERING,
+ this, bounds, new Rect(0, 0, mImageShowSize.x, mImageShowSize.y));
+ invalidatePartialPreview();
+ }
+
@Override
public void available(RenderingRequest request) {
if (request.getBitmap() == null) {
@@ -253,6 +315,10 @@
if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
mFiltersOnlyBitmap = request.getBitmap();
}
+ if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+ mPartialBitmap = request.getBitmap();
+ notifyObservers();
+ }
}
public static void reset() {
@@ -275,6 +341,7 @@
public void setScaleFactor(float scaleFactor) {
mScaleFactor = scaleFactor;
+ needsUpdateFullResPreview();
}
public Point getTranslation() {
@@ -282,7 +349,9 @@
}
public void setTranslation(Point translation) {
- mTranslation = translation;
+ mTranslation.x = translation.x;
+ mTranslation.y = translation.y;
+ needsUpdateFullResPreview();
}
public Point getOriginalTranslation() {
@@ -297,5 +366,6 @@
public void resetTranslation() {
mTranslation.x = 0;
mTranslation.y = 0;
+ needsUpdateFullResPreview();
}
}
diff --git a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
index 84266c5..ae5a034 100644
--- a/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/presets/ImagePreset.java
@@ -17,6 +17,7 @@
package com.android.gallery3d.filtershow.presets;
import android.graphics.Bitmap;
+import android.graphics.Rect;
import android.util.Log;
import com.android.gallery3d.filtershow.ImageStateAdapter;
@@ -52,6 +53,8 @@
private boolean mDoApplyFilters = true;
public final GeometryMetadata mGeoData = new GeometryMetadata();
+ private boolean mPartialRendering = false;
+ private Rect mPartialRenderingBounds;
public ImagePreset() {
setup();
@@ -421,6 +424,22 @@
return bitmap;
}
+ public boolean canDoPartialRendering() {
+ if (mGeoData.hasModifications()) {
+ return false;
+ }
+ for (int i = 0; i < mFilters.size(); i++) {
+ FilterRepresentation representation = null;
+ synchronized (mFilters) {
+ representation = mFilters.elementAt(i);
+ }
+ if (!representation.supportsPartialRendering()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public void fillImageStateAdapter(ImageStateAdapter imageStateAdapter) {
if (imageStateAdapter == null) {
return;
@@ -446,4 +465,17 @@
public void setScaleFactor(float value) {
mScaleFactor = value;
}
+
+ public void setPartialRendering(boolean partialRendering, Rect bounds) {
+ mPartialRendering = partialRendering;
+ mPartialRenderingBounds = bounds;
+ }
+
+ public boolean isPartialRendering() {
+ return mPartialRendering;
+ }
+
+ public Rect getPartialRenderingBounds() {
+ return mPartialRenderingBounds;
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
index e378fe2..89cfa6bd 100644
--- a/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
+++ b/src/com/android/gallery3d/filtershow/tools/SaveCopyTask.java
@@ -22,6 +22,7 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
@@ -173,37 +174,52 @@
}
ImagePreset preset = params[0];
InputStream is = null;
- try {
- Bitmap bitmap = ImageLoader.loadMutableBitmap(context, sourceUri);
- if (bitmap == null) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ boolean noBitmap = true;
+ int num_tries = 0;
+ // Stopgap fix for low-memory devices.
+ while(noBitmap) {
+ try {
+ // Try to do bitmap operations, downsample if low-memory
+ Bitmap bitmap = ImageLoader.loadMutableBitmap(context, sourceUri, options);
+ if (bitmap == null) {
+ return null;
+ }
+ bitmap = preset.applyGeometry(bitmap);
+ bitmap = preset.apply(bitmap);
+
+ Object xmp = null;
+ if (preset.isPanoramaSafe()) {
+ is = context.getContentResolver().openInputStream(sourceUri);
+ xmp = XmpUtilHelper.extractXMPMeta(is);
+ }
+ ExifData exif = getExifData(sourceUri);
+ if (exif != null) {
+ exif.addDateTimeStampTag(ExifTag.TAG_DATE_TIME, System.currentTimeMillis(),
+ TimeZone.getDefault());
+ // Since the image has been modified, set the orientation to normal.
+ exif.addTag(ExifTag.TAG_ORIENTATION).setValue(ExifTag.Orientation.TOP_LEFT);
+ }
+ saveBitmap(bitmap, this.destinationFile, xmp, exif);
+ bitmap.recycle();
+ noBitmap = false;
+ } catch (FileNotFoundException ex) {
+ Log.w(LOGTAG, "Failed to save image!", ex);
return null;
+ } catch (java.lang.OutOfMemoryError e) {
+ // Try 5 times before failing for good.
+ if (++num_tries >= 5) {
+ throw e;
+ }
+ System.gc();
+ options.inSampleSize *= 2;
+ } finally {
+ Utils.closeSilently(is);
}
- bitmap = preset.applyGeometry(bitmap);
- bitmap = preset.apply(bitmap);
-
- Object xmp = null;
- if (preset.isPanoramaSafe()) {
- is = context.getContentResolver().openInputStream(sourceUri);
- xmp = XmpUtilHelper.extractXMPMeta(is);
- }
- ExifData exif = getExifData(sourceUri);
- if (exif != null) {
- exif.addDateTimeStampTag(ExifTag.TAG_DATE_TIME, System.currentTimeMillis(),
- TimeZone.getDefault());
- // Since the image has been modified, set the orientation to normal.
- exif.addTag(ExifTag.TAG_ORIENTATION).setValue(ExifTag.Orientation.TOP_LEFT);
- }
- saveBitmap(bitmap, this.destinationFile, xmp, exif);
-
- Uri uri = insertContent(context, sourceUri, this.destinationFile, saveFileName);
- bitmap.recycle();
- return uri;
- } catch (FileNotFoundException ex) {
- Log.w(LOGTAG, "Failed to save image!", ex);
- return null;
- } finally {
- Utils.closeSilently(is);
}
+ Uri uri = insertContent(context, sourceUri, this.destinationFile, saveFileName);
+ return uri;
+
}
@Override
diff --git a/src/com/android/gallery3d/filtershow/ui/SliderController.java b/src/com/android/gallery3d/filtershow/ui/SliderController.java
deleted file mode 100644
index 7139ace..0000000
--- a/src/com/android/gallery3d/filtershow/ui/SliderController.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.gallery3d.filtershow.ui;
-
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.view.MotionEvent;
-
-public class SliderController {
- private static final String LOGTAG = "SliderController";
-
- private float mCenterX;
- private float mCenterY;
- private float mCurrentX;
- private float mCurrentY;
- private int mValue = 100;
- int mOriginalValue = 0;
-
- private int mWidth = 0;
- private int mHeight = 0;
-
- private String mToast = null;
-
- private final Paint mPaint = new Paint();
-
- private SliderListener mListener = null;
-
- private MODES mMode = MODES.NONE;
- private static int mTextSize = 128;
-
- private enum MODES {
- NONE, DOWN, UP, MOVE
- }
-
- public void onDraw(Canvas canvas) {
- if (mMode == MODES.NONE || mMode == MODES.UP) {
- return;
- }
- }
-
- public void drawToast(Canvas canvas) {
- if (mToast != null) {
- canvas.save();
- mPaint.setTextSize(mTextSize);
- float textWidth = mPaint.measureText(mToast);
- int toastX = (int) ((getWidth() - textWidth) / 2.0f);
- int toastY = (int) (getHeight() / 3.0f);
-
- mPaint.setARGB(255, 0, 0, 0);
- canvas.drawText(mToast, toastX - 2, toastY - 2, mPaint);
- canvas.drawText(mToast, toastX - 2, toastY, mPaint);
- canvas.drawText(mToast, toastX, toastY - 2, mPaint);
- canvas.drawText(mToast, toastX + 2, toastY + 2, mPaint);
- canvas.drawText(mToast, toastX + 2, toastY, mPaint);
- canvas.drawText(mToast, toastX, toastY + 2, mPaint);
- mPaint.setARGB(255, 255, 255, 255);
- canvas.drawText(mToast, toastX, toastY, mPaint);
- canvas.restore();
- }
- }
-
- protected int computeValue() {
- int delta = (int) (100 * (getCurrentX() - getCenterX()) / getWidth());
- int value = mOriginalValue + delta;
- if (value < -100) {
- value = -100;
- } else if (value > 100) {
- value = 100;
- }
- setValue(value);
- mToast = "" + value;
- return value;
- }
-
- public void setValue(int value) {
- mValue = value;
- }
-
- public int getWidth() {
- return mWidth;
- }
-
- public int getHeight() {
- return mHeight;
- }
-
- public void setWidth(int value) {
- mWidth = value;
- }
-
- public void setHeight(int value) {
- mHeight = value;
- }
-
- public float getCurrentX() {
- return mCurrentX;
- }
-
- public float getCurrentY() {
- return mCurrentY;
- }
-
- public float getCenterX() {
- return mCenterX;
- }
-
- public float getCenterY() {
- return mCenterY;
- }
-
- public void setActionDown(float x, float y) {
- mCenterX = x;
- mCenterY = y;
- mCurrentX = x;
- mCurrentY = y;
- mMode = MODES.DOWN;
- if (mListener != null) {
- mListener.onTouchDown(x, y);
- }
- }
-
- public void setActionMove(float x, float y) {
- mCurrentX = x;
- mCurrentY = y;
- mMode = MODES.MOVE;
- computeValue();
- if (mListener != null) {
- mListener.onNewValue(mValue);
- }
- }
-
- public void setActionUp() {
- mMode = MODES.UP;
- mOriginalValue = computeValue();
- if (mListener != null) {
- mListener.onTouchUp();
- }
- }
-
- public void setNoAction() {
- mMode = MODES.NONE;
- }
-
- public void setListener(SliderListener listener) {
- mListener = listener;
- }
-
- public boolean onTouchEvent(MotionEvent event) {
- setNoAction();
- switch (event.getActionMasked()) {
- case (MotionEvent.ACTION_DOWN): {
- setActionDown(event.getX(), event.getY());
- break;
- }
- case (MotionEvent.ACTION_UP): {
- setActionUp();
- break;
- }
- case (MotionEvent.ACTION_CANCEL): {
- setActionUp();
- break;
- }
- case (MotionEvent.ACTION_MOVE): {
- setActionMove(event.getX(), event.getY());
- break;
- }
- }
- return true;
- }
-
- public void reset() {
- mOriginalValue = 0;
- }
-
-}
diff --git a/src/com/android/gallery3d/ingest/IngestService.java b/src/com/android/gallery3d/ingest/IngestService.java
index 5e0ca0b..fa421e7 100644
--- a/src/com/android/gallery3d/ingest/IngestService.java
+++ b/src/com/android/gallery3d/ingest/IngestService.java
@@ -187,7 +187,6 @@
public void deviceRemoved(MtpDevice device) {
if (device == mDevice) {
setDevice(null);
- MtpBitmapFetch.onDeviceDisconnected(device);
}
}
diff --git a/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java
index 46a2051..5e1fb34 100644
--- a/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java
+++ b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java
@@ -25,19 +25,14 @@
import android.view.WindowManager;
import com.android.camera.Exif;
-import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.BitmapPool;
-
-import java.util.ArrayList;
+import com.android.photos.data.GalleryBitmapPool;
public class MtpBitmapFetch {
- private static final int BITMAP_POOL_SIZE = 32;
- private static BitmapPool sThumbnailPool = new BitmapPool(BITMAP_POOL_SIZE);
private static int sMaxSize = 0;
public static void recycleThumbnail(Bitmap b) {
if (b != null) {
- sThumbnailPool.recycle(b);
+ GalleryBitmapPool.getInstance().put(b);
}
}
@@ -48,7 +43,7 @@
o.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o);
if (o.outWidth == 0 || o.outHeight == 0) return null;
- o.inBitmap = sThumbnailPool.getBitmap(o.outWidth, o.outHeight);
+ o.inBitmap = GalleryBitmapPool.getInstance().get(o.outWidth, o.outHeight);
o.inMutable = true;
o.inJustDecodeBounds = false;
o.inSampleSize = 1;
@@ -86,10 +81,6 @@
return new BitmapWithMetadata(created, Exif.getOrientation(imageBytes));
}
- public static void onDeviceDisconnected(MtpDevice device) {
- sThumbnailPool.clear();
- }
-
public static void configureForContext(Context context) {
DisplayMetrics metrics = new DisplayMetrics();
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
diff --git a/src/com/android/gallery3d/ui/AlbumLabelMaker.java b/src/com/android/gallery3d/ui/AlbumLabelMaker.java
index 6eeeec0..da1cac0 100644
--- a/src/com/android/gallery3d/ui/AlbumLabelMaker.java
+++ b/src/com/android/gallery3d/ui/AlbumLabelMaker.java
@@ -27,8 +27,8 @@
import android.text.TextUtils;
import com.android.gallery3d.R;
-import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.DataSourceType;
+import com.android.photos.data.GalleryBitmapPool;
import com.android.gallery3d.util.ThreadPool;
import com.android.gallery3d.util.ThreadPool.JobContext;
@@ -41,7 +41,8 @@
private final Context mContext;
private int mLabelWidth;
- private BitmapPool mBitmapPool;
+ private int mBitmapWidth;
+ private int mBitmapHeight;
private final LazyLoadedBitmap mLocalSetIcon;
private final LazyLoadedBitmap mPicasaIcon;
@@ -109,8 +110,8 @@
if (mLabelWidth == width) return;
mLabelWidth = width;
int borders = 2 * BORDER_SIZE;
- mBitmapPool = new BitmapPool(
- width + borders, mSpec.labelBackgroundHeight + borders, 16);
+ mBitmapWidth = width + borders;
+ mBitmapHeight = mSpec.labelBackgroundHeight + borders;
}
public ThreadPool.Job<Bitmap> requestLabel(
@@ -152,7 +153,7 @@
synchronized (this) {
labelWidth = mLabelWidth;
- bitmap = mBitmapPool.getBitmap();
+ bitmap = GalleryBitmapPool.getInstance().get(mBitmapWidth, mBitmapHeight);
}
if (bitmap == null) {
@@ -200,10 +201,6 @@
}
public void recycleLabel(Bitmap label) {
- mBitmapPool.recycle(label);
- }
-
- public void clearRecycledLabels() {
- if (mBitmapPool != null) mBitmapPool.clear();
+ GalleryBitmapPool.getInstance().put(label);
}
}
diff --git a/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java b/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java
index d5a15b4..8149df4 100644
--- a/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java
+++ b/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java
@@ -23,7 +23,6 @@
import com.android.gallery3d.app.AbstractGalleryActivity;
import com.android.gallery3d.app.AlbumSetDataLoader;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.DataSourceType;
import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.data.MediaObject;
@@ -403,7 +402,6 @@
for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
freeSlotContent(i);
}
- mLabelMaker.clearRecycledLabels();
}
public void resume() {
@@ -429,12 +427,6 @@
}
@Override
- protected void recycleBitmap(Bitmap bitmap) {
- BitmapPool pool = MediaItem.getMicroThumbPool();
- if (pool != null) pool.recycle(bitmap);
- }
-
- @Override
protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) {
return mThreadPool.submit(mMediaItem.requestImage(
MediaItem.TYPE_MICROTHUMBNAIL), l);
@@ -505,11 +497,6 @@
}
@Override
- protected void recycleBitmap(Bitmap bitmap) {
- mLabelMaker.recycleLabel(bitmap);
- }
-
- @Override
protected void onLoadComplete(Bitmap bitmap) {
mHandler.obtainMessage(MSG_UPDATE_ALBUM_ENTRY, this).sendToTarget();
}
diff --git a/src/com/android/gallery3d/ui/AlbumSlidingWindow.java b/src/com/android/gallery3d/ui/AlbumSlidingWindow.java
index 8cd2cf5..fec7d1e 100644
--- a/src/com/android/gallery3d/ui/AlbumSlidingWindow.java
+++ b/src/com/android/gallery3d/ui/AlbumSlidingWindow.java
@@ -22,11 +22,10 @@
import com.android.gallery3d.app.AbstractGalleryActivity;
import com.android.gallery3d.app.AlbumDataLoader;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.MediaItem;
import com.android.gallery3d.data.MediaObject;
-import com.android.gallery3d.data.Path;
import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback;
+import com.android.gallery3d.data.Path;
import com.android.gallery3d.glrenderer.Texture;
import com.android.gallery3d.glrenderer.TiledTexture;
import com.android.gallery3d.util.Future;
@@ -296,12 +295,6 @@
}
@Override
- protected void recycleBitmap(Bitmap bitmap) {
- BitmapPool pool = MediaItem.getMicroThumbPool();
- if (pool != null) pool.recycle(bitmap);
- }
-
- @Override
protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) {
return mThreadPool.submit(
mItem.requestImage(MediaItem.TYPE_MICROTHUMBNAIL), this);
diff --git a/src/com/android/gallery3d/ui/BitmapLoader.java b/src/com/android/gallery3d/ui/BitmapLoader.java
index 4f07cc0..a708a90 100644
--- a/src/com/android/gallery3d/ui/BitmapLoader.java
+++ b/src/com/android/gallery3d/ui/BitmapLoader.java
@@ -18,6 +18,7 @@
import android.graphics.Bitmap;
+import com.android.photos.data.GalleryBitmapPool;
import com.android.gallery3d.util.Future;
import com.android.gallery3d.util.FutureListener;
@@ -51,7 +52,7 @@
mBitmap = future.get();
if (mState == STATE_RECYCLED) {
if (mBitmap != null) {
- recycleBitmap(mBitmap);
+ GalleryBitmapPool.getInstance().put(mBitmap);
mBitmap = null;
}
return; // don't call callback
@@ -84,7 +85,7 @@
public synchronized void recycle() {
mState = STATE_RECYCLED;
if (mBitmap != null) {
- recycleBitmap(mBitmap);
+ GalleryBitmapPool.getInstance().put(mBitmap);
mBitmap = null;
}
if (mTask != null) mTask.cancel();
@@ -103,6 +104,5 @@
}
abstract protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l);
- abstract protected void recycleBitmap(Bitmap bitmap);
abstract protected void onLoadComplete(Bitmap bitmap);
}
diff --git a/src/com/android/gallery3d/ui/BitmapTileProvider.java b/src/com/android/gallery3d/ui/BitmapTileProvider.java
index c3466e7..e1a8b76 100644
--- a/src/com/android/gallery3d/ui/BitmapTileProvider.java
+++ b/src/com/android/gallery3d/ui/BitmapTileProvider.java
@@ -21,7 +21,7 @@
import android.graphics.Canvas;
import com.android.gallery3d.common.BitmapUtils;
-import com.android.gallery3d.data.BitmapPool;
+import com.android.photos.data.GalleryBitmapPool;
import java.util.ArrayList;
@@ -71,12 +71,11 @@
}
@Override
- public Bitmap getTile(int level, int x, int y, int tileSize,
- BitmapPool pool) {
+ public Bitmap getTile(int level, int x, int y, int tileSize) {
x >>= level;
y >>= level;
- Bitmap result = pool == null ? null : pool.getBitmap();
+ Bitmap result = GalleryBitmapPool.getInstance().get(tileSize, tileSize);
if (result == null) {
result = Bitmap.createBitmap(tileSize, tileSize, mConfig);
} else {
diff --git a/src/com/android/gallery3d/ui/TileImageView.java b/src/com/android/gallery3d/ui/TileImageView.java
index f1c31e4..3185c75 100644
--- a/src/com/android/gallery3d/ui/TileImageView.java
+++ b/src/com/android/gallery3d/ui/TileImageView.java
@@ -27,10 +27,9 @@
import android.view.WindowManager;
import com.android.gallery3d.app.GalleryContext;
-import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.BitmapPool;
import com.android.gallery3d.data.DecodeUtils;
+import com.android.photos.data.GalleryBitmapPool;
import com.android.gallery3d.glrenderer.GLCanvas;
import com.android.gallery3d.glrenderer.UploadedTexture;
import com.android.gallery3d.util.Future;
@@ -50,8 +49,6 @@
// TILE_SIZE must be 2^N
private static int sTileSize;
- private static BitmapPool sTilePool;
-
/*
* This is the tile state in the CPU side.
* Life of a Tile:
@@ -143,8 +140,7 @@
// still refers to the coordinate on the original image.
//
// The method would be called in another thread.
- public Bitmap getTile(int level, int x, int y, int tileSize,
- BitmapPool pool);
+ public Bitmap getTile(int level, int x, int y, int tileSize);
}
public static boolean isHighResolution(Context context) {
@@ -164,10 +160,6 @@
} else {
sTileSize = 256;
}
- sTilePool =
- ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER
- ? new BitmapPool(sTileSize, sTileSize, 128)
- : null;
}
}
@@ -399,7 +391,6 @@
}
}
setScreenNail(null);
- if (sTilePool != null) sTilePool.clear();
}
public void prepareTextures() {
@@ -508,7 +499,7 @@
if (tile.mTileState == STATE_RECYCLING) {
tile.mTileState = STATE_RECYCLED;
if (tile.mDecodedTile != null) {
- if (sTilePool != null) sTilePool.recycle(tile.mDecodedTile);
+ GalleryBitmapPool.getInstance().put(tile.mDecodedTile);
tile.mDecodedTile = null;
}
mRecycledQueue.push(tile);
@@ -536,7 +527,7 @@
}
tile.mTileState = STATE_RECYCLED;
if (tile.mDecodedTile != null) {
- if (sTilePool != null) sTilePool.recycle(tile.mDecodedTile);
+ GalleryBitmapPool.getInstance().put(tile.mDecodedTile);
tile.mDecodedTile = null;
}
mRecycledQueue.push(tile);
@@ -675,7 +666,7 @@
@Override
protected void onFreeBitmap(Bitmap bitmap) {
- if (sTilePool != null) sTilePool.recycle(bitmap);
+ GalleryBitmapPool.getInstance().put(bitmap);
}
boolean decode() {
@@ -683,7 +674,7 @@
// by (1 << mTilelevel) from a region in the original image.
try {
mDecodedTile = DecodeUtils.ensureGLCompatibleBitmap(mModel.getTile(
- mTileLevel, mX, mY, sTileSize, sTilePool));
+ mTileLevel, mX, mY, sTileSize));
} catch (Throwable t) {
Log.w(TAG, "fail to decode tile", t);
}
diff --git a/src/com/android/gallery3d/ui/TileImageViewAdapter.java b/src/com/android/gallery3d/ui/TileImageViewAdapter.java
index 0d20b07..0c1f66d 100644
--- a/src/com/android/gallery3d/ui/TileImageViewAdapter.java
+++ b/src/com/android/gallery3d/ui/TileImageViewAdapter.java
@@ -26,7 +26,7 @@
import com.android.gallery3d.common.ApiHelper;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.BitmapPool;
+import com.android.photos.data.GalleryBitmapPool;
public class TileImageViewAdapter implements TileImageView.TileSource {
private static final String TAG = "TileImageViewAdapter";
@@ -84,7 +84,7 @@
// (44, 44, 256, 256) from the original photo and down sample it to 106.
@TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
@Override
- public Bitmap getTile(int level, int x, int y, int tileSize, BitmapPool pool) {
+ public Bitmap getTile(int level, int x, int y, int tileSize) {
if (!ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER) {
return getTileWithoutReusingBitmap(level, x, y, tileSize);
}
@@ -106,7 +106,7 @@
.contains(wantRegion);
}
- Bitmap bitmap = pool == null ? null : pool.getBitmap();
+ Bitmap bitmap = GalleryBitmapPool.getInstance().get(tileSize, tileSize);
if (bitmap != null) {
if (needClear) bitmap.eraseColor(0);
} else {
@@ -126,7 +126,7 @@
}
} finally {
if (options.inBitmap != bitmap && options.inBitmap != null) {
- if (pool != null) pool.recycle(options.inBitmap);
+ GalleryBitmapPool.getInstance().put(options.inBitmap);
options.inBitmap = null;
}
}
diff --git a/src/com/android/gallery3d/ui/TiledScreenNail.java b/src/com/android/gallery3d/ui/TiledScreenNail.java
index ab24f5b..860e230 100644
--- a/src/com/android/gallery3d/ui/TiledScreenNail.java
+++ b/src/com/android/gallery3d/ui/TiledScreenNail.java
@@ -20,8 +20,7 @@
import android.graphics.RectF;
import com.android.gallery3d.common.Utils;
-import com.android.gallery3d.data.BitmapPool;
-import com.android.gallery3d.data.MediaItem;
+import com.android.photos.data.GalleryBitmapPool;
import com.android.gallery3d.glrenderer.GLCanvas;
import com.android.gallery3d.glrenderer.TiledTexture;
@@ -83,11 +82,6 @@
mHeight = Math.round(scale * height);
}
- private static void recycleBitmap(BitmapPool pool, Bitmap bitmap) {
- if (pool == null || bitmap == null) return;
- pool.recycle(bitmap);
- }
-
// Combines the two ScreenNails.
// Returns the used one and recycle the unused one.
public ScreenNail combine(ScreenNail other) {
@@ -106,7 +100,7 @@
mWidth = newer.mWidth;
mHeight = newer.mHeight;
if (newer.mTexture != null) {
- recycleBitmap(MediaItem.getThumbPool(), mBitmap);
+ if (mBitmap != null) GalleryBitmapPool.getInstance().put(mBitmap);
if (mTexture != null) mTexture.recycle();
mBitmap = newer.mBitmap;
mTexture = newer.mTexture;
@@ -143,8 +137,10 @@
mTexture.recycle();
mTexture = null;
}
- recycleBitmap(MediaItem.getThumbPool(), mBitmap);
- mBitmap = null;
+ if (mBitmap != null) {
+ GalleryBitmapPool.getInstance().put(mBitmap);
+ mBitmap = null;
+ }
}
public static void disableDrawPlaceholder() {
diff --git a/src/com/android/gallery3d/filtershow/ui/SliderListener.java b/src/com/android/photos/AlbumSetFragment.java
similarity index 69%
rename from src/com/android/gallery3d/filtershow/ui/SliderListener.java
rename to src/com/android/photos/AlbumSetFragment.java
index 6d4718d..2d348c2 100644
--- a/src/com/android/gallery3d/filtershow/ui/SliderListener.java
+++ b/src/com/android/photos/AlbumSetFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.gallery3d.filtershow.ui;
+package com.android.photos;
-public interface SliderListener {
- public void onNewValue(int value);
- public void onTouchDown(float x, float y);
- public void onTouchUp();
+import android.app.Fragment;
+
+
+public class AlbumSetFragment extends Fragment {
+
}
diff --git a/src/com/android/photos/GalleryActivity.java b/src/com/android/photos/GalleryActivity.java
new file mode 100644
index 0000000..46b5140
--- /dev/null
+++ b/src/com/android/photos/GalleryActivity.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos;
+
+import android.app.ActionBar;
+import android.app.ActionBar.Tab;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.android.camera.CameraActivity;
+import com.android.gallery3d.R;
+
+public class GalleryActivity extends Activity {
+
+ private final String FTAG_PHOTOSET = "PhotoSet";
+ private final String FTAG_ALBUMSET = "AlbumSet";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setupActionBar();
+ }
+
+ private void setupActionBar() {
+ ActionBar ab = getActionBar();
+ ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ ab.setDisplayShowHomeEnabled(false);
+ ab.setDisplayShowTitleEnabled(false);
+ Tab tab = ab.newTab();
+ tab.setText(R.string.tab_photos);
+ tab.setTabListener(new TabListener<PhotoSetFragment>(this,
+ FTAG_PHOTOSET, PhotoSetFragment.class));
+ ab.addTab(tab, true);
+ tab = ab.newTab();
+ tab.setText(R.string.tab_albums);
+ tab.setTabListener(new TabListener<AlbumSetFragment>(this,
+ FTAG_ALBUMSET, AlbumSetFragment.class));
+ ab.addTab(tab);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.gallery, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_camera:
+ Intent intent = new Intent(this, CameraActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private static class TabListener<T extends Fragment> implements ActionBar.TabListener {
+ private Fragment mFragment;
+ private final Activity mActivity;
+ private final String mTag;
+ private final Class<T> mClass;
+
+ /** Constructor used each time a new tab is created.
+ * @param activity The host Activity, used to instantiate the fragment
+ * @param tag The identifier tag for the fragment
+ * @param clz The fragment's Class, used to instantiate the fragment
+ */
+ public TabListener(Activity activity, String tag, Class<T> clz) {
+ mActivity = activity;
+ mTag = tag;
+ mClass = clz;
+ }
+
+ /* The following are each of the ActionBar.TabListener callbacks */
+
+ @Override
+ public void onTabSelected(Tab tab, FragmentTransaction ft) {
+ // Check if the fragment is already initialized
+ if (mFragment == null) {
+ // If not, instantiate and add it to the activity
+ mFragment = Fragment.instantiate(mActivity, mClass.getName());
+ ft.add(android.R.id.content, mFragment, mTag);
+ } else {
+ // If it exists, simply attach it in order to show it
+ ft.attach(mFragment);
+ }
+ }
+
+ @Override
+ public void onTabUnselected(Tab tab, FragmentTransaction ft) {
+ if (mFragment != null) {
+ // Detach the fragment, because another one is being attached
+ ft.detach(mFragment);
+ }
+ }
+
+ @Override
+ public void onTabReselected(Tab tab, FragmentTransaction ft) {
+ // User selected the already selected tab. Usually do nothing.
+ }
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/ui/SliderListener.java b/src/com/android/photos/PhotoFragment.java
similarity index 69%
copy from src/com/android/gallery3d/filtershow/ui/SliderListener.java
copy to src/com/android/photos/PhotoFragment.java
index 6d4718d..3be6313 100644
--- a/src/com/android/gallery3d/filtershow/ui/SliderListener.java
+++ b/src/com/android/photos/PhotoFragment.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-package com.android.gallery3d.filtershow.ui;
-public interface SliderListener {
- public void onNewValue(int value);
- public void onTouchDown(float x, float y);
- public void onTouchUp();
+package com.android.photos;
+
+import android.app.Fragment;
+
+
+public class PhotoFragment extends Fragment {
+
}
diff --git a/src/com/android/photos/PhotoSetFragment.java b/src/com/android/photos/PhotoSetFragment.java
new file mode 100644
index 0000000..e9bfce5
--- /dev/null
+++ b/src/com/android/photos/PhotoSetFragment.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos;
+
+import android.app.Fragment;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Loader;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.MediaStore.Files.FileColumns;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CursorAdapter;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+
+import com.android.gallery3d.R;
+import com.android.photos.data.PhotoSetLoader;
+
+
+public class PhotoSetFragment extends Fragment implements LoaderCallbacks<Cursor> {
+
+ private static final int LOADER_PHOTOSET = 1;
+
+ private ListView mPhotoSetView;
+ private View mEmptyView;
+ private CursorAdapter mAdapter;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.photo_set, container, false);
+ mPhotoSetView = (ListView) root.findViewById(android.R.id.list);
+ mEmptyView = root.findViewById(android.R.id.empty);
+ mEmptyView.setVisibility(View.GONE);
+ mAdapter = new SimpleCursorAdapter(getActivity(),
+ android.R.layout.simple_list_item_1, null,
+ new String[] { FileColumns.DATA },
+ new int[] { android.R.id.text1 }, 0);
+ mPhotoSetView.setAdapter(mAdapter);
+ getLoaderManager().initLoader(LOADER_PHOTOSET, null, this);
+ updateEmptyStatus();
+ return root;
+ }
+
+ private void updateEmptyStatus() {
+ boolean empty = (mAdapter == null || mAdapter.getCount() == 0);
+ mPhotoSetView.setVisibility(empty ? View.GONE : View.VISIBLE);
+ mEmptyView.setVisibility(empty ? View.VISIBLE : View.GONE);
+ }
+
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ return new PhotoSetLoader(getActivity());
+ }
+
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader,
+ Cursor data) {
+ mAdapter.swapCursor(data);
+ updateEmptyStatus();
+ }
+
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ }
+}
diff --git a/src/com/android/photos/data/GalleryBitmapPool.java b/src/com/android/photos/data/GalleryBitmapPool.java
new file mode 100644
index 0000000..cddc160
--- /dev/null
+++ b/src/com/android/photos/data/GalleryBitmapPool.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos.data;
+
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.util.Pools.Pool;
+import android.util.Pools.SimplePool;
+
+import com.android.photos.data.SparseArrayBitmapPool.Node;
+
+public class GalleryBitmapPool {
+
+ private static final int CAPACITY_BYTES = 20971520;
+ private static final int POOL_INDEX_NONE = -1;
+ private static final int POOL_INDEX_SQUARE = 0;
+ private static final int POOL_INDEX_PHOTO = 1;
+ private static final int POOL_INDEX_MISC = 2;
+
+ private static final Point[] COMMON_PHOTO_ASPECT_RATIOS =
+ { new Point(4, 3), new Point(3, 2), new Point(16, 9) };
+
+ private int mCapacityBytes;
+ private SparseArrayBitmapPool [] mPools;
+ private Pool<Node> mSharedNodePool = new SimplePool<Node>(128);
+
+ private GalleryBitmapPool(int capacityBytes) {
+ mPools = new SparseArrayBitmapPool[3];
+ mPools[POOL_INDEX_SQUARE] = new SparseArrayBitmapPool(capacityBytes / 3, mSharedNodePool);
+ mPools[POOL_INDEX_PHOTO] = new SparseArrayBitmapPool(capacityBytes / 3, mSharedNodePool);
+ mPools[POOL_INDEX_MISC] = new SparseArrayBitmapPool(capacityBytes / 3, mSharedNodePool);
+ mCapacityBytes = capacityBytes;
+ }
+
+ private static GalleryBitmapPool sInstance;
+ public static GalleryBitmapPool getInstance() {
+ if (sInstance == null) {
+ sInstance = new GalleryBitmapPool(CAPACITY_BYTES);
+ }
+ return sInstance;
+ }
+
+ private SparseArrayBitmapPool getPoolForDimensions(int width, int height) {
+ int index = getPoolIndexForDimensions(width, height);
+ if (index == POOL_INDEX_NONE) {
+ return null;
+ } else {
+ return mPools[index];
+ }
+ }
+
+ private int getPoolIndexForDimensions(int width, int height) {
+ if (width <= 0 || height <= 0) {
+ return POOL_INDEX_NONE;
+ }
+ if (width == height) {
+ return POOL_INDEX_SQUARE;
+ }
+ int min, max;
+ if (width > height) {
+ min = height;
+ max = width;
+ } else {
+ min = width;
+ max = height;
+ }
+ for (Point ar : COMMON_PHOTO_ASPECT_RATIOS) {
+ if (min * ar.x == max * ar.y) {
+ return POOL_INDEX_PHOTO;
+ }
+ }
+ return POOL_INDEX_MISC;
+ }
+
+ public synchronized int getCapacity() {
+ return mCapacityBytes;
+ }
+
+ public synchronized int getSize() {
+ int total = 0;
+ for (SparseArrayBitmapPool p : mPools) {
+ total += p.getSize();
+ }
+ return total;
+ }
+
+ public Bitmap get(int width, int height) {
+ SparseArrayBitmapPool pool = getPoolForDimensions(width, height);
+ if (pool == null) {
+ return null;
+ } else {
+ return pool.get(width, height);
+ }
+ }
+
+ public boolean put(Bitmap b) {
+ if (b == null) {
+ return false;
+ }
+ SparseArrayBitmapPool pool = getPoolForDimensions(b.getWidth(), b.getHeight());
+ if (pool == null) {
+ b.recycle();
+ return false;
+ } else {
+ return pool.put(b);
+ }
+ }
+
+ public void clear() {
+ for (SparseArrayBitmapPool p : mPools) {
+ p.clear();
+ }
+ }
+}
diff --git a/src/com/android/photos/data/MediaSetLoader.java b/src/com/android/photos/data/MediaSetLoader.java
new file mode 100644
index 0000000..4afb7d9
--- /dev/null
+++ b/src/com/android/photos/data/MediaSetLoader.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos.data;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+
+import com.android.gallery3d.data.ContentListener;
+import com.android.gallery3d.data.DataManager;
+import com.android.gallery3d.data.MediaSet;
+import com.android.gallery3d.data.MediaSet.SyncListener;
+import com.android.gallery3d.util.Future;
+
+/**
+ * Proof of concept, don't use
+ */
+public class MediaSetLoader extends AsyncTaskLoader<MediaSet> {
+
+ private static final SyncListener sNullListener = new SyncListener() {
+ @Override
+ public void onSyncDone(MediaSet mediaSet, int resultCode) {
+ }
+ };
+
+ private MediaSet mMediaSet;
+ private Future<Integer> mSyncTask = null;
+ private ContentListener mObserver = new ContentListener() {
+ @Override
+ public void onContentDirty() {
+ onContentChanged();
+ }
+ };
+
+ public MediaSetLoader(Context context, String path) {
+ super(context);
+ mMediaSet = DataManager.from(getContext()).getMediaSet(path);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ super.onStartLoading();
+ mMediaSet.addContentListener(mObserver);
+ mSyncTask = mMediaSet.requestSync(sNullListener);
+ forceLoad();
+ }
+
+ @Override
+ protected boolean onCancelLoad() {
+ if (mSyncTask != null) {
+ mSyncTask.cancel();
+ mSyncTask = null;
+ }
+ return super.onCancelLoad();
+ }
+
+ @Override
+ protected void onStopLoading() {
+ super.onStopLoading();
+ cancelLoad();
+ mMediaSet.removeContentListener(mObserver);
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+ onStopLoading();
+ }
+
+ @Override
+ public MediaSet loadInBackground() {
+ mMediaSet.loadIfDirty();
+ return mMediaSet;
+ }
+
+}
diff --git a/src/com/android/photos/data/PhotoSetLoader.java b/src/com/android/photos/data/PhotoSetLoader.java
new file mode 100644
index 0000000..8c511a5
--- /dev/null
+++ b/src/com/android/photos/data/PhotoSetLoader.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos.data;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Files;
+import android.provider.MediaStore.Files.FileColumns;
+
+public class PhotoSetLoader extends CursorLoader {
+
+ private static final Uri CONTENT_URI = Files.getContentUri("external");
+ private static final String[] PROJECTION = new String[] {
+ FileColumns._ID,
+ FileColumns.DATA,
+ FileColumns.WIDTH,
+ FileColumns.HEIGHT,
+ FileColumns.DATE_ADDED,
+ FileColumns.MEDIA_TYPE,
+ };
+ private static final String SORT_ORDER = FileColumns.DATE_ADDED + " DESC";
+ private static final String SELECTION =
+ FileColumns.MEDIA_TYPE + " == " + FileColumns.MEDIA_TYPE_IMAGE
+ + " OR "
+ + FileColumns.MEDIA_TYPE + " == " + FileColumns.MEDIA_TYPE_VIDEO;
+
+ public static final int INDEX_ID = 0;
+ public static final int INDEX_DATA = 1;
+ public static final int INDEX_WIDTH = 2;
+ public static final int INDEX_HEIGHT = 3;
+ public static final int INDEX_DATE_ADDED = 4;
+ public static final int INDEX_MEDIA_TYPE = 5;
+
+ private static final Uri GLOBAL_CONTENT_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/external/");
+ private final ContentObserver mGlobalObserver = new ForceLoadContentObserver();
+
+ public PhotoSetLoader(Context context) {
+ super(context, CONTENT_URI, PROJECTION, SELECTION, null, SORT_ORDER);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ super.onStartLoading();
+ getContext().getContentResolver().registerContentObserver(GLOBAL_CONTENT_URI,
+ true, mGlobalObserver);
+ }
+
+ @Override
+ protected void onReset() {
+ super.onReset();
+ getContext().getContentResolver().unregisterContentObserver(mGlobalObserver);
+ }
+}
diff --git a/src/com/android/photos/data/SparseArrayBitmapPool.java b/src/com/android/photos/data/SparseArrayBitmapPool.java
new file mode 100644
index 0000000..8512590
--- /dev/null
+++ b/src/com/android/photos/data/SparseArrayBitmapPool.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.photos.data;
+
+import android.graphics.Bitmap;
+import android.util.SparseArray;
+
+import android.util.Pools.Pool;
+
+public class SparseArrayBitmapPool {
+
+ private static final int BITMAPS_TO_KEEP_AFTER_UNNEEDED_HINT = 4;
+ private int mCapacityBytes;
+ private SparseArray<Node> mStore = new SparseArray<Node>();
+ private int mSizeBytes = 0;
+
+ private Pool<Node> mNodePool;
+ private Node mPoolNodesHead = null;
+ private Node mPoolNodesTail = null;
+
+ protected static class Node {
+ Bitmap bitmap;
+ Node prevInBucket;
+ Node nextInBucket;
+ Node nextInPool;
+ Node prevInPool;
+ }
+
+ public SparseArrayBitmapPool(int capacityBytes, Pool<Node> nodePool) {
+ mCapacityBytes = capacityBytes;
+ mNodePool = nodePool;
+ }
+
+ public synchronized void setCapacity(int capacityBytes) {
+ mCapacityBytes = capacityBytes;
+ freeUpCapacity(0);
+ }
+
+ private void freeUpCapacity(int bytesNeeded) {
+ int targetSize = mCapacityBytes - bytesNeeded;
+ while (mPoolNodesTail != null && mSizeBytes > targetSize) {
+ unlinkAndRecycleNode(mPoolNodesTail, true);
+ }
+ }
+
+ private void unlinkAndRecycleNode(Node n, boolean recycleBitmap) {
+ // Remove the node from its spot in its bucket
+ if (n.prevInBucket != null) {
+ n.prevInBucket.nextInBucket = n.nextInBucket;
+ } else {
+ mStore.put(n.bitmap.getWidth(), n.nextInBucket);
+ }
+ if (n.nextInBucket != null) {
+ n.nextInBucket.prevInBucket = n.prevInBucket;
+ }
+
+ // Remove the node from its spot in the list of pool nodes
+ if (n.prevInPool != null) {
+ n.prevInPool.nextInPool = n.nextInPool;
+ } else {
+ mPoolNodesHead = n.nextInPool;
+ }
+ if (n.nextInPool != null) {
+ n.nextInPool.prevInPool = n.prevInPool;
+ } else {
+ mPoolNodesTail = n.prevInPool;
+ }
+
+ // Recycle the node
+ n.nextInBucket = null;
+ n.nextInPool = null;
+ n.prevInBucket = null;
+ n.prevInPool = null;
+ mSizeBytes -= n.bitmap.getByteCount();
+ if (recycleBitmap) n.bitmap.recycle();
+ n.bitmap = null;
+ mNodePool.release(n);
+ }
+
+ public synchronized int getCapacity() {
+ return mCapacityBytes;
+ }
+
+ public synchronized int getSize() {
+ return mSizeBytes;
+ }
+
+ public synchronized Bitmap get(int width, int height) {
+ Node cur = mStore.get(width);
+ while (cur != null) {
+ if (cur.bitmap.getHeight() == height) {
+ Bitmap b = cur.bitmap;
+ unlinkAndRecycleNode(cur, false);
+ return b;
+ }
+ cur = cur.nextInBucket;
+ }
+ return null;
+ }
+
+ public synchronized boolean put(Bitmap b) {
+ if (b == null) {
+ return false;
+ }
+ int bytes = b.getByteCount();
+ freeUpCapacity(bytes);
+ Node newNode = mNodePool.acquire();
+ if (newNode == null) {
+ newNode = new Node();
+ }
+ newNode.bitmap = b;
+ newNode.prevInBucket = null;
+ newNode.prevInPool = null;
+ newNode.nextInPool = mPoolNodesHead;
+ mPoolNodesHead = newNode;
+ int key = b.getWidth();
+ newNode.nextInBucket = mStore.get(key);
+ if (newNode.nextInBucket != null) {
+ newNode.nextInBucket.prevInBucket = newNode;
+ }
+ mStore.put(key, newNode);
+ if (newNode.nextInPool == null) {
+ mPoolNodesTail = newNode;
+ }
+ mSizeBytes += bytes;
+ return true;
+ }
+
+ public synchronized void clear() {
+ freeUpCapacity(mCapacityBytes);
+ }
+}
diff --git a/tests/src/com/android/gallery3d/StressTests.java b/tests/src/com/android/gallery3d/StressTests.java
index 32eefdc..b991e9e 100755
--- a/tests/src/com/android/gallery3d/StressTests.java
+++ b/tests/src/com/android/gallery3d/StressTests.java
@@ -41,7 +41,7 @@
result.addTestSuite(CameraLatency.class);
result.addTestSuite(CameraStartUp.class);
result.addTestSuite(ImageCapture.class);
- result.addTestSuite(SwitchPreview.class);
+// result.addTestSuite(SwitchPreview.class);
return result;
}
}
diff --git a/tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java b/tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java
index 57ae691..d3fb10d 100755
--- a/tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java
+++ b/tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java
@@ -25,8 +25,8 @@
// Default recorder settings
public static int mVideoDuration = 20000; // set default to 20 seconds
- public static int mVideoIterations = 100; // set default to 100 videos
- public static int mImageIterations = 100; // set default to 100 images
+ public static int mVideoIterations = 1; // set default to 1 video
+ public static int mImageIterations = 10; // set default to 10 images
@Override
public TestSuite getAllTests() {