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.drawable.Drawable;
21 import android.media.ExifInterface;
22 import android.support.rastermill.FrameSequence;
23 import android.support.rastermill.FrameSequenceDrawable;
24 
25 import com.android.messaging.util.Assert;
26 import com.android.messaging.util.LogUtil;
27 
28 import java.io.IOException;
29 import java.io.InputStream;
30 
31 public class GifImageResource extends ImageResource {
32     private FrameSequence mFrameSequence;
33 
GifImageResource(String key, FrameSequence frameSequence)34     public GifImageResource(String key, FrameSequence frameSequence) {
35         // GIF does not support exif tags
36         super(key, ExifInterface.ORIENTATION_NORMAL);
37         mFrameSequence = frameSequence;
38     }
39 
createGifImageResource(String key, InputStream inputStream)40     public static GifImageResource createGifImageResource(String key, InputStream inputStream) {
41         final FrameSequence frameSequence;
42         try {
43             frameSequence = FrameSequence.decodeStream(inputStream);
44         } finally {
45             try {
46                 inputStream.close();
47             } catch (IOException e) {
48                 // Nothing to do if we fail closing the stream
49             }
50         }
51         if (frameSequence == null) {
52             return null;
53         }
54         return new GifImageResource(key, frameSequence);
55     }
56 
57     @Override
getDrawable(Resources resources)58     public Drawable getDrawable(Resources resources) {
59         try {
60             return new FrameSequenceDrawable(mFrameSequence);
61         } catch (final Throwable t) {
62             // Malicious gif images can make the platform throw different kind of throwables, such
63             // as OutOfMemoryError and NullPointerException. Catch them all.
64             LogUtil.e(LogUtil.BUGLE_TAG, "Error getting drawable for GIF", t);
65             return null;
66         }
67     }
68 
69     @Override
getBitmap()70     public Bitmap getBitmap() {
71         Assert.fail("GetBitmap() should never be called on a gif.");
72         return null;
73     }
74 
75     @Override
getBytes()76     public byte[] getBytes() {
77         Assert.fail("GetBytes() should never be called on a gif.");
78         return null;
79     }
80 
81     @Override
reuseBitmap()82     public Bitmap reuseBitmap() {
83         return null;
84     }
85 
86     @Override
supportsBitmapReuse()87     public boolean supportsBitmapReuse() {
88         // FrameSequenceDrawable a.) takes two bitmaps and thus does not fit into the current
89         // bitmap pool architecture b.) will rarely use bitmaps from one FrameSequenceDrawable to
90         // the next that are the same sizes since they are used by attachments.
91         return false;
92     }
93 
94     @Override
getMediaSize()95     public int getMediaSize() {
96         Assert.fail("GifImageResource should not be used by a media cache");
97         // Only used by the media cache, which this does not use.
98         return 0;
99     }
100 
101     @Override
isCacheable()102     public boolean isCacheable() {
103         return false;
104     }
105 
106     @Override
close()107     protected void close() {
108         acquireLock();
109         try {
110             if (mFrameSequence != null) {
111                 mFrameSequence = null;
112             }
113         } finally {
114             releaseLock();
115         }
116     }
117 
118 }
119