LocalVideo.java revision 84440670da46866867ace3be2c358a54db984a6d
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
17package com.android.gallery3d.data;
18
19import android.content.ContentResolver;
20import android.database.Cursor;
21import android.graphics.Bitmap;
22import android.graphics.BitmapRegionDecoder;
23import android.net.Uri;
24import android.provider.MediaStore.Video;
25import android.provider.MediaStore.Video.VideoColumns;
26
27import com.android.gallery3d.app.GalleryApp;
28import com.android.gallery3d.common.BitmapUtils;
29import com.android.gallery3d.util.GalleryUtils;
30import com.android.gallery3d.util.ThreadPool.Job;
31import com.android.gallery3d.util.ThreadPool.JobContext;
32import com.android.gallery3d.util.UpdateHelper;
33
34// LocalVideo represents a video in the local storage.
35public 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
75    public LocalVideo(Path path, GalleryApp application, Cursor cursor) {
76        super(path, nextVersionNumber());
77        mApplication = application;
78        loadFromCursor(cursor);
79    }
80
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
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        filePath = cursor.getString(INDEX_DATA);
109        durationInSec = cursor.getInt(INDEX_DURATION) / 1000;
110        bucketId = cursor.getInt(INDEX_BUCKET_ID);
111        fileSize = cursor.getLong(INDEX_SIZE);
112        parseResolution(cursor.getString(INDEX_RESOLUTION));
113    }
114
115    private void parseResolution(String resolution) {
116        if (resolution == null) return;
117        int m = resolution.indexOf('x');
118        if (m == -1) return;
119        try {
120            int w = Integer.parseInt(resolution.substring(0, m));
121            int h = Integer.parseInt(resolution.substring(m + 1));
122            width = w;
123            height = h;
124        } catch (Throwable t) {
125            Log.w(TAG, t);
126        }
127    }
128
129    @Override
130    protected boolean updateFromCursor(Cursor cursor) {
131        UpdateHelper uh = new UpdateHelper();
132        id = uh.update(id, cursor.getInt(INDEX_ID));
133        caption = uh.update(caption, cursor.getString(INDEX_CAPTION));
134        mimeType = uh.update(mimeType, cursor.getString(INDEX_MIME_TYPE));
135        latitude = uh.update(latitude, cursor.getDouble(INDEX_LATITUDE));
136        longitude = uh.update(longitude, cursor.getDouble(INDEX_LONGITUDE));
137        dateTakenInMs = uh.update(
138                dateTakenInMs, cursor.getLong(INDEX_DATE_TAKEN));
139        dateAddedInSec = uh.update(
140                dateAddedInSec, cursor.getLong(INDEX_DATE_ADDED));
141        dateModifiedInSec = uh.update(
142                dateModifiedInSec, cursor.getLong(INDEX_DATE_MODIFIED));
143        filePath = uh.update(filePath, cursor.getString(INDEX_DATA));
144        durationInSec = uh.update(
145                durationInSec, cursor.getInt(INDEX_DURATION) / 1000);
146        bucketId = uh.update(bucketId, cursor.getInt(INDEX_BUCKET_ID));
147        fileSize = uh.update(fileSize, cursor.getLong(INDEX_SIZE));
148        return uh.isUpdated();
149    }
150
151    @Override
152    public Job<Bitmap> requestImage(int type) {
153        return new LocalVideoRequest(mApplication, getPath(), type, filePath);
154    }
155
156    public static class LocalVideoRequest extends ImageCacheRequest {
157        private String mLocalFilePath;
158
159        LocalVideoRequest(GalleryApp application, Path path, int type,
160                String localFilePath) {
161            super(application, path, type, MediaItem.getTargetSize(type));
162            mLocalFilePath = localFilePath;
163        }
164
165        @Override
166        public Bitmap onDecodeOriginal(JobContext jc, int type) {
167            Bitmap bitmap = BitmapUtils.createVideoThumbnail(mLocalFilePath);
168            if (bitmap == null || jc.isCancelled()) return null;
169            return bitmap;
170        }
171    }
172
173    @Override
174    public Job<BitmapRegionDecoder> requestLargeImage() {
175        throw new UnsupportedOperationException("Cannot regquest a large image"
176                + " to a local video!");
177    }
178
179    @Override
180    public int getSupportedOperations() {
181        return SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_PLAY | SUPPORT_INFO | SUPPORT_TRIM;
182    }
183
184    @Override
185    public void delete() {
186        GalleryUtils.assertNotInRenderThread();
187        Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI;
188        mApplication.getContentResolver().delete(baseUri, "_id=?",
189                new String[]{String.valueOf(id)});
190    }
191
192    @Override
193    public void rotate(int degrees) {
194        // TODO
195    }
196
197    @Override
198    public Uri getContentUri() {
199        Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI;
200        return baseUri.buildUpon().appendPath(String.valueOf(id)).build();
201    }
202
203    @Override
204    public Uri getPlayUri() {
205        return getContentUri();
206    }
207
208    @Override
209    public int getMediaType() {
210        return MEDIA_TYPE_VIDEO;
211    }
212
213    @Override
214    public MediaDetails getDetails() {
215        MediaDetails details = super.getDetails();
216        int s = durationInSec;
217        if (s > 0) {
218            details.addDetail(MediaDetails.INDEX_DURATION, GalleryUtils.formatDuration(
219                    mApplication.getAndroidContext(), durationInSec));
220        }
221        return details;
222    }
223
224    @Override
225    public int getWidth() {
226        return width;
227    }
228
229    @Override
230    public int getHeight() {
231        return height;
232    }
233
234    @Override
235    public String getFilePath() {
236        return filePath;
237    }
238}
239