From 0a93cd70de75bbd1547fa58330d68ba953607115 Mon Sep 17 00:00:00 2001 From: Angus Kong Date: Fri, 12 Apr 2013 15:30:33 -0700 Subject: Load video items in the new camera filmstrip. Also fixes: 1. NPE when no data to load. 2. The last item is skipped. 3. date and id should be long instead of int. Change-Id: I7cad06998d78e0d3f0a30be24e65eb0f777b9c0e --- src/com/android/camera/data/CameraDataAdapter.java | 240 ++++++++++++++++++--- 1 file changed, 210 insertions(+), 30 deletions(-) (limited to 'src/com/android/camera/data/CameraDataAdapter.java') diff --git a/src/com/android/camera/data/CameraDataAdapter.java b/src/com/android/camera/data/CameraDataAdapter.java index d1dad3ffb..cb67aacd7 100644 --- a/src/com/android/camera/data/CameraDataAdapter.java +++ b/src/com/android/camera/data/CameraDataAdapter.java @@ -23,10 +23,13 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.drawable.Drawable; +import android.media.MediaMetadataRetriever; import android.os.AsyncTask; import android.provider.MediaStore; import android.provider.MediaStore.Images; import android.provider.MediaStore.Images.ImageColumns; +import android.provider.MediaStore.Video; +import android.provider.MediaStore.Video.VideoColumns; import android.util.Log; import android.view.View; import android.widget.ImageView; @@ -36,6 +39,8 @@ import com.android.camera.ui.FilmStripView; import com.android.camera.ui.FilmStripView.ImageData; import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; import java.util.List; /** @@ -75,12 +80,13 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { @Override public int getTotalNumber() { + if (mImages == null) return 0; return mImages.size(); } @Override public ImageData getImageData(int id) { - if (id >= mImages.size()) return null; + if (mImages == null || id >= mImages.size()) return null; return mImages.get(id); } @@ -96,6 +102,7 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { @Override public View getView(Context c, int dataID) { + if (mImages == null) return null; if (dataID >= mImages.size() || dataID < 0) { return null; } @@ -129,7 +136,7 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { // Replace the old camera data. mImages.set(0, data); if (mListener != null) { - mListener.onDataUpdated(new StatusReporter() { + mListener.onDataUpdated(new UpdateReporter() { @Override public boolean isDataRemoved(int id) { return false; @@ -154,28 +161,55 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { private class QueryTask extends AsyncTask> { @Override protected List doInBackground(ContentResolver... resolver) { - List l = null; + List l = new ArrayList(); + // Photos Cursor c = resolver[0].query( Images.Media.EXTERNAL_CONTENT_URI, LocalPhotoData.QUERY_PROJECTION, MediaStore.Images.Media.DATA + " like ? ", CAMERA_PATH, LocalPhotoData.QUERY_ORDER); - if (c == null) return null; - - // build up the list. - l = new ArrayList(); - c.moveToFirst(); - while (!c.isLast()) { - LocalData data = LocalPhotoData.buildFromCursor(c); - if (data != null) { - l.add(data); - } else { - Log.e(TAG, "Error decoding file:" - + c.getString(LocalPhotoData.COL_DATA)); + if (c != null && c.moveToFirst()) { + // build up the list. + while (true) { + LocalData data = LocalPhotoData.buildFromCursor(c); + if (data != null) { + l.add(data); + } else { + Log.e(TAG, "Error loading data:" + + c.getString(LocalPhotoData.COL_DATA)); + } + if (c.isLast()) break; + c.moveToNext(); + } + } + if (c != null) c.close(); + + c = resolver[0].query( + Video.Media.EXTERNAL_CONTENT_URI, + LocalVideoData.QUERY_PROJECTION, + MediaStore.Video.Media.DATA + " like ? ", CAMERA_PATH, + LocalVideoData.QUERY_ORDER); + if (c != null && c.moveToFirst()) { + // build up the list. + c.moveToFirst(); + while (true) { + LocalData data = LocalVideoData.buildFromCursor(c); + if (data != null) { + l.add(data); + Log.v(TAG, "video data added:" + data); + } else { + Log.e(TAG, "Error loading data:" + + c.getString(LocalVideoData.COL_DATA)); + } + if (!c.isLast()) c.moveToNext(); + else break; } - c.moveToNext(); } - c.close(); + if (c != null) c.close(); + + if (l.size() == 0) return null; + + Collections.sort(l); return l; } @@ -185,14 +219,19 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { LocalData cameraData = null; if (mImages != null && mImages.size() > 0) { cameraData = mImages.get(0); - if (cameraData.getType() != ImageData.TYPE_CAMERA_PREVIEW) cameraData = null; + if (cameraData.getType() != ImageData.TYPE_CAMERA_PREVIEW) { + cameraData = null; + } } mImages = l; if (cameraData != null) { - l.add(0, cameraData); + // camera view exists, so we make sure at least have 1 data in the list. + if (mImages == null) mImages = new ArrayList(); + mImages.add(0, cameraData); if (mListener != null) { - mListener.onDataUpdated(new StatusReporter() { + // Only the camera data is not changed, everything else is changed. + mListener.onDataUpdated(new UpdateReporter() { @Override public boolean isDataRemoved(int id) { return false; @@ -212,15 +251,18 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { } } - private abstract static class LocalData implements FilmStripView.ImageData { - public int id; + private abstract static class LocalData implements + FilmStripView.ImageData, + Comparable { + public long id; public String title; public String mimeType; + public long dateTaken; + public long dateModified; public String path; // width and height should be adjusted according to orientation. public int width; public int height; - public int supportedAction; @Override public int getWidth() { @@ -237,6 +279,21 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { return false; } + private int compare(long v1, long v2) { + return ((v1 > v2) ? 1 : ((v1 < v2) ? -1 : 0)); + } + + @Override + public int compareTo(LocalData d) { + int cmp = compare(d.dateTaken, dateTaken); + if (cmp != 0) return cmp; + cmp = compare(d.dateModified, dateModified); + if (cmp != 0) return cmp; + cmp = d.title.compareTo(title); + if (cmp != 0) return cmp; + return compare(d.id, id); + } + @Override public abstract int getType(); @@ -276,14 +333,13 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { static final String[] QUERY_PROJECTION = { ImageColumns._ID, // 0, int ImageColumns.TITLE, // 1, string - ImageColumns.MIME_TYPE, // 2, tring + ImageColumns.MIME_TYPE, // 2, string ImageColumns.DATE_TAKEN, // 3, int ImageColumns.DATE_MODIFIED, // 4, int ImageColumns.DATA, // 5, string ImageColumns.ORIENTATION, // 6, int, 0, 90, 180, 270 ImageColumns.WIDTH, // 7, int ImageColumns.HEIGHT, // 8, int - ImageColumns.SIZE // 9, int }; private static final int COL_ID = 0; @@ -295,8 +351,6 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { private static final int COL_ORIENTATION = 6; private static final int COL_WIDTH = 7; private static final int COL_HEIGHT = 8; - private static final int COL_SIZE = 9; - // 32K buffer. private static final byte[] DECODE_TEMP_STORAGE = new byte[32 * 1024]; @@ -306,9 +360,11 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { static LocalPhotoData buildFromCursor(Cursor c) { LocalPhotoData d = new LocalPhotoData(); - d.id = c.getInt(COL_ID); + d.id = c.getLong(COL_ID); d.title = c.getString(COL_TITLE); d.mimeType = c.getString(COL_MIME_TYPE); + d.dateTaken = c.getLong(COL_DATE_TAKEN); + d.dateModified = c.getLong(COL_DATE_MODIFIED); d.path = c.getString(COL_DATA); d.orientation = c.getInt(COL_ORIENTATION); d.width = c.getInt(COL_WIDTH); @@ -348,11 +404,11 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { return v; } - @Override public String toString() { return "LocalPhotoData:" + ",data=" + path + ",mimeType=" + mimeType - + "," + width + "x" + height + ",orientation=" + orientation; + + "," + width + "x" + height + ",orientation=" + orientation + + ",date=" + new Date(dateTaken); } @Override @@ -421,4 +477,128 @@ public class CameraDataAdapter implements FilmStripView.DataAdapter { } } } + + private static class LocalVideoData extends LocalData { + static final String QUERY_ORDER = VideoColumns.DATE_TAKEN + " DESC, " + + VideoColumns._ID + " DESC"; + static final String[] QUERY_PROJECTION = { + VideoColumns._ID, // 0, int + VideoColumns.TITLE, // 1, string + VideoColumns.MIME_TYPE, // 2, string + VideoColumns.DATE_TAKEN, // 3, int + VideoColumns.DATE_MODIFIED, // 4, int + VideoColumns.DATA, // 5, string + VideoColumns.WIDTH, // 6, int + VideoColumns.HEIGHT, // 7, int + VideoColumns.RESOLUTION + }; + + private static final int COL_ID = 0; + private static final int COL_TITLE = 1; + private static final int COL_MIME_TYPE = 2; + private static final int COL_DATE_TAKEN = 3; + private static final int COL_DATE_MODIFIED = 4; + private static final int COL_DATA = 5; + private static final int COL_WIDTH = 6; + private static final int COL_HEIGHT = 7; + + public int resolutionW; + public int resolutionH; + + static LocalVideoData buildFromCursor(Cursor c) { + LocalVideoData d = new LocalVideoData(); + d.id = c.getLong(COL_ID); + d.title = c.getString(COL_TITLE); + d.mimeType = c.getString(COL_MIME_TYPE); + d.dateTaken = c.getLong(COL_DATE_TAKEN); + d.dateModified = c.getLong(COL_DATE_MODIFIED); + d.path = c.getString(COL_DATA); + d.width = c.getInt(COL_WIDTH); + d.height = c.getInt(COL_HEIGHT); + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(d.path); + String rotation = retriever.extractMetadata( + MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); + if (d.width == 0 || d.height == 0) { + d.width = Integer.parseInt(retriever.extractMetadata( + MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)); + d.height = Integer.parseInt(retriever.extractMetadata( + MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)); + } + retriever.release(); + if (rotation.equals("90") || rotation.equals("270")) { + int b = d.width; + d.width = d.height; + d.height = b; + } + return d; + } + + @Override + View getView(Context c, + int decodeWidth, int decodeHeight, Drawable placeHolder) { + ImageView v = new ImageView(c); + v.setImageDrawable(placeHolder); + + v.setScaleType(ImageView.ScaleType.FIT_XY); + LoadBitmapTask task = new LoadBitmapTask(v); + task.execute(); + return v; + } + + + @Override + public String toString() { + return "LocalVideoData:" + ",data=" + path + ",mimeType=" + mimeType + + "," + width + "x" + height + ",date=" + new Date(dateTaken); + } + + @Override + public int getType() { + return TYPE_PHOTO; + } + + private static Dimension decodeDimension(String path) { + Dimension d = new Dimension(); + return d; + } + + private static class Dimension { + public int width; + public int height; + } + + private class LoadBitmapTask extends AsyncTask { + private ImageView mView; + + public LoadBitmapTask(ImageView v) { + mView = v; + } + + @Override + protected Bitmap doInBackground(Void... v) { + android.media.MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(path); + byte[] data = retriever.getEmbeddedPicture(); + Bitmap bitmap = null; + if (data != null) { + bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); + } + if (bitmap == null) { + bitmap = (Bitmap) retriever.getFrameAtTime(); + } + retriever.release(); + return bitmap; + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap == null) { + Log.e(TAG, "Cannot decode video file:" + path); + return; + } + mView.setImageBitmap(bitmap); + } + } + } } -- cgit v1.2.3