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.setDaemon(true);
33        sWatcher.start();
34    };
35
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
45    public String toString() {
46        return "Bitmap " + mName + ": " + mWidth + "x" + mHeight + " (" +
47                mNativeWrapper.mNativeData + ")";
48    }
49
50    public void drawAt(int x, int y) {
51        System.out.println("Drawing " + this);
52    }
53
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     */
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
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 {
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 */
112class PhantomWrapper extends PhantomReference {
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 */
126class BitmapWatcher extends Thread {
127    ReferenceQueue<PhantomWrapper> mQueue;
128
129    BitmapWatcher(ReferenceQueue<PhantomWrapper> queue) {
130        mQueue = queue;
131        setName("Bitmap Watcher");
132    }
133
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
149    public void shutDown() {
150        interrupt();
151    }
152}
153