From 0d00a8907096b9970ac64f52abbd2bfc1ed751b6 Mon Sep 17 00:00:00 2001 From: Angus Kong Date: Tue, 26 Mar 2013 11:40:40 -0700 Subject: Add GPSDirection tag using ExifInterface. bug:8115825 Change-Id: Iefcbbddbb7f9fed0c386214b428d4743f67d0dd9 --- src/com/android/camera/Exif.java | 37 ++++++------ src/com/android/camera/MediaSaveService.java | 14 +++-- src/com/android/camera/PhotoModule.java | 86 ++++++++++++++++++++++++++-- src/com/android/camera/Storage.java | 17 ++++-- src/com/android/camera/VideoModule.java | 8 ++- 5 files changed, 129 insertions(+), 33 deletions(-) (limited to 'src/com/android/camera') diff --git a/src/com/android/camera/Exif.java b/src/com/android/camera/Exif.java index ee39d675e..c6ec6af50 100644 --- a/src/com/android/camera/Exif.java +++ b/src/com/android/camera/Exif.java @@ -20,32 +20,35 @@ import android.util.Log; import com.android.gallery3d.exif.ExifInterface; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; public class Exif { private static final String TAG = "CameraExif"; - // Returns the degrees in clockwise. Values are 0, 90, 180, or 270. - public static int getOrientation(byte[] jpeg) { - if (jpeg == null) { - return 0; - } - + public static ExifInterface getExif(byte[] jpegData) { ExifInterface exif = new ExifInterface(); - InputStream is = new ByteArrayInputStream(jpeg); try { - exif.readExif(is); - Integer val = exif.getTagIntValue(ExifInterface.TAG_ORIENTATION); - if (val == null) { - return 0; - } else { - return ExifInterface.getRotationForOrientationValue(val.shortValue()); - } + exif.readExif(jpegData); } catch (IOException e) { - Log.w(TAG, "Failed to read EXIF orientation", e); + Log.w(TAG, "Failed to read EXIF data", e); + } + return exif; + } + + // Returns the degrees in clockwise. Values are 0, 90, 180, or 270. + public static int getOrientation(ExifInterface exif) { + Integer val = exif.getTagIntValue(ExifInterface.TAG_ORIENTATION); + if (val == null) { return 0; + } else { + return ExifInterface.getRotationForOrientationValue(val.shortValue()); } } + + public static int getOrientation(byte[] jpegData) { + if (jpegData == null) return 0; + + ExifInterface exif = getExif(jpegData); + return getOrientation(exif); + } } diff --git a/src/com/android/camera/MediaSaveService.java b/src/com/android/camera/MediaSaveService.java index 48fb629e9..b1f47df77 100644 --- a/src/com/android/camera/MediaSaveService.java +++ b/src/com/android/camera/MediaSaveService.java @@ -26,6 +26,8 @@ import android.os.Binder; import android.os.IBinder; import android.util.Log; +import com.android.gallery3d.exif.ExifInterface; + /* * Service for saving images in the background thread. */ @@ -77,14 +79,14 @@ public class MediaSaveService extends Service { // Runs in main thread public void addImage(final byte[] data, String title, long date, Location loc, - int width, int height, int orientation, + int width, int height, int orientation, ExifInterface exif, OnMediaSavedListener l, ContentResolver resolver) { if (isQueueFull()) { Log.e(TAG, "Cannot add image when the queue is full"); return; } SaveTask t = new SaveTask(data, title, date, (loc == null) ? null : new Location(loc), - width, height, orientation, resolver, l); + width, height, orientation, exif, resolver, l); mTaskNumber++; if (isQueueFull()) { @@ -114,12 +116,13 @@ public class MediaSaveService extends Service { private Location loc; private int width, height; private int orientation; + private ExifInterface exif; private ContentResolver resolver; private OnMediaSavedListener listener; public SaveTask(byte[] data, String title, long date, Location loc, - int width, int height, int orientation, ContentResolver resolver, - OnMediaSavedListener listener) { + int width, int height, int orientation, ExifInterface exif, + ContentResolver resolver, OnMediaSavedListener listener) { this.data = data; this.title = title; this.date = date; @@ -127,6 +130,7 @@ public class MediaSaveService extends Service { this.width = width; this.height = height; this.orientation = orientation; + this.exif = exif; this.resolver = resolver; this.listener = listener; } @@ -139,7 +143,7 @@ public class MediaSaveService extends Service { @Override protected Uri doInBackground(Void... v) { return Storage.addImage( - resolver, title, date, loc, orientation, data, width, height); + resolver, title, date, loc, orientation, exif, data, width, height); } @Override diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index 037e0fdb3..ff2faf790 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -21,6 +21,7 @@ import android.app.Activity; import android.app.AlertDialog; import android.content.ContentProviderClient; import android.content.ContentResolver; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences.Editor; @@ -31,6 +32,10 @@ import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Parameters; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.Size; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; import android.location.Location; import android.media.CameraProfile; import android.net.Uri; @@ -56,6 +61,9 @@ import com.android.camera.ui.PopupManager; import com.android.camera.ui.RotateTextToast; import com.android.gallery3d.R; import com.android.gallery3d.common.ApiHelper; +import com.android.gallery3d.exif.ExifInterface; +import com.android.gallery3d.exif.ExifTag; +import com.android.gallery3d.exif.Rational; import com.android.gallery3d.filtershow.CropExtras; import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.util.UsageStatistics; @@ -77,7 +85,8 @@ public class PhotoModule CameraPreference.OnPreferenceChangedListener, ShutterButton.OnShutterButtonListener, MediaSaveService.Listener, - OnCountDownFinishedListener { + OnCountDownFinishedListener, + SensorEventListener { private static final String TAG = "CAM_PhotoModule"; @@ -239,6 +248,12 @@ public class PhotoModule CameraStartUpThread mCameraStartUpThread; ConditionVariable mStartPreviewPrerequisiteReady = new ConditionVariable(); + private SensorManager mSensorManager; + private float[] mGData = new float[3]; + private float[] mMData = new float[3]; + private float[] mR = new float[16]; + private int mHeading = -1; + private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = new MediaSaveService.OnMediaSavedListener() { @Override @@ -417,6 +432,8 @@ public class PhotoModule initializeControlByIntent(); mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); mLocationManager = new LocationManager(mActivity, mUI); + mSensorManager = (SensorManager)(mActivity.getSystemService(Context.SENSOR_SERVICE)); + } private void initializeControlByIntent() { @@ -792,7 +809,8 @@ public class PhotoModule if (!mIsImageCaptureIntent) { // Calculate the width and the height of the jpeg. Size s = mParameters.getPictureSize(); - int orientation = Exif.getOrientation(jpegData); + ExifInterface exif = Exif.getExif(jpegData); + int orientation = Exif.getOrientation(exif); int width, height; if ((mJpegRotation + orientation) % 180 == 0) { width = s.width; @@ -807,9 +825,20 @@ public class PhotoModule Log.e(TAG, "Unbalanced name/data pair"); } else { if (date == -1) date = mCaptureStartTime; + if (mHeading >= 0) { + // heading direction has been updated by the sensor. + ExifTag directionRefTag = exif.buildTag( + ExifInterface.TAG_GPS_IMG_DIRECTION_REF, + ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION); + ExifTag directionTag = exif.buildTag( + ExifInterface.TAG_GPS_IMG_DIRECTION, + new Rational(mHeading, 1)); + exif.setTag(directionRefTag); + exif.setTag(directionTag); + } mActivity.getMediaSaveService().addImage( jpegData, title, date, mLocation, width, height, - orientation, mOnMediaSavedListener, mContentResolver); + orientation, exif, mOnMediaSavedListener, mContentResolver); } } else { mJpegImageData = jpegData; @@ -1091,7 +1120,8 @@ public class PhotoModule Util.closeSilently(outputStream); } } else { - int orientation = Exif.getOrientation(data); + ExifInterface exif = Exif.getExif(data); + int orientation = Exif.getOrientation(exif); Bitmap bitmap = Util.makeBitmap(data, 50 * 1024); bitmap = Util.rotate(bitmap, orientation); mActivity.setResultEx(Activity.RESULT_OK, @@ -1258,6 +1288,16 @@ public class PhotoModule PopupManager.getInstance(mActivity).notifyShowPopup(null); UsageStatistics.onContentViewChanged( UsageStatistics.COMPONENT_CAMERA, "PhotoModule"); + + Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + if (gsensor != null) { + mSensorManager.registerListener(this, gsensor, SensorManager.SENSOR_DELAY_NORMAL); + } + + Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + if (msensor != null) { + mSensorManager.registerListener(this, msensor, SensorManager.SENSOR_DELAY_NORMAL); + } } void waitCameraStartUpThread() { @@ -1276,6 +1316,15 @@ public class PhotoModule @Override public void onPauseBeforeSuper() { mPaused = true; + Sensor gsensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + if (gsensor != null) { + mSensorManager.unregisterListener(this, gsensor); + } + + Sensor msensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + if (msensor != null) { + mSensorManager.unregisterListener(this, msensor); + } } @Override @@ -1975,4 +2024,33 @@ public class PhotoModule s.setListener(this); } } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + + @Override + public void onSensorChanged(SensorEvent event) { + int type = event.sensor.getType(); + float[] data; + if (type == Sensor.TYPE_ACCELEROMETER) { + data = mGData; + } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { + data = mMData; + } else { + // we should not be here. + return; + } + for (int i = 0; i < 3 ; i++) { + data[i] = event.values[i]; + } + float[] orientation = new float[3]; + SensorManager.getRotationMatrix(mR, null, mGData, mMData); + SensorManager.getOrientation(mR, orientation); + mHeading = (int) (orientation[0] * 180f / Math.PI) % 360; + if (mHeading < 0) { + mHeading += 360; + } + Log.v(TAG, "heading:" + mHeading); + } } diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java index 648fa7d87..ba995edef 100644 --- a/src/com/android/camera/Storage.java +++ b/src/com/android/camera/Storage.java @@ -30,6 +30,7 @@ import android.provider.MediaStore.MediaColumns; import android.util.Log; import com.android.gallery3d.common.ApiHelper; +import com.android.gallery3d.exif.ExifInterface; import java.io.File; import java.io.FileOutputStream; @@ -49,7 +50,7 @@ public class Storage { public static final long UNAVAILABLE = -1L; public static final long PREPARING = -2L; public static final long UNKNOWN_SIZE = -3L; - public static final long LOW_STORAGE_THRESHOLD= 50000000; + public static final long LOW_STORAGE_THRESHOLD = 50000000; @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private static void setImageSize(ContentValues values, int width, int height) { @@ -77,11 +78,19 @@ public class Storage { // Save the image and add it to media store. public static Uri addImage(ContentResolver resolver, String title, - long date, Location location, int orientation, byte[] jpeg, - int width, int height) { + long date, Location location, int orientation, ExifInterface exif, + byte[] jpeg, int width, int height) { // Save the image. String path = generateFilepath(title); - writeFile(path, jpeg); + if (exif != null) { + try { + exif.writeExif(jpeg, path); + } catch (Exception e) { + Log.e(TAG, "Failed to write data", e); + } + } else { + writeFile(path, jpeg); + } return addImage(resolver, title, date, location, orientation, jpeg.length, path, width, height); } diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 998bbf784..94c862502 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -58,6 +58,7 @@ import com.android.camera.ui.PopupManager; import com.android.camera.ui.RotateTextToast; import com.android.gallery3d.R; import com.android.gallery3d.common.ApiHelper; +import com.android.gallery3d.exif.ExifInterface; import com.android.gallery3d.util.AccessibilityUtils; import com.android.gallery3d.util.UsageStatistics; @@ -2213,11 +2214,12 @@ public class VideoModule implements CameraModule, private void storeImage(final byte[] data, Location loc) { long dateTaken = System.currentTimeMillis(); String title = Util.createJpegName(dateTaken); - int orientation = Exif.getOrientation(data); + ExifInterface exif = Exif.getExif(data); + int orientation = Exif.getOrientation(exif); Size s = mParameters.getPictureSize(); mActivity.getMediaSaveService().addImage( - data, title, dateTaken, loc, s.width, s.height, - orientation, mOnMediaSavedListener, mContentResolver); + data, title, dateTaken, loc, s.width, s.height, orientation, + exif, mOnMediaSavedListener, mContentResolver); } private boolean resetEffect() { -- cgit v1.2.3