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