michael@0: /* michael@0: * Copyright (C) 2014 Square, Inc. michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: package com.squareup.picasso; michael@0: michael@0: import android.content.ContentResolver; michael@0: import android.content.Context; michael@0: import android.database.Cursor; michael@0: import android.graphics.Bitmap; michael@0: import android.graphics.BitmapFactory; michael@0: import android.net.Uri; michael@0: import android.provider.MediaStore; michael@0: import java.io.IOException; michael@0: michael@0: import static android.content.ContentUris.parseId; michael@0: import static android.provider.MediaStore.Images.Thumbnails.FULL_SCREEN_KIND; michael@0: import static android.provider.MediaStore.Images.Thumbnails.MICRO_KIND; michael@0: import static android.provider.MediaStore.Images.Thumbnails.MINI_KIND; michael@0: import static android.provider.MediaStore.Images.Thumbnails.getThumbnail; michael@0: import static com.squareup.picasso.MediaStoreBitmapHunter.PicassoKind.FULL; michael@0: import static com.squareup.picasso.MediaStoreBitmapHunter.PicassoKind.MICRO; michael@0: import static com.squareup.picasso.MediaStoreBitmapHunter.PicassoKind.MINI; michael@0: michael@0: class MediaStoreBitmapHunter extends ContentStreamBitmapHunter { michael@0: private static final String[] CONTENT_ORIENTATION = new String[] { michael@0: MediaStore.Images.ImageColumns.ORIENTATION michael@0: }; michael@0: michael@0: MediaStoreBitmapHunter(Context context, Picasso picasso, Dispatcher dispatcher, Cache cache, michael@0: Stats stats, Action action) { michael@0: super(context, picasso, dispatcher, cache, stats, action); michael@0: } michael@0: michael@0: @Override Bitmap decode(Request data) throws IOException { michael@0: ContentResolver contentResolver = context.getContentResolver(); michael@0: setExifRotation(getExitOrientation(contentResolver, data.uri)); michael@0: michael@0: if (data.hasSize()) { michael@0: PicassoKind picassoKind = getPicassoKind(data.targetWidth, data.targetHeight); michael@0: if (picassoKind == FULL) { michael@0: return super.decode(data); michael@0: } michael@0: michael@0: long id = parseId(data.uri); michael@0: michael@0: BitmapFactory.Options options = new BitmapFactory.Options(); michael@0: options.inJustDecodeBounds = true; michael@0: michael@0: calculateInSampleSize(data.targetWidth, data.targetHeight, picassoKind.width, michael@0: picassoKind.height, options); michael@0: michael@0: Bitmap result = getThumbnail(contentResolver, id, picassoKind.androidKind, options); michael@0: michael@0: if (result != null) { michael@0: return result; michael@0: } michael@0: } michael@0: michael@0: return super.decode(data); michael@0: } michael@0: michael@0: static PicassoKind getPicassoKind(int targetWidth, int targetHeight) { michael@0: if (targetWidth <= MICRO.width && targetHeight <= MICRO.height) { michael@0: return MICRO; michael@0: } else if (targetWidth <= MINI.width && targetHeight <= MINI.height) { michael@0: return MINI; michael@0: } michael@0: return FULL; michael@0: } michael@0: michael@0: static int getExitOrientation(ContentResolver contentResolver, Uri uri) { michael@0: Cursor cursor = null; michael@0: try { michael@0: cursor = contentResolver.query(uri, CONTENT_ORIENTATION, null, null, null); michael@0: if (cursor == null || !cursor.moveToFirst()) { michael@0: return 0; michael@0: } michael@0: return cursor.getInt(0); michael@0: } catch (RuntimeException ignored) { michael@0: // If the orientation column doesn't exist, assume no rotation. michael@0: return 0; michael@0: } finally { michael@0: if (cursor != null) { michael@0: cursor.close(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: enum PicassoKind { michael@0: MICRO(MICRO_KIND, 96, 96), michael@0: MINI(MINI_KIND, 512, 384), michael@0: FULL(FULL_SCREEN_KIND, -1, -1); michael@0: michael@0: final int androidKind; michael@0: final int width; michael@0: final int height; michael@0: michael@0: PicassoKind(int androidKind, int width, int height) { michael@0: this.androidKind = androidKind; michael@0: this.width = width; michael@0: this.height = height; michael@0: } michael@0: } michael@0: }