1 /* 2 * Copyright (C) 2009 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 import java.lang.ref.ReferenceQueue; 18 import java.lang.ref.PhantomReference; 19 import java.util.ArrayList; 20 21 public class Bitmap { 22 String mName; /* for debugging */ 23 int mWidth, mHeight; 24 Bitmap.NativeWrapper mNativeWrapper; 25 26 private static int sSerial = 100; 27 private static ArrayList sPhantomList = new ArrayList<PhantomWrapper>(); 28 private static ReferenceQueue<PhantomWrapper> sPhantomQueue = 29 new ReferenceQueue<PhantomWrapper>(); 30 private static BitmapWatcher sWatcher = new BitmapWatcher(sPhantomQueue); 31 static { 32 sWatcher.start(); 33 }; 34 35 Bitmap(String name, int width, int height, Bitmap.NativeWrapper nativeData) { 36 mName = name; 37 mWidth = width; 38 mHeight = height; 39 mNativeWrapper = nativeData; 40 41 System.out.println("Created " + this); 42 } 43 44 public String toString() { 45 return "Bitmap " + mName + ": " + mWidth + "x" + mHeight + " (" + 46 mNativeWrapper.mNativeData + ")"; 47 } 48 49 public void drawAt(int x, int y) { 50 System.out.println("Drawing " + this); 51 } 52 53 public static void shutDown() { 54 sWatcher.shutDown(); 55 try { 56 sWatcher.join(); 57 } catch (InterruptedException ie) { 58 System.out.println("join intr"); 59 } 60 System.out.println("Bitmap has shut down"); 61 } 62 63 /* 64 * Pretend we're allocating native storage. Just returns a unique 65 * serial number. 66 */ 67 static Bitmap.NativeWrapper allocNativeStorage(int width, int height) { 68 int nativeData; 69 70 synchronized (Bitmap.class) { 71 nativeData = sSerial++; 72 } 73 74 Bitmap.NativeWrapper wrapper = new Bitmap.NativeWrapper(nativeData); 75 PhantomWrapper phan = new PhantomWrapper(wrapper, sPhantomQueue, 76 nativeData); 77 sPhantomList.add(phan); 78 return wrapper; 79 } 80 81 static void freeNativeStorage(int nativeDataPtr) { 82 System.out.println("freeNativeStorage: " + nativeDataPtr); 83 } 84 85 /* 86 * Wraps a native data pointer in an object. When this object is no 87 * longer referenced, we free the native data. 88 */ 89 static class NativeWrapper { 90 public NativeWrapper(int nativeDataPtr) { 91 mNativeData = nativeDataPtr; 92 } 93 public int mNativeData; 94 95 /* 96 @Override 97 protected void finalize() throws Throwable { 98 System.out.println("finalized " + mNativeData); 99 } 100 */ 101 } 102 } 103 104 /* 105 * Keep an eye on the native data. 106 * 107 * We keep a copy of the native data pointer value, and set the wrapper 108 * as our referent. We need the copy because you can't get the referred-to 109 * object back out of a PhantomReference. 110 */ 111 class PhantomWrapper extends PhantomReference { 112 PhantomWrapper(Bitmap.NativeWrapper wrapper, 113 ReferenceQueue<PhantomWrapper> queue, int nativeDataPtr) 114 { 115 super(wrapper, queue); 116 mNativeData = nativeDataPtr; 117 } 118 119 public int mNativeData; 120 } 121 122 /* 123 * Thread that watches for un-referenced bitmap data. 124 */ 125 class BitmapWatcher extends Thread { 126 ReferenceQueue<PhantomWrapper> mQueue; 127 volatile boolean mQuit = false; 128 129 BitmapWatcher(ReferenceQueue<PhantomWrapper> queue) { 130 mQueue = queue; 131 setName("Bitmap Watcher"); 132 } 133 134 public void run() { 135 while (!mQuit) { 136 try { 137 PhantomWrapper ref = (PhantomWrapper) mQueue.remove(); 138 //System.out.println("dequeued ref " + ref.mNativeData + 139 // " - " + ref); 140 Bitmap.freeNativeStorage(ref.mNativeData); 141 //ref.clear(); 142 } catch (InterruptedException ie) { 143 System.out.println("intr"); 144 } 145 } 146 } 147 148 public void shutDown() { 149 mQuit = true; 150 interrupt(); 151 } 152 } 153