1 /*
2  * Copyright (C) 2018 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 
17 package android.util.imagepool;
18 
19 import com.android.tools.layoutlib.annotations.NotNull;
20 
21 import java.awt.Graphics2D;
22 import java.awt.Image;
23 import java.awt.image.BufferedImage;
24 import java.awt.image.ImageObserver;
25 import java.util.function.Consumer;
26 
27 /**
28  * Simplified version of image pool that exists in Studio.
29  *
30  * Lacks:
31  * - PhantomReference and FinalizableReference to recognize the death of references automatically.
32  *   (Meaning devs need to be more deligent in dispose.)
33  * Has:
34  * + Debugger that allows us to better trace where image is being leaked in stack.
35  */
36 public interface ImagePool {
37 
38     /**
39      * Returns a new image of width w and height h.
40      */
41     @NotNull
acquire(final int w, final int h, final int type)42     Image acquire(final int w, final int h, final int type);
43 
44     /**
45      * Disposes the image pool, releasing all the references to the buffered images.
46      */
dispose()47     void dispose();
48 
49     /**
50      * Interface that represents a buffered image. Using this wrapper allows us ot better track
51      * memory usages around BufferedImage. When all of it's references are removed, it will
52      * automatically be pooled back into the image pool for re-use.
53      */
54     interface Image {
55 
56         /**
57          * Same as {@link BufferedImage#setRGB(int, int, int, int, int[], int, int)}
58          */
setRGB(int x, int y, int width, int height, int[] colors, int offset, int stride)59         void setRGB(int x, int y, int width, int height, int[] colors, int offset, int stride);
60 
61         /**
62          * Same as {@link Graphics2D#drawImage(java.awt.Image, int, int, ImageObserver)}
63          */
drawImage(Graphics2D graphics, int x, int y, ImageObserver o)64         void drawImage(Graphics2D graphics, int x, int y, ImageObserver o);
65 
66         /**
67          * Image orientation. It's not used at the moment. To be used later.
68          */
69         enum Orientation {
70             NONE,
71             CW_90
72         }
73 
getWidth()74         int getWidth();
getHeight()75         int getHeight();
76     }
77 
78     /**
79      * Policy for how to set up the memory pool.
80      */
81     class ImagePoolPolicy {
82 
83         public final int[] mBucketSizes;
84         public final int[] mNumberOfCopies;
85         public final long mBucketMaxCacheSize;
86 
87         /**
88          * @param bucketPixelSizes - list of pixel sizes to bucket (categorize) images. The list
89          * must be sorted (low to high).
90          * @param numberOfCopies - Allows users to create multiple copies of the bucket. It is
91          * recommended to create more copies for smaller images to avoid fragmentation in memory.
92          * It must match the size of bucketPixelSizes.
93          * @param bucketMaxCacheByteSize - Maximum cache byte sizes image pool is allowed to hold onto
94          * in memory.
95          */
ImagePoolPolicy( int[] bucketPixelSizes, int[] numberOfCopies, long bucketMaxCacheByteSize)96         public ImagePoolPolicy(
97                 int[] bucketPixelSizes, int[] numberOfCopies, long bucketMaxCacheByteSize) {
98             assert bucketPixelSizes.length == numberOfCopies.length;
99             mBucketSizes = bucketPixelSizes;
100             mNumberOfCopies = numberOfCopies;
101             mBucketMaxCacheSize = bucketMaxCacheByteSize;
102         }
103     }
104 }
105