| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.webkit; |
| |
| import android.content.ContentResolver; |
| import android.database.Cursor; |
| import android.graphics.Bitmap; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.provider.Browser; |
| import android.util.Log; |
| |
| import java.io.File; |
| import java.util.HashMap; |
| import java.util.Vector; |
| |
| class WebIconDatabaseClassic extends WebIconDatabase { |
| private static final String LOGTAG = "WebIconDatabase"; |
| // Global instance of a WebIconDatabase |
| private static WebIconDatabaseClassic sIconDatabase; |
| // EventHandler for handling messages before and after the WebCore thread is |
| // ready. |
| private final EventHandler mEventHandler = new EventHandler(); |
| |
| // Class to handle messages before WebCore is ready |
| private static class EventHandler extends Handler { |
| // Message ids |
| static final int OPEN = 0; |
| static final int CLOSE = 1; |
| static final int REMOVE_ALL = 2; |
| static final int REQUEST_ICON = 3; |
| static final int RETAIN_ICON = 4; |
| static final int RELEASE_ICON = 5; |
| static final int BULK_REQUEST_ICON = 6; |
| // Message for dispatching icon request results |
| private static final int ICON_RESULT = 10; |
| // Actual handler that runs in WebCore thread |
| private Handler mHandler; |
| // Vector of messages before the WebCore thread is ready |
| private Vector<Message> mMessages = new Vector<Message>(); |
| // Class to handle a result dispatch |
| private class IconResult { |
| private final String mUrl; |
| private final Bitmap mIcon; |
| private final IconListener mListener; |
| IconResult(String url, Bitmap icon, IconListener l) { |
| mUrl = url; |
| mIcon = icon; |
| mListener = l; |
| } |
| void dispatch() { |
| mListener.onReceivedIcon(mUrl, mIcon); |
| } |
| } |
| |
| @Override |
| public void handleMessage(Message msg) { |
| // Note: This is the message handler for the UI thread. |
| switch (msg.what) { |
| case ICON_RESULT: |
| ((IconResult) msg.obj).dispatch(); |
| break; |
| } |
| } |
| |
| // Called by WebCore thread to create the actual handler |
| private synchronized void createHandler() { |
| if (mHandler == null) { |
| mHandler = new Handler() { |
| @Override |
| public void handleMessage(Message msg) { |
| // Note: This is the message handler for the WebCore |
| // thread. |
| switch (msg.what) { |
| case OPEN: |
| nativeOpen((String) msg.obj); |
| break; |
| |
| case CLOSE: |
| nativeClose(); |
| break; |
| |
| case REMOVE_ALL: |
| nativeRemoveAllIcons(); |
| break; |
| |
| case REQUEST_ICON: |
| IconListener l = (IconListener) msg.obj; |
| String url = msg.getData().getString("url"); |
| requestIconAndSendResult(url, l); |
| break; |
| |
| case BULK_REQUEST_ICON: |
| bulkRequestIcons(msg); |
| break; |
| |
| case RETAIN_ICON: |
| nativeRetainIconForPageUrl((String) msg.obj); |
| break; |
| |
| case RELEASE_ICON: |
| nativeReleaseIconForPageUrl((String) msg.obj); |
| break; |
| } |
| } |
| }; |
| // Transfer all pending messages |
| for (int size = mMessages.size(); size > 0; size--) { |
| mHandler.sendMessage(mMessages.remove(0)); |
| } |
| mMessages = null; |
| } |
| } |
| |
| private synchronized boolean hasHandler() { |
| return mHandler != null; |
| } |
| |
| private synchronized void postMessage(Message msg) { |
| if (mMessages != null) { |
| mMessages.add(msg); |
| } else { |
| mHandler.sendMessage(msg); |
| } |
| } |
| |
| private void bulkRequestIcons(Message msg) { |
| HashMap map = (HashMap) msg.obj; |
| IconListener listener = (IconListener) map.get("listener"); |
| ContentResolver cr = (ContentResolver) map.get("contentResolver"); |
| String where = (String) map.get("where"); |
| |
| Cursor c = null; |
| try { |
| c = cr.query( |
| Browser.BOOKMARKS_URI, |
| new String[] { Browser.BookmarkColumns.URL }, |
| where, null, null); |
| if (c.moveToFirst()) { |
| do { |
| String url = c.getString(0); |
| requestIconAndSendResult(url, listener); |
| } while (c.moveToNext()); |
| } |
| } catch (IllegalStateException e) { |
| Log.e(LOGTAG, "BulkRequestIcons", e); |
| } finally { |
| if (c != null) c.close(); |
| } |
| } |
| |
| private void requestIconAndSendResult(String url, IconListener listener) { |
| Bitmap icon = nativeIconForPageUrl(url); |
| if (icon != null) { |
| sendMessage(obtainMessage(ICON_RESULT, |
| new IconResult(url, icon, listener))); |
| } |
| } |
| } |
| |
| @Override |
| public void open(String path) { |
| if (path != null) { |
| // Make the directories and parents if they don't exist |
| File db = new File(path); |
| if (!db.exists()) { |
| db.mkdirs(); |
| } |
| mEventHandler.postMessage( |
| Message.obtain(null, EventHandler.OPEN, db.getAbsolutePath())); |
| } |
| } |
| |
| @Override |
| public void close() { |
| mEventHandler.postMessage( |
| Message.obtain(null, EventHandler.CLOSE)); |
| } |
| |
| @Override |
| public void removeAllIcons() { |
| mEventHandler.postMessage( |
| Message.obtain(null, EventHandler.REMOVE_ALL)); |
| } |
| |
| /** |
| * Request the Bitmap representing the icon for the given page |
| * url. If the icon exists, the listener will be called with the result. |
| * @param url The page's url. |
| * @param listener An implementation on IconListener to receive the result. |
| */ |
| public void requestIconForPageUrl(String url, IconListener listener) { |
| if (listener == null || url == null) { |
| return; |
| } |
| Message msg = Message.obtain(null, EventHandler.REQUEST_ICON, listener); |
| msg.getData().putString("url", url); |
| mEventHandler.postMessage(msg); |
| } |
| |
| /** {@hide} |
| */ |
| public void bulkRequestIconForPageUrl(ContentResolver cr, String where, |
| IconListener listener) { |
| if (listener == null) { |
| return; |
| } |
| |
| // Special case situation: we don't want to add this message to the |
| // queue if there is no handler because we may never have a real |
| // handler to service the messages and the cursor will never get |
| // closed. |
| if (mEventHandler.hasHandler()) { |
| // Don't use Bundle as it is parcelable. |
| HashMap<String, Object> map = new HashMap<String, Object>(); |
| map.put("contentResolver", cr); |
| map.put("where", where); |
| map.put("listener", listener); |
| Message msg = |
| Message.obtain(null, EventHandler.BULK_REQUEST_ICON, map); |
| mEventHandler.postMessage(msg); |
| } |
| } |
| |
| @Override |
| public void retainIconForPageUrl(String url) { |
| if (url != null) { |
| mEventHandler.postMessage( |
| Message.obtain(null, EventHandler.RETAIN_ICON, url)); |
| } |
| } |
| |
| @Override |
| public void releaseIconForPageUrl(String url) { |
| if (url != null) { |
| mEventHandler.postMessage( |
| Message.obtain(null, EventHandler.RELEASE_ICON, url)); |
| } |
| } |
| |
| /** |
| * Get the global instance of WebIconDatabase. |
| * @return A single instance of WebIconDatabase. It will be the same |
| * instance for the current process each time this method is |
| * called. |
| */ |
| public static WebIconDatabaseClassic getInstance() { |
| // XXX: Must be created in the UI thread. |
| if (sIconDatabase == null) { |
| sIconDatabase = new WebIconDatabaseClassic(); |
| } |
| return sIconDatabase; |
| } |
| |
| /** |
| * Create the internal handler and transfer all pending messages. |
| * XXX: Called by WebCore thread only! |
| */ |
| /*package*/ void createHandler() { |
| mEventHandler.createHandler(); |
| } |
| |
| /** |
| * Private constructor to avoid anyone else creating an instance. |
| */ |
| private WebIconDatabaseClassic() {} |
| |
| // Native functions |
| private static native void nativeOpen(String path); |
| private static native void nativeClose(); |
| private static native void nativeRemoveAllIcons(); |
| private static native Bitmap nativeIconForPageUrl(String url); |
| private static native void nativeRetainIconForPageUrl(String url); |
| private static native void nativeReleaseIconForPageUrl(String url); |
| } |