blob: aa233fd6f8c43a08e61d4a086a489975e59a22df [file] [log] [blame]
John Reck0ebd3ac2010-12-09 11:14:04 -08001/*
2 * Copyright (C) 2010 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
17
18package com.android.browser;
19
20import android.content.ContentResolver;
21import android.content.ContentUris;
22import android.content.ContentValues;
23import android.content.Context;
24import android.database.Cursor;
John Recke969cc52010-12-21 17:24:43 -080025import android.database.sqlite.SQLiteException;
John Reck0ebd3ac2010-12-09 11:14:04 -080026import android.os.Handler;
John Reck0ebd3ac2010-12-09 11:14:04 -080027import android.os.Message;
John Recke969cc52010-12-21 17:24:43 -080028import android.provider.BrowserContract;
John Reck0ebd3ac2010-12-09 11:14:04 -080029import android.provider.BrowserContract.History;
John Recke969cc52010-12-21 17:24:43 -080030import android.util.Log;
31
32import java.util.concurrent.BlockingQueue;
33import java.util.concurrent.LinkedBlockingQueue;
John Reck0ebd3ac2010-12-09 11:14:04 -080034
35public class DataController {
John Recke969cc52010-12-21 17:24:43 -080036 private static final String LOGTAG = "DataController";
John Reck0ebd3ac2010-12-09 11:14:04 -080037 // Message IDs
38 private static final int HISTORY_UPDATE_VISITED = 100;
39 private static final int HISTORY_UPDATE_TITLE = 101;
John Recke969cc52010-12-21 17:24:43 -080040 public static final int QUERY_URL_IS_BOOKMARK = 200;
John Reck0ebd3ac2010-12-09 11:14:04 -080041 private static DataController sInstance;
42
43 private Context mContext;
John Recke969cc52010-12-21 17:24:43 -080044 private DataControllerHandler mDataHandler;
45 private Handler mCbHandler; // To respond on the UI thread
46
47 /* package */ static interface OnQueryUrlIsBookmark {
48 void onQueryUrlIsBookmark(String url, boolean isBookmark);
49 }
50 private static class CallbackContainer {
51 Object replyTo;
52 Object[] args;
53 }
54
55 private static class DCMessage {
56 int what;
57 Object obj;
58 Object replyTo;
59 DCMessage(int w, Object o) {
60 what = w;
61 obj = o;
62 }
63 }
John Reck0ebd3ac2010-12-09 11:14:04 -080064
65 /* package */ static DataController getInstance(Context c) {
66 if (sInstance == null) {
67 sInstance = new DataController(c);
68 }
69 return sInstance;
70 }
71
72 private DataController(Context c) {
73 mContext = c.getApplicationContext();
John Recke969cc52010-12-21 17:24:43 -080074 mDataHandler = new DataControllerHandler();
75 mDataHandler.setDaemon(true);
76 mDataHandler.start();
77 mCbHandler = new Handler() {
78 @Override
79 public void handleMessage(Message msg) {
80 CallbackContainer cc = (CallbackContainer) msg.obj;
81 switch (msg.what) {
82 case QUERY_URL_IS_BOOKMARK: {
83 OnQueryUrlIsBookmark cb = (OnQueryUrlIsBookmark) cc.replyTo;
84 String url = (String) cc.args[0];
85 boolean isBookmark = (Boolean) cc.args[1];
86 cb.onQueryUrlIsBookmark(url, isBookmark);
87 break;
88 }
89 }
90 }
91 };
John Reck0ebd3ac2010-12-09 11:14:04 -080092 }
93
94 public void updateVisitedHistory(String url) {
John Recke969cc52010-12-21 17:24:43 -080095 mDataHandler.sendMessage(HISTORY_UPDATE_VISITED, url);
John Reck0ebd3ac2010-12-09 11:14:04 -080096 }
97
98 public void updateHistoryTitle(String url, String title) {
John Recke969cc52010-12-21 17:24:43 -080099 mDataHandler.sendMessage(HISTORY_UPDATE_TITLE, new String[] { url, title });
John Reck0ebd3ac2010-12-09 11:14:04 -0800100 }
101
John Recke969cc52010-12-21 17:24:43 -0800102 public void queryBookmarkStatus(String url, OnQueryUrlIsBookmark replyTo) {
103 mDataHandler.sendMessage(QUERY_URL_IS_BOOKMARK, url, replyTo);
104 }
105
106 // The standard Handler and Message classes don't allow the queue manipulation
107 // we want (such as peeking). So we use our own queue.
108 class DataControllerHandler extends Thread {
109 private BlockingQueue<DCMessage> mMessageQueue
110 = new LinkedBlockingQueue<DCMessage>();
John Reck0ebd3ac2010-12-09 11:14:04 -0800111
112 @Override
John Recke969cc52010-12-21 17:24:43 -0800113 public void run() {
114 super.run();
115 while (true) {
116 try {
117 handleMessage(mMessageQueue.take());
118 } catch (InterruptedException ex) {
119 break;
120 }
121 }
122 }
123
124 void sendMessage(int what, Object obj) {
125 DCMessage m = new DCMessage(what, obj);
126 mMessageQueue.add(m);
127 }
128
129 void sendMessage(int what, Object obj, Object replyTo) {
130 DCMessage m = new DCMessage(what, obj);
131 m.replyTo = replyTo;
132 mMessageQueue.add(m);
133 }
134
135 private void handleMessage(DCMessage msg) {
John Reck0ebd3ac2010-12-09 11:14:04 -0800136 switch (msg.what) {
137 case HISTORY_UPDATE_VISITED:
138 doUpdateVisitedHistory((String) msg.obj);
139 break;
140 case HISTORY_UPDATE_TITLE:
141 String[] args = (String[]) msg.obj;
142 doUpdateHistoryTitle(args[0], args[1]);
143 break;
John Recke969cc52010-12-21 17:24:43 -0800144 case QUERY_URL_IS_BOOKMARK:
145 // TODO: Look for identical messages in the queue and remove them
146 // TODO: Also, look for partial matches and merge them (such as
147 // multiple callbacks querying the same URL)
148 doQueryBookmarkStatus((String) msg.obj, msg.replyTo);
149 break;
John Reck0ebd3ac2010-12-09 11:14:04 -0800150 }
151 }
John Reck0ebd3ac2010-12-09 11:14:04 -0800152
John Recke969cc52010-12-21 17:24:43 -0800153 private void doUpdateVisitedHistory(String url) {
154 ContentResolver cr = mContext.getContentResolver();
155 Cursor c = null;
156 try {
157 c = cr.query(History.CONTENT_URI, new String[] { History._ID, History.VISITS },
158 History.URL + "=?", new String[] { url }, null);
159 if (c.moveToFirst()) {
160 ContentValues values = new ContentValues();
161 values.put(History.VISITS, c.getInt(1) + 1);
162 values.put(History.DATE_LAST_VISITED, System.currentTimeMillis());
163 cr.update(ContentUris.withAppendedId(History.CONTENT_URI, c.getLong(0)),
164 values, null, null);
165 } else {
166 android.provider.Browser.truncateHistory(cr);
167 ContentValues values = new ContentValues();
168 values.put(History.URL, url);
169 values.put(History.VISITS, 1);
170 values.put(History.DATE_LAST_VISITED, System.currentTimeMillis());
171 values.put(History.TITLE, url);
172 values.put(History.DATE_CREATED, 0);
173 values.put(History.USER_ENTERED, 0);
174 cr.insert(History.CONTENT_URI, values);
175 }
176 } finally {
177 if (c != null) c.close();
John Reck0ebd3ac2010-12-09 11:14:04 -0800178 }
John Reck0ebd3ac2010-12-09 11:14:04 -0800179 }
John Reck0ebd3ac2010-12-09 11:14:04 -0800180
John Recke969cc52010-12-21 17:24:43 -0800181 private void doQueryBookmarkStatus(String url, Object replyTo) {
182 ContentResolver cr = mContext.getContentResolver();
183 // Check to see if the site is bookmarked
184 Cursor cursor = null;
185 boolean isBookmark = false;
186 try {
187 cursor = mContext.getContentResolver().query(
188 BookmarkUtils.getBookmarksUri(mContext),
189 new String[] { BrowserContract.Bookmarks.URL },
190 BrowserContract.Bookmarks.URL + " == ?",
191 new String[] { url },
192 null);
193 isBookmark = cursor.moveToFirst();
194 } catch (SQLiteException e) {
195 Log.e(LOGTAG, "Error checking for bookmark: " + e);
196 } finally {
197 if (cursor != null) cursor.close();
198 }
199 CallbackContainer cc = new CallbackContainer();
200 cc.replyTo = replyTo;
201 cc.args = new Object[] { url, isBookmark };
202 mCbHandler.obtainMessage(QUERY_URL_IS_BOOKMARK, cc).sendToTarget();
203 }
204
205 private void doUpdateHistoryTitle(String url, String title) {
206 ContentResolver cr = mContext.getContentResolver();
207 ContentValues values = new ContentValues();
208 values.put(History.TITLE, title);
209 cr.update(History.CONTENT_URI, values, History.URL + "=?",
210 new String[] { url });
211 }
John Reck0ebd3ac2010-12-09 11:14:04 -0800212 }
213}