Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2015 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 package com.android.messaging.datamodel.media;
     17 
     18 import android.content.Context;
     19 import android.graphics.Bitmap;
     20 import android.graphics.BitmapFactory;
     21 import android.media.ExifInterface;
     22 
     23 import com.android.messaging.datamodel.media.PoolableImageCache.ReusableImageResourcePool;
     24 import com.android.messaging.util.ImageUtils;
     25 import com.android.messaging.util.LogUtil;
     26 
     27 import java.io.IOException;
     28 
     29 /**
     30  * Serves file system based image requests. Since file paths can be expressed in Uri form, this
     31  * extends regular UriImageRequest but performs additional optimizations such as loading thumbnails
     32  * directly from Exif information.
     33  */
     34 public class FileImageRequest extends UriImageRequest {
     35     private final String mPath;
     36     private final boolean mCanUseThumbnail;
     37 
     38     public FileImageRequest(final Context context,
     39             final FileImageRequestDescriptor descriptor) {
     40         super(context, descriptor);
     41         mPath = descriptor.path;
     42         mCanUseThumbnail = descriptor.canUseThumbnail;
     43     }
     44 
     45     @Override
     46     protected Bitmap loadBitmapInternal()
     47             throws IOException {
     48         // Before using the FileInputStream, check if the Exif has a thumbnail that we can use.
     49         if (mCanUseThumbnail) {
     50             byte[] thumbnail = null;
     51             try {
     52                 final ExifInterface exif = new ExifInterface(mPath);
     53                 if (exif.hasThumbnail()) {
     54                     thumbnail = exif.getThumbnail();
     55                 }
     56             } catch (final IOException e) {
     57                 // Nothing to do
     58             }
     59 
     60             if (thumbnail != null) {
     61                 final BitmapFactory.Options options = PoolableImageCache.getBitmapOptionsForPool(
     62                         false /* scaled */, 0 /* inputDensity */, 0 /* targetDensity */);
     63                 // First, check dimensions of the bitmap.
     64                 options.inJustDecodeBounds = true;
     65                 BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length, options);
     66 
     67                 // Calculate inSampleSize
     68                 options.inSampleSize = ImageUtils.get().calculateInSampleSize(options,
     69                         mDescriptor.desiredWidth, mDescriptor.desiredHeight);
     70 
     71                 options.inJustDecodeBounds = false;
     72 
     73                 // Actually decode the bitmap, optionally using the bitmap pool.
     74                 try {
     75                     // Get the orientation. We should be able to get the orientation from
     76                     // the thumbnail itself but at least on some phones, the thumbnail
     77                     // doesn't have an orientation tag. So use the outer image's orientation
     78                     // tag and hope for the best.
     79                     mOrientation = ImageUtils.getOrientation(getInputStreamForResource());
     80                     if (com.android.messaging.util.exif.ExifInterface.
     81                             getOrientationParams(mOrientation).invertDimensions) {
     82                         mDescriptor.updateSourceDimensions(options.outHeight, options.outWidth);
     83                     } else {
     84                         mDescriptor.updateSourceDimensions(options.outWidth, options.outHeight);
     85                     }
     86                     final ReusableImageResourcePool bitmapPool = getBitmapPool();
     87                     if (bitmapPool == null) {
     88                         return BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length,
     89                                 options);
     90                     } else {
     91                         final int sampledWidth = options.outWidth / options.inSampleSize;
     92                         final int sampledHeight = options.outHeight / options.inSampleSize;
     93                         return bitmapPool.decodeByteArray(thumbnail, options, sampledWidth,
     94                                 sampledHeight);
     95                     }
     96                 } catch (IOException ex) {
     97                     // If the thumbnail is broken due to IOException, this will
     98                     // fall back to default bitmap loading.
     99                     LogUtil.e(LogUtil.BUGLE_IMAGE_TAG, "FileImageRequest: failed to load " +
    100                             "thumbnail from Exif", ex);
    101                 }
    102             }
    103         }
    104 
    105         // Fall back to default InputStream-based loading if no thumbnails could be retrieved.
    106         return super.loadBitmapInternal();
    107     }
    108 }
    109