WebIconDatabase.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/*
2 * Copyright (C) 2006 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
17package android.webkit;
18
19import android.os.Handler;
20import android.os.Message;
21import android.graphics.Bitmap;
22
23import java.util.Vector;
24
25/**
26 * Functions for manipulating the icon database used by WebView.
27 * These functions require that a WebView be constructed before being invoked
28 * and WebView.getIconDatabase() will return a WebIconDatabase object. This
29 * WebIconDatabase object is a single instance and all methods operate on that
30 * single object.
31 */
32public final class WebIconDatabase {
33    // Global instance of a WebIconDatabase
34    private static WebIconDatabase sIconDatabase;
35    // EventHandler for handling messages before and after the WebCore thread is
36    // ready.
37    private final EventHandler mEventHandler = new EventHandler();
38
39    // Class to handle messages before WebCore is ready
40    private class EventHandler extends Handler {
41        // Message ids
42        static final int OPEN         = 0;
43        static final int CLOSE        = 1;
44        static final int REMOVE_ALL   = 2;
45        static final int REQUEST_ICON = 3;
46        static final int RETAIN_ICON  = 4;
47        static final int RELEASE_ICON = 5;
48        // Message for dispatching icon request results
49        private static final int ICON_RESULT = 10;
50        // Actual handler that runs in WebCore thread
51        private Handler mHandler;
52        // Vector of messages before the WebCore thread is ready
53        private Vector<Message> mMessages = new Vector<Message>();
54        // Class to handle a result dispatch
55        private class IconResult {
56            private final String mUrl;
57            private final Bitmap mIcon;
58            private final IconListener mListener;
59            IconResult(String url, Bitmap icon, IconListener l) {
60                mUrl = url;
61                mIcon = icon;
62                mListener = l;
63            }
64            void dispatch() {
65                mListener.onReceivedIcon(mUrl, mIcon);
66            }
67        }
68
69        @Override
70        public void handleMessage(Message msg) {
71            // Note: This is the message handler for the UI thread.
72            switch (msg.what) {
73                case ICON_RESULT:
74                    ((IconResult) msg.obj).dispatch();
75                    break;
76            }
77        }
78
79        // Called by WebCore thread to create the actual handler
80        private synchronized void createHandler() {
81            if (mHandler == null) {
82                mHandler = new Handler() {
83                    @Override
84                    public void handleMessage(Message msg) {
85                        // Note: This is the message handler for the WebCore
86                        // thread.
87                        switch (msg.what) {
88                            case OPEN:
89                                nativeOpen((String) msg.obj);
90                                break;
91
92                            case CLOSE:
93                                nativeClose();
94                                break;
95
96                            case REMOVE_ALL:
97                                nativeRemoveAllIcons();
98                                break;
99
100                            case REQUEST_ICON:
101                                IconListener l = (IconListener) msg.obj;
102                                String url = msg.getData().getString("url");
103                                Bitmap icon = nativeIconForPageUrl(url);
104                                if (icon != null) {
105                                    EventHandler.this.sendMessage(
106                                            Message.obtain(null, ICON_RESULT,
107                                                new IconResult(url, icon, l)));
108                                }
109                                break;
110
111                            case RETAIN_ICON:
112                                nativeRetainIconForPageUrl((String) msg.obj);
113                                break;
114
115                            case RELEASE_ICON:
116                                nativeReleaseIconForPageUrl((String) msg.obj);
117                                break;
118                        }
119                    }
120                };
121                // Transfer all pending messages
122                for (int size = mMessages.size(); size > 0; size--) {
123                    mHandler.sendMessage(mMessages.remove(0));
124                }
125                mMessages = null;
126            }
127        }
128
129        private synchronized void postMessage(Message msg) {
130            if (mMessages != null) {
131                mMessages.add(msg);
132            } else {
133                mHandler.sendMessage(msg);
134            }
135        }
136    }
137
138    /**
139     * Interface for receiving icons from the database.
140     */
141    public interface IconListener {
142        /**
143         * Called when the icon has been retrieved from the database and the
144         * result is non-null.
145         * @param url The url passed in the request.
146         * @param icon The favicon for the given url.
147         */
148        public void onReceivedIcon(String url, Bitmap icon);
149    }
150
151    /**
152     * Open a the icon database and store the icons in the given path.
153     * @param path The directory path where the icon database will be stored.
154     * @return True if the database was successfully opened or created in
155     *         the given path.
156     */
157    public void open(String path) {
158        if (path != null) {
159            mEventHandler.postMessage(
160                    Message.obtain(null, EventHandler.OPEN, path));
161        }
162    }
163
164    /**
165     * Close the shared instance of the icon database.
166     */
167    public void close() {
168        mEventHandler.postMessage(
169                Message.obtain(null, EventHandler.CLOSE));
170    }
171
172    /**
173     * Removes all the icons in the database.
174     */
175    public void removeAllIcons() {
176        mEventHandler.postMessage(
177                Message.obtain(null, EventHandler.REMOVE_ALL));
178    }
179
180    /**
181     * Request the Bitmap representing the icon for the given page
182     * url. If the icon exists, the listener will be called with the result.
183     * @param url The page's url.
184     * @param listener An implementation on IconListener to receive the result.
185     */
186    public void requestIconForPageUrl(String url, IconListener listener) {
187        if (listener == null || url == null) {
188            return;
189        }
190        Message msg = Message.obtain(null, EventHandler.REQUEST_ICON, listener);
191        msg.getData().putString("url", url);
192        mEventHandler.postMessage(msg);
193    }
194
195    /**
196     * Retain the icon for the given page url.
197     * @param url The page's url.
198     */
199    public void retainIconForPageUrl(String url) {
200        if (url != null) {
201            mEventHandler.postMessage(
202                    Message.obtain(null, EventHandler.RETAIN_ICON, url));
203        }
204    }
205
206    /**
207     * Release the icon for the given page url.
208     * @param url The page's url.
209     */
210    public void releaseIconForPageUrl(String url) {
211        if (url != null) {
212            mEventHandler.postMessage(
213                    Message.obtain(null, EventHandler.RELEASE_ICON, url));
214        }
215    }
216
217    /**
218     * Get the global instance of WebIconDatabase.
219     * @return A single instance of WebIconDatabase. It will be the same
220     *         instance for the current process each time this method is
221     *         called.
222     */
223    public static WebIconDatabase getInstance() {
224        // XXX: Must be created in the UI thread.
225        if (sIconDatabase == null) {
226            sIconDatabase = new WebIconDatabase();
227        }
228        return sIconDatabase;
229    }
230
231    /**
232     * Create the internal handler and transfer all pending messages.
233     * XXX: Called by WebCore thread only!
234     */
235    /*package*/ void createHandler() {
236        mEventHandler.createHandler();
237    }
238
239    /**
240     * Private constructor to avoid anyone else creating an instance.
241     */
242    private WebIconDatabase() {}
243
244    // Native functions
245    private static native void nativeOpen(String path);
246    private static native void nativeClose();
247    private static native void nativeRemoveAllIcons();
248    private static native Bitmap nativeIconForPageUrl(String url);
249    private static native void nativeRetainIconForPageUrl(String url);
250    private static native void nativeReleaseIconForPageUrl(String url);
251}
252