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.LogTag; 22 import com.android.mms.dom.smil.SmilMediaElementImpl; 23 import com.android.mms.drm.DrmWrapper; 24 import com.android.mms.ui.UriImage; 25 import com.android.mms.ui.MessageUtils; 26 import com.google.android.mms.MmsException; 27 28 import org.w3c.dom.events.Event; 29 import org.w3c.dom.smil.ElementTime; 30 31 import android.content.Context; 32 import android.drm.mobile1.DrmException; 33 import android.graphics.Bitmap; 34 import android.graphics.BitmapFactory; 35 import android.net.Uri; 36 import android.text.TextUtils; 37 import android.util.Config; 38 import android.util.Log; 39 40 import java.io.FileNotFoundException; 41 import java.io.IOException; 42 import java.io.InputStream; 43 import java.lang.ref.SoftReference; 44 45 46 public class ImageModel extends RegionMediaModel { 47 private static final String TAG = "Mms/image"; 48 private static final boolean DEBUG = false; 49 private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; 50 51 private static final int THUMBNAIL_BOUNDS_LIMIT = 480; 52 53 private int mWidth; 54 private int mHeight; 55 private SoftReference<Bitmap> mBitmapCache = new SoftReference<Bitmap>(null); 56 ImageModel(Context context, Uri uri, RegionModel region)57 public ImageModel(Context context, Uri uri, RegionModel region) 58 throws MmsException { 59 super(context, SmilHelper.ELEMENT_TAG_IMAGE, uri, region); 60 initModelFromUri(uri); 61 checkContentRestriction(); 62 } 63 ImageModel(Context context, String contentType, String src, Uri uri, RegionModel region)64 public ImageModel(Context context, String contentType, String src, 65 Uri uri, RegionModel region) throws DrmException, MmsException { 66 super(context, SmilHelper.ELEMENT_TAG_IMAGE, 67 contentType, src, uri, region); 68 decodeImageBounds(); 69 } 70 ImageModel(Context context, String contentType, String src, DrmWrapper wrapper, RegionModel regionModel)71 public ImageModel(Context context, String contentType, String src, 72 DrmWrapper wrapper, RegionModel regionModel) throws IOException { 73 super(context, SmilHelper.ELEMENT_TAG_IMAGE, contentType, src, 74 wrapper, regionModel); 75 } 76 initModelFromUri(Uri uri)77 private void initModelFromUri(Uri uri) throws MmsException { 78 UriImage uriImage = new UriImage(mContext, uri); 79 80 mContentType = uriImage.getContentType(); 81 if (TextUtils.isEmpty(mContentType)) { 82 throw new MmsException("Type of media is unknown."); 83 } 84 mSrc = uriImage.getSrc(); 85 mWidth = uriImage.getWidth(); 86 mHeight = uriImage.getHeight(); 87 88 if (LOCAL_LOGV) { 89 Log.v(TAG, "New ImageModel created:" 90 + " mSrc=" + mSrc 91 + " mContentType=" + mContentType 92 + " mUri=" + uri); 93 } 94 } 95 decodeImageBounds()96 private void decodeImageBounds() throws DrmException { 97 UriImage uriImage = new UriImage(mContext, getUriWithDrmCheck()); 98 mWidth = uriImage.getWidth(); 99 mHeight = uriImage.getHeight(); 100 101 if (LOCAL_LOGV) { 102 Log.v(TAG, "Image bounds: " + mWidth + "x" + mHeight); 103 } 104 } 105 106 // EventListener Interface handleEvent(Event evt)107 public void handleEvent(Event evt) { 108 if (evt.getType().equals(SmilMediaElementImpl.SMIL_MEDIA_START_EVENT)) { 109 mVisible = true; 110 } else if (mFill != ElementTime.FILL_FREEZE) { 111 mVisible = false; 112 } 113 114 notifyModelChanged(false); 115 } 116 getWidth()117 public int getWidth() { 118 return mWidth; 119 } 120 getHeight()121 public int getHeight() { 122 return mHeight; 123 } 124 checkContentRestriction()125 protected void checkContentRestriction() throws ContentRestrictionException { 126 ContentRestriction cr = ContentRestrictionFactory.getContentRestriction(); 127 cr.checkImageContentType(mContentType); 128 cr.checkResolution(mWidth, mHeight); 129 } 130 getBitmap()131 public Bitmap getBitmap() { 132 return internalGetBitmap(getUri()); 133 } 134 getBitmapWithDrmCheck()135 public Bitmap getBitmapWithDrmCheck() throws DrmException { 136 return internalGetBitmap(getUriWithDrmCheck()); 137 } 138 internalGetBitmap(Uri uri)139 private Bitmap internalGetBitmap(Uri uri) { 140 Bitmap bm = mBitmapCache.get(); 141 if (bm == null) { 142 try { 143 bm = createThumbnailBitmap(THUMBNAIL_BOUNDS_LIMIT, uri); 144 if (bm != null) { 145 mBitmapCache = new SoftReference<Bitmap>(bm); 146 } 147 } catch (OutOfMemoryError ex) { 148 // fall through and return a null bitmap. The callers can handle a null 149 // result and show R.drawable.ic_missing_thumbnail_picture 150 } 151 } 152 return bm; 153 } 154 createThumbnailBitmap(int thumbnailBoundsLimit, Uri uri)155 private Bitmap createThumbnailBitmap(int thumbnailBoundsLimit, Uri uri) { 156 int outWidth = mWidth; 157 int outHeight = mHeight; 158 159 int s = 1; 160 while ((outWidth / s > thumbnailBoundsLimit) 161 || (outHeight / s > thumbnailBoundsLimit)) { 162 s *= 2; 163 } 164 if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { 165 Log.v(TAG, "createThumbnailBitmap: scale=" + s + ", w=" + outWidth / s 166 + ", h=" + outHeight / s); 167 } 168 BitmapFactory.Options options = new BitmapFactory.Options(); 169 options.inSampleSize = s; 170 171 InputStream input = null; 172 try { 173 input = mContext.getContentResolver().openInputStream(uri); 174 return BitmapFactory.decodeStream(input, null, options); 175 } catch (FileNotFoundException e) { 176 Log.e(TAG, e.getMessage(), e); 177 return null; 178 } catch (OutOfMemoryError ex) { 179 MessageUtils.writeHprofDataToFile(); 180 throw ex; 181 } finally { 182 if (input != null) { 183 try { 184 input.close(); 185 } catch (IOException e) { 186 Log.e(TAG, e.getMessage(), e); 187 } 188 } 189 } 190 } 191 192 } 193