Add shutter animation when taking pictures
Additionally to playing shutter sounds, add support for showing
a shutter animation.
Can be toggled in settings, enabled by default.
Change-Id: If40a90a93a7582aaa103a9646307a80099e89a71
Signed-off-by: Alexander Martinz <amartinz@shiftphones.com>
diff --git a/res/drawable/ic_custom_shutter_animation.xml b/res/drawable/ic_custom_shutter_animation.xml
new file mode 100644
index 0000000..881f0e6
--- /dev/null
+++ b/res/drawable/ic_custom_shutter_animation.xml
@@ -0,0 +1,10 @@
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9.4,10.5l4.77,-8.26C13.47,2.09 12.75,2 12,2c-2.4,0 -4.6,0.85 -6.32,2.25l3.66,6.35 0.06,-0.1zM21.54,9c-0.92,-2.92 -3.15,-5.26 -6,-6.34L11.88,9h9.66zM21.8,10h-7.49l0.29,0.5 4.76,8.25C21,16.97 22,14.61 22,12c0,-0.69 -0.07,-1.35 -0.2,-2zM8.54,12l-3.9,-6.75C3.01,7.03 2,9.39 2,12c0,0.69 0.07,1.35 0.2,2h7.49l-1.15,-2zM2.46,15c0.92,2.92 3.15,5.26 6,6.34L12.12,15L2.46,15zM13.73,15l-3.9,6.76c0.7,0.15 1.42,0.24 2.17,0.24 2.4,0 4.6,-0.85 6.32,-2.25l-3.66,-6.35 -0.93,1.6z" />
+</vector>
diff --git a/res/values-de/qcomstrings.xml b/res/values-de/qcomstrings.xml
index 4710427..9aee98e 100644
--- a/res/values-de/qcomstrings.xml
+++ b/res/values-de/qcomstrings.xml
@@ -311,6 +311,9 @@
<string name="pref_camera_scenemode_entry_promode">Pro-Modus</string>
<string name="bestpicture_done">FERTIG</string>
<string name="bestpicture_at_least_one_picture">Es muss mindestens ein Bild ausgewählt werden.</string>
+ <string name="pref_camera2_shutter_animation_entry_on">An</string>
+ <string name="pref_camera2_shutter_animation_entry_off">Aus</string>
+ <string name="pref_camera2_shutter_animation_title">Auslöse-Animation</string>
<string name="pref_camera2_shutter_sound_entry_on">An</string>
<string name="pref_camera2_shutter_sound_entry_off">Aus</string>
<string name="pref_camera2_shutter_sound_title">Auslöser-Ton</string>
diff --git a/res/values/camera2arrays.xml b/res/values/camera2arrays.xml
index f0368be..f102d13 100755
--- a/res/values/camera2arrays.xml
+++ b/res/values/camera2arrays.xml
@@ -898,6 +898,16 @@
<item>@string/pref_camera2_timer_value_10sec</item>
</string-array>
+ <string-array name="pref_camera2_shutter_animation_entries" translatable="true">
+ <item>@string/pref_camera2_shutter_animation_entry_on</item>
+ <item>@string/pref_camera2_shutter_animation_entry_off</item>
+ </string-array>
+
+ <string-array name="pref_camera2_shutter_animation_entryvalues" translatable="false">
+ <item>@string/pref_camera2_shutter_animation_value_on</item>
+ <item>@string/pref_camera2_shutter_animation_value_off</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>
diff --git a/res/values/qcomstrings.xml b/res/values/qcomstrings.xml
index 1f70121..417727c 100755
--- a/res/values/qcomstrings.xml
+++ b/res/values/qcomstrings.xml
@@ -984,6 +984,14 @@
<string name="bestpicture_done">DONE</string>
<string name="bestpicture_at_least_one_picture">At least one picture has to be chosen.</string>
+ <string name="pref_camera2_shutter_animation_default" translatable="false">on</string>
+ <string name="pref_camera2_shutter_animation_value_on" translatable="false">on</string>
+ <string name="pref_camera2_shutter_animation_value_off" translatable="false">off</string>
+
+ <string name="pref_camera2_shutter_animation_entry_on">On</string>
+ <string name="pref_camera2_shutter_animation_entry_off">Off</string>
+ <string name="pref_camera2_shutter_animation_title">Shutter animation</string>
+
<string name="pref_camera2_shutter_sound_default" translatable="false">on</string>
<string name="pref_camera2_shutter_sound_value_on" translatable="false">on</string>
<string name="pref_camera2_shutter_sound_value_off" translatable="false">off</string>
diff --git a/res/xml/capture_preferences.xml b/res/xml/capture_preferences.xml
index 5c47e7b..89b12cd 100755
--- a/res/xml/capture_preferences.xml
+++ b/res/xml/capture_preferences.xml
@@ -294,6 +294,13 @@
camera:title="@string/pref_selfie_flash_title" />
<ListPreference
+ camera:defaultValue="@string/pref_camera2_shutter_animation_default"
+ camera:entries="@array/pref_camera2_shutter_animation_entries"
+ camera:entryValues="@array/pref_camera2_shutter_animation_entryvalues"
+ camera:key="pref_camera2_shutter_animation_key"
+ camera:title="@string/pref_camera2_shutter_animation_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"
diff --git a/res/xml/setting_menu_preferences.xml b/res/xml/setting_menu_preferences.xml
index de286ff..f392936 100755
--- a/res/xml/setting_menu_preferences.xml
+++ b/res/xml/setting_menu_preferences.xml
@@ -122,6 +122,12 @@
<SwitchPreference
android:defaultValue="true"
+ android:icon="@drawable/ic_custom_shutter_animation"
+ android:key="pref_camera2_shutter_animation_key"
+ android:title="@string/pref_camera2_shutter_animation_title" />
+
+ <SwitchPreference
+ android:defaultValue="true"
android:icon="@drawable/ic_custom_shutter_sound"
android:key="pref_camera2_shutter_sound_key"
android:title="@string/pref_camera2_shutter_sound_title" />
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java
index 787f24e..077eee8 100755
--- a/src/com/android/camera/CaptureModule.java
+++ b/src/com/android/camera/CaptureModule.java
@@ -2070,7 +2070,7 @@
private boolean takeZSLPicture(int cameraId) {
if(mPostProcessor.isZSLEnabled() && mPostProcessor.takeZSLPicture()) {
- checkAndPlayShutterSound(getMainCameraId());
+ checkAndPlayShutterEffects(getMainCameraId());
mUI.enableShutter(true);
return true;
}
@@ -2435,7 +2435,7 @@
VendorTagUtil.setCdsMode(captureBuilder, 2); // CDS 0-OFF, 1-ON, 2-AUTO
applySettingsForCapture(captureBuilder, id);
applySettingsForLockExposure(captureBuilder, id);
- checkAndPlayShutterSound(id);
+ checkAndPlayShutterEffects(id);
if(mPaused || !mCamerasOpened) {
//for avoid occurring crash when click back before capture finished.
//CameraDevice was already closed
@@ -2447,7 +2447,7 @@
private void captureStillPictureForFilter(CaptureRequest.Builder captureBuilder, int id) throws CameraAccessException{
applySettingsForLockExposure(captureBuilder, id);
- checkAndPlayShutterSound(id);
+ checkAndPlayShutterEffects(id);
if(mPaused || !mCamerasOpened) {
//for avoid occurring crash when click back before capture finished.
//CameraDevice was already closed
@@ -2480,7 +2480,7 @@
}
Log.d(TAG, "captureStillPictureForLongshot onCaptureCompleted: " + mNumFramesArrived.get() + " " + mShotNum);
if (mLongshotActive) {
- checkAndPlayShutterSound(getMainCameraId());
+ checkAndPlayShutterEffects(getMainCameraId());
}
mLongshoting = false;
}
@@ -2567,7 +2567,7 @@
}
private void captureStillPictureForCommon(CaptureRequest.Builder captureBuilder, int id) throws CameraAccessException{
- checkAndPlayShutterSound(id);
+ checkAndPlayShutterEffects(id);
if(mLongshoting) mLongshoting = false;
if(isMpoOn()) {
mCaptureStartTime = System.currentTimeMillis();
@@ -2640,7 +2640,7 @@
warningToast("Camera is not ready yet to take a video snapshot.");
return;
}
- checkAndPlayShutterSound(id);
+ checkAndPlayShutterEffects(id);
CaptureRequest.Builder captureBuilder =
mCameraDevice[id].createCaptureRequest(CameraDevice.TEMPLATE_VIDEO_SNAPSHOT);
@@ -6803,12 +6803,17 @@
}
}
- public void checkAndPlayShutterSound(int id) {
+ public void checkAndPlayShutterEffects(int id) {
if (id == getMainCameraId()) {
String value = mSettingsManager.getValue(SettingsManager.KEY_SHUTTER_SOUND);
- if (value != null && value.equals("on") && mSoundPlayer != null) {
+ if (mSoundPlayer != null && "on".equals(value)) {
mSoundPlayer.play(SoundClips.SHUTTER_CLICK);
}
+
+ value = mSettingsManager.getValue(SettingsManager.KEY_SHUTTER_ANIMATION);
+ if ("on".equals(value)) {
+ mUI.triggerShutterEffect();
+ }
}
}
diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java
index 9cef708..611217b 100755
--- a/src/com/android/camera/CaptureUI.java
+++ b/src/com/android/camera/CaptureUI.java
@@ -20,6 +20,9 @@
package com.android.camera;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
@@ -254,6 +257,32 @@
}
}
+ public void triggerShutterEffect() {
+ final AnimatorSet shutterSet = new AnimatorSet();
+
+ final ObjectAnimator showAnimator = ObjectAnimator.ofFloat(mPreviewCover, View.ALPHA, 0.0f, 1.0f);
+ showAnimator.setDuration(150L);
+ showAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ showPreviewCover();
+ }
+ });
+
+ final ObjectAnimator hideAnimator = ObjectAnimator.ofFloat(mPreviewCover, View.ALPHA, 1.0f, 0.0f);
+ hideAnimator.setDuration(100L);
+ hideAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ hidePreviewCover();
+ }
+ });
+
+ shutterSet.playSequentially(showAnimator, hideAnimator);
+ mPreviewCover.post(shutterSet::start);
+ }
+
public void initThumbnail() {
if (mThumbnail == null)
mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);
diff --git a/src/com/android/camera/SettingsManager.java b/src/com/android/camera/SettingsManager.java
index a2a7f10..d00de3d 100755
--- a/src/com/android/camera/SettingsManager.java
+++ b/src/com/android/camera/SettingsManager.java
@@ -168,6 +168,7 @@
public static final String KEY_FACE_DETECTION = "pref_camera2_facedetection_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_ANIMATION = "pref_camera2_shutter_animation_key";
public static final String KEY_SHUTTER_SOUND = "pref_camera2_shutter_sound_key";
public static final String KEY_DEVELOPER_MENU = "pref_camera2_developer_menu_key";
public static final String KEY_RESTORE_DEFAULT = "pref_camera2_restore_default_key";
diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java
index 6d66e33..e7de95c 100755
--- a/src/com/android/camera/imageprocessor/PostProcessor.java
+++ b/src/com/android/camera/imageprocessor/PostProcessor.java
@@ -527,7 +527,7 @@
private void reprocessImage(Image image, TotalCaptureResult metadata) {
if(mController.isLongShotActive()) {
- mController.checkAndPlayShutterSound(mController.getMainCameraId());
+ mController.checkAndPlayShutterEffects(mController.getMainCameraId());
}
synchronized (lock) {
if(mCameraDevice == null || mCaptureSession == null || mImageReader == null) {
@@ -1107,7 +1107,7 @@
mActivity.getContentResolver(), "jpeg");
}
if (mFilterIndex == FILTER_UBIFOCUS && numImage > 0) {
- mController.checkAndPlayShutterSound(mController.getMainCameraId());
+ mController.checkAndPlayShutterEffects(mController.getMainCameraId());
}
mFilter.addImage(yBuf, vuBuf, numImage, null);
mImages[numImage] = image;