• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.gallery3d.data;
18 
19 import android.content.ContentResolver;
20 import android.database.Cursor;
21 import android.graphics.Bitmap;
22 import android.graphics.BitmapRegionDecoder;
23 import android.net.Uri;
24 import android.provider.MediaStore.Video;
25 import android.provider.MediaStore.Video.VideoColumns;
26 
27 import com.android.gallery3d.app.GalleryApp;
28 import com.android.gallery3d.common.BitmapUtils;
29 import com.android.gallery3d.util.GalleryUtils;
30 import com.android.gallery3d.util.ThreadPool.Job;
31 import com.android.gallery3d.util.ThreadPool.JobContext;
32 import com.android.gallery3d.util.UpdateHelper;
33 
34 // LocalVideo represents a video in the local storage.
35 public class LocalVideo extends LocalMediaItem {
36     private static final String TAG = "LocalVideo";
37     static final Path ITEM_PATH = Path.fromString("/local/video/item");
38 
39     // Must preserve order between these indices and the order of the terms in
40     // the following PROJECTION array.
41     private static final int INDEX_ID = 0;
42     private static final int INDEX_CAPTION = 1;
43     private static final int INDEX_MIME_TYPE = 2;
44     private static final int INDEX_LATITUDE = 3;
45     private static final int INDEX_LONGITUDE = 4;
46     private static final int INDEX_DATE_TAKEN = 5;
47     private static final int INDEX_DATE_ADDED = 6;
48     private static final int INDEX_DATE_MODIFIED = 7;
49     private static final int INDEX_DATA = 8;
50     private static final int INDEX_DURATION = 9;
51     private static final int INDEX_BUCKET_ID = 10;
52     private static final int INDEX_SIZE = 11;
53     private static final int INDEX_RESOLUTION = 12;
54 
55     static final String[] PROJECTION = new String[] {
56             VideoColumns._ID,
57             VideoColumns.TITLE,
58             VideoColumns.MIME_TYPE,
59             VideoColumns.LATITUDE,
60             VideoColumns.LONGITUDE,
61             VideoColumns.DATE_TAKEN,
62             VideoColumns.DATE_ADDED,
63             VideoColumns.DATE_MODIFIED,
64             VideoColumns.DATA,
65             VideoColumns.DURATION,
66             VideoColumns.BUCKET_ID,
67             VideoColumns.SIZE,
68             VideoColumns.RESOLUTION,
69     };
70 
71     private final GalleryApp mApplication;
72 
73     public int durationInSec;
74 
LocalVideo(Path path, GalleryApp application, Cursor cursor)75     public LocalVideo(Path path, GalleryApp application, Cursor cursor) {
76         super(path, nextVersionNumber());
77         mApplication = application;
78         loadFromCursor(cursor);
79     }
80 
LocalVideo(Path path, GalleryApp context, int id)81     public LocalVideo(Path path, GalleryApp context, int id) {
82         super(path, nextVersionNumber());
83         mApplication = context;
84         ContentResolver resolver = mApplication.getContentResolver();
85         Uri uri = Video.Media.EXTERNAL_CONTENT_URI;
86         Cursor cursor = LocalAlbum.getItemCursor(resolver, uri, PROJECTION, id);
87         if (cursor == null) {
88             throw new RuntimeException("cannot get cursor for: " + path);
89         }
90         try {
91             if (cursor.moveToNext()) {
92                 loadFromCursor(cursor);
93             } else {
94                 throw new RuntimeException("cannot find data for: " + path);
95             }
96         } finally {
97             cursor.close();
98         }
99     }
100 
loadFromCursor(Cursor cursor)101     private void loadFromCursor(Cursor cursor) {
102         id = cursor.getInt(INDEX_ID);
103         caption = cursor.getString(INDEX_CAPTION);
104         mimeType = cursor.getString(INDEX_MIME_TYPE);
105         latitude = cursor.getDouble(INDEX_LATITUDE);
106         longitude = cursor.getDouble(INDEX_LONGITUDE);
107         dateTakenInMs = cursor.getLong(INDEX_DATE_TAKEN);
108         dateAddedInSec = cursor.getLong(INDEX_DATE_ADDED);
109         dateModifiedInSec = cursor.getLong(INDEX_DATE_MODIFIED);
110         filePath = cursor.getString(INDEX_DATA);
111         durationInSec = cursor.getInt(INDEX_DURATION) / 1000;
112         bucketId = cursor.getInt(INDEX_BUCKET_ID);
113         fileSize = cursor.getLong(INDEX_SIZE);
114         parseResolution(cursor.getString(INDEX_RESOLUTION));
115     }
116 
parseResolution(String resolution)117     private void parseResolution(String resolution) {
118         if (resolution == null) return;
119         int m = resolution.indexOf('x');
120         if (m == -1) return;
121         try {
122             int w = Integer.parseInt(resolution.substring(0, m));
123             int h = Integer.parseInt(resolution.substring(m + 1));
124             width = w;
125             height = h;
126         } catch (Throwable t) {
127             Log.w(TAG, t);
128         }
129     }
130 
131     @Override
updateFromCursor(Cursor cursor)132     protected boolean updateFromCursor(Cursor cursor) {
133         UpdateHelper uh = new UpdateHelper();
134         id = uh.update(id, cursor.getInt(INDEX_ID));
135         caption = uh.update(caption, cursor.getString(INDEX_CAPTION));
136         mimeType = uh.update(mimeType, cursor.getString(INDEX_MIME_TYPE));
137         latitude = uh.update(latitude, cursor.getDouble(INDEX_LATITUDE));
138         longitude = uh.update(longitude, cursor.getDouble(INDEX_LONGITUDE));
139         dateTakenInMs = uh.update(
140                 dateTakenInMs, cursor.getLong(INDEX_DATE_TAKEN));
141         dateAddedInSec = uh.update(
142                 dateAddedInSec, cursor.getLong(INDEX_DATE_ADDED));
143         dateModifiedInSec = uh.update(
144                 dateModifiedInSec, cursor.getLong(INDEX_DATE_MODIFIED));
145         filePath = uh.update(filePath, cursor.getString(INDEX_DATA));
146         durationInSec = uh.update(
147                 durationInSec, cursor.getInt(INDEX_DURATION) / 1000);
148         bucketId = uh.update(bucketId, cursor.getInt(INDEX_BUCKET_ID));
149         fileSize = uh.update(fileSize, cursor.getLong(INDEX_SIZE));
150         return uh.isUpdated();
151     }
152 
153     @Override
requestImage(int type)154     public Job<Bitmap> requestImage(int type) {
155         return new LocalVideoRequest(mApplication, getPath(), type, filePath);
156     }
157 
158     public static class LocalVideoRequest extends ImageCacheRequest {
159         private String mLocalFilePath;
160 
LocalVideoRequest(GalleryApp application, Path path, int type, String localFilePath)161         LocalVideoRequest(GalleryApp application, Path path, int type,
162                 String localFilePath) {
163             super(application, path, type, MediaItem.getTargetSize(type));
164             mLocalFilePath = localFilePath;
165         }
166 
167         @Override
onDecodeOriginal(JobContext jc, int type)168         public Bitmap onDecodeOriginal(JobContext jc, int type) {
169             Bitmap bitmap = BitmapUtils.createVideoThumbnail(mLocalFilePath);
170             if (bitmap == null || jc.isCancelled()) return null;
171             return bitmap;
172         }
173     }
174 
175     @Override
requestLargeImage()176     public Job<BitmapRegionDecoder> requestLargeImage() {
177         throw new UnsupportedOperationException("Cannot regquest a large image"
178                 + " to a local video!");
179     }
180 
181     @Override
getSupportedOperations()182     public int getSupportedOperations() {
183         return SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_PLAY | SUPPORT_INFO | SUPPORT_TRIM | SUPPORT_MUTE;
184     }
185 
186     @Override
delete()187     public void delete() {
188         GalleryUtils.assertNotInRenderThread();
189         Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI;
190         mApplication.getContentResolver().delete(baseUri, "_id=?",
191                 new String[]{String.valueOf(id)});
192     }
193 
194     @Override
rotate(int degrees)195     public void rotate(int degrees) {
196         // TODO
197     }
198 
199     @Override
getContentUri()200     public Uri getContentUri() {
201         Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI;
202         return baseUri.buildUpon().appendPath(String.valueOf(id)).build();
203     }
204 
205     @Override
getPlayUri()206     public Uri getPlayUri() {
207         return getContentUri();
208     }
209 
210     @Override
getMediaType()211     public int getMediaType() {
212         return MEDIA_TYPE_VIDEO;
213     }
214 
215     @Override
getDetails()216     public MediaDetails getDetails() {
217         MediaDetails details = super.getDetails();
218         int s = durationInSec;
219         if (s > 0) {
220             details.addDetail(MediaDetails.INDEX_DURATION, GalleryUtils.formatDuration(
221                     mApplication.getAndroidContext(), durationInSec));
222         }
223         return details;
224     }
225 
226     @Override
getWidth()227     public int getWidth() {
228         return width;
229     }
230 
231     @Override
getHeight()232     public int getHeight() {
233         return height;
234     }
235 
236     @Override
getFilePath()237     public String getFilePath() {
238         return filePath;
239     }
240 }
241