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.Canvas;
21 import android.graphics.Matrix;
22 import android.graphics.Paint;
23 import android.graphics.RectF;
24 import android.media.ExifInterface;
25 
26 import com.android.messaging.util.Assert;
27 import com.android.messaging.util.ImageUtils;
28 
29 import java.io.FileNotFoundException;
30 import java.io.InputStream;
31 import java.util.List;
32 
33 /**
34  * Requests a composite image resource. The composite image resource is constructed by first
35  * sequentially requesting a number of sub image resources specified by
36  * {@link CompositeImageRequestDescriptor#getChildRequestDescriptors()}. After this, the
37  * individual sub images are composed into the final image onto their respective target rects
38  * returned by {@link CompositeImageRequestDescriptor#getChildRequestTargetRects()}.
39  */
40 public class CompositeImageRequest<D extends CompositeImageRequestDescriptor>
41         extends ImageRequest<D> {
42     private final Bitmap mBitmap;
43     private final Canvas mCanvas;
44     private final Paint mPaint;
45 
CompositeImageRequest(final Context context, final D descriptor)46     public CompositeImageRequest(final Context context, final D descriptor) {
47         super(context, descriptor);
48         mBitmap = getBitmapPool().createOrReuseBitmap(
49                 mDescriptor.desiredWidth, mDescriptor.desiredHeight);
50         mCanvas = new Canvas(mBitmap);
51         mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
52     }
53 
54     @Override
loadMediaInternal(List<MediaRequest<ImageResource>> chainedTask)55     protected ImageResource loadMediaInternal(List<MediaRequest<ImageResource>> chainedTask) {
56         final List<? extends ImageRequestDescriptor> descriptors =
57                 mDescriptor.getChildRequestDescriptors();
58         final List<RectF> targetRects = mDescriptor.getChildRequestTargetRects();
59         Assert.equals(descriptors.size(), targetRects.size());
60         Assert.isTrue(descriptors.size() > 1);
61 
62         for (int i = 0; i < descriptors.size(); i++) {
63             final MediaRequest<ImageResource> request =
64                     descriptors.get(i).buildSyncMediaRequest(mContext);
65             // Synchronously request the child image.
66             final ImageResource resource =
67                     MediaResourceManager.get().requestMediaResourceSync(request);
68             if (resource != null) {
69                 try {
70                     final RectF avatarDestOnGroup = targetRects.get(i);
71 
72                     // Draw the bitmap into a smaller size with a circle mask.
73                     final Bitmap resourceBitmap = resource.getBitmap();
74                     final RectF resourceRect = new RectF(
75                             0, 0, resourceBitmap.getWidth(), resourceBitmap.getHeight());
76                     final Bitmap smallCircleBitmap = getBitmapPool().createOrReuseBitmap(
77                             Math.round(avatarDestOnGroup.width()),
78                             Math.round(avatarDestOnGroup.height()));
79                     final RectF smallCircleRect = new RectF(
80                             0, 0, smallCircleBitmap.getWidth(), smallCircleBitmap.getHeight());
81                     final Canvas smallCircleCanvas = new Canvas(smallCircleBitmap);
82                     ImageUtils.drawBitmapWithCircleOnCanvas(resource.getBitmap(), smallCircleCanvas,
83                             resourceRect, smallCircleRect, null /* bitmapPaint */,
84                             false /* fillBackground */,
85                             ImageUtils.DEFAULT_CIRCLE_BACKGROUND_COLOR /* circleBackgroundColor */,
86                             ImageUtils.DEFAULT_CIRCLE_STROKE_COLOR /* circleStrokeColor */);
87                     final Matrix matrix = new Matrix();
88                     matrix.setRectToRect(smallCircleRect, avatarDestOnGroup,
89                             Matrix.ScaleToFit.FILL);
90                     mCanvas.drawBitmap(smallCircleBitmap, matrix, mPaint);
91                 } finally {
92                     resource.release();
93                 }
94             }
95         }
96 
97         return new DecodedImageResource(getKey(), mBitmap, ExifInterface.ORIENTATION_NORMAL);
98     }
99 
100     @Override
getCacheId()101     public int getCacheId() {
102         return BugleMediaCacheManager.AVATAR_IMAGE_CACHE;
103     }
104 
105     @Override
getInputStreamForResource()106     protected InputStream getInputStreamForResource() throws FileNotFoundException {
107         throw new IllegalStateException("Composite image request doesn't support input stream!");
108     }
109 }
110