10ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck/*
20ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck * Copyright (C) 2010 The Android Open Source Project
30ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck *
40ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck * Licensed under the Apache License, Version 2.0 (the "License");
50ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck * you may not use this file except in compliance with the License.
60ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck * You may obtain a copy of the License at
70ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck *
80ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck *      http://www.apache.org/licenses/LICENSE-2.0
90ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck *
100ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck * Unless required by applicable law or agreed to in writing, software
110ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck * distributed under the License is distributed on an "AS IS" BASIS,
120ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck * See the License for the specific language governing permissions and
140ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck * limitations under the License.
150ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck */
160ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
170ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
180ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckpackage com.android.browser;
190ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
200ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckimport android.content.ContentResolver;
210ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckimport android.content.ContentUris;
220ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckimport android.content.ContentValues;
230ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckimport android.content.Context;
240ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckimport android.database.Cursor;
25e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reckimport android.database.sqlite.SQLiteException;
264eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reckimport android.graphics.Bitmap;
274eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reckimport android.net.Uri;
280ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckimport android.os.Handler;
290ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckimport android.os.Message;
30e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reckimport android.provider.BrowserContract;
310ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckimport android.provider.BrowserContract.History;
32e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reckimport android.util.Log;
33e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck
344eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reckimport com.android.browser.provider.BrowserProvider2.Thumbnails;
354eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck
364eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reckimport java.nio.ByteBuffer;
37e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reckimport java.util.concurrent.BlockingQueue;
38e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reckimport java.util.concurrent.LinkedBlockingQueue;
390ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
400ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reckpublic class DataController {
41e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    private static final String LOGTAG = "DataController";
420ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    // Message IDs
430ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    private static final int HISTORY_UPDATE_VISITED = 100;
440ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    private static final int HISTORY_UPDATE_TITLE = 101;
454eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    private static final int QUERY_URL_IS_BOOKMARK = 200;
464eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    private static final int TAB_LOAD_THUMBNAIL = 201;
474eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    private static final int TAB_SAVE_THUMBNAIL = 202;
484eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    private static final int TAB_DELETE_THUMBNAIL = 203;
490ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    private static DataController sInstance;
500ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
510ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    private Context mContext;
52e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    private DataControllerHandler mDataHandler;
53e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    private Handler mCbHandler; // To respond on the UI thread
544eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    private ByteBuffer mBuffer; // to capture thumbnails
55e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck
56e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    /* package */ static interface OnQueryUrlIsBookmark {
57e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        void onQueryUrlIsBookmark(String url, boolean isBookmark);
58e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    }
59e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    private static class CallbackContainer {
60e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        Object replyTo;
61e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        Object[] args;
62e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    }
63e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck
64e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    private static class DCMessage {
65e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        int what;
66e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        Object obj;
67e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        Object replyTo;
68e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        DCMessage(int w, Object o) {
69e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            what = w;
70e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            obj = o;
71e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        }
72e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    }
730ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
740ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    /* package */ static DataController getInstance(Context c) {
750ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck        if (sInstance == null) {
760ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck            sInstance = new DataController(c);
770ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck        }
780ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck        return sInstance;
790ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    }
800ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
810ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    private DataController(Context c) {
820ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck        mContext = c.getApplicationContext();
83e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        mDataHandler = new DataControllerHandler();
84e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        mDataHandler.start();
85e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        mCbHandler = new Handler() {
86e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            @Override
87e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            public void handleMessage(Message msg) {
88e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                CallbackContainer cc = (CallbackContainer) msg.obj;
89e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                switch (msg.what) {
90e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    case QUERY_URL_IS_BOOKMARK: {
91e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        OnQueryUrlIsBookmark cb = (OnQueryUrlIsBookmark) cc.replyTo;
92e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        String url = (String) cc.args[0];
93e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        boolean isBookmark = (Boolean) cc.args[1];
94e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        cb.onQueryUrlIsBookmark(url, isBookmark);
95e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        break;
96e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    }
97e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                }
98e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            }
99e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        };
1000ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    }
1010ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
1020ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    public void updateVisitedHistory(String url) {
103e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        mDataHandler.sendMessage(HISTORY_UPDATE_VISITED, url);
1040ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    }
1050ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
1060ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    public void updateHistoryTitle(String url, String title) {
107e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        mDataHandler.sendMessage(HISTORY_UPDATE_TITLE, new String[] { url, title });
1080ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    }
1090ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
110e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    public void queryBookmarkStatus(String url, OnQueryUrlIsBookmark replyTo) {
1116c702eed5791d0d46fbe3dfd3054549997f218dcJohn Reck        if (url == null || url.trim().length() == 0) {
1126c702eed5791d0d46fbe3dfd3054549997f218dcJohn Reck            // null or empty url is never a bookmark
1136c702eed5791d0d46fbe3dfd3054549997f218dcJohn Reck            replyTo.onQueryUrlIsBookmark(url, false);
1146c702eed5791d0d46fbe3dfd3054549997f218dcJohn Reck            return;
1156c702eed5791d0d46fbe3dfd3054549997f218dcJohn Reck        }
1166c702eed5791d0d46fbe3dfd3054549997f218dcJohn Reck        mDataHandler.sendMessage(QUERY_URL_IS_BOOKMARK, url.trim(), replyTo);
117e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    }
118e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck
1194eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    public void loadThumbnail(Tab tab) {
1204eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        mDataHandler.sendMessage(TAB_LOAD_THUMBNAIL, tab);
1214eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    }
1224eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck
1234eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    public void deleteThumbnail(Tab tab) {
1244eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        mDataHandler.sendMessage(TAB_DELETE_THUMBNAIL, tab.getId());
1254eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    }
1264eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck
1274eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    public void saveThumbnail(Tab tab) {
1284eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        mDataHandler.sendMessage(TAB_SAVE_THUMBNAIL, tab);
1294eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck    }
1304eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck
131e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    // The standard Handler and Message classes don't allow the queue manipulation
132e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    // we want (such as peeking). So we use our own queue.
133e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck    class DataControllerHandler extends Thread {
134e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        private BlockingQueue<DCMessage> mMessageQueue
135e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                = new LinkedBlockingQueue<DCMessage>();
1360ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
1374eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        public DataControllerHandler() {
1384eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            super("DataControllerHandler");
1394eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        }
1404eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck
1410ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck        @Override
142e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        public void run() {
1434eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            setPriority(Thread.MIN_PRIORITY);
144e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            while (true) {
145e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                try {
146e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    handleMessage(mMessageQueue.take());
147e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                } catch (InterruptedException ex) {
148e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    break;
149e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                }
150e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            }
151e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        }
152e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck
153e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        void sendMessage(int what, Object obj) {
154e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            DCMessage m = new DCMessage(what, obj);
155e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            mMessageQueue.add(m);
156e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        }
157e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck
158e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        void sendMessage(int what, Object obj, Object replyTo) {
159e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            DCMessage m = new DCMessage(what, obj);
160e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            m.replyTo = replyTo;
161e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            mMessageQueue.add(m);
162e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        }
163e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck
164e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        private void handleMessage(DCMessage msg) {
1650ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck            switch (msg.what) {
1660ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck            case HISTORY_UPDATE_VISITED:
1670ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck                doUpdateVisitedHistory((String) msg.obj);
1680ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck                break;
1690ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck            case HISTORY_UPDATE_TITLE:
1700ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck                String[] args = (String[]) msg.obj;
1710ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck                doUpdateHistoryTitle(args[0], args[1]);
1720ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck                break;
173e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            case QUERY_URL_IS_BOOKMARK:
174e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                // TODO: Look for identical messages in the queue and remove them
175e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                // TODO: Also, look for partial matches and merge them (such as
176e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                //       multiple callbacks querying the same URL)
177e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                doQueryBookmarkStatus((String) msg.obj, msg.replyTo);
178e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                break;
1794eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            case TAB_LOAD_THUMBNAIL:
1804eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                doLoadThumbnail((Tab) msg.obj);
1814eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                break;
1824eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            case TAB_DELETE_THUMBNAIL:
1834eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                ContentResolver cr = mContext.getContentResolver();
1844eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                try {
1854eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                    cr.delete(ContentUris.withAppendedId(
1864eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                            Thumbnails.CONTENT_URI, (Long)msg.obj),
1874eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                            null, null);
1884eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                } catch (Throwable t) {}
1894eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                break;
1904eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            case TAB_SAVE_THUMBNAIL:
1914eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                doSaveThumbnail((Tab)msg.obj);
1924eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                break;
1934eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            }
1944eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        }
1954eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck
1964eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        private byte[] getCaptureBlob(Tab tab) {
1974eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            synchronized (tab) {
1984eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                Bitmap capture = tab.getScreenshot();
1994eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                if (capture == null) {
2004eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                    return null;
2014eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                }
2024eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                if (mBuffer == null || mBuffer.limit() < capture.getByteCount()) {
2034eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                    mBuffer = ByteBuffer.allocate(capture.getByteCount());
2044eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                }
2054eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                capture.copyPixelsToBuffer(mBuffer);
2064eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                mBuffer.rewind();
2074eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                return mBuffer.array();
2084eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            }
2094eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        }
2104eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck
2114eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        private void doSaveThumbnail(Tab tab) {
2124eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            byte[] blob = getCaptureBlob(tab);
2134eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            if (blob == null) {
2144eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                return;
2154eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            }
2164eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            ContentResolver cr = mContext.getContentResolver();
2174eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            ContentValues values = new ContentValues();
2184eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            values.put(Thumbnails._ID, tab.getId());
2194eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            values.put(Thumbnails.THUMBNAIL, blob);
2204eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            cr.insert(Thumbnails.CONTENT_URI, values);
2214eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        }
2224eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck
2234eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck        private void doLoadThumbnail(Tab tab) {
2244eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            ContentResolver cr = mContext.getContentResolver();
2254eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            Cursor c = null;
2264eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            try {
2274eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                Uri uri = ContentUris.withAppendedId(Thumbnails.CONTENT_URI, tab.getId());
2284eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                c = cr.query(uri, new String[] {Thumbnails._ID,
2294eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                        Thumbnails.THUMBNAIL}, null, null, null);
2304eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                if (c.moveToFirst()) {
2314eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                    byte[] data = c.getBlob(1);
2324eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                    if (data != null && data.length > 0) {
2334eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                        tab.updateCaptureFromBlob(data);
2344eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                    }
2354eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                }
2364eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck            } finally {
2374eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                if (c != null) {
2384eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                    c.close();
2394eadc34fc528b1b63ac8d87bfd7f06e50b738b6dJohn Reck                }
2400ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck            }
2410ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck        }
2420ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
243e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        private void doUpdateVisitedHistory(String url) {
244e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            ContentResolver cr = mContext.getContentResolver();
245e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            Cursor c = null;
246e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            try {
247e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                c = cr.query(History.CONTENT_URI, new String[] { History._ID, History.VISITS },
248e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        History.URL + "=?", new String[] { url }, null);
249e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                if (c.moveToFirst()) {
250e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    ContentValues values = new ContentValues();
251e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    values.put(History.VISITS, c.getInt(1) + 1);
252e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    values.put(History.DATE_LAST_VISITED, System.currentTimeMillis());
253e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    cr.update(ContentUris.withAppendedId(History.CONTENT_URI, c.getLong(0)),
254e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                            values, null, null);
255e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                } else {
256e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    android.provider.Browser.truncateHistory(cr);
257e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    ContentValues values = new ContentValues();
258e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    values.put(History.URL, url);
259e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    values.put(History.VISITS, 1);
260e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    values.put(History.DATE_LAST_VISITED, System.currentTimeMillis());
261e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    values.put(History.TITLE, url);
262e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    values.put(History.DATE_CREATED, 0);
263e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    values.put(History.USER_ENTERED, 0);
264e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    cr.insert(History.CONTENT_URI, values);
265e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                }
266e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            } finally {
267e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                if (c != null) c.close();
2680ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck            }
2690ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck        }
2700ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck
271e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        private void doQueryBookmarkStatus(String url, Object replyTo) {
272e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            // Check to see if the site is bookmarked
273e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            Cursor cursor = null;
274e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            boolean isBookmark = false;
275e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            try {
276e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                cursor = mContext.getContentResolver().query(
277e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        BookmarkUtils.getBookmarksUri(mContext),
278e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        new String[] { BrowserContract.Bookmarks.URL },
279e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        BrowserContract.Bookmarks.URL + " == ?",
280e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        new String[] { url },
281e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                        null);
282e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                isBookmark = cursor.moveToFirst();
283e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            } catch (SQLiteException e) {
284e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                Log.e(LOGTAG, "Error checking for bookmark: " + e);
285e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            } finally {
286e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                if (cursor != null) cursor.close();
287e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            }
288e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            CallbackContainer cc = new CallbackContainer();
289e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            cc.replyTo = replyTo;
290e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            cc.args = new Object[] { url, isBookmark };
291e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            mCbHandler.obtainMessage(QUERY_URL_IS_BOOKMARK, cc).sendToTarget();
292e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        }
293e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck
294e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        private void doUpdateHistoryTitle(String url, String title) {
295e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            ContentResolver cr = mContext.getContentResolver();
296e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            ContentValues values = new ContentValues();
297e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            values.put(History.TITLE, title);
298e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck            cr.update(History.CONTENT_URI, values, History.URL + "=?",
299e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck                    new String[] { url });
300e969cc59ddcc763ab9d6349a854dd17a6456d1a4John Reck        }
3010ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck    }
3020ebd3ac69a76ec76d9caab65a1947f971242994eJohn Reck}
303