summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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-xhdpi/ic_settings_selfiemirror.pngbin0 -> 2329 bytes
-rw-r--r--res/drawable-xxhdpi/ic_settings_selfiemirror.pngbin0 -> 3215 bytes
-rw-r--r--res/values/qcomarrays.xml10
-rw-r--r--res/values/qcomstrings.xml6
-rw-r--r--res/xml/camera_preferences.xml7
-rw-r--r--src/com/android/camera/CameraSettings.java1
-rwxr-xr-xsrc/com/android/camera/PhotoMenu.java4
-rw-r--r--src/com/android/camera/PhotoModule.java40
-rw-r--r--src/com/android/camera/imageprocessor/FrameProcessor.java50
-rw-r--r--src/com/android/camera/imageprocessor/PostProcessor.java4
12 files changed, 120 insertions, 32 deletions
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-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-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/values/qcomarrays.xml b/res/values/qcomarrays.xml
index 7574992b9..4858ab3c0 100644
--- a/res/values/qcomarrays.xml
+++ b/res/values/qcomarrays.xml
@@ -587,6 +587,16 @@
<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>
+
<!-- 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..e03a47344 100644
--- a/res/values/qcomstrings.xml
+++ b/res/values/qcomstrings.xml
@@ -322,6 +322,12 @@
<!-- 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>
+
<!-- Default mce setting. Do not translate. -->
<string name="pref_camera_mce_default">enable</string>
diff --git a/res/xml/camera_preferences.xml b/res/xml/camera_preferences.xml
index 7e024b298..9c6d64670 100644
--- a/res/xml/camera_preferences.xml
+++ b/res/xml/camera_preferences.xml
@@ -285,6 +285,13 @@
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" />
<ListPreference
camera:key="pref_camera_selectablezoneaf_key"
camera:defaultValue="@string/pref_camera_selectablezoneaf_default"
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java
index f700d2187..bf31724df 100644
--- a/src/com/android/camera/CameraSettings.java
+++ b/src/com/android/camera/CameraSettings.java
@@ -100,6 +100,7 @@ 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_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/PhotoMenu.java b/src/com/android/camera/PhotoMenu.java
index c2f9a538b..2c339f68b 100755
--- a/src/com/android/camera/PhotoMenu.java
+++ b/src/com/android/camera/PhotoMenu.java
@@ -191,7 +191,8 @@ 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
};
mOtherKeys2 = new String[] {
@@ -234,6 +235,7 @@ public class PhotoMenu extends MenuController
CameraSettings.KEY_MANUAL_EXPOSURE,
CameraSettings.KEY_MANUAL_WB,
CameraSettings.KEY_MANUAL_FOCUS,
+ CameraSettings.KEY_SELFIE_MIRROR,
SettingsManager.KEY_CAMERA2
};
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index b4f8c3a74..52e99ad1c 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;
@@ -1260,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;
@@ -1269,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()) {
@@ -1361,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) {
@@ -1973,8 +2001,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,
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..a1cea3530 100644
--- a/src/com/android/camera/imageprocessor/PostProcessor.java
+++ b/src/com/android/camera/imageprocessor/PostProcessor.java
@@ -488,5 +488,9 @@ public class PostProcessor implements ImageReader.OnImageAvailableListener{
}
}
+ private native int nativeFlipVerticalNV21(byte[] buf, int stride, int height);
+ static {
+ System.loadLibrary("jni_imageutil");
+ }
}