Home | History | Annotate | Download | only in model
      1 /*
      2  * Copyright (C) 2008 Esmertec AG.
      3  * Copyright (C) 2008 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.mms.model;
     19 
     20 import com.android.mms.ContentRestrictionException;
     21 import com.android.mms.ExceedMessageSizeException;
     22 import com.android.mms.LogTag;
     23 import com.android.mms.MmsConfig;
     24 import com.android.mms.dom.smil.SmilMediaElementImpl;
     25 import android.drm.mobile1.DrmException;
     26 import com.android.mms.drm.DrmWrapper;
     27 import com.android.mms.ui.UriImage;
     28 import com.android.mms.ui.MessageUtils;
     29 import com.google.android.mms.MmsException;
     30 import com.google.android.mms.pdu.PduPart;
     31 import com.google.android.mms.pdu.PduPersister;
     32 
     33 import org.w3c.dom.events.Event;
     34 import org.w3c.dom.smil.ElementTime;
     35 
     36 import android.content.Context;
     37 import android.graphics.Bitmap;
     38 import android.graphics.BitmapFactory;
     39 import android.net.Uri;
     40 import android.text.TextUtils;
     41 import android.util.Config;
     42 import android.util.Log;
     43 
     44 import java.io.FileNotFoundException;
     45 import java.io.IOException;
     46 import java.io.InputStream;
     47 import java.lang.ref.SoftReference;
     48 
     49 
     50 public class ImageModel extends RegionMediaModel {
     51     private static final String TAG = "Mms/image";
     52     private static final boolean DEBUG = false;
     53     private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
     54 
     55     private static final int THUMBNAIL_BOUNDS_LIMIT = 480;
     56 
     57     private int mWidth;
     58     private int mHeight;
     59     private SoftReference<Bitmap> mBitmapCache = new SoftReference<Bitmap>(null);
     60 
     61     public ImageModel(Context context, Uri uri, RegionModel region)
     62             throws MmsException {
     63         super(context, SmilHelper.ELEMENT_TAG_IMAGE, uri, region);
     64         initModelFromUri(uri);
     65         checkContentRestriction();
     66     }
     67 
     68     public ImageModel(Context context, String contentType, String src,
     69             Uri uri, RegionModel region) throws DrmException, MmsException {
     70         super(context, SmilHelper.ELEMENT_TAG_IMAGE,
     71                 contentType, src, uri, region);
     72         decodeImageBounds();
     73     }
     74 
     75     public ImageModel(Context context, String contentType, String src,
     76             DrmWrapper wrapper, RegionModel regionModel) throws IOException {
     77         super(context, SmilHelper.ELEMENT_TAG_IMAGE, contentType, src,
     78                 wrapper, regionModel);
     79     }
     80 
     81     private void initModelFromUri(Uri uri) throws MmsException {
     82         UriImage uriImage = new UriImage(mContext, uri);
     83 
     84         mContentType = uriImage.getContentType();
     85         if (TextUtils.isEmpty(mContentType)) {
     86             throw new MmsException("Type of media is unknown.");
     87         }
     88         mSrc = uriImage.getSrc();
     89         mWidth = uriImage.getWidth();
     90         mHeight = uriImage.getHeight();
     91 
     92         if (LOCAL_LOGV) {
     93             Log.v(TAG, "New ImageModel created:"
     94                     + " mSrc=" + mSrc
     95                     + " mContentType=" + mContentType
     96                     + " mUri=" + uri);
     97         }
     98     }
     99 
    100     private void decodeImageBounds() throws DrmException {
    101         UriImage uriImage = new UriImage(mContext, getUriWithDrmCheck());
    102         mWidth = uriImage.getWidth();
    103         mHeight = uriImage.getHeight();
    104 
    105         if (LOCAL_LOGV) {
    106             Log.v(TAG, "Image bounds: " + mWidth + "x" + mHeight);
    107         }
    108     }
    109 
    110     // EventListener Interface
    111     public void handleEvent(Event evt) {
    112         if (evt.getType().equals(SmilMediaElementImpl.SMIL_MEDIA_START_EVENT)) {
    113             mVisible = true;
    114         } else if (mFill != ElementTime.FILL_FREEZE) {
    115             mVisible = false;
    116         }
    117 
    118         notifyModelChanged(false);
    119     }
    120 
    121     public int getWidth() {
    122         return mWidth;
    123     }
    124 
    125     public int getHeight() {
    126         return mHeight;
    127     }
    128 
    129     protected void checkContentRestriction() throws ContentRestrictionException {
    130         ContentRestriction cr = ContentRestrictionFactory.getContentRestriction();
    131         cr.checkImageContentType(mContentType);
    132     }
    133 
    134     public Bitmap getBitmap() {
    135         return internalGetBitmap(getUri());
    136     }
    137 
    138     public Bitmap getBitmapWithDrmCheck() throws DrmException {
    139         return internalGetBitmap(getUriWithDrmCheck());
    140     }
    141 
    142     private Bitmap internalGetBitmap(Uri uri) {
    143         Bitmap bm = mBitmapCache.get();
    144         if (bm == null) {
    145             try {
    146                 bm = createThumbnailBitmap(THUMBNAIL_BOUNDS_LIMIT, uri);
    147                 if (bm != null) {
    148                     mBitmapCache = new SoftReference<Bitmap>(bm);
    149                 }
    150             } catch (OutOfMemoryError ex) {
    151                 // fall through and return a null bitmap. The callers can handle a null
    152                 // result and show R.drawable.ic_missing_thumbnail_picture
    153             }
    154         }
    155         return bm;
    156     }
    157 
    158     private Bitmap createThumbnailBitmap(int thumbnailBoundsLimit, Uri uri) {
    159         int outWidth = mWidth;
    160         int outHeight = mHeight;
    161 
    162         int s = 1;
    163         while ((outWidth / s > thumbnailBoundsLimit)
    164                 || (outHeight / s > thumbnailBoundsLimit)) {
    165             s *= 2;
    166         }
    167         if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
    168             Log.v(TAG, "createThumbnailBitmap: scale=" + s + ", w=" + outWidth / s
    169                     + ", h=" + outHeight / s);
    170         }
    171         BitmapFactory.Options options = new BitmapFactory.Options();
    172         options.inSampleSize = s;
    173 
    174         InputStream input = null;
    175         try {
    176             input = mContext.getContentResolver().openInputStream(uri);
    177             return BitmapFactory.decodeStream(input, null, options);
    178         } catch (FileNotFoundException e) {
    179             Log.e(TAG, e.getMessage(), e);
    180             return null;
    181         } catch (OutOfMemoryError ex) {
    182             MessageUtils.writeHprofDataToFile();
    183             throw ex;
    184         } finally {
    185             if (input != null) {
    186                 try {
    187                     input.close();
    188                 } catch (IOException e) {
    189                     Log.e(TAG, e.getMessage(), e);
    190                 }
    191             }
    192         }
    193     }
    194 
    195     @Override
    196     public boolean getMediaResizable() {
    197         return true;
    198     }
    199 
    200     @Override
    201     protected void resizeMedia(int byteLimit, long messageId) throws MmsException {
    202         UriImage image = new UriImage(mContext, getUri());
    203         if (image == null) {
    204             throw new ExceedMessageSizeException("No room to resize picture: " + getUri());
    205         }
    206         PduPart part = image.getResizedImageAsPart(
    207                 MmsConfig.getMaxImageWidth(),
    208                 MmsConfig.getMaxImageHeight(),
    209                 byteLimit);
    210 
    211         if (part == null) {
    212             throw new ExceedMessageSizeException("Not enough memory to turn image into part: " +
    213                     getUri());
    214         }
    215 
    216         String src = getSrc();
    217         byte[] srcBytes = src.getBytes();
    218         part.setContentLocation(srcBytes);
    219         int period = src.lastIndexOf(".");
    220         byte[] contentId = period != -1 ? src.substring(0, period).getBytes() : srcBytes;
    221         part.setContentId(contentId);
    222 
    223         PduPersister persister = PduPersister.getPduPersister(mContext);
    224         this.mSize = part.getData().length;
    225         Uri newUri = persister.persistPart(part, messageId);
    226         setUri(newUri);
    227     }
    228 }
    229