193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/*
293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Copyright (C) 2013 The Android Open Source Project
393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Licensed under the Apache License, Version 2.0 (the "License");
593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * you may not use this file except in compliance with the License.
693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * You may obtain a copy of the License at
793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *      http://www.apache.org/licenses/LICENSE-2.0
993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
1093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Unless required by applicable law or agreed to in writing, software
1193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * distributed under the License is distributed on an "AS IS" BASIS,
1293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * See the License for the specific language governing permissions and
1493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * limitations under the License.
1593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */
1693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
1793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpackage com.android.bitmap;
1893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
1993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.Log;
2093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.util.LruCache;
2193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
2293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.ReusableBitmap.NullReusableBitmap;
2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport com.android.bitmap.util.Trace;
2493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
2593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/**
2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This subclass provides custom pool behavior. The pool can be set to block on {@link #poll()} if
2793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * nothing can be returned. This is useful if you know you will incur high costs upon receiving
2893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * nothing from the pool, and you do not want to incur those costs at the critical moment when the
2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * UI is animating.
3093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
3193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * This subclass provides custom cache behavior. Null values can be cached. Later,
3293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * when the same key is used to retrieve the value, a {@link NullReusableBitmap} singleton will
3393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * be returned.
3493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */
3540662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzsteinpublic class UnrefedBitmapCache extends UnrefedPooledCache<RequestKey, ReusableBitmap>
3693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        implements BitmapCache {
3793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private boolean mBlocking = false;
3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final Object mLock = new Object();
3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4040662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein    private LruCache<RequestKey, NullReusableBitmap> mNullRequests;
4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
42cea0c012d538f11b3ee97d4b7e78f4c1ea73d5beMark Wei    private final static boolean DEBUG = DecodeTask.DEBUG;
4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final static String TAG = UnrefedBitmapCache.class.getSimpleName();
4493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public UnrefedBitmapCache(final int targetSizeBytes, final float nonPooledFraction,
4693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final int nullCapacity) {
4793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        super(targetSizeBytes, nonPooledFraction);
4893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (nullCapacity > 0) {
5040662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein            mNullRequests = new LruCache<RequestKey, NullReusableBitmap>(nullCapacity);
5193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
5293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
5393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
5493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
5593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * Declare that {@link #poll()} should now block until it can return something.
5693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
5793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
5893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void setBlocking(final boolean blocking) {
5993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        synchronized (mLock) {
6093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (DEBUG) {
6193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Log.d(TAG, String.format("AltBitmapCache: block %b", blocking));
6293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
6393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mBlocking = blocking;
6493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (!mBlocking) {
6593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                // no longer blocking. Notify every thread.
6693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                mLock.notifyAll();
6793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
6893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
6993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
7093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
7193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
7293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    protected int sizeOf(final ReusableBitmap value) {
7393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return value.getByteCount();
7493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
7593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
7693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
7793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * If {@link #setBlocking(boolean)} has been called with true, this method will block until a
7893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * resource is available.
7993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * @return an available resource, or null if none are available. Null will never be returned
8093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * until blocking is set to false.
8193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
8293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
8393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public ReusableBitmap poll() {
8493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        ReusableBitmap bitmap;
8593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        synchronized (mLock) {
8693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            while ((bitmap = super.poll()) == null && mBlocking) {
8793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                if (DEBUG) {
8893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    Log.d(TAG, String.format(
8993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                            "AltBitmapCache: %s waiting", Thread.currentThread().getName()));
9093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
9193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Trace.beginSection("sleep");
9293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                try {
9393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    // block
9493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    mLock.wait();
9593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    if (DEBUG) {
9693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                        Log.d(TAG, String.format("AltBitmapCache: %s notified",
9793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                                Thread.currentThread().getName()));
9893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    }
9993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                } catch (InterruptedException ignored) {
10093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
10193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Trace.endSection();
10293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
10393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
10493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return bitmap;
10593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
10693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
10793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
10893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void offer(final ReusableBitmap value) {
10993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        synchronized (mLock) {
11093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            super.offer(value);
11193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (DEBUG) {
11293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                Log.d(TAG, "AltBitmapCache: offer +1");
11393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
11493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            // new resource gained. Notify one thread.
11593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mLock.notify();
11693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
11793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
11893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
11993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
12040662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein    public ReusableBitmap get(final RequestKey key, final boolean incrementRefCount) {
12193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (mNullRequests != null && mNullRequests.get(key) != null) {
12293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return NullReusableBitmap.getInstance();
12393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
12493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return super.get(key, incrementRefCount);
12593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
12693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
12793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
12893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * Note: The cache only supports same-sized bitmaps.
12993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
13093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
13140662f4b39e795d9c64502b13036e7c37fa2d373Sam Blitzstein    public ReusableBitmap put(final RequestKey key, final ReusableBitmap value) {
13293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (mNullRequests != null && (value == null || value == NullReusableBitmap.getInstance())) {
13393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mNullRequests.put(key, NullReusableBitmap.getInstance());
13493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return null;
13593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
13693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
13793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return super.put(key, value);
13893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
13993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein}
140