summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/CameraActivity.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/CameraActivity.java')
-rw-r--r--src/com/android/camera/CameraActivity.java216
1 files changed, 179 insertions, 37 deletions
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index b3a7680a9..dd4a9897a 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -36,7 +36,18 @@ import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader;
import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.media.ThumbnailUtils;
import android.nfc.NfcAdapter;
@@ -86,6 +97,7 @@ import com.android.camera.data.LocalDataAdapter;
import com.android.camera.data.LocalMediaObserver;
import com.android.camera.data.MediaDetails;
import com.android.camera.data.SimpleViewData;
+import com.android.camera.exif.ExifInterface;
import com.android.camera.tinyplanet.TinyPlanetFragment;
import com.android.camera.ui.ModuleSwitcher;
import com.android.camera.ui.DetailsDialog;
@@ -101,6 +113,7 @@ import com.android.camera.util.UsageStatistics;
import org.codeaurora.snapcam.R;
import java.io.File;
+import java.io.IOException;
import static com.android.camera.CameraManager.CameraOpenErrorCallback;
@@ -214,7 +227,12 @@ public class CameraActivity extends Activity
private Intent mImageShareIntent;
public static int SETTING_LIST_WIDTH_1 = 250;
public static int SETTING_LIST_WIDTH_2 = 250;
- private Bitmap mPreviewThumbnailBitmap;
+
+ private ImageView mThumbnail;
+ private CircularDrawable mThumbnailDrawable;
+ // FilmStripView.setDataAdapter fires 2 onDataLoaded calls before any data is actually loaded
+ // Keep track of data request here to avoid creating useless UpdateThumbnailTask.
+ private boolean mDataRequested;
private AudioManager mAudioManager;
private int mShutterVol;
@@ -650,48 +668,47 @@ public class CameraActivity extends Activity
return s;
}
- public void setPreviewThumbnailBitmap(Bitmap bitmap) {
- mPreviewThumbnailBitmap = bitmap;
+ public void updateThumbnail(final byte[] jpegData) {
+ (new UpdateThumbnailTask(jpegData, false)).execute();
}
- public Bitmap getPreviewThumbBitmap() {
- return mPreviewThumbnailBitmap;
+ public void updateThumbnail(final Bitmap bitmap) {
+ mThumbnailDrawable = new CircularDrawable(bitmap);
+ if (mThumbnail != null) {
+ mThumbnail.setImageDrawable(mThumbnailDrawable);
+ mThumbnail.setVisibility(View.VISIBLE);
+ }
}
- public void updatePreviewThumbnail() {
- if (mCurrentModule != null) {
- if (mCurrentModule instanceof VideoModule) {
- ((VideoModule) mCurrentModule).updatePreviewThumbnail();
- }
- else if (mCurrentModule instanceof WideAnglePanoramaModule) {
- ((WideAnglePanoramaModule) mCurrentModule).updatePreviewThumbnail();
- }
- else if (mCurrentModule instanceof PhotoModule) {
- ((PhotoModule) mCurrentModule).updatePreviewThumbnail();
- }
+ public void updateThumbnail(ImageView thumbnail) {
+ mThumbnail = thumbnail;
+ if (mThumbnailDrawable != null) {
+ mThumbnail.setImageDrawable(mThumbnailDrawable);
+ mThumbnail.setVisibility(View.VISIBLE);
}
}
- public void updatePreviewThumbnailForVideo() {
- if (mCurrentModule != null) {
- if (mCurrentModule instanceof VideoModule) {
- ((VideoModule) mCurrentModule).updatePreviewThumbnail();
- }
+ public void updateThumbnail(boolean videoOnly) {
+ // Only handle OnDataInserted if it's video.
+ // Photo and Panorama have their own way of updating thumbnail.
+ if (!videoOnly || (mCurrentModule instanceof VideoModule)) {
+ (new UpdateThumbnailTask(null, true)).execute();
}
}
- public class UpdatePreviewThumbnail extends AsyncTask<Void, Void, Bitmap> {
- private ImageView imgView;
- private Bitmap imgBitmap = null;
+ private class UpdateThumbnailTask extends AsyncTask<Void, Void, Bitmap> {
+ private final byte[] mJpegData;
+ private final boolean mCheckOrientation;
- public UpdatePreviewThumbnail(ImageView view) {
- imgView = view;
+ public UpdateThumbnailTask(final byte[] jpegData, boolean checkOrientation) {
+ mJpegData = jpegData;
+ mCheckOrientation = checkOrientation;
}
@Override
protected Bitmap doInBackground(Void... params) {
- if (imgBitmap != null)
- return imgBitmap;
+ if (mJpegData != null)
+ return decodeImageCenter(null);
LocalDataAdapter adapter = getDataAdapter();
ImageData img = adapter.getImageData(1);
@@ -705,22 +722,146 @@ public class CameraActivity extends Activity
}
else {
if (img.isPhoto()) {
- BitmapFactory.Options opt = new BitmapFactory.Options();
- opt.inSampleSize = 4;
- return BitmapFactory.decodeFile(path, opt);
+ return decodeImageCenter(path);
} else {
return ThumbnailUtils
- .createVideoThumbnail(path, MediaStore.Video.Thumbnails.MICRO_KIND);
+ .createVideoThumbnail(path, MediaStore.Video.Thumbnails.MINI_KIND);
}
}
}
@Override
protected void onPostExecute(Bitmap bitmap) {
- if (imgView == null)
- return;
- imgView.setImageBitmap(bitmap);
- setPreviewThumbnailBitmap(bitmap);
+ if (bitmap == null) {
+ if (mThumbnail != null) {
+ mThumbnail.setVisibility(View.GONE);
+ }
+ } else {
+ updateThumbnail(bitmap);
+ }
+ }
+
+ private Bitmap decodeImageCenter(final String path) {
+ // Check photo orientation for Panorama. This is necessary during app launch because
+ // Panorama module generates thumbnail bitmap with orientation adjustment but only
+ // saves jpeg with orientation tag set.
+ int orientation = 0;
+ if (mCheckOrientation) {
+ ExifInterface exif = new ExifInterface();
+ try {
+ if (mJpegData != null) {
+ exif.readExif(mJpegData);
+ } else {
+ exif.readExif(path);
+ }
+ orientation = Exif.getOrientation(exif);
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ final BitmapFactory.Options opt = new BitmapFactory.Options();
+ opt.inJustDecodeBounds = true;
+ if (mJpegData != null) {
+ BitmapFactory.decodeByteArray(mJpegData, 0, mJpegData.length, opt);
+ } else {
+ BitmapFactory.decodeFile(path, opt);
+ }
+
+ int w = opt.outWidth;
+ int h = opt.outHeight;
+ int d = w > h ? h : w;
+ final Rect rect = w > h ? new Rect((w - h) / 2, 0, (w + h) / 2, h)
+ : new Rect(0, (h - w) / 2, w, (h + w) / 2);
+
+ final int target = getResources().getDimensionPixelSize(R.dimen.capture_size);
+ int sample = 1;
+ if (d > target) {
+ while (d / sample / 2 > target) {
+ sample *= 2;
+ }
+ }
+
+ opt.inJustDecodeBounds = false;
+ opt.inSampleSize = sample;
+ final BitmapRegionDecoder decoder;
+ try {
+ if (mJpegData == null) {
+ decoder = BitmapRegionDecoder.newInstance(path, true);
+ } else {
+ decoder = BitmapRegionDecoder.newInstance(mJpegData, 0, mJpegData.length, true);
+ }
+ } catch (IOException e) {
+ return null;
+ }
+ Bitmap bitmap = decoder.decodeRegion(rect, opt);
+ if (orientation != 0) {
+ Matrix matrix = new Matrix();
+ matrix.setRotate(orientation);
+ bitmap = Bitmap.createBitmap(bitmap, 0, 0,
+ bitmap.getWidth(), bitmap.getHeight(), matrix, false);
+ }
+ return bitmap;
+ }
+ }
+
+ private class CircularDrawable extends Drawable {
+ private final BitmapShader mBitmapShader;
+ private final Paint mPaint;
+ private Rect mRect;
+ private int mLength;
+
+ public CircularDrawable(Bitmap bitmap) {
+ int w = bitmap.getWidth();
+ int h = bitmap.getHeight();
+ if (w > h) {
+ mLength = h;
+ bitmap = Bitmap.createBitmap(bitmap, (w - h) / 2, 0, h, h);
+ } else if (w < h) {
+ mLength = w;
+ bitmap = Bitmap.createBitmap(bitmap, 0, (h - w) / 2, w, w);
+ }
+
+ mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setShader(mBitmapShader);
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ mRect = bounds;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ canvas.drawRoundRect(new RectF(mRect), (mRect.right - mRect.left) / 2,
+ (mRect.bottom - mRect.top) / 2, mPaint);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mPaint.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter filter) {
+ mPaint.setColorFilter(filter);
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mLength;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mLength;
}
}
@@ -1306,6 +1447,7 @@ public class CameraActivity extends Activity
mFilmStripView.setDataAdapter(mDataAdapter);
if (!isCaptureIntent()) {
mDataAdapter.requestLoad(getContentResolver());
+ mDataRequested = true;
}
} else {
// Put a lock placeholder as the last image by setting its date to
@@ -1455,7 +1597,7 @@ public class CameraActivity extends Activity
// If it's secure camera, requestLoad() should not be called
// as it will load all the data.
mDataAdapter.requestLoad(getContentResolver());
- setPreviewThumbnailBitmap(null);
+ mThumbnailDrawable = null;
}
}
mLocalImagesObserver.setActivityPaused(false);