summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rwxr-xr-xAndroidManifest.xml39
-rw-r--r--assets/dependency.json7
-rw-r--r--jni/image_util_jni.cpp30
-rw-r--r--res/drawable-hdpi/ic_settings_selfiemirror.pngbin0 -> 1480 bytes
-rw-r--r--res/drawable-hdpi/ic_settings_shuttersound.pngbin0 -> 3581 bytes
-rw-r--r--res/drawable-hdpi/pick_the_best_photo.pngbin0 -> 55579 bytes
-rw-r--r--res/drawable-hdpi/pick_the_best_photo_selected.pngbin0 -> 1151 bytes
-rw-r--r--res/drawable-hdpi/pick_the_best_photo_unselected.pngbin0 -> 1005 bytes
-rw-r--r--res/drawable-xhdpi/ic_settings_selfiemirror.pngbin0 -> 2329 bytes
-rw-r--r--res/drawable-xhdpi/pick_the_best_photo.pngbin0 -> 56319 bytes
-rw-r--r--res/drawable-xhdpi/pick_the_best_photo_selected.pngbin0 -> 1726 bytes
-rw-r--r--res/drawable-xhdpi/pick_the_best_photo_unselected.pngbin0 -> 1523 bytes
-rw-r--r--res/drawable-xxhdpi/ic_settings_selfiemirror.pngbin0 -> 3215 bytes
-rw-r--r--res/drawable-xxhdpi/pick_the_best_photo.pngbin0 -> 57779 bytes
-rw-r--r--res/drawable-xxhdpi/pick_the_best_photo_selected.pngbin0 -> 2306 bytes
-rw-r--r--res/drawable-xxhdpi/pick_the_best_photo_unselected.pngbin0 -> 2118 bytes
-rw-r--r--res/layout/bestpicture_editor.xml69
-rw-r--r--res/layout/bestpicture_page.xml58
-rw-r--r--res/layout/capture_module.xml2
-rw-r--r--res/values/camera2arrays.xml13
-rw-r--r--res/values/qcomarrays.xml19
-rw-r--r--res/values/qcomstrings.xml22
-rw-r--r--res/xml/camera_preferences.xml14
-rw-r--r--res/xml/capture_preferences.xml24
-rw-r--r--src/com/android/camera/BestpictureActivity.java348
-rw-r--r--src/com/android/camera/BestpictureFragment.java93
-rwxr-xr-xsrc/com/android/camera/CameraActivity.java27
-rw-r--r--src/com/android/camera/CameraSettings.java2
-rw-r--r--src/com/android/camera/CaptureModule.java279
-rw-r--r--src/com/android/camera/CaptureUI.java39
-rw-r--r--src/com/android/camera/PermissionsActivity.java26
-rwxr-xr-xsrc/com/android/camera/PhotoMenu.java12
-rw-r--r--src/com/android/camera/PhotoModule.java65
-rw-r--r--src/com/android/camera/PhotoUI.java9
-rw-r--r--src/com/android/camera/PreviewGestures.java25
-rw-r--r--src/com/android/camera/SettingsManager.java113
-rwxr-xr-xsrc/com/android/camera/VideoModule.java6
-rw-r--r--src/com/android/camera/VideoUI.java3
-rw-r--r--src/com/android/camera/WideAnglePanoramaModule.java6
-rw-r--r--src/com/android/camera/imageprocessor/FrameProcessor.java50
-rw-r--r--src/com/android/camera/imageprocessor/PostProcessor.java33
-rw-r--r--src/com/android/camera/imageprocessor/filter/BestpictureFilter.java252
-rw-r--r--src/com/android/camera/imageprocessor/filter/StillmoreFilter.java175
-rw-r--r--src/com/android/camera/imageprocessor/filter/UbifocusFilter.java21
-rw-r--r--src/com/android/camera/ui/DotsView.java98
-rw-r--r--src/com/android/camera/ui/DotsViewItem.java35
-rw-r--r--src/com/android/camera/util/PersistUtil.java4
48 files changed, 1876 insertions, 143 deletions
diff --git a/Android.mk b/Android.mk
index 5077a1c06..2f9723815 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,6 +5,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-v4
LOCAL_STATIC_JAVA_LIBRARIES += xmp_toolkit
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 37ce25f8b..6ec0df351 100755
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -54,18 +54,6 @@
android:taskAffinity="com.android.camera.CameraActivity"
android:theme="@style/Theme.Camera"
android:windowSoftInputMode="stateAlwaysHidden|adjustPan" >
- <intent-filter>
- <action android:name="android.media.action.IMAGE_CAPTURE" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- <intent-filter>
- <action android:name="android.media.action.STILL_IMAGE_CAMERA" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- </intent-filter>
<meta-data
android:name="com.android.keyguard.layout"
@@ -95,13 +83,33 @@
</intent-filter>
</activity-alias>
+ <activity-alias
+ android:name="com.android.camera.PhotoCamera"
+ android:icon="@mipmap/ic_launcher_camera"
+ android:label="@string/snapcam_app_name"
+ android:launchMode="singleTop"
+ android:targetActivity="com.android.camera.PermissionsActivity">
+ <intent-filter>
+ <action android:name="android.media.action.IMAGE_CAPTURE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.media.action.STILL_IMAGE_CAMERA" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity-alias>
+
<!-- Video camera and capture use the Camcorder label and icon. -->
<activity-alias
android:name="com.android.camera.VideoCamera"
android:icon="@mipmap/ic_launcher_video_camera"
android:label="@string/video_camera_label"
android:launchMode="singleTop"
- android:targetActivity="com.android.camera.CameraActivity">
+ android:targetActivity="com.android.camera.PermissionsActivity">
<intent-filter>
<action android:name="android.media.action.VIDEO_CAMERA" />
<category android:name="android.intent.category.DEFAULT" />
@@ -164,6 +172,11 @@
android:configChanges="keyboardHidden|orientation|screenSize">
</activity>
+ <activity
+ android:name="com.android.camera.BestpictureActivity"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+ </activity>
+
<receiver android:name="com.android.camera.DisableCameraReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
diff --git a/assets/dependency.json b/assets/dependency.json
index 390adcde4..39f9f91b0 100644
--- a/assets/dependency.json
+++ b/assets/dependency.json
@@ -53,5 +53,12 @@
"off":{},
"on":
{"pref_camera2_mpo_key":"on"}
+ },
+ "pref_camera2_video_time_lapse_frame_interval_key":
+ {
+ "default":
+ {"pref_camera2_hfr_key":"off"}
+ ,
+ "0":{}
}
}
diff --git a/jni/image_util_jni.cpp b/jni/image_util_jni.cpp
index 2297f9164..a4779b3d7 100644
--- a/jni/image_util_jni.cpp
+++ b/jni/image_util_jni.cpp
@@ -44,6 +44,8 @@ JNIEXPORT jint JNICALL Java_com_android_camera_imageprocessor_FrameProcessor_nat
jint imageWidth, jint imageHeight, jint degree, jobjectArray outBuf);
JNIEXPORT jint JNICALL Java_com_android_camera_imageprocessor_FrameProcessor_nativeNV21toRgb(
JNIEnv *env, jobject thiz, jobjectArray yvuBuf, jobjectArray rgbBuf, jint width, jint height);
+JNIEXPORT jint JNICALL Java_com_android_camera_imageprocessor_PostProcessor_nativeFlipVerticalNV21(
+ JNIEnv* env, jobject thiz, jbyteArray yvuBytes, jint width, jint height);
#ifdef __cplusplus
}
#endif
@@ -150,4 +152,32 @@ jint JNICALL Java_com_android_camera_imageprocessor_FrameProcessor_nativeNV21toR
}
}
return 0;
+}
+
+jint JNICALL Java_com_android_camera_imageprocessor_PostProcessor_nativeFlipVerticalNV21(
+ JNIEnv* env, jobject thiz, jbyteArray yvuBytes, jint width, jint height)
+{
+ jbyte* imageDataNV21Array = env->GetByteArrayElements(yvuBytes, NULL);
+ uint8_t *buf = (uint8_t *)imageDataNV21Array;
+ int ysize = width * height;
+ uint8_t temp1, temp2;
+ for(int x=0; x < width; x++) {
+ for(int y=0; y < height/2; y++) {
+ temp1 = buf[y*width + x];
+ buf[y*width + x] = buf[(height-1-y)*width + x];
+ buf[(height-1-y)*width + x] = temp1;
+ }
+ }
+ for(int x=0; x < width; x+=2) {
+ for(int y=0; y < height/4; y++) {
+ temp1 = buf[ysize + y*width + x];
+ temp2 = buf[ysize + y*width + x + 1];
+ buf[ysize + y*width + x] = buf[ysize + (height/2-1-y)*width + x];
+ buf[ysize + y*width + x + 1] = buf[ysize + (height/2-1-y)*width + x + 1];
+ buf[ysize + (height/2-1-y)*width + x] = temp1;
+ buf[ysize + (height/2-1-y)*width + x + 1] = temp2;
+ }
+ }
+ env->ReleaseByteArrayElements(yvuBytes, imageDataNV21Array, JNI_ABORT);
+ return 0;
} \ No newline at end of file
diff --git a/res/drawable-hdpi/ic_settings_selfiemirror.png b/res/drawable-hdpi/ic_settings_selfiemirror.png
new file mode 100644
index 000000000..c6d0f8be7
--- /dev/null
+++ b/res/drawable-hdpi/ic_settings_selfiemirror.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_settings_shuttersound.png b/res/drawable-hdpi/ic_settings_shuttersound.png
new file mode 100644
index 000000000..ba1e42321
--- /dev/null
+++ b/res/drawable-hdpi/ic_settings_shuttersound.png
Binary files differ
diff --git a/res/drawable-hdpi/pick_the_best_photo.png b/res/drawable-hdpi/pick_the_best_photo.png
new file mode 100644
index 000000000..f0b892136
--- /dev/null
+++ b/res/drawable-hdpi/pick_the_best_photo.png
Binary files differ
diff --git a/res/drawable-hdpi/pick_the_best_photo_selected.png b/res/drawable-hdpi/pick_the_best_photo_selected.png
new file mode 100644
index 000000000..d2b5f1508
--- /dev/null
+++ b/res/drawable-hdpi/pick_the_best_photo_selected.png
Binary files differ
diff --git a/res/drawable-hdpi/pick_the_best_photo_unselected.png b/res/drawable-hdpi/pick_the_best_photo_unselected.png
new file mode 100644
index 000000000..13bdec3e3
--- /dev/null
+++ b/res/drawable-hdpi/pick_the_best_photo_unselected.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_settings_selfiemirror.png b/res/drawable-xhdpi/ic_settings_selfiemirror.png
new file mode 100644
index 000000000..975448e94
--- /dev/null
+++ b/res/drawable-xhdpi/ic_settings_selfiemirror.png
Binary files differ
diff --git a/res/drawable-xhdpi/pick_the_best_photo.png b/res/drawable-xhdpi/pick_the_best_photo.png
new file mode 100644
index 000000000..629af4a09
--- /dev/null
+++ b/res/drawable-xhdpi/pick_the_best_photo.png
Binary files differ
diff --git a/res/drawable-xhdpi/pick_the_best_photo_selected.png b/res/drawable-xhdpi/pick_the_best_photo_selected.png
new file mode 100644
index 000000000..92f11cb17
--- /dev/null
+++ b/res/drawable-xhdpi/pick_the_best_photo_selected.png
Binary files differ
diff --git a/res/drawable-xhdpi/pick_the_best_photo_unselected.png b/res/drawable-xhdpi/pick_the_best_photo_unselected.png
new file mode 100644
index 000000000..a558c7a1f
--- /dev/null
+++ b/res/drawable-xhdpi/pick_the_best_photo_unselected.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_settings_selfiemirror.png b/res/drawable-xxhdpi/ic_settings_selfiemirror.png
new file mode 100644
index 000000000..b49b6fa4a
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_settings_selfiemirror.png
Binary files differ
diff --git a/res/drawable-xxhdpi/pick_the_best_photo.png b/res/drawable-xxhdpi/pick_the_best_photo.png
new file mode 100644
index 000000000..2374b1848
--- /dev/null
+++ b/res/drawable-xxhdpi/pick_the_best_photo.png
Binary files differ
diff --git a/res/drawable-xxhdpi/pick_the_best_photo_selected.png b/res/drawable-xxhdpi/pick_the_best_photo_selected.png
new file mode 100644
index 000000000..522e9f2ba
--- /dev/null
+++ b/res/drawable-xxhdpi/pick_the_best_photo_selected.png
Binary files differ
diff --git a/res/drawable-xxhdpi/pick_the_best_photo_unselected.png b/res/drawable-xxhdpi/pick_the_best_photo_unselected.png
new file mode 100644
index 000000000..98e18b07e
--- /dev/null
+++ b/res/drawable-xxhdpi/pick_the_best_photo_unselected.png
Binary files differ
diff --git a/res/layout/bestpicture_editor.xml b/res/layout/bestpicture_editor.xml
new file mode 100644
index 000000000..6c35c27a1
--- /dev/null
+++ b/res/layout/bestpicture_editor.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v4.view.ViewPager
+ android:id="@+id/bestpicture_pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:background="#b2191919">
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentRight="true">
+ <TextView
+ android:id="@+id/bestpicture_done"
+ android:text="@string/bestpicture_done"
+ android:textColor="#ffffff"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"/>
+ </LinearLayout>
+ </RelativeLayout>
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="50dp"
+ android:layout_gravity="bottom"
+ android:background="#b2191919">
+ <com.android.camera.ui.DotsView
+ android:id="@+id/dots_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true" />
+ </RelativeLayout>
+</FrameLayout>
diff --git a/res/layout/bestpicture_page.xml b/res/layout/bestpicture_page.xml
new file mode 100644
index 000000000..d6b6022c8
--- /dev/null
+++ b/res/layout/bestpicture_page.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView
+ android:id="@+id/image_view"
+ android:adjustViewBounds="true"
+ android:scaleType="fitXY"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center" />
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:id="@+id/click_view">
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="150dp"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true">
+ <ImageView
+ android:id="@+id/picture_select"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:layout_marginRight="20dp"/>
+ </LinearLayout>
+ </RelativeLayout>
+</FrameLayout>
diff --git a/res/layout/capture_module.xml b/res/layout/capture_module.xml
index dd7d3cb1b..41757c535 100644
--- a/res/layout/capture_module.xml
+++ b/res/layout/capture_module.xml
@@ -27,7 +27,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center">
-
+ <include layout="@layout/selfie_flash_view" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/res/values/camera2arrays.xml b/res/values/camera2arrays.xml
index 37a33ec17..1f590fc32 100644
--- a/res/values/camera2arrays.xml
+++ b/res/values/camera2arrays.xml
@@ -133,6 +133,7 @@
<item>8</item>
<item>9</item>
<item>-1</item>
+ <item>103</item>
</string-array>
<!-- Camera Preferences Scene Mode dialog box entries -->
@@ -153,6 +154,7 @@
<item>@string/pref_camera_scenemode_entry_beach</item>
<item>@string/pref_camera_scenemode_entry_snow</item>
<item>@string/pref_camera_scenemode_entry_asd</item>
+ <item>@string/pref_camera_scenemode_entry_bestpicture</item>
</string-array>
<array name="pref_camera2_scenemode_thumbnails" translatable="false">
@@ -172,6 +174,7 @@
<item>@drawable/ic_scene_mode_beach</item>
<item>@drawable/ic_scene_mode_snow</item>
<item>@drawable/ic_scene_mode_smartauto</item>
+ <item>@drawable/pick_the_best_photo</item>
</array>
<string-array name="pref_camera2_whitebalance_entryvalues" translatable="false">
@@ -826,4 +829,14 @@ for time lapse recording -->
<item>@string/pref_camera2_videosnap_value_enable</item>
<item>@string/pref_camera2_videosnap_value_disable</item>
</string-array>
+
+ <string-array name="pref_camera2_shutter_sound_entries" translatable="true">
+ <item>@string/pref_camera2_shutter_sound_entry_on</item>
+ <item>@string/pref_camera2_shutter_sound_entry_off</item>
+ </string-array>
+
+ <string-array name="pref_camera2_shutter_sound_entryvalues" translatable="false">
+ <item>@string/pref_camera2_shutter_sound_value_on</item>
+ <item>@string/pref_camera2_shutter_sound_value_off</item>
+ </string-array>
</resources>
diff --git a/res/values/qcomarrays.xml b/res/values/qcomarrays.xml
index 7574992b9..5a7f7a309 100644
--- a/res/values/qcomarrays.xml
+++ b/res/values/qcomarrays.xml
@@ -587,6 +587,25 @@
<item>disable</item>
<item>enable</item>
</string-array>
+
+ <string-array name="pref_camera_selfiemirror_entries" translatable="false">
+ <item>@string/pref_camera_selfiemirror_entry_disable</item>
+ <item>@string/pref_camera_selfiemirror_entry_enable</item>
+ </string-array>
+ <string-array name="pref_camera_selfiemirror_entryvalues" translatable="false">
+ <item>disable</item>
+ <item>enable</item>
+ </string-array>
+
+ <string-array name="pref_camera_shuttersound_entries" translatable="false">
+ <item>@string/pref_camera_shuttersound_entry_disable</item>
+ <item>@string/pref_camera_shuttersound_entry_enable</item>
+ </string-array>
+ <string-array name="pref_camera_shuttersound_entryvalues" translatable="false">
+ <item>disable</item>
+ <item>enable</item>
+ </string-array>
+
<!-- Camera Preferences Selectable Zone AF dialog box entries -->
<string-array name="pref_camera_selectablezoneaf_entries" translatable="false">
<item>@string/pref_camera_selectablezoneaf_entry_auto</item>
diff --git a/res/values/qcomstrings.xml b/res/values/qcomstrings.xml
index 0fb750590..330cb8979 100644
--- a/res/values/qcomstrings.xml
+++ b/res/values/qcomstrings.xml
@@ -322,6 +322,17 @@
<!-- Settings menu, redeye reduction choices -->
<string name="pref_camera_redeyereduction_entry_enable">Enable</string>
<string name="pref_camera_redeyereduction_entry_disable">Disable</string>
+
+ <string name="pref_camera_selfiemirror_default" translatable="false">disable</string>
+ <string name="pref_camera_selfiemirror_title" translatable="true">Selfie Mirror</string>
+ <string name="pref_camera_selfiemirror_entry_enable">Enable</string>
+ <string name="pref_camera_selfiemirror_entry_disable">Disable</string>
+
+ <string name="pref_camera_shuttersound_default" translatable="false">enable</string>
+ <string name="pref_camera_shuttersound_title" translatable="true">Shutter Sound</string>
+ <string name="pref_camera_shuttersound_entry_enable">Enable</string>
+ <string name="pref_camera_shuttersound_entry_disable">Disable</string>
+
<!-- Default mce setting. Do not translate. -->
<string name="pref_camera_mce_default">enable</string>
@@ -1012,5 +1023,16 @@
<string name="pref_camera2_videosnap_entry_enable" translatable="true">Enable</string>
<string name="pref_camera2_videosnap_entry_disable" translatable="true">Disable</string>
<string name="pref_camera2_trackingfocus_title" translatable="true">Tracking Focus</string>
+ <string name="pref_camera_scenemode_entry_bestpicture" translatable="true">BestPicture</string>
+ <string name="bestpicture_done" translatable="true">DONE</string>
+ <string name="bestpicture_at_least_one_picture" translatable="true">At least, one picture has to be chosen.</string>
+
+ <string name="pref_camera2_shutter_sound_default" translatable="true">on</string>
+ <string name="pref_camera2_shutter_sound_value_on" translatable="true">on</string>
+ <string name="pref_camera2_shutter_sound_value_off" translatable="true">off</string>
+
+ <string name="pref_camera2_shutter_sound_entry_on" translatable="true">On</string>
+ <string name="pref_camera2_shutter_sound_entry_off" translatable="true">Off</string>
+ <string name="pref_camera2_shutter_sound_title" translatable="true">Shutter Sound</string>
</resources>
diff --git a/res/xml/camera_preferences.xml b/res/xml/camera_preferences.xml
index 7e024b298..742c09d33 100644
--- a/res/xml/camera_preferences.xml
+++ b/res/xml/camera_preferences.xml
@@ -285,6 +285,20 @@
camera:entries="@array/pref_camera_redeyereduction_entries"
camera:singleIcon="@drawable/ic_settings_redeye"
camera:entryValues="@array/pref_camera_redeyereduction_entryvalues" />
+ <IconListPreference
+ camera:key="pref_camera_selfiemirror_key"
+ camera:defaultValue="@string/pref_camera_selfiemirror_default"
+ camera:title="@string/pref_camera_selfiemirror_title"
+ camera:entries="@array/pref_camera_selfiemirror_entries"
+ camera:singleIcon="@drawable/ic_settings_selfiemirror"
+ camera:entryValues="@array/pref_camera_selfiemirror_entryvalues" />
+ <IconListPreference
+ camera:key="pref_camera_shuttersound_key"
+ camera:defaultValue="@string/pref_camera_shuttersound_default"
+ camera:title="@string/pref_camera_shuttersound_title"
+ camera:entries="@array/pref_camera_shuttersound_entries"
+ camera:singleIcon="@drawable/ic_settings_shuttersound"
+ camera:entryValues="@array/pref_camera_shuttersound_entryvalues" />
<ListPreference
camera:key="pref_camera_selectablezoneaf_key"
camera:defaultValue="@string/pref_camera_selectablezoneaf_default"
diff --git a/res/xml/capture_preferences.xml b/res/xml/capture_preferences.xml
index 2f0849442..dae2c5f7d 100644
--- a/res/xml/capture_preferences.xml
+++ b/res/xml/capture_preferences.xml
@@ -280,10 +280,34 @@
camera:entryValues="@array/pref_camera2_videosnap_entryvalues"
camera:key="pref_camera2_videosnap_key"
camera:title="@string/pref_camera2_videosnap_title" />
+
<ListPreference
camera:defaultValue="off"
camera:key="pref_camera2_trackingfocus_key"
camera:entries="@array/pref_camera2_trackingfocus_entries"
camera:entryValues="@array/pref_camera2_trackingfocus_entryvalues"
camera:title="@string/pref_camera2_trackingfocus_title"/>
+
+ <IconListPreference
+ camera:defaultValue="@string/pref_camera_hfr_default"
+ camera:entries="@array/pref_camera_hfr_entries"
+ camera:entryValues="@array/pref_camera_hfr_entryvalues"
+ camera:key="pref_camera2_hfr_key"
+ camera:singleIcon="@drawable/ic_settings_fps"
+ camera:title="@string/pref_camera_hfr_title" />
+
+ <IconListPreference
+ camera:defaultValue="@string/pref_selfie_flash_default"
+ camera:entries="@array/pref_selfie_flash_entries"
+ camera:entryValues="@array/pref_selfie_flash_entryvalues"
+ camera:key="pref_selfie_flash_key"
+ camera:singleIcon="@drawable/ic_settings_flash"
+ camera:title="@string/pref_selfie_flash_title" />
+
+ <ListPreference
+ camera:defaultValue="@string/pref_camera2_shutter_sound_default"
+ camera:entries="@array/pref_camera2_shutter_sound_entries"
+ camera:entryValues="@array/pref_camera2_shutter_sound_entryvalues"
+ camera:key="pref_camera2_shutter_sound_key"
+ camera:title="@string/pref_camera2_shutter_sound_title" />
</PreferenceGroup>
diff --git a/src/com/android/camera/BestpictureActivity.java b/src/com/android/camera/BestpictureActivity.java
new file mode 100644
index 000000000..bb519e74f
--- /dev/null
+++ b/src/com/android/camera/BestpictureActivity.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.camera;
+
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.v13.app.FragmentStatePagerAdapter;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.Log;
+import android.view.Display;
+import android.view.Menu;
+import android.view.View;
+import android.support.v4.app.FragmentActivity;
+import android.widget.Toast;
+
+import com.android.camera.exif.ExifInterface;
+import com.android.camera.ui.DotsView;
+import com.android.camera.ui.DotsViewItem;
+import com.android.camera.ui.RotateTextToast;
+import com.android.camera.util.CameraUtil;
+
+import org.codeaurora.snapcam.R;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+public class BestpictureActivity extends FragmentActivity{
+ private static final String TAG = "BestpictureActivity";
+ public static final String[] NAMES = {
+ "00", "01", "02", "03", "04", "05", "06", "07", "08", "09"
+ };
+
+ public static final int NUM_IMAGES = 10;
+
+ private ViewPager mImagePager;
+ private PagerAdapter mImagePagerAdapter;
+ private int mWidth;
+ private int mHeight;
+ private String mFilesPath;
+ private ProgressDialog mProgressDialog;
+ private BestpictureActivity mActivity;
+ private DotsView mDotsView;
+ private ImageItems mImageItems;
+ private ImageLoadingThread mLoadingThread;
+ private PhotoModule.NamedImages mNamedImages;
+ private Uri mPlaceHolderUri;
+ public static int BESTPICTURE_ACTIVITY_CODE = 11;
+
+ static class ImageItems implements Parcelable, DotsViewItem {
+ private Bitmap[] mBitmap;
+ private boolean[] mChosen;
+ private BestpictureActivity mActivity;
+
+ public ImageItems(BestpictureActivity activity) {
+ mBitmap = new Bitmap[NUM_IMAGES];
+ mChosen = new boolean[NUM_IMAGES];
+ for (int i = 0; i < mChosen.length; i++) {
+ if (i == 0) {
+ mChosen[i] = true;
+ } else {
+ mChosen[i] = false;
+ }
+ }
+ mActivity = activity;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public Bitmap getBitmap(int index) {
+ return mBitmap[index];
+ }
+
+ public void setBitmap(int index, Bitmap bitmap) {
+ mBitmap[index] = bitmap;
+ }
+
+ @Override
+ public int getTotalItemNums() {
+ return NUM_IMAGES;
+ }
+
+ public boolean isChosen(int index) {
+ return mChosen[index];
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+
+ public void toggleImageSelection(int num) {
+ mChosen[num] = !mChosen[num];
+ boolean isChosen = false;
+ for(int i=0; i < mChosen.length; i++) {
+ isChosen |= mChosen[i];
+ }
+ if(!isChosen) {
+ mChosen[num] = true;
+ RotateTextToast.makeText(mActivity,
+ mActivity.getResources().getString(R.string.bestpicture_at_least_one_picture),
+ Toast.LENGTH_SHORT).show();
+ }
+ mActivity.mDotsView.update();
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle state) {
+ super.onCreate(state);
+ mActivity = this;
+ mFilesPath = getFilesDir()+"/Bestpicture";
+ setContentView(R.layout.bestpicture_editor);
+ Display display = getWindowManager().getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+ mWidth = size.x/2;
+ mHeight = size.y/2;
+ mNamedImages = new PhotoModule.NamedImages();
+
+ mImageItems = new ImageItems(mActivity);
+ mDotsView = (DotsView) findViewById(R.id.dots_view);
+ mDotsView.setItems(mImageItems);
+ mPlaceHolderUri = getIntent().getData();
+
+ mImagePager = (ViewPager) findViewById(R.id.bestpicture_pager);
+ mImagePagerAdapter = new ImagePagerAdapter(getFragmentManager());
+ mImagePager.setAdapter(mImagePagerAdapter);
+ mImagePager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ mDotsView.update(position, positionOffset);
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ }
+ });
+ findViewById(R.id.bestpicture_done).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ int index = -1;
+ for(int i=0; i < mImageItems.mChosen.length; i++) {
+ if (mImageItems.mChosen[i]) {
+ if(index != -1) {
+ new SaveImageTask().execute(mFilesPath + "/" + NAMES[i] + ".jpg");
+ } else {
+ index = i;
+ saveForground(mFilesPath + "/" + NAMES[i] + ".jpg");
+ }
+ }
+ }
+ setResult(RESULT_OK, new Intent());
+ finish();
+ }
+ });
+ }
+
+ private class ImageLoadingThread extends Thread {
+ public void run() {
+ showProgressDialog();
+ for(int i=0; i < NUM_IMAGES; i++) {
+ String path = mFilesPath + "/" + BestpictureActivity.NAMES[i] + ".jpg";
+ final BitmapFactory.Options o = new BitmapFactory.Options();
+ o.inJustDecodeBounds = true;
+ BitmapFactory.decodeFile(path, o);
+ ExifInterface exif = new ExifInterface();
+ int orientation = 0;
+ try {
+ exif.readExif(path);
+ orientation = Exif.getOrientation(exif);
+ } catch (IOException e) {
+ }
+ int h = o.outHeight;
+ int w = o.outWidth;
+ int sample = 1;
+ if (h > mHeight || w > mWidth) {
+ while (h / sample / 2 > mHeight && w / sample / 2 > mWidth) {
+ sample *= 2;
+ }
+ }
+
+ o.inJustDecodeBounds = false;
+ o.inSampleSize = sample;
+ Bitmap bitmap = BitmapFactory.decodeFile(path, o);
+ if (orientation != 0) {
+ Matrix matrix = new Matrix();
+ matrix.setRotate(orientation);
+ bitmap = Bitmap.createBitmap(bitmap, 0, 0,
+ bitmap.getWidth(), bitmap.getHeight(), matrix, false);
+ }
+ mImageItems.setBitmap(i, bitmap);
+ }
+ dismissProgressDialog();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mLoadingThread == null) {
+ mLoadingThread = new ImageLoadingThread();
+ mLoadingThread.start();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ }
+
+ private void showProgressDialog() {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mProgressDialog = ProgressDialog.show(mActivity, "", "Processing...", true, false);
+ mProgressDialog.show();
+ }
+ });
+ }
+
+ private void dismissProgressDialog() {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ if (mProgressDialog != null && mProgressDialog.isShowing()) {
+ mProgressDialog.dismiss();
+ mProgressDialog = null;
+ }
+ }
+ });
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ return true;
+ }
+
+ private class ImagePagerAdapter extends FragmentStatePagerAdapter {
+ public ImagePagerAdapter(android.app.FragmentManager manager) {
+ super(manager);
+ }
+
+ @Override
+ public android.app.Fragment getItem(int imageNum) {
+ while(mImageItems.getBitmap(imageNum) == null) {
+ try {
+ Thread.sleep(5);
+ } catch (Exception e) {
+ }
+ }
+ return BestpictureFragment.create(imageNum, mImageItems);
+ }
+
+ @Override
+ public int getCount() {
+ return NUM_IMAGES;
+ }
+ }
+
+ private void saveForground(String path) {
+ long captureStartTime = System.currentTimeMillis();
+ mNamedImages.nameNewImage(captureStartTime);
+ PhotoModule.NamedImages.NamedEntity name = mNamedImages.getNextNameEntity();
+ String title = (name == null) ? null : name.title;
+ String outPath = mPlaceHolderUri.getPath();
+ try {
+ FileOutputStream out = new FileOutputStream(outPath);
+ FileInputStream in = new FileInputStream(path);
+ byte[] buf = new byte[4096];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ in.close();
+ out.close();
+ } catch (Exception e) {
+ }
+ }
+
+ private class SaveImageTask extends AsyncTask<String, Void, Void> {
+ protected Void doInBackground(String... path) {
+ long captureStartTime = System.currentTimeMillis();
+ mNamedImages.nameNewImage(captureStartTime);
+ PhotoModule.NamedImages.NamedEntity name = mNamedImages.getNextNameEntity();
+ String title = (name == null) ? null : name.title;
+ String outPath = Storage.generateFilepath(title, "jpeg");
+ try {
+ FileOutputStream out = new FileOutputStream(outPath);
+ FileInputStream in = new FileInputStream(path[0]);
+ byte[] buf = new byte[4096];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ in.close();
+ out.close();
+ } catch (Exception e) {
+ }
+ Uri uri = Uri.fromFile(new File(outPath));
+ Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
+ sendBroadcast(intent);
+ return null;
+ }
+
+ protected void onPostExecute(Void v) {
+ }
+ }
+}
diff --git a/src/com/android/camera/BestpictureFragment.java b/src/com/android/camera/BestpictureFragment.java
new file mode 100644
index 000000000..6dc4ebd59
--- /dev/null
+++ b/src/com/android/camera/BestpictureFragment.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.camera;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import org.codeaurora.snapcam.R;
+
+public class BestpictureFragment extends Fragment {
+ public static final String PARAM_IMAGE_NUM = "image_num";
+ private static final String TAG = "BestpictureFilter";
+ private int mImageNum;
+ private ImageView mImageView;
+ private ImageView mPictureSelectButton;
+ private BestpictureActivity.ImageItems mImageItems;
+
+ public static BestpictureFragment create(int imageNum, BestpictureActivity.ImageItems items) {
+ BestpictureFragment fragment = new BestpictureFragment();
+ Bundle args = new Bundle();
+ args.putInt(PARAM_IMAGE_NUM, imageNum);
+ args.putParcelable("imageItems", items);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ public BestpictureFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mImageNum = getArguments().getInt(PARAM_IMAGE_NUM);
+ mImageItems = getArguments().getParcelable("imageItems");
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ ViewGroup rootView = (ViewGroup) inflater
+ .inflate(R.layout.bestpicture_page, container, false);
+ mImageView = (ImageView) rootView.findViewById(R.id.image_view);
+ mPictureSelectButton = (ImageView) rootView.findViewById(R.id.picture_select);
+ initSelectButton();
+ mImageView.setImageBitmap(mImageItems.getBitmap(mImageNum));
+ rootView.findViewById(R.id.picture_select).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ mImageItems.toggleImageSelection(mImageNum);
+ initSelectButton();
+ }
+ });
+ return rootView;
+ }
+
+ private void initSelectButton() {
+ if(mImageItems.isChosen(mImageNum)) {
+ mPictureSelectButton.setBackground(getResources().getDrawable(R.drawable.pick_the_best_photo_selected, null));
+ } else {
+ mPictureSelectButton.setBackground(getResources().getDrawable(R.drawable.pick_the_best_photo_unselected, null));
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index 5666331fa..e5c24fff8 100755
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -16,6 +16,8 @@
package com.android.camera;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.view.Display;
import android.graphics.Point;
import android.Manifest;
@@ -67,7 +69,6 @@ import android.os.PowerManager.WakeLock;
import android.os.SystemProperties;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
-import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -224,6 +225,7 @@ public class CameraActivity extends Activity
private FrameLayout mPreviewContentLayout;
private boolean mPaused = true;
private boolean mHasCriticalPermissions;
+ private boolean mForceReleaseCamera = false;
private Uri[] mNfcPushUris = new Uri[1];
@@ -1642,6 +1644,13 @@ public class CameraActivity extends Activity
if(resultCode == RESULT_OK) {
mCaptureModule.setRefocusLastTaken(false);
}
+ } else if (requestCode == BestpictureActivity.BESTPICTURE_ACTIVITY_CODE) {
+ if(resultCode == RESULT_OK) {
+ byte[] jpeg = data.getByteArrayExtra("thumbnail");
+ if(jpeg != null) {
+ updateThumbnail(jpeg);
+ }
+ }
} else {
super.onActivityResult(requestCode, resultCode, data);
}
@@ -1672,8 +1681,7 @@ public class CameraActivity extends Activity
} else {
mHasCriticalPermissions = false;
}
- if ((checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
- !mHasCriticalPermissions) {
+ if (!mHasCriticalPermissions) {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean isRequestShown = prefs.getBoolean(CameraSettings.KEY_REQUEST_PERMISSION, false);
if(!isRequestShown || !mHasCriticalPermissions) {
@@ -1903,9 +1911,9 @@ public class CameraActivity extends Activity
switch (requestCode) {
case PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION: {
// If request is cancelled, the result arrays are empty.
- mCurrentModule.waitingLocationPermissionResult(false);
+ mCurrentModule.waitingLocationPermissionResult(false);
if (grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.v(TAG, "Location permission is granted");
mCurrentModule.enableRecordingLocation(true);
} else {
@@ -1917,11 +1925,17 @@ public class CameraActivity extends Activity
}
}
+ public boolean isForceReleaseCamera() {
+ return mForceReleaseCamera;
+ }
+
@Override
public void onModuleSelected(int moduleIndex) {
boolean cam2on = SettingsManager.getInstance().isCamera2On();
- if (cam2on && moduleIndex == ModuleSwitcher.PHOTO_MODULE_INDEX)
+ mForceReleaseCamera = cam2on && moduleIndex == ModuleSwitcher.PHOTO_MODULE_INDEX;
+ if (mForceReleaseCamera) {
moduleIndex = ModuleSwitcher.CAPTURE_MODULE_INDEX;
+ }
if (mCurrentModuleIndex == moduleIndex) {
if (mCurrentModuleIndex != ModuleSwitcher.CAPTURE_MODULE_INDEX) {
return;
@@ -1932,6 +1946,7 @@ public class CameraActivity extends Activity
setModuleFromIndex(moduleIndex);
openModule(mCurrentModule);
+ mForceReleaseCamera = false;
mCurrentModule.onOrientationChanged(mLastRawOrientation);
if (mMediaSaveService != null) {
mCurrentModule.onMediaSaveServiceConnected(mMediaSaveService);
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index f700d2187..b09d147bf 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -100,6 +100,8 @@ public class CameraSettings {
public static final String KEY_DENOISE = "pref_camera_denoise_key";
public static final String KEY_BRIGHTNESS = "pref_camera_brightness_key";
public static final String KEY_REDEYE_REDUCTION = "pref_camera_redeyereduction_key";
+ public static final String KEY_SELFIE_MIRROR = "pref_camera_selfiemirror_key";
+ public static final String KEY_SHUTTER_SOUND = "pref_camera_shuttersound_key";
public static final String KEY_CDS_MODE = "pref_camera_cds_mode_key";
public static final String KEY_VIDEO_CDS_MODE = "pref_camera_video_cds_mode_key";
public static final String KEY_TNR_MODE = "pref_camera_tnr_mode_key";
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index 4edf3ab9e..1a7811000 100644
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -35,6 +35,7 @@ import android.graphics.RectF;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
@@ -51,6 +52,7 @@ import android.media.CamcorderProfile;
import android.media.CameraProfile;
import android.media.Image;
import android.media.ImageReader;
+import android.media.MediaActionSound;
import android.media.MediaMetadataRetriever;
import android.media.MediaRecorder;
import android.net.Uri;
@@ -62,13 +64,12 @@ import android.os.Message;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.util.Log;
+import android.util.Range;
import android.util.Size;
-import android.view.Display;
import android.view.KeyEvent;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.SurfaceHolder;
-import android.view.SurfaceView;
import android.view.View;
import android.widget.Toast;
@@ -80,6 +81,7 @@ import com.android.camera.imageprocessor.FrameProcessor;
import com.android.camera.PhotoModule.NamedImages;
import com.android.camera.PhotoModule.NamedImages.NamedEntity;
import com.android.camera.imageprocessor.filter.SharpshooterFilter;
+import com.android.camera.imageprocessor.filter.StillmoreFilter;
import com.android.camera.ui.CountDownView;
import com.android.camera.ui.ModuleSwitcher;
import com.android.camera.ui.RotateTextToast;
@@ -157,8 +159,6 @@ public class CaptureModule implements CameraModule, PhotoController,
// we can change it based on memory status or other requirements.
private static final int LONGSHOT_CANCEL_THRESHOLD = 40 * 1024 * 1024;
- private static final int MAX_IMAGE_NUM = 8;
-
MeteringRectangle[][] mAFRegions = new MeteringRectangle[MAX_NUM_CAM][];
MeteringRectangle[][] mAERegions = new MeteringRectangle[MAX_NUM_CAM][];
CaptureRequest.Key<Byte> BayerMonoLinkEnableKey =
@@ -251,6 +251,7 @@ public class CaptureModule implements CameraModule, PhotoController,
private CameraCaptureSession mCurrentSession;
private Size mPreviewSize;
private Size mPictureSize;
+ private Size mVideoPreviewSize;
private Size mVideoSize;
private Size mVideoSnapshotSize;
@@ -271,6 +272,30 @@ public class CaptureModule implements CameraModule, PhotoController,
private long mRecordingTotalTime;
private boolean mRecordingTimeCountsDown = false;
private ImageReader mVideoSnapshotImageReader;
+ private Range mHighSpeedFPSRange;
+ private boolean mHighSpeedCapture = false;
+ private boolean mHighSpeedCaptureSlowMode = false; //HFR
+ private int mHighSpeedCaptureRate;
+
+ private static final int SELFIE_FLASH_DURATION = 680;
+
+ private MediaActionSound mSound;
+
+ private class SelfieThread extends Thread {
+ public void run() {
+ try {
+ Thread.sleep(SELFIE_FLASH_DURATION);
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ takePicture();
+ }
+ });
+ } catch(InterruptedException e) {
+ }
+ selfieThread = null;
+ }
+ }
+ private SelfieThread selfieThread;
private class MediaSaveNotifyThread extends Thread {
private Uri uri;
@@ -1039,6 +1064,7 @@ public class CaptureModule implements CameraModule, PhotoController,
warningToast("Camera is not ready yet to take a picture.");
return;
}
+ checkAndPlayShutterSound(id);
final boolean csEnabled = isClearSightOn();
CaptureRequest.Builder captureBuilder;
@@ -1165,6 +1191,7 @@ public class CaptureModule implements CameraModule, PhotoController,
warningToast("Camera is not ready yet to take a video snapshot.");
return;
}
+ checkAndPlayShutterSound(id);
CaptureRequest.Builder captureBuilder =
mCameraDevice[id].createCaptureRequest(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
@@ -1265,7 +1292,7 @@ public class CaptureModule implements CameraModule, PhotoController,
} else {
// No Clearsight
mImageReader[i] = ImageReader.newInstance(mPictureSize.getWidth(),
- mPictureSize.getHeight(), imageFormat, MAX_IMAGE_NUM);
+ mPictureSize.getHeight(), imageFormat, PostProcessor.MAX_REQUIRED_IMAGE_NUM);
if((mPostProcessor.isFilterOn() || getFrameFilters().size() != 0)
&& i == getMainCameraId()) {
mImageReader[i].setOnImageAvailableListener(mPostProcessor, mImageAvailableHandler);
@@ -1315,7 +1342,7 @@ public class CaptureModule implements CameraModule, PhotoController,
mVideoSnapshotImageReader.close();
}
mVideoSnapshotImageReader = ImageReader.newInstance(mVideoSnapshotSize.getWidth(),
- mVideoSnapshotSize.getHeight(), ImageFormat.JPEG, MAX_IMAGE_NUM);
+ mVideoSnapshotSize.getHeight(), ImageFormat.JPEG, mPostProcessor.MAX_REQUIRED_IMAGE_NUM);
mVideoSnapshotImageReader.setOnImageAvailableListener(
new ImageReader.OnImageAvailableListener() {
@Override
@@ -1371,6 +1398,7 @@ public class CaptureModule implements CameraModule, PhotoController,
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
+ mUI.stopSelfieFlash();
mUI.enableShutter(true);
}
});
@@ -1600,6 +1628,14 @@ public class CaptureModule implements CameraModule, PhotoController,
if (mIsRecordingVideo) {
stopRecordingVideo(getMainCameraId());
}
+ if (mSound != null) {
+ mSound.release();
+ mSound = null;
+ }
+ if (selfieThread != null) {
+ selfieThread.interrupt();
+ }
+ mUI.stopSelfieFlash();
}
@Override
@@ -1664,6 +1700,10 @@ public class CaptureModule implements CameraModule, PhotoController,
return PostProcessor.FILTER_SHARPSHOOTER;
} else if (mode == SettingsManager.SCENE_MODE_UBIFOCUS_INT) {
return PostProcessor.FILTER_UBIFOCUS;
+ } else if (mode == SettingsManager.SCENE_MODE_AUTO_INT && StillmoreFilter.isSupportedStatic()) {
+ return PostProcessor.FILTER_STILLMORE;
+ } else if (mode == SettingsManager.SCENE_MODE_BESTPICTURE_INT) {
+ return PostProcessor.FILTER_BESTPICTURE;
}
return PostProcessor.FILTER_NONE;
}
@@ -1677,14 +1717,57 @@ public class CaptureModule implements CameraModule, PhotoController,
updateMaxVideoDuration();
}
+ private void updatePreviewSize() {
+ int preview_resolution = PersistUtil.getCameraPreviewSize();
+ int width = mPreviewSize.getWidth();
+ int height = mPreviewSize.getHeight();
+ switch (preview_resolution) {
+ case 1: {
+ width = 640;
+ height = 480;
+ Log.v(TAG, "Preview resolution hardcoded to 640x480");
+ break;
+ }
+ case 2: {
+ width = 720;
+ height = 480;
+ Log.v(TAG, "Preview resolution hardcoded to 720x480");
+ break;
+ }
+ case 3: {
+ width = 1280;
+ height = 720;
+ Log.v(TAG, "Preview resolution hardcoded to 1280x720");
+ break;
+ }
+ case 4: {
+ width = 1920;
+ height = 1080;
+ Log.v(TAG, "Preview resolution hardcoded to 1920x1080");
+ break;
+ }
+ default: {
+ Log.v(TAG, "Preview resolution as per Snapshot aspect ratio");
+ break;
+ }
+ }
+ mPreviewSize = new Size(width, height);
+ mUI.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
+ }
+
@Override
public void onResumeAfterSuper() {
Log.d(TAG, "onResume " + getCameraMode());
initializeValues();
- mUI.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());;
+ updatePreviewSize();
mUI.showSurfaceView();
mUI.setSwitcherIndex();
mCameraIdList = new ArrayList<>();
+
+ if (mSound == null) {
+ mSound = new MediaActionSound();
+ }
+
if(mPostProcessor != null) {
String scene = mSettingsManager.getValue(SettingsManager.KEY_SCENE_MODE);
if (scene != null) {
@@ -1937,10 +2020,27 @@ public class CaptureModule implements CameraModule, PhotoController,
}
}
+ private void checkSelfieFlashAndTakePicture() {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_SELFIE_FLASH);
+ if (value == null) {
+ takePicture();
+ return;
+ }
+ if (value.equals("on") && getMainCameraId() == FRONT_ID) {
+ mUI.startSelfieFlash();
+ if (selfieThread == null) {
+ selfieThread = new SelfieThread();
+ selfieThread.start();
+ }
+ } else {
+ takePicture();
+ }
+ }
+
@Override
public void onCountDownFinished() {
mUI.showUIAfterCountDown();
- takePicture();
+ checkSelfieFlashAndTakePicture();
}
@Override
@@ -2094,6 +2194,11 @@ public class CaptureModule implements CameraModule, PhotoController,
private void updateVideoSize() {
String videoSize = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_QUALITY);
mVideoSize = parsePictureSize(videoSize);
+ Point screenSize = new Point();
+ mActivity.getWindowManager().getDefaultDisplay().getSize(screenSize);
+ Size[] prevSizes = mSettingsManager.getSupportedOutputSize(getMainCameraId(),
+ MediaRecorder.class);
+ mVideoPreviewSize = getOptimalPreviewSize(mVideoSize, prevSizes, screenSize.x, screenSize.y);
}
private void updateVideoSnapshotSize() {
@@ -2132,7 +2237,8 @@ public class CaptureModule implements CameraModule, PhotoController,
mControlAFMode = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
closePreviewSession();
mFrameProcessor.onClose();
- boolean changed = mUI.setPreviewSize(mVideoSize.getWidth(), mVideoSize.getHeight());
+ boolean changed = mUI.setPreviewSize(mVideoPreviewSize.getWidth(),
+ mVideoPreviewSize.getHeight());
if (changed) {
mUI.hideSurfaceView();
mUI.showSurfaceView();
@@ -2146,46 +2252,96 @@ public class CaptureModule implements CameraModule, PhotoController,
List<Surface> surfaces = new ArrayList<>();
Surface surface = getPreviewSurfaceForSession(cameraId);
- mFrameProcessor.init(mVideoSize);
+
if(mFrameProcessor.isFrameFilterEnabled()) {
+ mFrameProcessor.init(mVideoSize);
mActivity.runOnUiThread(new Runnable() {
public void run() {
mUI.getSurfaceHolder().setFixedSize(mVideoSize.getHeight(), mVideoSize.getWidth());
}
});
+ mFrameProcessor.setOutputSurface(surface);
+ mFrameProcessor.setVideoOutputSurface(mMediaRecorder.getSurface());
+ addPreviewSurface(mPreviewBuilder, surfaces, cameraId);
+ } else {
+ surfaces.add(surface);
+ mPreviewBuilder.addTarget(surface);
+ surfaces.add(mMediaRecorder.getSurface());
+ mPreviewBuilder.addTarget(mMediaRecorder.getSurface());
}
- mFrameProcessor.setOutputSurface(surface);
- mFrameProcessor.setVideoOutputSurface(mMediaRecorder.getSurface());
- addPreviewSurface(mPreviewBuilder, surfaces, cameraId);
- surfaces.add(mVideoSnapshotImageReader.getSurface());
- mCameraDevice[cameraId].createCaptureSession(surfaces, new CameraCaptureSession
- .StateCallback() {
+ if (!mHighSpeedCapture) surfaces.add(mVideoSnapshotImageReader.getSurface());
+ else mPreviewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, mHighSpeedFPSRange);
- @Override
- public void onConfigured(CameraCaptureSession cameraCaptureSession) {
- Log.d(TAG, "StartRecordingVideo session onConfigured");
- mCurrentSession = cameraCaptureSession;
- try {
- setUpVideoCaptureRequestBuilder(mPreviewBuilder);
- mCurrentSession.setRepeatingRequest(mPreviewBuilder.build(), null, mCameraHandler);
- } catch (CameraAccessException e) {
- e.printStackTrace();
+ if (!mHighSpeedCapture) {
+ mCameraDevice[cameraId].createCaptureSession(surfaces, new CameraCaptureSession
+ .StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ Log.d(TAG, "StartRecordingVideo session onConfigured");
+ mCurrentSession = cameraCaptureSession;
+ try {
+ setUpVideoCaptureRequestBuilder(mPreviewBuilder);
+ mCurrentSession.setRepeatingRequest(mPreviewBuilder.build(), null, mCameraHandler);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ }
+ mMediaRecorder.start();
+ mUI.clearFocus();
+ mUI.resetPauseButton();
+ mRecordingTotalTime = 0L;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ mUI.showRecordingUI(true);
+ updateRecordingTime();
}
- mMediaRecorder.start();
- mUI.clearFocus();
- mUI.resetPauseButton();
- mRecordingTotalTime = 0L;
- mRecordingStartTime = SystemClock.uptimeMillis();
- mUI.showRecordingUI(true);
- updateRecordingTime();
- }
- @Override
- public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
- Toast.makeText(mActivity, "Video Failed", Toast.LENGTH_SHORT).show();
- }
- }, null);
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Toast.makeText(mActivity, "Video Failed", Toast.LENGTH_SHORT).show();
+ }
+ }, null);
+ } else {
+ mCameraDevice[cameraId].createConstrainedHighSpeedCaptureSession(surfaces, new
+ CameraConstrainedHighSpeedCaptureSession.StateCallback() {
+
+ @Override
+ public void onConfigured(CameraCaptureSession cameraCaptureSession) {
+ mCurrentSession = cameraCaptureSession;
+ CameraConstrainedHighSpeedCaptureSession session =
+ (CameraConstrainedHighSpeedCaptureSession) mCurrentSession;
+ try {
+ List list = session
+ .createHighSpeedRequestList(mPreviewBuilder.build());
+ session.setRepeatingBurst(list, null, mCameraHandler);
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "Failed to start high speed video recording "
+ + e.getMessage());
+ e.printStackTrace();
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Failed to start high speed video recording "
+ + e.getMessage());
+ e.printStackTrace();
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Failed to start high speed video recording "
+ + e.getMessage());
+ e.printStackTrace();
+ }
+ mMediaRecorder.start();
+ mUI.clearFocus();
+ mUI.resetPauseButton();
+ mRecordingTotalTime = 0L;
+ mRecordingStartTime = SystemClock.uptimeMillis();
+ mUI.showRecordingUI(true);
+ updateRecordingTime();
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
+ Toast.makeText(mActivity, "Failed", Toast.LENGTH_SHORT).show();
+ }
+ }, null);
+ }
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (IOException e) {
@@ -2203,6 +2359,19 @@ public class CaptureModule implements CameraModule, PhotoController,
mUI.showTimeLapseUI(mCaptureTimeLapse);
}
+ private void updateHFRSetting() {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_HIGH_FRAME_RATE);
+ if (value == null) return;
+ if (value.equals("off")) {
+ mHighSpeedCapture = false;
+ } else {
+ mHighSpeedCapture = true;
+ String mode = value.substring(0, 3);
+ mHighSpeedCaptureSlowMode = mode.equals("hsr");
+ mHighSpeedCaptureRate = Integer.parseInt(value.substring(3));
+ }
+ }
+
private void setUpVideoCaptureRequestBuilder(CaptureRequest.Builder builder) {
builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest
@@ -2426,8 +2595,11 @@ public class CaptureModule implements CameraModule, PhotoController,
Log.d(TAG, "setUpMediaRecorder");
String videoSize = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_QUALITY);
int size = CameraSettings.VIDEO_QUALITY_TABLE.get(videoSize);
- if (mCaptureTimeLapse)
+ if (mCaptureTimeLapse) {
size = CameraSettings.getTimeLapseQualityFor(size);
+ }
+ updateHFRSetting();
+ boolean hfr = mHighSpeedCapture && !mHighSpeedCaptureSlowMode;
mProfile = CamcorderProfile.get(cameraId, size);
int videoEncoder = SettingTranslation
@@ -2437,7 +2609,7 @@ public class CaptureModule implements CameraModule, PhotoController,
int outputFormat = MediaRecorder.OutputFormat.MPEG_4;
- if (!mCaptureTimeLapse) {
+ if (!mCaptureTimeLapse && !hfr) {
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
}
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
@@ -2454,7 +2626,7 @@ public class CaptureModule implements CameraModule, PhotoController,
mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
}
mMediaRecorder.setVideoEncoder(videoEncoder);
- if (!mCaptureTimeLapse) {
+ if (!mCaptureTimeLapse && !hfr) {
mMediaRecorder.setAudioEncodingBitRate(mProfile.audioBitRate);
mMediaRecorder.setAudioChannels(mProfile.audioChannels);
mMediaRecorder.setAudioSamplingRate(mProfile.audioSampleRate);
@@ -2464,7 +2636,21 @@ public class CaptureModule implements CameraModule, PhotoController,
if (mCaptureTimeLapse) {
double fps = 1000 / (double) mTimeBetweenTimeLapseFrameCaptureMs;
mMediaRecorder.setCaptureRate(fps);
+ } else if (mHighSpeedCapture) {
+ mHighSpeedFPSRange = new Range(mHighSpeedCaptureRate, mHighSpeedCaptureRate);
+ int fps = (int) mHighSpeedFPSRange.getUpper();
+ mMediaRecorder.setCaptureRate(fps);
+ if (mHighSpeedCaptureSlowMode) {
+ mMediaRecorder.setVideoFrameRate(30);
+ } else {
+ mMediaRecorder.setVideoFrameRate(fps);
+ }
+
+ int scaledBitrate = mProfile.videoBitRate * fps / mProfile.videoFrameRate;
+ Log.i(TAG, "Scaled Video bitrate : " + scaledBitrate);
+ mMediaRecorder.setVideoEncodingBitRate(scaledBitrate);
}
+
Location loc = mLocationManager.getCurrentLocation();
if (loc != null) {
mMediaRecorder.setLocation((float) loc.getLatitude(),
@@ -2520,7 +2706,7 @@ public class CaptureModule implements CameraModule, PhotoController,
warningToast("It's still busy processing previous scene mode request.");
return;
}
- takePicture();
+ checkSelfieFlashAndTakePicture();
}
}
}
@@ -2839,6 +3025,15 @@ public class CaptureModule implements CameraModule, PhotoController,
}
}
+ private void checkAndPlayShutterSound(int id) {
+ if (id == getMainCameraId()) {
+ String value = mSettingsManager.getValue(SettingsManager.KEY_SHUTTER_SOUND);
+ if (value != null && value.equals("on")) {
+ mSound.play(MediaActionSound.SHUTTER_CLICK);
+ }
+ }
+ }
+
private Surface getPreviewSurfaceForSession(int id) {
if (isBackCamera()) {
if (getCameraMode() == DUAL_MODE && id == MONO_ID) {
diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java
index dadbb3144..cf3ca6d3a 100644
--- a/src/com/android/camera/CaptureUI.java
+++ b/src/com/android/camera/CaptureUI.java
@@ -44,6 +44,7 @@ import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
+import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -67,6 +68,7 @@ import com.android.camera.ui.RenderOverlay;
import com.android.camera.ui.RotateImageView;
import com.android.camera.ui.RotateLayout;
import com.android.camera.ui.RotateTextToast;
+import com.android.camera.ui.SelfieFlashView;
import com.android.camera.ui.TrackingFocusRenderer;
import com.android.camera.ui.ZoomRenderer;
import com.android.camera.util.CameraUtil;
@@ -100,6 +102,7 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
private static final int ANIMATION_DURATION = 300;
private static final int CLICK_THRESHOLD = 200;
String[] mSettingKeys = new String[]{
+ SettingsManager.KEY_SELFIE_FLASH,
SettingsManager.KEY_FLASH_MODE,
SettingsManager.KEY_RECORD_LOCATION,
SettingsManager.KEY_PICTURE_SIZE,
@@ -111,12 +114,15 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
SettingsManager.KEY_WHITE_BALANCE,
SettingsManager.KEY_CAMERA2,
SettingsManager.KEY_FACE_DETECTION,
+ SettingsManager.KEY_VIDEO_HIGH_FRAME_RATE,
SettingsManager.KEY_VIDEO_FLASH_MODE,
SettingsManager.KEY_VIDEO_DURATION,
SettingsManager.KEY_VIDEO_QUALITY,
SettingsManager.KEY_TRACKINGFOCUS,
- SettingsManager.KEY_MAKEUP
- };
+ SettingsManager.KEY_MAKEUP,
+ SettingsManager.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL,
+ SettingsManager.KEY_SHUTTER_SOUND
+ };
String[] mDeveloperKeys = new String[]{
SettingsManager.KEY_REDEYE_REDUCTION,
SettingsManager.KEY_MONO_ONLY,
@@ -127,7 +133,6 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
SettingsManager.KEY_DIS,
SettingsManager.KEY_VIDEO_ENCODER,
SettingsManager.KEY_AUDIO_ENCODER,
- SettingsManager.KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL,
SettingsManager.KEY_VIDEO_ROTATION,
SettingsManager.KEY_AUTO_VIDEOSNAP_SIZE
};
@@ -155,6 +160,8 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
private ImageView mThumbnail;
private Camera2FaceView mFaceView;
private Point mDisplaySize = new Point();
+ private SelfieFlashView mSelfieView;
+ private float mScreenBrightness = 0.0f;
private SurfaceHolder.Callback callbackMono = new SurfaceHolder.Callback() {
// SurfaceHolder callbacks
@@ -1673,6 +1680,32 @@ public class CaptureUI implements FocusOverlayManager.FocusUI,
}
}
+ public void startSelfieFlash() {
+ if (mSelfieView == null)
+ mSelfieView = (SelfieFlashView) (mRootView.findViewById(R.id.selfie_flash));
+ mSelfieView.bringToFront();
+ mSelfieView.open();
+ mScreenBrightness = setScreenBrightness(1F);
+ }
+
+ public void stopSelfieFlash() {
+ if (mSelfieView == null)
+ mSelfieView = (SelfieFlashView) (mRootView.findViewById(R.id.selfie_flash));
+ mSelfieView.close();
+ if (mScreenBrightness != 0.0f)
+ setScreenBrightness(mScreenBrightness);
+ }
+
+ private float setScreenBrightness(float brightness) {
+ float originalBrightness;
+ Window window = mActivity.getWindow();
+ WindowManager.LayoutParams layout = window.getAttributes();
+ originalBrightness = layout.screenBrightness;
+ layout.screenBrightness = brightness;
+ window.setAttributes(layout);
+ return originalBrightness;
+ }
+
public void hideSurfaceView() {
mSurfaceView.setVisibility(View.INVISIBLE);
}
diff --git a/src/com/android/camera/PermissionsActivity.java b/src/com/android/camera/PermissionsActivity.java
index c5e43e56d..5ebe72075 100644
--- a/src/com/android/camera/PermissionsActivity.java
+++ b/src/com/android/camera/PermissionsActivity.java
@@ -33,16 +33,20 @@ public class PermissionsActivity extends Activity {
private boolean mFlagHasMicrophonePermission;
private boolean mFlagHasStoragePermission;
private boolean mCriticalPermissionDenied;
+ private Intent mIntent;
+ private boolean mIsReturnResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mIntent = getIntent();
+ mIsReturnResult = false;
}
@Override
protected void onResume() {
super.onResume();
- if (!mCriticalPermissionDenied) {
+ if (!mCriticalPermissionDenied && !mIsReturnResult) {
mNumPermissionsToRequest = 0;
checkPermissions();
} else {
@@ -160,9 +164,16 @@ public class PermissionsActivity extends Activity {
}
private void handlePermissionsSuccess() {
- Intent intent = new Intent(this, CameraActivity.class);
- startActivity(intent);
- finish();
+ if (mIntent != null) {
+ mIsReturnResult = true;
+ mIntent.setClass(this, CameraActivity.class);
+ startActivityForResult(mIntent, 1);
+ } else {
+ mIsReturnResult = false;
+ Intent intent = new Intent(this, CameraActivity.class);
+ startActivity(intent);
+ finish();
+ }
}
private void handlePermissionsFailure() {
@@ -187,4 +198,11 @@ public class PermissionsActivity extends Activity {
})
.show();
}
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ setResult(resultCode, data);
+ finish();
+ }
}
diff --git a/src/com/android/camera/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java
index c2f9a538b..dca66d1cb 100755
--- a/src/com/android/camera/PhotoMenu.java
+++ b/src/com/android/camera/PhotoMenu.java
@@ -191,7 +191,9 @@ public class PhotoMenu extends MenuController
CameraSettings.KEY_EXPOSURE,
CameraSettings.KEY_WHITE_BALANCE,
CameraSettings.KEY_QC_CHROMA_FLASH,
- CameraSettings.KEY_REDEYE_REDUCTION
+ CameraSettings.KEY_REDEYE_REDUCTION,
+ CameraSettings.KEY_SELFIE_MIRROR,
+ CameraSettings.KEY_SHUTTER_SOUND
};
mOtherKeys2 = new String[] {
@@ -234,6 +236,8 @@ public class PhotoMenu extends MenuController
CameraSettings.KEY_MANUAL_EXPOSURE,
CameraSettings.KEY_MANUAL_WB,
CameraSettings.KEY_MANUAL_FOCUS,
+ CameraSettings.KEY_SELFIE_MIRROR,
+ CameraSettings.KEY_SHUTTER_SOUND,
SettingsManager.KEY_CAMERA2
};
@@ -1478,6 +1482,12 @@ public class PhotoMenu extends MenuController
mActivity.getString(R.string.pref_camera_coloreffect_default));
}
+ String stillMoreOn = mActivity.getString(R.string.
+ pref_camera_advanced_feature_value_stillmore_on);
+ if (same(pref, CameraSettings.KEY_ADVANCED_FEATURES, stillMoreOn)) {
+ setPreference(CameraSettings.KEY_FLASH_MODE, Parameters.FLASH_MODE_OFF);
+ }
+
ListPreference autoHdrPref = mPreferenceGroup.findPreference(CameraSettings.KEY_AUTO_HDR);
if (autoHdrPref != null && autoHdrPref.getValue().equalsIgnoreCase("enable")) {
mHdrSwitcher.setVisibility(View.GONE);
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 3a7e41976..279c903d4 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -24,7 +24,10 @@ import android.content.Intent;
import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
@@ -47,6 +50,7 @@ import android.os.Message;
import android.os.MessageQueue;
import android.os.SystemClock;
import android.provider.MediaStore;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.OrientationEventListener;
@@ -88,6 +92,7 @@ import android.text.TextUtils;
import com.android.internal.util.MemInfoReader;
import android.app.ActivityManager;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -720,6 +725,7 @@ public class PhotoModule
Log.v(TAG, "Start to switch camera. id=" + mPendingSwitchCameraId);
mCameraId = mPendingSwitchCameraId;
mPendingSwitchCameraId = -1;
+ mSnapshotOnIdle = false;
setCameraId(mCameraId);
// from onPause
@@ -1259,6 +1265,19 @@ public class PhotoModule
}
}
+ private byte[] flipJpeg(byte[] jpegData) {
+ Bitmap srcBitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
+ Matrix m = new Matrix();
+ m.preScale(-1, 1);
+ Bitmap dstBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight(), m, false);
+ dstBitmap.setDensity(DisplayMetrics.DENSITY_DEFAULT);
+ int size = dstBitmap.getWidth() * dstBitmap.getHeight();
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream(size);
+ dstBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
+
+ return outStream.toByteArray();
+ }
+
private final class JpegPictureCallback
implements CameraPictureCallback {
Location mLocation;
@@ -1268,7 +1287,7 @@ public class PhotoModule
}
@Override
- public void onPictureTaken(final byte [] jpegData, CameraProxy camera) {
+ public void onPictureTaken(byte [] jpegData, CameraProxy camera) {
mUI.stopSelfieFlash();
mUI.enableShutter(true);
if (mUI.isPreviewCoverVisible()) {
@@ -1360,6 +1379,16 @@ public class PhotoModule
if (!mRefocus || (mRefocus && mReceivedSnapNum == 7)) {
ExifInterface exif = Exif.getExif(jpegData);
int orientation = Exif.getOrientation(exif);
+ if(mCameraId == CameraHolder.instance().getFrontCameraId()) {
+ IconListPreference selfieMirrorPref = (IconListPreference) mPreferenceGroup
+ .findPreference(CameraSettings.KEY_SELFIE_MIRROR);
+ if (selfieMirrorPref != null && selfieMirrorPref.getValue() != null &&
+ selfieMirrorPref.getValue().equalsIgnoreCase("enable")) {
+ jpegData = flipJpeg(jpegData);
+ exif = Exif.getExif(jpegData);
+ exif.addOrientationTag(orientation);
+ }
+ }
if (!mIsImageCaptureIntent) {
// Burst snapshot. Generate new image name.
if (mReceivedSnapNum > 1) {
@@ -1689,7 +1718,12 @@ public class PhotoModule
new JpegPictureCallback(loc));
}
} else {
- mCameraDevice.enableShutterSound(!mRefocus);
+ if (!isShutterSoundOn()) {
+ mCameraDevice.enableShutterSound(false);
+ } else {
+ mCameraDevice.enableShutterSound(!mRefocus);
+ }
+
mCameraDevice.takePicture(mHandler,
new ShutterCallback(!animateBefore),
mRawPictureCallback, mPostViewPictureCallback,
@@ -1972,8 +2006,16 @@ public class PhotoModule
mUI.overrideSettings(CameraSettings.KEY_FLASH_MODE, flashMode);
}
- if(mCameraId != CameraHolder.instance().getFrontCameraId())
+ if(mCameraId != CameraHolder.instance().getFrontCameraId()) {
CameraSettings.removePreferenceFromScreen(mPreferenceGroup, CameraSettings.KEY_SELFIE_FLASH);
+ CameraSettings.removePreferenceFromScreen(mPreferenceGroup, CameraSettings.KEY_SELFIE_MIRROR);
+ } else {
+ ListPreference prefSelfieMirror = mPreferenceGroup.findPreference(CameraSettings.KEY_SELFIE_MIRROR);
+ if(prefSelfieMirror != null && prefSelfieMirror.getValue() != null
+ && prefSelfieMirror.getValue().equalsIgnoreCase("enable")) {
+ mUI.overrideSettings(CameraSettings.KEY_LONGSHOT, "off");
+ }
+ }
}
private void overrideCameraSettings(final String flashMode,
@@ -2288,14 +2330,23 @@ public class PhotoModule
String zsl = mPreferences.getString(CameraSettings.KEY_ZSL,
mActivity.getString(R.string.pref_camera_zsl_default));
mUI.overrideSettings(CameraSettings.KEY_ZSL, zsl);
- mUI.startCountDown(seconds, playSound);
-
+ mUI.startCountDown(seconds, isShutterSoundOn());
} else {
mSnapshotOnIdle = false;
initiateSnap();
}
}
+ private boolean isShutterSoundOn() {
+ IconListPreference shutterSoundPref = (IconListPreference) mPreferenceGroup
+ .findPreference(CameraSettings.KEY_SHUTTER_SOUND);
+ if (shutterSoundPref != null && shutterSoundPref.getValue() != null &&
+ shutterSoundPref.getValue().equalsIgnoreCase("disable")) {
+ return false;
+ }
+ return true;
+ }
+
private void initiateSnap()
{
if(mPreferences.getString(CameraSettings.KEY_SELFIE_FLASH,
@@ -2792,7 +2843,7 @@ public class PhotoModule
mCameraDevice.setFaceDetectionCallback(null, null);
mCameraDevice.setErrorCallback(null);
- if (mActivity.isSecureCamera()) {
+ if (mActivity.isSecureCamera() || mActivity.isForceReleaseCamera()) {
// Blocks until camera is actually released.
CameraHolder.instance().strongRelease();
} else {
@@ -3002,7 +3053,7 @@ public class PhotoModule
mParameters.set(CameraSettings.KEY_QC_MULTI_TOUCH_FOCUS, multiTouchFocus);
}
if (CameraUtil.isSupported(stillMore,
- CameraSettings.getSupportedStillMoreModes(mParameters))) {
+ CameraSettings.getSupportedStillMoreModes(mParameters))) {
mParameters.set(CameraSettings.KEY_QC_STILL_MORE, stillMore);
}
}
diff --git a/src/com/android/camera/PhotoUI.java b/src/com/android/camera/PhotoUI.java
index fd4b18186..fd848c623 100644
--- a/src/com/android/camera/PhotoUI.java
+++ b/src/com/android/camera/PhotoUI.java
@@ -458,6 +458,7 @@ public class PhotoUI implements PieListener,
}
mSurfaceView.setLayoutParams(lp);
+ mRootView.requestLayout();
if (mFaceView != null) {
mFaceView.setLayoutParams(lp);
}
@@ -1252,7 +1253,10 @@ public class PhotoUI implements PieListener,
@Override
public void clearFocus() {
- FocusIndicator indicator = getFocusIndicator();
+ FocusIndicator indicator = mPieRenderer;
+ if (hasFaces()) {
+ mFaceView.showStart();
+ }
if (indicator != null) indicator.clear();
}
@@ -1295,6 +1299,9 @@ public class PhotoUI implements PieListener,
mFaceView.setVisibility(View.VISIBLE);
mFaceView.setDisplayOrientation(orientation);
mFaceView.setMirror(mirror);
+ LayoutParams layoutParams = new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ mFaceView.setLayoutParams(layoutParams);
mFaceView.resume();
}
diff --git a/src/com/android/camera/PreviewGestures.java b/src/com/android/camera/PreviewGestures.java
index 48bfb7e58..0ac6ce01c 100644
--- a/src/com/android/camera/PreviewGestures.java
+++ b/src/com/android/camera/PreviewGestures.java
@@ -87,29 +87,8 @@ public class PreviewGestures
return false;
}
if (mZoomOnly || mMode == MODE_ZOOM) return false;
- int deltaX = (int) (e1.getX() - e2.getX());
- int deltaY = (int) (e1.getY() - e2.getY());
-
- int orientation = 0;
- if (mPhotoMenu != null)
- orientation = mPhotoMenu.getOrientation();
- else if (mVideoMenu != null)
- orientation = mVideoMenu.getOrientation();
- else if (mCaptureUI != null)
- orientation = mCaptureUI.getOrientation();
-
- if (isLeftSwipe(orientation, deltaX, deltaY)) {
- waitUntilNextDown = true;
- if (mPhotoMenu != null && !mPhotoMenu.isMenuBeingShown())
- mPhotoMenu.openFirstLevel();
- else if (mVideoMenu != null && !mVideoMenu.isMenuBeingShown())
- mVideoMenu.openFirstLevel();
- else if (mCaptureUI != null && !mCaptureUI.isMenuBeingShown())
- mCaptureUI.showSettingMenu();
- return true;
- } else {
- return onSingleTapUp(e2);
- }
+
+ return onSingleTapUp(e2);
}
private boolean isLeftSwipe(int orientation, int deltaX, int deltaY) {
diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java
index 7e2e3bf6a..c8f3f8c7b 100644
--- a/src/com/android/camera/SettingsManager.java
+++ b/src/com/android/camera/SettingsManager.java
@@ -45,6 +45,7 @@ import android.util.Rational;
import android.util.Size;
import com.android.camera.imageprocessor.filter.BeautificationFilter;
+import com.android.camera.imageprocessor.filter.BestpictureFilter;
import com.android.camera.imageprocessor.filter.OptizoomFilter;
import com.android.camera.imageprocessor.filter.TrackingFocusFrameListener;
import com.android.camera.imageprocessor.filter.UbifocusFilter;
@@ -69,12 +70,15 @@ import java.util.Set;
public class SettingsManager implements ListMenu.SettingsListener {
public static final int RESOURCE_TYPE_THUMBNAIL = 0;
public static final int RESOURCE_TYPE_LARGEICON = 1;
+
+ public static final int SCENE_MODE_AUTO_INT = 0;
public static final int SCENE_MODE_NIGHT_INT = 5;
// Custom-Scenemodes start from 100
public static final int SCENE_MODE_DUAL_INT = 100;
public static final int SCENE_MODE_OPTIZOOM_INT = 101;
public static final int SCENE_MODE_UBIFOCUS_INT = 102;
+ public static final int SCENE_MODE_BESTPICTURE_INT = 103;
public static final String SCENE_MODE_DUAL_STRING = "100";
public static final String KEY_CAMERA_SAVEPATH = "pref_camera2_savepath_key";
public static final String KEY_RECORD_LOCATION = "pref_camera2_recordlocation_key";
@@ -111,6 +115,9 @@ public class SettingsManager implements ListMenu.SettingsListener {
"pref_camera2_video_time_lapse_frame_interval_key";
public static final String KEY_FACE_DETECTION = "pref_camera2_facedetection_key";
public static final String KEY_AUTO_VIDEOSNAP_SIZE = "pref_camera2_videosnap_key";
+ public static final String KEY_VIDEO_HIGH_FRAME_RATE = "pref_camera2_hfr_key";
+ public static final String KEY_SELFIE_FLASH = "pref_selfie_flash_key";
+ public static final String KEY_SHUTTER_SOUND = "pref_camera2_shutter_sound_key";
private static final String TAG = "SnapCam_SettingsManager";
private static SettingsManager sInstance;
@@ -124,6 +131,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
private boolean mIsMonoCameraPresent = false;
private boolean mIsFrontCameraPresent = false;
private JSONObject mDependency;
+ private int mCameraId;
private SettingsManager(Context context) {
mListeners = new ArrayList<>();
@@ -197,6 +205,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
@Override
public void onSettingChanged(ListPreference pref) {
String key = pref.getKey();
+ if (pref.getKey().equals(KEY_VIDEO_QUALITY)) buildHFR();
List changed = checkDependencyAndUpdate(key);
if (changed == null) return;
notifyListeners(changed);
@@ -215,6 +224,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
private void setLocalIdAndInitialize(int cameraId) {
mPreferences.setLocalId(mContext, cameraId);
+ mCameraId = cameraId;
CameraSettings.upgradeLocalPreferences(mPreferences.getLocal());
PreferenceInflater inflater = new PreferenceInflater(mContext);
@@ -501,6 +511,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
ListPreference faceDetection = mPreferenceGroup.findPreference(KEY_FACE_DETECTION);
ListPreference makeup = mPreferenceGroup.findPreference(KEY_MAKEUP);
ListPreference trackingfocus = mPreferenceGroup.findPreference(KEY_TRACKINGFOCUS);
+ ListPreference hfr = mPreferenceGroup.findPreference(KEY_VIDEO_HIGH_FRAME_RATE);
if (whiteBalance != null) {
CameraSettings.filterUnsupportedOptions(mPreferenceGroup,
@@ -587,6 +598,14 @@ public class SettingsManager implements ListMenu.SettingsListener {
if (!TrackingFocusFrameListener.isSupportedStatic())
removePreference(mPreferenceGroup, KEY_TRACKINGFOCUS);
}
+
+ if (hfr != null) {
+ buildHFR();
+ }
+
+ if (!mIsFrontCameraPresent || !isFacingFront(mCameraId)) {
+ removePreference(mPreferenceGroup, KEY_SELFIE_FLASH);
+ }
}
private void buildExposureCompensation(int cameraId) {
@@ -649,6 +668,86 @@ public class SettingsManager implements ListMenu.SettingsListener {
cameraIdPref.setEntries(entries);
}
+ private void buildHFR() {
+ ListPreference hfrPref = mPreferenceGroup.findPreference(KEY_VIDEO_HIGH_FRAME_RATE);
+
+
+ Size[] highSpeedVideoSize = getSupportedHighSpeedVideoSize(mCameraId);
+ if (highSpeedVideoSize.length == 0) {
+ CharSequence[] entryValues = new CharSequence[1];
+ CharSequence[] entries = new CharSequence[1];
+ entryValues[0] = "off";
+ entries[0] = "off";
+ hfrPref.setEntryValues(entryValues);
+ hfrPref.setEntries(entries);
+ hfrPref.setValueIndex(0);
+ return;
+ }
+
+ ListPreference videoQuality = mPreferenceGroup.findPreference(KEY_VIDEO_QUALITY);
+ String video = videoQuality.getValue();
+ int x = video.indexOf('x');
+ Size videoSize = new Size(Integer.parseInt(video.substring(0, x)),
+ Integer.parseInt(video.substring(x + 1)));
+
+ boolean found = false;
+ for (Size s : highSpeedVideoSize) {
+ if (videoSize.equals(s)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ CharSequence[] entryValues = new CharSequence[1];
+ CharSequence[] entries = new CharSequence[1];
+ entryValues[0] = "off";
+ entries[0] = "Off";
+ hfrPref.setEntryValues(entryValues);
+ hfrPref.setEntries(entries);
+ hfrPref.setValueIndex(0);
+ return;
+ }
+
+ Range[] range = getSupportedHighSpeedVideoFPSRange(mCameraId, highSpeedVideoSize[0]);
+ ArrayList<Range> list = new ArrayList<>();
+ for (Range r : range) {
+ if (r.getLower() == r.getUpper()) {
+ list.add(r);
+ }
+ }
+
+ if (list.size() == 0) {
+ CharSequence[] entryValues = new CharSequence[1];
+ CharSequence[] entries = new CharSequence[1];
+ entryValues[0] = "off";
+ entries[0] = "Off";
+ hfrPref.setEntryValues(entryValues);
+ hfrPref.setEntries(entries);
+ hfrPref.setValueIndex(0);
+ return;
+ }
+
+ CharSequence[] entryValues = new CharSequence[list.size() * 2 + 1];
+ CharSequence[] entries = new CharSequence[list.size() * 2 + 1];
+ entryValues[0] = "off";
+ entries[0] = "Off";
+ int i = 1;
+ for (Range r : list) {
+ entries[i] = "HFR " + r.getLower();
+ entryValues[i] = "hfr" + r.getLower();
+ i++;
+ }
+ for (Range r : list) {
+ entries[i] = "HSR " + r.getLower();
+ entryValues[i] = "hsr" + r.getLower();
+ i++;
+ }
+
+ hfrPref.setEntryValues(entryValues);
+ hfrPref.setEntries(entries);
+ }
+
private boolean removePreference(PreferenceGroup group, String key) {
for (int i = 0, n = group.size(); i < n; i++) {
CameraPreference child = group.get(i);
@@ -812,6 +911,18 @@ public class SettingsManager implements ListMenu.SettingsListener {
return res;
}
+ public Size[] getSupportedHighSpeedVideoSize(int cameraId) {
+ StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ return map.getHighSpeedVideoSizes();
+ }
+
+ public Range[] getSupportedHighSpeedVideoFPSRange(int cameraId, Size videoSize) {
+ StreamConfigurationMap map = mCharacteristics.get(cameraId).get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ return map.getHighSpeedVideoFpsRangesFor(videoSize);
+ }
+
private List<String> getSupportedRedeyeReduction(int cameraId) {
int[] flashModes = mCharacteristics.get(cameraId).get(CameraCharacteristics
.CONTROL_AE_AVAILABLE_MODES);
@@ -844,6 +955,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
if (mIsMonoCameraPresent) modes.add(SCENE_MODE_DUAL_STRING); // need special case handle for dual mode
if (OptizoomFilter.isSupportedStatic()) modes.add(SCENE_MODE_OPTIZOOM_INT + "");
if (UbifocusFilter.isSupportedStatic() && cameraId == CaptureModule.BAYER_ID) modes.add(SCENE_MODE_UBIFOCUS_INT + "");
+ if (BestpictureFilter.isSupportedStatic() && cameraId == CaptureModule.BAYER_ID) modes.add(SCENE_MODE_BESTPICTURE_INT + "");
for (int mode : sceneModes) {
modes.add("" + mode);
}
@@ -978,6 +1090,7 @@ public class SettingsManager implements ListMenu.SettingsListener {
JSONObject dependencyMap = getDependencyMapForKey(key);
if (dependencyMap == null) return null;
if (!dependencyMap.has(value)) value = "default";
+ if (!dependencyMap.has(value)) return null;
value = getDependencyKey(dependencyMap, value);
try {
return dependencyMap.getJSONObject(value);
diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java
index a93cff611..b0699bb08 100755
--- a/src/com/android/camera/VideoModule.java
+++ b/src/com/android/camera/VideoModule.java
@@ -1268,7 +1268,11 @@ public class VideoModule implements CameraModule,
mCameraDevice.setZoomChangeListener(null);
mCameraDevice.setErrorCallback(null);
mCameraDevice.setFaceDetectionCallback(null, null);
- CameraHolder.instance().release();
+ if (mActivity.isForceReleaseCamera()) {
+ CameraHolder.instance().strongRelease();
+ } else {
+ CameraHolder.instance().release();
+ }
mCameraDevice = null;
mPreviewing = false;
mSnapshotInProgress = false;
diff --git a/src/com/android/camera/VideoUI.java b/src/com/android/camera/VideoUI.java
index cf93feeac..41b9cfd89 100644
--- a/src/com/android/camera/VideoUI.java
+++ b/src/com/android/camera/VideoUI.java
@@ -1250,6 +1250,9 @@ public class VideoUI implements PieRenderer.PieListener,
mFaceView.setVisibility(View.VISIBLE);
mFaceView.setDisplayOrientation(orientation);
mFaceView.setMirror(mirror);
+ LayoutParams layoutParams = new LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ mFaceView.setLayoutParams(layoutParams);
mFaceView.resume();
}
diff --git a/src/com/android/camera/WideAnglePanoramaModule.java b/src/com/android/camera/WideAnglePanoramaModule.java
index 210fe3600..8d7243c5c 100644
--- a/src/com/android/camera/WideAnglePanoramaModule.java
+++ b/src/com/android/camera/WideAnglePanoramaModule.java
@@ -380,7 +380,11 @@ public class WideAnglePanoramaModule
private void releaseCamera() {
if (mCameraDevice != null) {
- CameraHolder.instance().release();
+ if (mActivity.isForceReleaseCamera()) {
+ CameraHolder.instance().strongRelease();
+ } else {
+ CameraHolder.instance().release();
+ }
mCameraDevice.setErrorCallback(null);
mCameraDevice = null;
mCameraState = PREVIEW_STOPPED;
diff --git a/src/com/android/camera/imageprocessor/FrameProcessor.java b/src/com/android/camera/imageprocessor/FrameProcessor.java
index 74db08b31..4bee19194 100644
--- a/src/com/android/camera/imageprocessor/FrameProcessor.java
+++ b/src/com/android/camera/imageprocessor/FrameProcessor.java
@@ -125,7 +125,7 @@ public class FrameProcessor {
mOutingHandler = new Handler(mOutingThread.getLooper());
}
- if(mListeningThread == null) {
+ if (mListeningThread == null) {
mListeningThread = new HandlerThread("FrameListeningThread");
mListeningThread.start();
mListeningHandler = new Handler(mListeningThread.getLooper());
@@ -256,10 +256,10 @@ public class FrameProcessor {
} catch (InterruptedException e) {
}
}
- for(ImageFilter filter : mPreviewFilters) {
+ for (ImageFilter filter : mPreviewFilters) {
filter.deinit();
}
- for(ImageFilter filter : mFinalFilters) {
+ for (ImageFilter filter : mFinalFilters) {
filter.deinit();
}
}
@@ -275,14 +275,14 @@ public class FrameProcessor {
public List<Surface> getInputSurfaces() {
List<Surface> surfaces = new ArrayList<Surface>();
- if(mPreviewFilters.size() == 0 && mFinalFilters.size() == 0) {
+ if (mPreviewFilters.size() == 0 && mFinalFilters.size() == 0) {
surfaces.add(mSurfaceAsItIs);
- if(mIsVideoOn) {
+ if (mIsVideoOn) {
surfaces.add(mVideoSurfaceAsItIs);
}
} else if (mFinalFilters.size() == 0) {
surfaces.add(mSurfaceAsItIs);
- if(mIsVideoOn) {
+ if (mIsVideoOn) {
surfaces.add(mVideoSurfaceAsItIs);
}
surfaces.add(getReaderSurface());
@@ -293,7 +293,7 @@ public class FrameProcessor {
}
public boolean isFrameFilterEnabled() {
- if(mFinalFilters.size() == 0) {
+ if (mFinalFilters.size() == 0) {
return false;
}
return true;
@@ -301,13 +301,13 @@ public class FrameProcessor {
public void setOutputSurface(Surface surface) {
mSurfaceAsItIs = surface;
- if(mFinalFilters.size() != 0) {
+ if (mFinalFilters.size() != 0) {
mOutputAllocation.setSurface(surface);
}
}
public void setVideoOutputSurface(Surface surface) {
- if(surface == null) {
+ if (surface == null) {
synchronized (mAllocationLock) {
if (mVideoOutputAllocation != null) {
mVideoOutputAllocation.destroy();
@@ -319,7 +319,7 @@ public class FrameProcessor {
}
mVideoSurfaceAsItIs = surface;
mIsVideoOn = true;
- if(mFinalFilters.size() != 0) {
+ if (mFinalFilters.size() != 0) {
synchronized (mAllocationLock) {
if (mVideoOutputAllocation == null) {
Type.Builder rgbTypeBuilder = new Type.Builder(mRs, Element.RGBA_8888(mRs));
@@ -346,32 +346,32 @@ public class FrameProcessor {
@Override
public void onImageAvailable(ImageReader reader) {
synchronized (mAllocationLock) {
- if(mOutputAllocation == null) {
+ if (mOutputAllocation == null) {
return;
}
try {
Image image = reader.acquireLatestImage();
- if(image == null) {
+ if (image == null) {
return;
}
- if(!mIsActive) {
+ if (!mIsActive) {
image.close();
return;
}
mIsAllocationEverUsed = true;
ByteBuffer bY = image.getPlanes()[0].getBuffer();
ByteBuffer bVU = image.getPlanes()[2].getBuffer();
- if(yvuBytes == null || width != mSize.getWidth() || height != mSize.getHeight()) {
+ if (yvuBytes == null || width != mSize.getWidth() || height != mSize.getHeight()) {
stride = image.getPlanes()[0].getRowStride();
width = mSize.getWidth();
height = mSize.getHeight();
ySize = stride * mSize.getHeight();
- yvuBytes = new byte[ySize*3/2];
+ yvuBytes = new byte[ySize * 3 / 2];
}
boolean needToFeedSurface = false;
//Start processing yvu buf
for (ImageFilter filter : mPreviewFilters) {
- if(filter.isFrameListener()) {
+ if (filter.isFrameListener()) {
if (mListeningTask.setParam(filter, bY, bVU, mSize.getWidth(), mSize.getHeight(), stride)) {
mListeningHandler.post(mListeningTask);
}
@@ -384,7 +384,7 @@ public class FrameProcessor {
bVU.rewind();
}
//End processing yvu buf
- if(needToFeedSurface) {
+ if (needToFeedSurface) {
bY.get(yvuBytes, 0, bY.remaining());
bVU.get(yvuBytes, ySize, bVU.remaining());
mOutingHandler.post(this);
@@ -398,17 +398,17 @@ public class FrameProcessor {
@Override
public void run() {
synchronized (mAllocationLock) {
- if(!mIsActive) {
+ if (!mIsActive) {
return;
}
- if(mInputAllocation == null) {
+ if (mInputAllocation == null) {
createAllocation(stride, height, stride - width);
}
mInputAllocation.copyFrom(yvuBytes);
mRsRotator.forEach_rotate90andMerge(mInputAllocation);
mRsYuvToRGB.forEach_nv21ToRgb(mOutputAllocation);
mOutputAllocation.ioSend();
- if(mVideoOutputAllocation != null) {
+ if (mVideoOutputAllocation != null) {
mVideoOutputAllocation.copyFrom(mOutputAllocation);
mVideoOutputAllocation.ioSend();
}
@@ -425,7 +425,7 @@ public class FrameProcessor {
Semaphore mMutureLock = new Semaphore(1);
public boolean setParam(ImageFilter filter, ByteBuffer bY, ByteBuffer bVU, int width, int height, int stride) {
- if(!mIsActive) {
+ if (!mIsActive) {
return false;
}
if (!mMutureLock.tryAcquire()) {
@@ -467,13 +467,5 @@ public class FrameProcessor {
}
}
}
-
- private native int nativeRotateNV21(ByteBuffer inBuf, int imageWidth, int imageHeight, int degree, ByteBuffer outBuf);
-
- private native int nativeNV21toRgb(ByteBuffer yvuBuf, ByteBuffer rgbBuf, int width, int height);
-
- static {
- System.loadLibrary("jni_imageutil");
- }
}
diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java
index 8c0d2ff88..295707afd 100644
--- a/src/com/android/camera/imageprocessor/PostProcessor.java
+++ b/src/com/android/camera/imageprocessor/PostProcessor.java
@@ -51,8 +51,10 @@ import com.android.camera.MediaSaveService;
import com.android.camera.PhotoModule;
import com.android.camera.SettingsManager;
import com.android.camera.exif.ExifInterface;
+import com.android.camera.imageprocessor.filter.BestpictureFilter;
import com.android.camera.imageprocessor.filter.OptizoomFilter;
import com.android.camera.imageprocessor.filter.SharpshooterFilter;
+import com.android.camera.imageprocessor.filter.StillmoreFilter;
import com.android.camera.imageprocessor.filter.UbifocusFilter;
import com.android.camera.ui.RotateTextToast;
@@ -76,8 +78,12 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
public static final int FILTER_OPTIZOOM = 1;
public static final int FILTER_SHARPSHOOTER = 2;
public static final int FILTER_UBIFOCUS = 3;
- public static final int FILTER_MAX = 4;
+ public static final int FILTER_STILLMORE = 4;
+ public static final int FILTER_BESTPICTURE = 5;
+ public static final int FILTER_MAX = 6;
+ //Max image is now Bestpicture filter with 10
+ public static final int MAX_REQUIRED_IMAGE_NUM = 10;
private int mCurrentNumImage = 0;
private ImageFilter mFilter;
private int mFilterIndex;
@@ -285,6 +291,12 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
case FILTER_UBIFOCUS:
mFilter = new UbifocusFilter(mController, mActivity);
break;
+ case FILTER_STILLMORE:
+ mFilter = new StillmoreFilter(mController);
+ break;
+ case FILTER_BESTPICTURE:
+ mFilter = new BestpictureFilter(mController, mActivity);
+ break;
}
}
@@ -435,10 +447,12 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
}
}
}
- //Start processing FrameProcessor filter as well
- for (ImageFilter filter : mController.getFrameFilters()) {
- filter.init(resultImage.width, resultImage.height, resultImage.stride, resultImage.stride);
- filter.addImage(resultImage.outBuffer, null, 0, new Boolean(false));
+ if(resultImage != null) {
+ //Start processing FrameProcessor filter as well
+ for (ImageFilter filter : mController.getFrameFilters()) {
+ filter.init(resultImage.width, resultImage.height, resultImage.stride, resultImage.stride);
+ filter.addImage(resultImage.outBuffer, null, 0, new Boolean(false));
+ }
}
//End processing FrameProessor filter
clear();
@@ -446,10 +460,11 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
if(mWatchdog != null) {
mWatchdog.stopMonitor();
}
- if((resultImage.outRoi.left + resultImage.outRoi.width() > resultImage.width) ||
+ if(resultImage == null ||
+ (resultImage.outRoi.left + resultImage.outRoi.width() > resultImage.width) ||
(resultImage.outRoi.top + resultImage.outRoi.height() > resultImage.height)
) {
- Log.e(TAG, "Processed outRoi is not within picture range");
+ Log.d(TAG, "Result image is not valid.");
} else {
if(mFilter != null && DEBUG_FILTER) {
bytes = nv21ToJpeg(mDebugResultImage, mOrientation);
@@ -488,5 +503,9 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
}
}
+ private native int nativeFlipVerticalNV21(byte[] buf, int stride, int height);
+ static {
+ System.loadLibrary("jni_imageutil");
+ }
}
diff --git a/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java b/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java
new file mode 100644
index 000000000..638d037ce
--- /dev/null
+++ b/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java
@@ -0,0 +1,252 @@
+/*
+Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.camera.imageprocessor.filter;
+
+import android.content.Intent;
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
+import android.graphics.YuvImage;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.camera.BestpictureActivity;
+import com.android.camera.CameraActivity;
+import com.android.camera.CaptureModule;
+import com.android.camera.MediaSaveService;
+import com.android.camera.PhotoModule;
+import com.android.camera.imageprocessor.PostProcessor;
+import com.android.camera.util.CameraUtil;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+public class BestpictureFilter implements ImageFilter {
+ public static final int NUM_REQUIRED_IMAGE = 10;
+ private int mWidth;
+ private int mHeight;
+ private int mStrideY;
+ private int mStrideVU;
+ private static String TAG = "BestpictureFilter";
+ private static final boolean DEBUG = false;
+ private static boolean mIsSupported = true;
+ private CaptureModule mModule;
+ private CameraActivity mActivity;
+ private int mOrientation = 0;
+ final String[] NAMES = {"00.jpg", "01.jpg", "02.jpg", "03.jpg",
+ "04.jpg", "05.jpg", "06.jpg", "07.jpg", "08.jpg"
+ ,"09.jpg"};
+
+ private final static int TIME_DELAY = 50;
+ private int mSavedCount = 0;
+ private PhotoModule.NamedImages mNamedImages;
+ private ByteBuffer mBY;
+ private ByteBuffer mBVU;
+
+ private static void Log(String msg) {
+ if (DEBUG) {
+ Log.d(TAG, msg);
+ }
+ }
+
+ public BestpictureFilter(CaptureModule module, CameraActivity activity) {
+ mModule = module;
+ mActivity = activity;
+ mNamedImages = new PhotoModule.NamedImages();
+ }
+
+ @Override
+ public List<CaptureRequest> setRequiredImages(CaptureRequest.Builder builder) {
+ List<CaptureRequest> list = new ArrayList<CaptureRequest>();
+ for(int i=0; i < NUM_REQUIRED_IMAGE; i++) {
+ list.add(builder.build());
+ }
+ return list;
+ }
+
+ @Override
+ public String getStringName() {
+ return "BestpictureFilter";
+ }
+
+ @Override
+ public int getNumRequiredImage() {
+ return NUM_REQUIRED_IMAGE;
+ }
+
+ @Override
+ public void init(int width, int height, int strideY, int strideVU) {
+ Log("init");
+ mWidth = width/2*2;
+ mHeight = height/2*2;
+ mStrideY = strideY/2*2;
+ mStrideVU = strideVU / 2 * 2;
+ Log("width: " + mWidth + " height: " + mHeight + " strideY: " + mStrideY + " strideVU: " + mStrideVU);
+ }
+
+ @Override
+ public void deinit() {
+ Log("deinit");
+ }
+
+ @Override
+ public void addImage(final ByteBuffer bY, final ByteBuffer bVU, final int imageNum, Object param) {
+ Log("addImage");
+ if(imageNum == 0) {
+ mOrientation = CameraUtil.getJpegRotation(mModule.getMainCameraId(), mModule.getDisplayOrientation());
+ mSavedCount = 0;
+ mBY = bY;
+ mBVU = bVU;
+ }
+ new Thread() {
+ public void run() {
+ saveToPrivateFile(imageNum, nv21ToJpeg(bY, bVU, new Rect(0, 0, mWidth, mHeight), mOrientation));
+ mSavedCount++;
+ }
+ }.start();
+ }
+
+ @Override
+ public ResultImage processImage() {
+ long captureStartTime = System.currentTimeMillis();
+ mNamedImages.nameNewImage(captureStartTime);
+ PhotoModule.NamedImages.NamedEntity name = mNamedImages.getNextNameEntity();
+ String title = (name == null) ? null : name.title;
+ long date = (name == null) ? -1 : name.date;
+ mActivity.getMediaSaveService().addImage(
+ nv21ToJpeg(mBY, mBVU, new Rect(0, 0, mWidth, mHeight), mOrientation), title, date, null, mWidth, mHeight,
+ mOrientation, null, new MediaSaveService.OnMediaSavedListener() {
+ @Override
+ public void onMediaSaved(Uri uri) {
+ if (uri != null) {
+ mActivity.notifyNewMedia(uri);
+ }
+ startBestpictureActivity(uri);
+ }
+ }
+ , mActivity.getContentResolver(), "jpeg");
+ while(mSavedCount < NUM_REQUIRED_IMAGE) {
+ try {
+ Thread.sleep(1);
+ } catch (Exception e) {
+ }
+ }
+ return null;
+ }
+
+ private void startBestpictureActivity(Uri uri) {
+ Intent intent = new Intent();
+ intent.setData(uri);
+ intent.setClass(mActivity, BestpictureActivity.class);
+ mActivity.startActivityForResult(intent, BestpictureActivity.BESTPICTURE_ACTIVITY_CODE);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return mIsSupported;
+ }
+
+ @Override
+ public boolean isFrameListener() {
+ return false;
+ }
+
+ @Override
+ public boolean isManualMode() {
+ return false;
+ }
+
+ @Override
+ public void manualCapture(CaptureRequest.Builder builder, CameraCaptureSession captureSession,
+ CameraCaptureSession.CaptureCallback callback, Handler handler) throws CameraAccessException {
+ for(int i=0; i < NUM_REQUIRED_IMAGE; i++) {
+ captureSession.capture(builder.build(), callback, handler);
+ try {
+ Thread.sleep(TIME_DELAY);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ public static boolean isSupportedStatic() {
+ return mIsSupported;
+ }
+
+ private byte[] nv21ToJpeg(ByteBuffer bY, ByteBuffer bVU, Rect roi, int orientation) {
+ ByteBuffer buf = ByteBuffer.allocate(mStrideY*mHeight*3/2);
+ buf.put(bY);
+ bY.rewind();
+ if(bVU != null) {
+ buf.put(bVU);
+ bVU.rewind();
+ }
+ BitmapOutputStream bos = new BitmapOutputStream(1024);
+ YuvImage im = new YuvImage(buf.array(), ImageFormat.NV21,
+ mWidth, mHeight, new int[]{mStrideY, mStrideVU});
+ im.compressToJpeg(roi, 50, bos);
+ byte[] bytes = bos.getArray();
+ bytes = PostProcessor.addExifTags(bytes, orientation);
+ return bytes;
+ }
+
+ private class BitmapOutputStream extends ByteArrayOutputStream {
+ public BitmapOutputStream(int size) {
+ super(size);
+ }
+
+ public byte[] getArray() {
+ return buf;
+ }
+ }
+
+ private void saveToPrivateFile(final int index, final byte[] bytes) {
+ String filesPath = mActivity.getFilesDir()+"/Bestpicture";
+ File file = new File(filesPath);
+ if(!file.exists()) {
+ file.mkdir();
+ }
+ file = new File(filesPath+"/"+NAMES[index]);
+ try {
+ FileOutputStream out = new FileOutputStream(file);
+ out.write(bytes, 0, bytes.length);
+ out.close();
+ } catch (Exception e) {
+ }
+ }
+}
diff --git a/src/com/android/camera/imageprocessor/filter/StillmoreFilter.java b/src/com/android/camera/imageprocessor/filter/StillmoreFilter.java
new file mode 100644
index 000000000..e5c2c03d9
--- /dev/null
+++ b/src/com/android/camera/imageprocessor/filter/StillmoreFilter.java
@@ -0,0 +1,175 @@
+/*
+Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.camera.imageprocessor.filter;
+
+import android.graphics.Rect;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.os.Handler;
+import android.util.Log;
+import android.util.Range;
+
+import com.android.camera.CaptureModule;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+public class StillmoreFilter implements ImageFilter{
+ public static final int NUM_REQUIRED_IMAGE = 5;
+ private int mWidth;
+ private int mHeight;
+ private int mStrideY;
+ private int mStrideVU;
+ private static String TAG = "StillmoreFilter";
+ private static final boolean DEBUG = false;
+ private static boolean mIsSupported = false;
+ private ByteBuffer mOutBuf;
+ private CaptureModule mModule;
+ private int mSenseValue = 0;
+ private long mExpoTime;
+
+ private static void Log(String msg) {
+ if(DEBUG) {
+ Log.d(TAG, msg);
+ }
+ }
+
+ public StillmoreFilter(CaptureModule module) {
+ mModule = module;
+ }
+
+ @Override
+ public List<CaptureRequest> setRequiredImages(CaptureRequest.Builder builder) {
+ mExpoTime = (mModule.getPreviewCaptureResult().get(CaptureResult.SENSOR_EXPOSURE_TIME));
+ mSenseValue = (mModule.getPreviewCaptureResult().get(CaptureResult.SENSOR_SENSITIVITY)).intValue();
+
+ List<CaptureRequest> list = new ArrayList<CaptureRequest>();
+ for(int i=0; i < NUM_REQUIRED_IMAGE; i++) {
+ list.add(builder.build());
+ }
+ return list;
+ }
+
+ @Override
+ public String getStringName() {
+ return "StillmoreFilter";
+ }
+
+ @Override
+ public int getNumRequiredImage() {
+ return NUM_REQUIRED_IMAGE;
+ }
+
+ @Override
+ public void init(int width, int height, int strideY, int strideVU) {
+ Log("init");
+ mWidth = width/2*2;
+ mHeight = height/2*2;
+ mStrideY = strideY/2*2;
+ mStrideVU = strideVU/2*2;
+ mOutBuf = ByteBuffer.allocate(mStrideY*mHeight*3/2);
+ Log("width: "+mWidth+" height: "+mHeight+" strideY: "+mStrideY+" strideVU: "+mStrideVU);
+ nativeInit(mWidth, mHeight, mStrideY, mStrideVU,
+ 0, 0, mWidth, mHeight, NUM_REQUIRED_IMAGE);
+ }
+
+ @Override
+ public void deinit() {
+ Log("deinit");
+ mOutBuf = null;
+ nativeDeinit();
+ }
+
+ @Override
+ public void addImage(ByteBuffer bY, ByteBuffer bVU, int imageNum, Object param) {
+ Log("addImage");
+ int yActualSize = bY.remaining();
+ int vuActualSize = bVU.remaining();
+ int status = nativeAddImage(bY, bVU, yActualSize, vuActualSize, imageNum);
+ if(status != 0) {
+ Log.e(TAG, "Fail to add image");
+ }
+ }
+
+ @Override
+ public ResultImage processImage() {
+ Log("processImage ");
+ int[] roi = new int[4];
+ int status = nativeProcessImage(mOutBuf.array(), (int) (mExpoTime / 1000000), mSenseValue, roi);
+ Log("processImage done");
+ if(status < 0) { //In failure case, library will return the first image as it is.
+ Log.w(TAG, "Fail to process the image.");
+ }
+ return new ResultImage(mOutBuf, new Rect(roi[0], roi[1], roi[0]+roi[2], roi[1] + roi[3]), mWidth, mHeight, mStrideY);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return mIsSupported;
+ }
+
+ @Override
+ public boolean isFrameListener() {
+ return false;
+ }
+
+ @Override
+ public boolean isManualMode() {
+ return false;
+ }
+
+ @Override
+ public void manualCapture(CaptureRequest.Builder builder, CameraCaptureSession captureSession,
+ CameraCaptureSession.CaptureCallback callback, Handler handler) {
+
+ }
+
+ public static boolean isSupportedStatic() {
+ return mIsSupported;
+ }
+
+ private native int nativeInit(int width, int height, int yStride, int vuStride,
+ int roiX, int roiY, int roiW, int roiH, int numImages);
+ private native int nativeDeinit();
+ private native int nativeAddImage(ByteBuffer yB, ByteBuffer vuB, int ySize, int vuSize, int imageNum);
+ private native int nativeProcessImage(byte[] buffer, int expoTime, int isoValue, int[] roi);
+
+ static {
+ try {
+ System.loadLibrary("jni_stillmore");
+ mIsSupported = true;
+ }catch(UnsatisfiedLinkError e) {
+ Log.d(TAG, e.toString());
+ mIsSupported = false;
+ }
+ }
+}
diff --git a/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java b/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java
index b410e01b4..c68b5091e 100644
--- a/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java
+++ b/src/com/android/camera/imageprocessor/filter/UbifocusFilter.java
@@ -63,7 +63,7 @@ public class UbifocusFilter implements ImageFilter {
private int mStrideY;
private int mStrideVU;
private static String TAG = "UbifocusFilter";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final int FOCUS_ADJUST_TIME_OUT = 200;
private static final int META_BYTES_SIZE = 25;
private int temp;
@@ -76,6 +76,8 @@ public class UbifocusFilter implements ImageFilter {
final String[] NAMES = {"00.jpg", "01.jpg", "02.jpg", "03.jpg",
"04.jpg", "DepthMapImage.y", "AllFocusImage.jpg"};
+ private int mSavedCount = 0;
+
private static void Log(String msg) {
if (DEBUG) {
Log.d(TAG, msg);
@@ -122,18 +124,24 @@ public class UbifocusFilter implements ImageFilter {
}
@Override
- public void addImage(ByteBuffer bY, ByteBuffer bVU, int imageNum, Object param) {
+ public void addImage(final ByteBuffer bY, final ByteBuffer bVU, final int imageNum, Object param) {
Log("addImage");
if(imageNum == 0) {
mModule.setRefocusLastTaken(false);
mOrientation = CameraUtil.getJpegRotation(mModule.getMainCameraId(), mModule.getDisplayOrientation());
+ mSavedCount = 0;
}
- saveToPrivateFile(imageNum, nv21ToJpeg(bY, bVU, new Rect(0, 0, mWidth, mHeight), mOrientation));
int yActualSize = bY.remaining();
int vuActualSize = bVU.remaining();
if(nativeAddImage(bY, bVU, yActualSize, vuActualSize, imageNum) < 0) {
Log.e(TAG, "Fail to add image");
}
+ new Thread() {
+ public void run() {
+ saveToPrivateFile(imageNum, nv21ToJpeg(bY, bVU, new Rect(0, 0, mWidth, mHeight), mOrientation));
+ mSavedCount++;
+ }
+ }.start();
}
@Override
@@ -151,7 +159,12 @@ public class UbifocusFilter implements ImageFilter {
saveToPrivateFile(NAMES.length - 1, nv21ToJpeg(mOutBuf, null, new Rect(roi[0], roi[1], roi[0] + roi[2], roi[1] + roi[3]), mOrientation));
mModule.setRefocusLastTaken(true);
}
-
+ while(mSavedCount < NUM_REQUIRED_IMAGE) {
+ try {
+ Thread.sleep(1);
+ } catch (Exception e) {
+ }
+ }
ResultImage result = new ResultImage(mOutBuf, new Rect(roi[0], roi[1], roi[0]+roi[2], roi[1] + roi[3]), mWidth, mHeight, mStrideY);
Log("processImage done");
return result;
diff --git a/src/com/android/camera/ui/DotsView.java b/src/com/android/camera/ui/DotsView.java
new file mode 100644
index 000000000..f08b96713
--- /dev/null
+++ b/src/com/android/camera/ui/DotsView.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.camera.ui;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class DotsView extends View {
+ private Paint mTargetPaint;
+ private int mPosition;
+ private float mPositionOffset;
+ private DotsViewItem mItems;
+
+ public DotsView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mTargetPaint = new Paint();
+ mTargetPaint.setColor(Color.WHITE);
+ mTargetPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ }
+
+ public void update(int position, float positionOffest) {
+ mPosition = position;
+ mPositionOffset = positionOffest;
+ invalidate();
+ }
+
+ public void setItems(DotsViewItem item) {
+ mItems = item;
+ }
+
+ public void update() {
+ invalidate();
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ if(mItems == null) {
+ return;
+ }
+
+ int dx = canvas.getWidth()/(mItems.getTotalItemNums()+1);
+ int dy = canvas.getHeight()/(mItems.getTotalItemNums()+1);
+ int y = canvas.getHeight()/2;
+ float radius = Math.min(dx, dy)/2f;
+ for(int i=0; i < mItems.getTotalItemNums(); i++) {
+ if(i-1 == mPosition && mPositionOffset > 0f) {
+ drawDot(canvas, (i + 1) * dx, y, radius + radius * mPositionOffset, mItems.isChosen(i));
+ } else if(i+1 == mPosition && mPositionOffset < 0f) {
+ drawDot(canvas, (i + 1) * dx, y, radius - radius*mPositionOffset, mItems.isChosen(i));
+ } else if(i == mPosition) {
+ drawDot(canvas, (i + 1) * dx, y, radius + radius * (1 - Math.abs(mPositionOffset)), mItems.isChosen(i));
+ } else {
+ drawDot(canvas, (i + 1) * dx, y, radius, mItems.isChosen(i));
+ }
+ }
+ }
+
+ private void drawDot(Canvas canvas, float cx, float cy, float radius, boolean isChosen) {
+ if(isChosen) {
+ mTargetPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+ canvas.drawCircle(cx, cy, radius, mTargetPaint);
+ } else {
+ mTargetPaint.setStyle(Paint.Style.STROKE);
+ canvas.drawCircle(cx, cy, radius, mTargetPaint);
+ }
+ }
+}
diff --git a/src/com/android/camera/ui/DotsViewItem.java b/src/com/android/camera/ui/DotsViewItem.java
new file mode 100644
index 000000000..eb342938c
--- /dev/null
+++ b/src/com/android/camera/ui/DotsViewItem.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.camera.ui;
+
+public interface DotsViewItem {
+ int getTotalItemNums();
+ boolean isChosen(int index);
+}
diff --git a/src/com/android/camera/util/PersistUtil.java b/src/com/android/camera/util/PersistUtil.java
index c9a5a474a..a39abaa82 100644
--- a/src/com/android/camera/util/PersistUtil.java
+++ b/src/com/android/camera/util/PersistUtil.java
@@ -35,6 +35,7 @@ public class PersistUtil {
private static final String PERSIST_MEMORY_LIMIT = "persist.camera.perf.memlimit";
private static final String PERSIST_SKIP_MEMORY_CHECK = "persist.camera.perf.skip_memck";
private static final String PERSIST_LONGSHOT_SHOT_LIMIT = "persist.camera.longshot.shotnum";
+ private static final String PERSIST_CAMERA_PREVIEW_SIZE = "persist.camera.preview.size";
public static int getMemoryLimit() {
return SystemProperties.getInt(PERSIST_MEMORY_LIMIT, 60);
@@ -48,4 +49,7 @@ public class PersistUtil {
return SystemProperties.getInt(PERSIST_LONGSHOT_SHOT_LIMIT, 20);
}
+ public static int getCameraPreviewSize() {
+ return SystemProperties.getInt(PERSIST_CAMERA_PREVIEW_SIZE, 0);
+ }
}