blob: f006ccb8c724725a0022a63da6a1a501738815e5 [file] [log] [blame]
/*
* Copyright (C) 2009 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.cooliris.media;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import android.os.Process;
import com.cooliris.cache.CacheService;
public final class MediaItemTexture extends Texture {
public static final int MAX_FACES = 1;
private static final String TAG = "MediaItemTexture";
private static final int CACHE_HEADER_SIZE = 12;
private final Config mConfig;
private final MediaItem mItem;
private Context mContext;
private boolean mIsRetrying;
private boolean mCached;
public static final class Config {
public int thumbnailWidth;
public int thumbnailHeight;
}
public MediaItemTexture(Context context, Config config, MediaItem item) {
mConfig = config;
mContext = context;
mItem = item;
mCached = computeCache();
}
private boolean computeCache() {
final Config config = mConfig;
final MediaItem item = mItem;
DiskCache cache = null;
MediaSet parentMediaSet = item.mParentMediaSet;
if (config != null && parentMediaSet != null && parentMediaSet.mDataSource != null) {
cache = parentMediaSet.mDataSource.getThumbnailCache();
if (cache == LocalDataSource.sThumbnailCache) {
if (item.mMimeType != null && item.mMimeType.contains("video")) {
cache = LocalDataSource.sThumbnailCacheVideo;
}
}
}
if (cache == null) {
return false;
}
synchronized (cache) {
long id = parentMediaSet.mPicasaAlbumId == Shared.INVALID ? Utils.Crc64Long(item.mFilePath) : item.mId;
return cache.isDataAvailable(id, item.mDateModifiedInSec * 1000);
}
}
@Override
public boolean isUncachedVideo() {
if (isCached())
return false;
if (mItem.mParentMediaSet == null || mItem.mMimeType == null)
return false;
if (mItem.mParentMediaSet.mPicasaAlbumId == Shared.INVALID && mItem.mMimeType.contains("video")) {
return true;
} else {
return false;
}
}
@Override
public boolean isCached() {
return mCached;
}
protected Bitmap load(RenderView view) {
final Config config = mConfig;
final MediaItem item = mItem;
// Special case for non-MediaStore content URIs, do not cache the
// thumbnail.
String uriString = item.mContentUri;
if (uriString != null) {
Uri uri = Uri.parse(uriString);
if (uri.getScheme().equals("content") && !uri.getAuthority().equals("media")) {
try {
return UriTexture.createFromUri(mContext, item.mThumbnailUri, 128, 128, 0, null);
} catch (IOException e) {
return null;
} catch (URISyntaxException e) {
return null;
}
}
}
// Look up the thumbnail in the disk cache.
if (config == null) {
Bitmap retVal = null;
try {
if (mItem.getMediaType() == MediaItem.MEDIA_TYPE_IMAGE) {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
try {
// We first dirty the cache if the timestamp has changed
DiskCache cache = null;
MediaSet parentMediaSet = item.mParentMediaSet;
if (parentMediaSet != null && parentMediaSet.mDataSource != null) {
cache = parentMediaSet.mDataSource.getThumbnailCache();
if (cache == LocalDataSource.sThumbnailCache) {
if (item.mMimeType != null && item.mMimeType.contains("video")) {
cache = LocalDataSource.sThumbnailCacheVideo;
}
final long crc64 = Utils.Crc64Long(item.mFilePath);
if (!cache.isDataAvailable(crc64, item.mDateModifiedInSec * 1000)) {
UriTexture.invalidateCache(crc64, UriTexture.MAX_RESOLUTION);
}
}
}
retVal = UriTexture.createFromUri(mContext, mItem.mContentUri, UriTexture.MAX_RESOLUTION,
UriTexture.MAX_RESOLUTION, Utils.Crc64Long(item.mFilePath), null);
} catch (IOException e) {
;
} catch (URISyntaxException e) {
;
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
} else {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
new Thread() {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
;
}
try {
MediaStore.Video.Thumbnails.cancelThumbnailRequest(mContext.getContentResolver(), mItem.mId);
} catch (Exception e) {
;
}
}
}.start();
retVal = MediaStore.Video.Thumbnails.getThumbnail(mContext.getContentResolver(), mItem.mId,
MediaStore.Video.Thumbnails.MINI_KIND, null);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
} catch (OutOfMemoryError e) {
Log.i(TAG, "Bitmap creation fail, outofmemory");
view.handleLowMemory();
try {
if (!mIsRetrying) {
Thread.sleep(1000);
mIsRetrying = true;
retVal = load(view);
}
} catch (InterruptedException eInterrupted) {
}
}
return retVal;
} else {
byte[] data = null;
MediaSet parentMediaSet = item.mParentMediaSet;
if (parentMediaSet != null && !parentMediaSet.mIsLocal) {
DiskCache thumbnailCache = parentMediaSet.mDataSource.getThumbnailCache();
data = thumbnailCache.get(item.mId, 0);
if (data == null) {
// We need to generate the cache.
try {
Bitmap retVal = UriTexture.createFromUri(mContext, item.mThumbnailUri, 256, 256, 0, null);
data = CacheService.writeBitmapToCache(thumbnailCache, item.mId, item.mId, retVal, config.thumbnailWidth,
config.thumbnailHeight, item.mDateModifiedInSec * 1000);
} catch (IOException e) {
return null;
} catch (URISyntaxException e) {
return null;
}
}
} else {
long dateToUse = (item.mDateAddedInSec > item.mDateModifiedInSec) ? item.mDateAddedInSec : item.mDateModifiedInSec;
data = CacheService.queryThumbnail(mContext, Utils.Crc64Long(item.mFilePath), item.mId,
item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO, dateToUse * 1000);
}
if (data != null) {
try {
// Parse record header.
final ByteArrayInputStream cacheInput = new ByteArrayInputStream(data);
final DataInputStream dataInput = new DataInputStream(cacheInput);
item.mThumbnailId = dataInput.readLong();
item.mThumbnailFocusX = dataInput.readShort();
item.mThumbnailFocusY = dataInput.readShort();
// Decode the thumbnail.
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = true;
options.inScaled = false;
options.inPreferredConfig = Bitmap.Config.RGB_565;
final Bitmap bitmap = BitmapFactory.decodeByteArray(data, CACHE_HEADER_SIZE, data.length - CACHE_HEADER_SIZE,
options);
return bitmap;
} catch (IOException e) {
// Fall through to regenerate the cached thumbnail.
}
}
}
return null;
}
}