All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.util.imagepool.ImagePoolHelper Maven / Gradle / Ivy

/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.util.imagepool;

import com.android.tools.layoutlib.annotations.Nullable;

import android.util.imagepool.Bucket.BucketCreationMetaData;
import android.util.imagepool.ImagePool.Image.Orientation;
import android.util.imagepool.ImagePool.ImagePoolPolicy;

import java.awt.image.BufferedImage;
import java.util.Map;

/* private package */ class ImagePoolHelper {

    @Nullable
    public static BucketCreationMetaData getBucketCreationMetaData(int w, int h, int type, ImagePoolPolicy poolPolicy, ImagePoolStats stats) {
        // Find the bucket sizes for both dimensions
        int widthBucket = -1;
        int heightBucket = -1;
        int index = 0;

        for (int bucketMinSize : poolPolicy.mBucketSizes) {
            if (widthBucket == -1 && w <= bucketMinSize) {
                widthBucket = bucketMinSize;

                if (heightBucket != -1) {
                    break;
                }
            }
            if (heightBucket == -1 && h <= bucketMinSize) {
                heightBucket = bucketMinSize;

                if (widthBucket != -1) {
                    break;
                }
            }
            ++index;
        }

        stats.recordBucketRequest(w, h);

        if (index >= poolPolicy.mNumberOfCopies.length) {
            return null;
        }

        // TODO: Apply orientation
//        if (widthBucket < heightBucket) {
//            return new BucketCreationMetaData(heightBucket, widthBucket, type, poolPolicy.mNumberOfCopies[index],
//                    Orientation.CW_90, poolPolicy.mBucketMaxCacheSize);
//        }
        return new BucketCreationMetaData(widthBucket, heightBucket, type, poolPolicy.mNumberOfCopies[index],
                Orientation.NONE, poolPolicy.mBucketMaxCacheSize);
    }

    @Nullable
    public static BufferedImage getBufferedImage(
            Bucket bucket, BucketCreationMetaData metaData, ImagePoolStats stats) {

        // strongref is just for gc.
        BufferedImage strongRef = populateBucket(bucket, metaData, stats);

        // pool is too small to create the requested buffer.
        if (bucket.isEmpty()) {
            assert strongRef == null;
            return null;
        }

        // Go through the bucket of soft references to find the first buffer that's not null.
        // Even if gc is triggered here, strongref should survive.
        BufferedImage img = bucket.remove();
        while (img == null && !bucket.isEmpty()) {
            img = bucket.remove();
        }

        if (img == null && bucket.isEmpty()) {
            // Whole buffer was null. Recurse.
            return getBufferedImage(bucket, metaData, stats);
        }
        return img;
    }

    /**
     * Populate the bucket in greedy manner to avoid fragmentation.
     * Behaviour is controlled by {@link ImagePoolPolicy}.
     * Returns one strong referenced buffer to avoid getting results gc'd. Null if pool is not large
     * enough.
     */
    @Nullable
    private static BufferedImage populateBucket(
            Bucket bucket, BucketCreationMetaData metaData, ImagePoolStats stats) {
        if (!bucket.isEmpty()) {
            // If not empty no need to populate.
            return null;
        }

        BufferedImage strongRef = null;
        for (int i = 0; i < metaData.mNumberOfCopies; i++) {
            if (!stats.fitsMaxCacheSize(
                    metaData.mWidth, metaData.mHeight, metaData.mMaxCacheSize)) {
                break;
            }
            strongRef =new BufferedImage(metaData.mWidth, metaData.mHeight,
                    metaData.mType);
            bucket.offer(strongRef);
            stats.recordBucketCreation(metaData.mWidth, metaData.mHeight);
        }
        return strongRef;
    }

    private static String toKey(int w, int h, int type) {
        return new StringBuilder()
                .append(w)
                .append('x')
                .append(h)
                .append(':')
                .append(type)
                .toString();
    }

    public static Bucket getBucket(Map map, BucketCreationMetaData metaData, ImagePoolPolicy mPolicy) {
        String key = toKey(metaData.mWidth, metaData.mHeight, metaData.mType);
        Bucket bucket = map.get(key);
        if (bucket == null) {
            bucket = new Bucket();
            map.put(key, bucket);
        }
        return bucket;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy