Bitmap.java revision 7365493ad8d360c1dcf9cd8b6eee62747af01cae
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
17import java.lang.ref.ReferenceQueue;
18import java.lang.ref.PhantomReference;
19import java.util.ArrayList;
20
21public 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 */
111class 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 */
125class 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