| /* |
| * Copyright (C) 2010 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.gallery3d.data; |
| |
| import android.content.ContentResolver; |
| import android.database.Cursor; |
| import android.graphics.Bitmap; |
| import android.graphics.BitmapRegionDecoder; |
| import android.net.Uri; |
| import android.provider.MediaStore.Video; |
| import android.provider.MediaStore.Video.VideoColumns; |
| |
| import com.android.gallery3d.app.GalleryApp; |
| import com.android.gallery3d.common.BitmapUtils; |
| import com.android.gallery3d.util.GalleryUtils; |
| import com.android.gallery3d.util.ThreadPool.Job; |
| import com.android.gallery3d.util.ThreadPool.JobContext; |
| import com.android.gallery3d.util.UpdateHelper; |
| |
| // LocalVideo represents a video in the local storage. |
| public class LocalVideo extends LocalMediaItem { |
| private static final String TAG = "LocalVideo"; |
| static final Path ITEM_PATH = Path.fromString("/local/video/item"); |
| |
| // Must preserve order between these indices and the order of the terms in |
| // the following PROJECTION array. |
| private static final int INDEX_ID = 0; |
| private static final int INDEX_CAPTION = 1; |
| private static final int INDEX_MIME_TYPE = 2; |
| private static final int INDEX_LATITUDE = 3; |
| private static final int INDEX_LONGITUDE = 4; |
| private static final int INDEX_DATE_TAKEN = 5; |
| private static final int INDEX_DATE_ADDED = 6; |
| private static final int INDEX_DATE_MODIFIED = 7; |
| private static final int INDEX_DATA = 8; |
| private static final int INDEX_DURATION = 9; |
| private static final int INDEX_BUCKET_ID = 10; |
| private static final int INDEX_SIZE = 11; |
| private static final int INDEX_RESOLUTION = 12; |
| |
| static final String[] PROJECTION = new String[] { |
| VideoColumns._ID, |
| VideoColumns.TITLE, |
| VideoColumns.MIME_TYPE, |
| VideoColumns.LATITUDE, |
| VideoColumns.LONGITUDE, |
| VideoColumns.DATE_TAKEN, |
| VideoColumns.DATE_ADDED, |
| VideoColumns.DATE_MODIFIED, |
| VideoColumns.DATA, |
| VideoColumns.DURATION, |
| VideoColumns.BUCKET_ID, |
| VideoColumns.SIZE, |
| VideoColumns.RESOLUTION, |
| }; |
| |
| private final GalleryApp mApplication; |
| |
| public int durationInSec; |
| |
| public LocalVideo(Path path, GalleryApp application, Cursor cursor) { |
| super(path, nextVersionNumber()); |
| mApplication = application; |
| loadFromCursor(cursor); |
| } |
| |
| public LocalVideo(Path path, GalleryApp context, int id) { |
| super(path, nextVersionNumber()); |
| mApplication = context; |
| ContentResolver resolver = mApplication.getContentResolver(); |
| Uri uri = Video.Media.EXTERNAL_CONTENT_URI; |
| Cursor cursor = LocalAlbum.getItemCursor(resolver, uri, PROJECTION, id); |
| if (cursor == null) { |
| throw new RuntimeException("cannot get cursor for: " + path); |
| } |
| try { |
| if (cursor.moveToNext()) { |
| loadFromCursor(cursor); |
| } else { |
| throw new RuntimeException("cannot find data for: " + path); |
| } |
| } finally { |
| cursor.close(); |
| } |
| } |
| |
| private void loadFromCursor(Cursor cursor) { |
| id = cursor.getInt(INDEX_ID); |
| caption = cursor.getString(INDEX_CAPTION); |
| mimeType = cursor.getString(INDEX_MIME_TYPE); |
| latitude = cursor.getDouble(INDEX_LATITUDE); |
| longitude = cursor.getDouble(INDEX_LONGITUDE); |
| dateTakenInMs = cursor.getLong(INDEX_DATE_TAKEN); |
| filePath = cursor.getString(INDEX_DATA); |
| durationInSec = cursor.getInt(INDEX_DURATION) / 1000; |
| bucketId = cursor.getInt(INDEX_BUCKET_ID); |
| fileSize = cursor.getLong(INDEX_SIZE); |
| parseResolution(cursor.getString(INDEX_RESOLUTION)); |
| } |
| |
| private void parseResolution(String resolution) { |
| if (resolution == null) return; |
| int m = resolution.indexOf('x'); |
| if (m == -1) return; |
| try { |
| int w = Integer.parseInt(resolution.substring(0, m)); |
| int h = Integer.parseInt(resolution.substring(m + 1)); |
| width = w; |
| height = h; |
| } catch (Throwable t) { |
| Log.w(TAG, t); |
| } |
| } |
| |
| @Override |
| protected boolean updateFromCursor(Cursor cursor) { |
| UpdateHelper uh = new UpdateHelper(); |
| id = uh.update(id, cursor.getInt(INDEX_ID)); |
| caption = uh.update(caption, cursor.getString(INDEX_CAPTION)); |
| mimeType = uh.update(mimeType, cursor.getString(INDEX_MIME_TYPE)); |
| latitude = uh.update(latitude, cursor.getDouble(INDEX_LATITUDE)); |
| longitude = uh.update(longitude, cursor.getDouble(INDEX_LONGITUDE)); |
| dateTakenInMs = uh.update( |
| dateTakenInMs, cursor.getLong(INDEX_DATE_TAKEN)); |
| dateAddedInSec = uh.update( |
| dateAddedInSec, cursor.getLong(INDEX_DATE_ADDED)); |
| dateModifiedInSec = uh.update( |
| dateModifiedInSec, cursor.getLong(INDEX_DATE_MODIFIED)); |
| filePath = uh.update(filePath, cursor.getString(INDEX_DATA)); |
| durationInSec = uh.update( |
| durationInSec, cursor.getInt(INDEX_DURATION) / 1000); |
| bucketId = uh.update(bucketId, cursor.getInt(INDEX_BUCKET_ID)); |
| fileSize = uh.update(fileSize, cursor.getLong(INDEX_SIZE)); |
| return uh.isUpdated(); |
| } |
| |
| @Override |
| public Job<Bitmap> requestImage(int type) { |
| return new LocalVideoRequest(mApplication, getPath(), type, filePath); |
| } |
| |
| public static class LocalVideoRequest extends ImageCacheRequest { |
| private String mLocalFilePath; |
| |
| LocalVideoRequest(GalleryApp application, Path path, int type, |
| String localFilePath) { |
| super(application, path, type, MediaItem.getTargetSize(type)); |
| mLocalFilePath = localFilePath; |
| } |
| |
| @Override |
| public Bitmap onDecodeOriginal(JobContext jc, int type) { |
| Bitmap bitmap = BitmapUtils.createVideoThumbnail(mLocalFilePath); |
| if (bitmap == null || jc.isCancelled()) return null; |
| return bitmap; |
| } |
| } |
| |
| @Override |
| public Job<BitmapRegionDecoder> requestLargeImage() { |
| throw new UnsupportedOperationException("Cannot regquest a large image" |
| + " to a local video!"); |
| } |
| |
| @Override |
| public int getSupportedOperations() { |
| return SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_PLAY | SUPPORT_INFO | SUPPORT_TRIM; |
| } |
| |
| @Override |
| public void delete() { |
| GalleryUtils.assertNotInRenderThread(); |
| Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI; |
| mApplication.getContentResolver().delete(baseUri, "_id=?", |
| new String[]{String.valueOf(id)}); |
| mApplication.getDataManager().broadcastLocalDeletion(); |
| } |
| |
| @Override |
| public void rotate(int degrees) { |
| // TODO |
| } |
| |
| @Override |
| public Uri getContentUri() { |
| Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI; |
| return baseUri.buildUpon().appendPath(String.valueOf(id)).build(); |
| } |
| |
| @Override |
| public Uri getPlayUri() { |
| return getContentUri(); |
| } |
| |
| @Override |
| public int getMediaType() { |
| return MEDIA_TYPE_VIDEO; |
| } |
| |
| @Override |
| public MediaDetails getDetails() { |
| MediaDetails details = super.getDetails(); |
| int s = durationInSec; |
| if (s > 0) { |
| details.addDetail(MediaDetails.INDEX_DURATION, GalleryUtils.formatDuration( |
| mApplication.getAndroidContext(), durationInSec)); |
| } |
| return details; |
| } |
| |
| @Override |
| public int getWidth() { |
| return width; |
| } |
| |
| @Override |
| public int getHeight() { |
| return height; |
| } |
| |
| @Override |
| public String getFilePath() { |
| return filePath; |
| } |
| } |