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.res.Resources; 19 import android.graphics.Bitmap; 20 import android.graphics.BitmapFactory; 21 import android.graphics.drawable.Drawable; 22 23 import com.android.messaging.util.Assert; 24 import com.android.messaging.util.Assert.DoesNotRunOnMainThread; 25 26 import java.util.Arrays; 27 import java.util.List; 28 29 /** 30 * A cache-facing image resource that's much more compact than the raw Bitmap objects stored in 31 * {@link com.android.messaging.datamodel.media.DecodedImageResource}. 32 * 33 * This resource is created from a regular Bitmap-based ImageResource before being pushed to 34 * {@link com.android.messaging.datamodel.media.MediaCache}, if the image request 35 * allows for resource encoding/compression. 36 * 37 * During resource retrieval on cache hit, 38 * {@link #getMediaDecodingRequest(MediaRequest)} is invoked to create a async 39 * decode task, which decodes the compressed byte array back to a regular image resource to 40 * be consumed by the UI. 41 */ 42 public class EncodedImageResource extends ImageResource { 43 private final byte[] mImageBytes; 44 45 public EncodedImageResource(String key, byte[] imageBytes, int orientation) { 46 super(key, orientation); 47 mImageBytes = imageBytes; 48 } 49 50 @Override 51 @DoesNotRunOnMainThread 52 public Bitmap getBitmap() { 53 acquireLock(); 54 try { 55 // This should only be called during the decode request. 56 Assert.isNotMainThread(); 57 return BitmapFactory.decodeByteArray(mImageBytes, 0, mImageBytes.length); 58 } finally { 59 releaseLock(); 60 } 61 } 62 63 @Override 64 public byte[] getBytes() { 65 acquireLock(); 66 try { 67 return Arrays.copyOf(mImageBytes, mImageBytes.length); 68 } finally { 69 releaseLock(); 70 } 71 } 72 73 @Override 74 public Bitmap reuseBitmap() { 75 return null; 76 } 77 78 @Override 79 public boolean supportsBitmapReuse() { 80 return false; 81 } 82 83 @Override 84 public int getMediaSize() { 85 return mImageBytes.length; 86 } 87 88 @Override 89 protected void close() { 90 } 91 92 @Override 93 public Drawable getDrawable(Resources resources) { 94 return null; 95 } 96 97 @Override 98 boolean isEncoded() { 99 return true; 100 } 101 102 @Override 103 MediaRequest<? extends RefCountedMediaResource> getMediaDecodingRequest( 104 final MediaRequest<? extends RefCountedMediaResource> originalRequest) { 105 Assert.isTrue(isEncoded()); 106 return new DecodeImageRequest(); 107 } 108 109 /** 110 * A MediaRequest that decodes the encoded image resource. This class is chained to the 111 * original media request that requested the image, so it inherits the listener and 112 * properties such as binding. 113 */ 114 private class DecodeImageRequest implements MediaRequest<ImageResource> { 115 public DecodeImageRequest() { 116 // Hold a ref onto the encoded resource before the request finishes. 117 addRef(); 118 } 119 120 @Override 121 public String getKey() { 122 return EncodedImageResource.this.getKey(); 123 } 124 125 @Override 126 @DoesNotRunOnMainThread 127 public ImageResource loadMediaBlocking(List<MediaRequest<ImageResource>> chainedTask) 128 throws Exception { 129 Assert.isNotMainThread(); 130 acquireLock(); 131 try { 132 final Bitmap decodedBitmap = BitmapFactory.decodeByteArray(mImageBytes, 0, 133 mImageBytes.length); 134 return new DecodedImageResource(getKey(), decodedBitmap, getOrientation()); 135 } finally { 136 releaseLock(); 137 release(); 138 } 139 } 140 141 @Override 142 public MediaCache<ImageResource> getMediaCache() { 143 // Decoded resource is non-cachable, it's for UI consumption only (for now at least) 144 return null; 145 } 146 147 @Override 148 public int getCacheId() { 149 return 0; 150 } 151 152 @Override 153 public int getRequestType() { 154 return REQUEST_DECODE_MEDIA; 155 } 156 157 @Override 158 public MediaRequestDescriptor<ImageResource> getDescriptor() { 159 return null; 160 } 161 } 162 } 163