/*
|
* Copyright (C) 2009 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.
|
*/
|
|
import java.lang.ref.ReferenceQueue;
|
import java.lang.ref.PhantomReference;
|
import java.util.ArrayList;
|
import java.util.concurrent.CountDownLatch;
|
|
public class Bitmap {
|
String mName; /* for debugging */
|
int mWidth, mHeight;
|
Bitmap.NativeWrapper mNativeWrapper;
|
|
private static int sSerial = 100;
|
private static ArrayList sPhantomList = new ArrayList<PhantomWrapper>();
|
private static ReferenceQueue<PhantomWrapper> sPhantomQueue =
|
new ReferenceQueue<PhantomWrapper>();
|
private static BitmapWatcher sWatcher = new BitmapWatcher(sPhantomQueue);
|
static {
|
sWatcher.setDaemon(true);
|
sWatcher.start();
|
};
|
|
Bitmap(String name, int width, int height, Bitmap.NativeWrapper nativeData) {
|
mName = name;
|
mWidth = width;
|
mHeight = height;
|
mNativeWrapper = nativeData;
|
|
System.out.println("Created " + this);
|
}
|
|
public String toString() {
|
return "Bitmap " + mName + ": " + mWidth + "x" + mHeight + " (" +
|
mNativeWrapper.mNativeData + ")";
|
}
|
|
public void drawAt(int x, int y) {
|
System.out.println("Drawing " + this);
|
}
|
|
public static void shutDown() {
|
sWatcher.shutDown();
|
try {
|
sWatcher.join();
|
} catch (InterruptedException ie) {
|
System.out.println("join intr");
|
}
|
System.out.println("Bitmap has shut down");
|
}
|
|
/*
|
* Pretend we're allocating native storage. Just returns a unique
|
* serial number.
|
*/
|
static Bitmap.NativeWrapper allocNativeStorage(int width, int height) {
|
int nativeData;
|
|
synchronized (Bitmap.class) {
|
nativeData = sSerial++;
|
}
|
|
Bitmap.NativeWrapper wrapper = new Bitmap.NativeWrapper(nativeData);
|
PhantomWrapper phan = new PhantomWrapper(wrapper, sPhantomQueue,
|
nativeData);
|
sPhantomList.add(phan);
|
wrapper.mPhantomWrapper = phan;
|
return wrapper;
|
}
|
|
static void freeNativeStorage(int nativeDataPtr, CountDownLatch freeSignal) {
|
System.out.println("freeNativeStorage: " + nativeDataPtr);
|
// Wake up the main thread that is [or will be] blocked until this native data is freed.
|
freeSignal.countDown();
|
}
|
|
/*
|
* Wraps a native data pointer in an object. When this object is no
|
* longer referenced, we free the native data.
|
*/
|
static class NativeWrapper {
|
public NativeWrapper(int nativeDataPtr) {
|
mNativeData = nativeDataPtr;
|
}
|
public int mNativeData;
|
|
// The PhantomWrapper corresponding to this NativeWrapper.
|
public PhantomWrapper mPhantomWrapper;
|
|
/*
|
@Override
|
protected void finalize() throws Throwable {
|
System.out.println("finalized " + mNativeData);
|
}
|
*/
|
}
|
}
|
|
/*
|
* Keep an eye on the native data.
|
*
|
* We keep a copy of the native data pointer value, and set the wrapper
|
* as our referent. We need the copy because you can't get the referred-to
|
* object back out of a PhantomReference.
|
*/
|
class PhantomWrapper extends PhantomReference {
|
PhantomWrapper(Bitmap.NativeWrapper wrapper,
|
ReferenceQueue<PhantomWrapper> queue, int nativeDataPtr)
|
{
|
super(wrapper, queue);
|
mNativeData = nativeDataPtr;
|
}
|
|
public int mNativeData;
|
// This will be signaled once mNativeData has been freed.
|
public CountDownLatch mFreeSignal = new CountDownLatch(1);
|
}
|
|
/*
|
* Thread that watches for un-referenced bitmap data.
|
*/
|
class BitmapWatcher extends Thread {
|
ReferenceQueue<PhantomWrapper> mQueue;
|
|
BitmapWatcher(ReferenceQueue<PhantomWrapper> queue) {
|
mQueue = queue;
|
setName("Bitmap Watcher");
|
}
|
|
public void run() {
|
while (true) {
|
try {
|
PhantomWrapper ref = (PhantomWrapper) mQueue.remove();
|
//System.out.println("dequeued ref " + ref.mNativeData +
|
// " - " + ref);
|
Bitmap.freeNativeStorage(ref.mNativeData, ref.mFreeSignal);
|
} catch (InterruptedException ie) {
|
System.out.println("intr");
|
break;
|
}
|
}
|
}
|
|
public void shutDown() {
|
interrupt();
|
}
|
}
|