• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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.cooliris.media;
18 
19 import java.io.ByteArrayInputStream;
20 import java.io.DataInputStream;
21 import java.io.IOException;
22 import java.net.URISyntaxException;
23 
24 import android.content.Context;
25 import android.graphics.Bitmap;
26 import android.graphics.BitmapFactory;
27 import android.net.Uri;
28 import android.provider.MediaStore;
29 import android.util.Log;
30 import android.os.Process;
31 
32 import com.cooliris.cache.CacheService;
33 
34 public final class MediaItemTexture extends Texture {
35     public static final int MAX_FACES = 1;
36     private static final String TAG = "MediaItemTexture";
37     private static final int CACHE_HEADER_SIZE = 12;
38 
39     private final Config mConfig;
40     private final MediaItem mItem;
41     private Context mContext;
42     private boolean mIsRetrying;
43     private boolean mCached;
44 
45     public static final class Config {
46         public int thumbnailWidth;
47         public int thumbnailHeight;
48     }
49 
MediaItemTexture(Context context, Config config, MediaItem item)50     public MediaItemTexture(Context context, Config config, MediaItem item) {
51         mConfig = config;
52         mContext = context;
53         mItem = item;
54         mCached = computeCache();
55     }
56 
computeCache()57     private boolean computeCache() {
58         final Config config = mConfig;
59         final MediaItem item = mItem;
60         DiskCache cache = null;
61         MediaSet parentMediaSet = item.mParentMediaSet;
62         if (config != null && parentMediaSet != null && parentMediaSet.mDataSource != null) {
63             cache = parentMediaSet.mDataSource.getThumbnailCache();
64             if (cache == LocalDataSource.sThumbnailCache) {
65                 if (item.mMimeType != null && item.mMimeType.contains("video")) {
66                     cache = LocalDataSource.sThumbnailCacheVideo;
67                 }
68             }
69         }
70         if (cache == null) {
71             return false;
72         }
73         synchronized (cache) {
74             long id = parentMediaSet.mPicasaAlbumId == Shared.INVALID ? Utils.Crc64Long(item.mFilePath) : item.mId;
75             return cache.isDataAvailable(id, item.mDateModifiedInSec * 1000);
76         }
77     }
78 
79     @Override
isUncachedVideo()80     public boolean isUncachedVideo() {
81         if (isCached())
82             return false;
83         if (mItem.mParentMediaSet == null || mItem.mMimeType == null)
84             return false;
85         if (mItem.mParentMediaSet.mPicasaAlbumId == Shared.INVALID && mItem.mMimeType.contains("video")) {
86             return true;
87         } else {
88             return false;
89         }
90     }
91 
92     @Override
isCached()93     public boolean isCached() {
94         return mCached;
95     }
96 
load(RenderView view)97     protected Bitmap load(RenderView view) {
98         final Config config = mConfig;
99         final MediaItem item = mItem;
100 
101         // Special case for non-MediaStore content URIs, do not cache the
102         // thumbnail.
103         String uriString = item.mContentUri;
104         if (uriString != null) {
105             Uri uri = Uri.parse(uriString);
106             if (uri.getScheme().equals("content") && !uri.getAuthority().equals("media")) {
107                 try {
108                     return UriTexture.createFromUri(mContext, item.mThumbnailUri, 128, 128, 0, null);
109                 } catch (IOException e) {
110                     return null;
111                 } catch (URISyntaxException e) {
112                     return null;
113                 }
114             }
115         }
116 
117         // Look up the thumbnail in the disk cache.
118         if (config == null) {
119             Bitmap retVal = null;
120             try {
121                 if (mItem.getMediaType() == MediaItem.MEDIA_TYPE_IMAGE) {
122                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
123                     try {
124                         // We first dirty the cache if the timestamp has changed
125                         DiskCache cache = null;
126                         MediaSet parentMediaSet = item.mParentMediaSet;
127                         if (parentMediaSet != null && parentMediaSet.mDataSource != null) {
128                             cache = parentMediaSet.mDataSource.getThumbnailCache();
129                             if (cache == LocalDataSource.sThumbnailCache) {
130                                 if (item.mMimeType != null && item.mMimeType.contains("video")) {
131                                     cache = LocalDataSource.sThumbnailCacheVideo;
132                                 }
133                                 final long crc64 = Utils.Crc64Long(item.mFilePath);
134                                 if (!cache.isDataAvailable(crc64, item.mDateModifiedInSec * 1000)) {
135                                     UriTexture.invalidateCache(crc64, UriTexture.MAX_RESOLUTION);
136                                 }
137                             }
138                         }
139                         retVal = UriTexture.createFromUri(mContext, mItem.mContentUri, UriTexture.MAX_RESOLUTION,
140                                 UriTexture.MAX_RESOLUTION, Utils.Crc64Long(item.mFilePath), null);
141                     } catch (IOException e) {
142                         ;
143                     } catch (URISyntaxException e) {
144                         ;
145                     }
146                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
147                 } else {
148                     Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
149                     new Thread() {
150                         public void run() {
151                             try {
152                                 Thread.sleep(5000);
153                             } catch (InterruptedException e) {
154                                 ;
155                             }
156                             try {
157                                 MediaStore.Video.Thumbnails.cancelThumbnailRequest(mContext.getContentResolver(), mItem.mId);
158                             } catch (Exception e) {
159                                 ;
160                             }
161                         }
162                     }.start();
163                     retVal = MediaStore.Video.Thumbnails.getThumbnail(mContext.getContentResolver(), mItem.mId,
164                             MediaStore.Video.Thumbnails.MINI_KIND, null);
165                     Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
166                 }
167             } catch (OutOfMemoryError e) {
168                 Log.i(TAG, "Bitmap creation fail, outofmemory");
169                 view.handleLowMemory();
170                 try {
171                     if (!mIsRetrying) {
172                         Thread.sleep(1000);
173                         mIsRetrying = true;
174                         retVal = load(view);
175                     }
176                 } catch (InterruptedException eInterrupted) {
177 
178                 }
179             }
180             return retVal;
181         } else {
182             byte[] data = null;
183             MediaSet parentMediaSet = item.mParentMediaSet;
184             if (parentMediaSet != null && !parentMediaSet.mIsLocal) {
185                 DiskCache thumbnailCache = parentMediaSet.mDataSource.getThumbnailCache();
186                 data = thumbnailCache.get(item.mId, 0);
187                 if (data == null) {
188                     // We need to generate the cache.
189                     try {
190                         Bitmap retVal = UriTexture.createFromUri(mContext, item.mThumbnailUri, 256, 256, 0, null);
191                         data = CacheService.writeBitmapToCache(thumbnailCache, item.mId, item.mId, retVal, config.thumbnailWidth,
192                                 config.thumbnailHeight, item.mDateModifiedInSec * 1000);
193                     } catch (IOException e) {
194                         return null;
195                     } catch (URISyntaxException e) {
196                         return null;
197                     }
198                 }
199             } else {
200                 long dateToUse = (item.mDateAddedInSec > item.mDateModifiedInSec) ? item.mDateAddedInSec : item.mDateModifiedInSec;
201                 data = CacheService.queryThumbnail(mContext, Utils.Crc64Long(item.mFilePath), item.mId,
202                         item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO, dateToUse * 1000);
203             }
204             if (data != null) {
205                 try {
206                     // Parse record header.
207                     final ByteArrayInputStream cacheInput = new ByteArrayInputStream(data);
208                     final DataInputStream dataInput = new DataInputStream(cacheInput);
209                     item.mThumbnailId = dataInput.readLong();
210                     item.mThumbnailFocusX = dataInput.readShort();
211                     item.mThumbnailFocusY = dataInput.readShort();
212                     // Decode the thumbnail.
213                     final BitmapFactory.Options options = new BitmapFactory.Options();
214                     options.inDither = true;
215                     options.inScaled = false;
216                     options.inPreferredConfig = Bitmap.Config.RGB_565;
217                     final Bitmap bitmap = BitmapFactory.decodeByteArray(data, CACHE_HEADER_SIZE, data.length - CACHE_HEADER_SIZE,
218                             options);
219                     return bitmap;
220                 } catch (IOException e) {
221                     // Fall through to regenerate the cached thumbnail.
222                 }
223             }
224         }
225         return null;
226     }
227 }
228