blob: a56fce8b9b0f9483a6ec31987b64cb56f6b670ac [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) {
John Reck6c702ee2011-01-07 09:41:53 -0800103 if (url == null || url.trim().length() == 0) {
104 // null or empty url is never a bookmark
105 replyTo.onQueryUrlIsBookmark(url, false);
106 return;
107 }
108 mDataHandler.sendMessage(QUERY_URL_IS_BOOKMARK, url.trim(), replyTo);
John Recke969cc52010-12-21 17:24:43 -0800109 }
110
111 // The standard Handler and Message classes don't allow the queue manipulation
112 // we want (such as peeking). So we use our own queue.
113 class DataControllerHandler extends Thread {
114 private BlockingQueue<DCMessage> mMessageQueue
115 = new LinkedBlockingQueue<DCMessage>();
John Reck0ebd3ac2010-12-09 11:14:04 -0800116
117 @Override
John Recke969cc52010-12-21 17:24:43 -0800118 public void run() {
119 super.run();
120 while (true) {
121 try {
122 handleMessage(mMessageQueue.take());
123 } catch (InterruptedException ex) {
124 break;
125 }
126 }
127 }
128
129 void sendMessage(int what, Object obj) {
130 DCMessage m = new DCMessage(what, obj);
131 mMessageQueue.add(m);
132 }
133
134 void sendMessage(int what, Object obj, Object replyTo) {
135 DCMessage m = new DCMessage(what, obj);
136 m.replyTo = replyTo;
137 mMessageQueue.add(m);
138 }
139
140 private void handleMessage(DCMessage msg) {
John Reck0ebd3ac2010-12-09 11:14:04 -0800141 switch (msg.what) {
142 case HISTORY_UPDATE_VISITED:
143 doUpdateVisitedHistory((String) msg.obj);
144 break;
145 case HISTORY_UPDATE_TITLE:
146 String[] args = (String[]) msg.obj;
147 doUpdateHistoryTitle(args[0], args[1]);
148 break;
John Recke969cc52010-12-21 17:24:43 -0800149 case QUERY_URL_IS_BOOKMARK:
150 // TODO: Look for identical messages in the queue and remove them
151 // TODO: Also, look for partial matches and merge them (such as
152 // multiple callbacks querying the same URL)
153 doQueryBookmarkStatus((String) msg.obj, msg.replyTo);
154 break;
John Reck0ebd3ac2010-12-09 11:14:04 -0800155 }
156 }
John Reck0ebd3ac2010-12-09 11:14:04 -0800157
John Recke969cc52010-12-21 17:24:43 -0800158 private void doUpdateVisitedHistory(String url) {
159 ContentResolver cr = mContext.getContentResolver();
160 Cursor c = null;
161 try {
162 c = cr.query(History.CONTENT_URI, new String[] { History._ID, History.VISITS },
163 History.URL + "=?", new String[] { url }, null);
164 if (c.moveToFirst()) {
165 ContentValues values = new ContentValues();
166 values.put(History.VISITS, c.getInt(1) + 1);
167 values.put(History.DATE_LAST_VISITED, System.currentTimeMillis());
168 cr.update(ContentUris.withAppendedId(History.CONTENT_URI, c.getLong(0)),
169 values, null, null);
170 } else {
171 android.provider.Browser.truncateHistory(cr);
172 ContentValues values = new ContentValues();
173 values.put(History.URL, url);
174 values.put(History.VISITS, 1);
175 values.put(History.DATE_LAST_VISITED, System.currentTimeMillis());
176 values.put(History.TITLE, url);
177 values.put(History.DATE_CREATED, 0);
178 values.put(History.USER_ENTERED, 0);
179 cr.insert(History.CONTENT_URI, values);
180 }
181 } finally {
182 if (c != null) c.close();
John Reck0ebd3ac2010-12-09 11:14:04 -0800183 }
John Reck0ebd3ac2010-12-09 11:14:04 -0800184 }
John Reck0ebd3ac2010-12-09 11:14:04 -0800185
John Recke969cc52010-12-21 17:24:43 -0800186 private void doQueryBookmarkStatus(String url, Object replyTo) {
187 ContentResolver cr = mContext.getContentResolver();
188 // Check to see if the site is bookmarked
189 Cursor cursor = null;
190 boolean isBookmark = false;
191 try {
192 cursor = mContext.getContentResolver().query(
193 BookmarkUtils.getBookmarksUri(mContext),
194 new String[] { BrowserContract.Bookmarks.URL },
195 BrowserContract.Bookmarks.URL + " == ?",
196 new String[] { url },
197 null);
198 isBookmark = cursor.moveToFirst();
199 } catch (SQLiteException e) {
200 Log.e(LOGTAG, "Error checking for bookmark: " + e);
201 } finally {
202 if (cursor != null) cursor.close();
203 }
204 CallbackContainer cc = new CallbackContainer();
205 cc.replyTo = replyTo;
206 cc.args = new Object[] { url, isBookmark };
207 mCbHandler.obtainMessage(QUERY_URL_IS_BOOKMARK, cc).sendToTarget();
208 }
209
210 private void doUpdateHistoryTitle(String url, String title) {
211 ContentResolver cr = mContext.getContentResolver();
212 ContentValues values = new ContentValues();
213 values.put(History.TITLE, title);
214 cr.update(History.CONTENT_URI, values, History.URL + "=?",
215 new String[] { url });
216 }
John Reck0ebd3ac2010-12-09 11:14:04 -0800217 }
218}