blob: cba16a00cbfc8a29f57921a2b394fb7d9a54b78d [file] [log] [blame]
The Android Open Source Project0c908882009-03-03 19:32:16 -08001/*
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 com.android.browser;
18
Bjorn Bringertd69f51d2010-09-13 14:06:41 +010019import com.android.browser.search.SearchEngine;
20
The Android Open Source Project0c908882009-03-03 19:32:16 -080021import android.app.SearchManager;
Christopher Tateb6a65442010-03-05 15:47:48 -080022import android.app.backup.BackupManager;
The Android Open Source Project0c908882009-03-03 19:32:16 -080023import android.content.ContentProvider;
Christopher Tatef0c36f72009-07-28 15:24:05 -070024import android.content.ContentResolver;
The Android Open Source Project0c908882009-03-03 19:32:16 -080025import android.content.ContentUris;
26import android.content.ContentValues;
27import android.content.Context;
28import android.content.Intent;
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -070029import android.content.SharedPreferences;
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -070030import android.content.SharedPreferences.Editor;
Jeff Hamilton84029622010-08-05 14:29:28 -050031import android.content.UriMatcher;
Michael Kolbfe251992010-07-08 15:41:55 -070032import android.content.res.Configuration;
The Android Open Source Project0c908882009-03-03 19:32:16 -080033import android.database.AbstractCursor;
34import android.database.Cursor;
Jeff Hamilton8b139742010-07-29 16:06:53 -050035import android.database.DatabaseUtils;
The Android Open Source Project0c908882009-03-03 19:32:16 -080036import android.database.sqlite.SQLiteDatabase;
Bjorn Bringertbcd20b32009-04-29 21:52:09 +010037import android.database.sqlite.SQLiteOpenHelper;
The Android Open Source Project0c908882009-03-03 19:32:16 -080038import android.net.Uri;
Andrei Popescu93bea962010-03-23 15:04:36 +000039import android.os.Process;
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -070040import android.preference.PreferenceManager;
The Android Open Source Project0c908882009-03-03 19:32:16 -080041import android.provider.Browser;
Christopher Tatef0c36f72009-07-28 15:24:05 -070042import android.provider.Browser.BookmarkColumns;
Jeff Hamilton84029622010-08-05 14:29:28 -050043import android.provider.Settings;
Leon Scrogginsa1cc3fd2010-02-01 16:14:11 -050044import android.speech.RecognizerResultsIntent;
Mike LeBeau21beb132009-05-13 14:57:50 -070045import android.text.TextUtils;
Bjorn Bringertbcd20b32009-04-29 21:52:09 +010046import android.util.Log;
Dianne Hackborn385effd2010-02-24 20:03:04 -080047import android.util.Patterns;
Dan Egnor5ee906c2009-11-18 12:11:49 -080048
Andrei Popescu1b20b9d2009-09-21 18:49:42 +010049import java.io.File;
50import java.io.FilenameFilter;
Leon Scroggins58d56c62010-01-28 15:12:40 -050051import java.util.ArrayList;
Bjorn Bringertbcd20b32009-04-29 21:52:09 +010052import java.util.Date;
Mike LeBeauc42f81b2009-05-14 15:04:19 -070053import java.util.regex.Matcher;
54import java.util.regex.Pattern;
The Android Open Source Project0c908882009-03-03 19:32:16 -080055
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -070056
The Android Open Source Project0c908882009-03-03 19:32:16 -080057public class BrowserProvider extends ContentProvider {
58
59 private SQLiteOpenHelper mOpenHelper;
Christopher Tate9c0dd8c2009-07-10 17:51:48 -070060 private BackupManager mBackupManager;
The Android Open Source Project0c908882009-03-03 19:32:16 -080061 private static final String sDatabaseName = "browser.db";
62 private static final String TAG = "BrowserProvider";
63 private static final String ORDER_BY = "visits DESC, date DESC";
64
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -070065 private static final String PICASA_URL = "http://picasaweb.google.com/m/" +
66 "viewer?source=androidclient";
67
The Android Open Source Project0c908882009-03-03 19:32:16 -080068 private static final String[] TABLE_NAMES = new String[] {
Bjorn Bringerta7611812010-03-24 11:12:02 +000069 "bookmarks", "searches"
The Android Open Source Project0c908882009-03-03 19:32:16 -080070 };
71 private static final String[] SUGGEST_PROJECTION = new String[] {
Leon Scrogginsb4464432009-11-25 12:37:50 -050072 "_id", "url", "title", "bookmark", "user_entered"
The Android Open Source Project0c908882009-03-03 19:32:16 -080073 };
Satish Sampath565505b2009-05-29 15:37:27 +010074 private static final String SUGGEST_SELECTION =
Leon Scrogginsb4464432009-11-25 12:37:50 -050075 "(url LIKE ? OR url LIKE ? OR url LIKE ? OR url LIKE ?"
76 + " OR title LIKE ?) AND (bookmark = 1 OR user_entered = 1)";
Leon Scrogginsbd359cc2009-05-26 15:57:35 -040077 private String[] SUGGEST_ARGS = new String[5];
The Android Open Source Project0c908882009-03-03 19:32:16 -080078
79 // shared suggestion array index, make sure to match COLUMNS
80 private static final int SUGGEST_COLUMN_INTENT_ACTION_ID = 1;
81 private static final int SUGGEST_COLUMN_INTENT_DATA_ID = 2;
82 private static final int SUGGEST_COLUMN_TEXT_1_ID = 3;
83 private static final int SUGGEST_COLUMN_TEXT_2_ID = 4;
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +000084 private static final int SUGGEST_COLUMN_TEXT_2_URL_ID = 5;
85 private static final int SUGGEST_COLUMN_ICON_1_ID = 6;
86 private static final int SUGGEST_COLUMN_ICON_2_ID = 7;
87 private static final int SUGGEST_COLUMN_QUERY_ID = 8;
Bjorn Bringert04851702009-09-22 10:36:01 +010088 private static final int SUGGEST_COLUMN_INTENT_EXTRA_DATA = 9;
The Android Open Source Project0c908882009-03-03 19:32:16 -080089
Michael Kolbfe251992010-07-08 15:41:55 -070090 // how many suggestions will be shown in dropdown
91 // 0..SHORT: filled by browser db
92 private static final int MAX_SUGGEST_SHORT_SMALL = 3;
93 // SHORT..LONG: filled by search suggestions
94 private static final int MAX_SUGGEST_LONG_SMALL = 6;
95
96 // large screen size shows more
97 private static final int MAX_SUGGEST_SHORT_LARGE = 6;
98 private static final int MAX_SUGGEST_LONG_LARGE = 9;
99
100
The Android Open Source Project0c908882009-03-03 19:32:16 -0800101 // shared suggestion columns
102 private static final String[] COLUMNS = new String[] {
103 "_id",
104 SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
105 SearchManager.SUGGEST_COLUMN_INTENT_DATA,
106 SearchManager.SUGGEST_COLUMN_TEXT_1,
107 SearchManager.SUGGEST_COLUMN_TEXT_2,
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000108 SearchManager.SUGGEST_COLUMN_TEXT_2_URL,
The Android Open Source Project0c908882009-03-03 19:32:16 -0800109 SearchManager.SUGGEST_COLUMN_ICON_1,
110 SearchManager.SUGGEST_COLUMN_ICON_2,
Mike LeBeau1ef26a32009-05-13 20:11:00 -0700111 SearchManager.SUGGEST_COLUMN_QUERY,
Bjorn Bringert04851702009-09-22 10:36:01 +0100112 SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA};
The Android Open Source Project0c908882009-03-03 19:32:16 -0800113
The Android Open Source Project0c908882009-03-03 19:32:16 -0800114
115 // make sure that these match the index of TABLE_NAMES
116 private static final int URI_MATCH_BOOKMARKS = 0;
117 private static final int URI_MATCH_SEARCHES = 1;
118 // (id % 10) should match the table name index
119 private static final int URI_MATCH_BOOKMARKS_ID = 10;
120 private static final int URI_MATCH_SEARCHES_ID = 11;
121 //
122 private static final int URI_MATCH_SUGGEST = 20;
Bjorn Bringert346dafb2009-04-29 21:41:47 +0100123 private static final int URI_MATCH_BOOKMARKS_SUGGEST = 21;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800124
125 private static final UriMatcher URI_MATCHER;
126
127 static {
128 URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
129 URI_MATCHER.addURI("browser", TABLE_NAMES[URI_MATCH_BOOKMARKS],
130 URI_MATCH_BOOKMARKS);
131 URI_MATCHER.addURI("browser", TABLE_NAMES[URI_MATCH_BOOKMARKS] + "/#",
132 URI_MATCH_BOOKMARKS_ID);
133 URI_MATCHER.addURI("browser", TABLE_NAMES[URI_MATCH_SEARCHES],
134 URI_MATCH_SEARCHES);
135 URI_MATCHER.addURI("browser", TABLE_NAMES[URI_MATCH_SEARCHES] + "/#",
136 URI_MATCH_SEARCHES_ID);
137 URI_MATCHER.addURI("browser", SearchManager.SUGGEST_URI_PATH_QUERY,
138 URI_MATCH_SUGGEST);
Bjorn Bringert346dafb2009-04-29 21:41:47 +0100139 URI_MATCHER.addURI("browser",
140 TABLE_NAMES[URI_MATCH_BOOKMARKS] + "/" + SearchManager.SUGGEST_URI_PATH_QUERY,
141 URI_MATCH_BOOKMARKS_SUGGEST);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800142 }
143
144 // 1 -> 2 add cache table
145 // 2 -> 3 update history table
146 // 3 -> 4 add passwords table
147 // 4 -> 5 add settings table
148 // 5 -> 6 ?
149 // 6 -> 7 ?
150 // 7 -> 8 drop proxy table
151 // 8 -> 9 drop settings table
152 // 9 -> 10 add form_urls and form_data
153 // 10 -> 11 add searches table
154 // 11 -> 12 modify cache table
155 // 12 -> 13 modify cache table
156 // 13 -> 14 correspond with Google Bookmarks schema
157 // 14 -> 15 move couple of tables to either browser private database or webview database
158 // 15 -> 17 Set it up for the SearchManager
159 // 17 -> 18 Added favicon in bookmarks table for Home shortcuts
160 // 18 -> 19 Remove labels table
Leon Scrogginsb6b7f9e2009-06-18 12:05:28 -0400161 // 19 -> 20 Added thumbnail
Patrick Scott3918d442009-08-04 13:22:29 -0400162 // 20 -> 21 Added touch_icon
Grace Kloba6b52a552009-09-03 16:29:56 -0700163 // 21 -> 22 Remove "clientid"
Leon Scrogginsb4464432009-11-25 12:37:50 -0500164 // 22 -> 23 Added user_entered
Magnus Lindhult655e8672010-09-29 18:36:07 +0200165 // 23 -> 24 Url not allowed to be null anymore.
166 private static final int DATABASE_VERSION = 24;
Satish Sampath565505b2009-05-29 15:37:27 +0100167
Mike LeBeauc42f81b2009-05-14 15:04:19 -0700168 // Regular expression which matches http://, followed by some stuff, followed by
169 // optionally a trailing slash, all matched as separate groups.
170 private static final Pattern STRIP_URL_PATTERN = Pattern.compile("^(http://)(.*?)(/$)?");
Satish Sampath565505b2009-05-29 15:37:27 +0100171
Bjorn Bringertd69f51d2010-09-13 14:06:41 +0100172 private BrowserSettings mSettings;
Bjorn Bringertd8b0ad22009-06-22 10:36:29 +0100173
Michael Kolbfe251992010-07-08 15:41:55 -0700174 private int mMaxSuggestionShortSize;
175 private int mMaxSuggestionLongSize;
176
The Android Open Source Project0c908882009-03-03 19:32:16 -0800177 public BrowserProvider() {
178 }
Satish Sampath565505b2009-05-29 15:37:27 +0100179
Patrick Scott43914692010-02-19 10:10:10 -0500180 // XXX: This is a major hack to remove our dependency on gsf constants and
181 // its content provider. http://b/issue?id=2425179
182 static String getClientId(ContentResolver cr) {
183 String ret = "android-google";
184 Cursor c = null;
185 try {
186 c = cr.query(Uri.parse("content://com.google.settings/partner"),
187 new String[] { "value" }, "name='client_id'", null, null);
188 if (c != null && c.moveToNext()) {
189 ret = c.getString(0);
190 }
191 } catch (RuntimeException ex) {
192 // fall through to return the default
193 } finally {
194 if (c != null) {
195 c.close();
196 }
197 }
198 return ret;
199 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800200
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700201 private static CharSequence replaceSystemPropertyInString(Context context, CharSequence srcString) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800202 StringBuffer sb = new StringBuffer();
203 int lastCharLoc = 0;
Satish Sampath565505b2009-05-29 15:37:27 +0100204
Patrick Scott43914692010-02-19 10:10:10 -0500205 final String client_id = getClientId(context.getContentResolver());
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700206
The Android Open Source Project0c908882009-03-03 19:32:16 -0800207 for (int i = 0; i < srcString.length(); ++i) {
208 char c = srcString.charAt(i);
209 if (c == '{') {
210 sb.append(srcString.subSequence(lastCharLoc, i));
211 lastCharLoc = i;
212 inner:
213 for (int j = i; j < srcString.length(); ++j) {
214 char k = srcString.charAt(j);
215 if (k == '}') {
216 String propertyKeyValue = srcString.subSequence(i + 1, j).toString();
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700217 if (propertyKeyValue.equals("CLIENT_ID")) {
218 sb.append(client_id);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800219 } else {
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700220 sb.append("unknown");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800221 }
222 lastCharLoc = j + 1;
223 i = j;
224 break inner;
225 }
226 }
227 }
228 }
229 if (srcString.length() - lastCharLoc > 0) {
230 // Put on the tail, if there is one
231 sb.append(srcString.subSequence(lastCharLoc, srcString.length()));
232 }
233 return sb;
234 }
235
236 private static class DatabaseHelper extends SQLiteOpenHelper {
237 private Context mContext;
238
239 public DatabaseHelper(Context context) {
240 super(context, sDatabaseName, null, DATABASE_VERSION);
241 mContext = context;
242 }
243
244 @Override
245 public void onCreate(SQLiteDatabase db) {
246 db.execSQL("CREATE TABLE bookmarks (" +
247 "_id INTEGER PRIMARY KEY," +
248 "title TEXT," +
Magnus Lindhult655e8672010-09-29 18:36:07 +0200249 "url TEXT NOT NULL," +
The Android Open Source Project0c908882009-03-03 19:32:16 -0800250 "visits INTEGER," +
251 "date LONG," +
252 "created LONG," +
253 "description TEXT," +
254 "bookmark INTEGER," +
Leon Scrogginsb6b7f9e2009-06-18 12:05:28 -0400255 "favicon BLOB DEFAULT NULL," +
Patrick Scott3918d442009-08-04 13:22:29 -0400256 "thumbnail BLOB DEFAULT NULL," +
Leon Scrogginsb4464432009-11-25 12:37:50 -0500257 "touch_icon BLOB DEFAULT NULL," +
258 "user_entered INTEGER" +
The Android Open Source Project0c908882009-03-03 19:32:16 -0800259 ");");
260
261 final CharSequence[] bookmarks = mContext.getResources()
262 .getTextArray(R.array.bookmarks);
263 int size = bookmarks.length;
264 try {
265 for (int i = 0; i < size; i = i + 2) {
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700266 CharSequence bookmarkDestination = replaceSystemPropertyInString(mContext, bookmarks[i + 1]);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800267 db.execSQL("INSERT INTO bookmarks (title, url, visits, " +
268 "date, created, bookmark)" + " VALUES('" +
Satish Sampath565505b2009-05-29 15:37:27 +0100269 bookmarks[i] + "', '" + bookmarkDestination +
The Android Open Source Project0c908882009-03-03 19:32:16 -0800270 "', 0, 0, 0, 1);");
271 }
272 } catch (ArrayIndexOutOfBoundsException e) {
273 }
274
275 db.execSQL("CREATE TABLE searches (" +
276 "_id INTEGER PRIMARY KEY," +
277 "search TEXT," +
278 "date LONG" +
279 ");");
280 }
281
282 @Override
283 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
284 Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
Leon Scrogginsb6b7f9e2009-06-18 12:05:28 -0400285 + newVersion);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800286 if (oldVersion == 18) {
287 db.execSQL("DROP TABLE IF EXISTS labels");
Leon Scrogginsb6b7f9e2009-06-18 12:05:28 -0400288 }
289 if (oldVersion <= 19) {
290 db.execSQL("ALTER TABLE bookmarks ADD COLUMN thumbnail BLOB DEFAULT NULL;");
Patrick Scott3918d442009-08-04 13:22:29 -0400291 }
292 if (oldVersion < 21) {
293 db.execSQL("ALTER TABLE bookmarks ADD COLUMN touch_icon BLOB DEFAULT NULL;");
Grace Kloba6b52a552009-09-03 16:29:56 -0700294 }
295 if (oldVersion < 22) {
296 db.execSQL("DELETE FROM bookmarks WHERE (bookmark = 0 AND url LIKE \"%.google.%client=ms-%\")");
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100297 removeGears();
Leon Scrogginsb4464432009-11-25 12:37:50 -0500298 }
299 if (oldVersion < 23) {
300 db.execSQL("ALTER TABLE bookmarks ADD COLUMN user_entered INTEGER;");
Magnus Lindhult655e8672010-09-29 18:36:07 +0200301 }
302 if (oldVersion < 24) {
303 /* SQLite does not support ALTER COLUMN, hence the lengthy code. */
304 db.execSQL("DELETE FROM bookmarks WHERE url IS NULL;");
305 db.execSQL("ALTER TABLE bookmarks RENAME TO bookmarks_temp;");
306 db.execSQL("CREATE TABLE bookmarks (" +
307 "_id INTEGER PRIMARY KEY," +
308 "title TEXT," +
309 "url TEXT NOT NULL," +
310 "visits INTEGER," +
311 "date LONG," +
312 "created LONG," +
313 "description TEXT," +
314 "bookmark INTEGER," +
315 "favicon BLOB DEFAULT NULL," +
316 "thumbnail BLOB DEFAULT NULL," +
317 "touch_icon BLOB DEFAULT NULL," +
318 "user_entered INTEGER" +
319 ");");
320 db.execSQL("INSERT INTO bookmarks SELECT * FROM bookmarks_temp;");
321 db.execSQL("DROP TABLE bookmarks_temp;");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800322 } else {
323 db.execSQL("DROP TABLE IF EXISTS bookmarks");
324 db.execSQL("DROP TABLE IF EXISTS searches");
325 onCreate(db);
326 }
327 }
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100328
329 private void removeGears() {
Andrei Popescu93bea962010-03-23 15:04:36 +0000330 new Thread() {
331 @Override
332 public void run() {
333 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100334 String browserDataDirString = mContext.getApplicationInfo().dataDir;
335 final String appPluginsDirString = "app_plugins";
336 final String gearsPrefix = "gears";
337 File appPluginsDir = new File(browserDataDirString + File.separator
338 + appPluginsDirString);
339 if (!appPluginsDir.exists()) {
Andrei Popescu93bea962010-03-23 15:04:36 +0000340 return;
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100341 }
342 // Delete the Gears plugin files
343 File[] gearsFiles = appPluginsDir.listFiles(new FilenameFilter() {
344 public boolean accept(File dir, String filename) {
345 return filename.startsWith(gearsPrefix);
346 }
347 });
348 for (int i = 0; i < gearsFiles.length; ++i) {
349 if (gearsFiles[i].isDirectory()) {
350 deleteDirectory(gearsFiles[i]);
351 } else {
352 gearsFiles[i].delete();
353 }
354 }
355 // Delete the Gears data files
356 File gearsDataDir = new File(browserDataDirString + File.separator
357 + gearsPrefix);
358 if (!gearsDataDir.exists()) {
Andrei Popescu93bea962010-03-23 15:04:36 +0000359 return;
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100360 }
361 deleteDirectory(gearsDataDir);
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100362 }
363
364 private void deleteDirectory(File currentDir) {
365 File[] files = currentDir.listFiles();
366 for (int i = 0; i < files.length; ++i) {
367 if (files[i].isDirectory()) {
368 deleteDirectory(files[i]);
369 }
370 files[i].delete();
371 }
372 currentDir.delete();
373 }
Andrei Popescu93bea962010-03-23 15:04:36 +0000374 }.start();
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100375 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800376 }
377
378 @Override
379 public boolean onCreate() {
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700380 final Context context = getContext();
Michael Kolbfe251992010-07-08 15:41:55 -0700381 boolean xlargeScreenSize = (context.getResources().getConfiguration().screenLayout
382 & Configuration.SCREENLAYOUT_SIZE_MASK)
383 == Configuration.SCREENLAYOUT_SIZE_XLARGE;
384 boolean isPortrait = (context.getResources().getConfiguration().orientation
385 == Configuration.ORIENTATION_PORTRAIT);
386
387
388 if (xlargeScreenSize && isPortrait) {
389 mMaxSuggestionLongSize = MAX_SUGGEST_LONG_LARGE;
390 mMaxSuggestionShortSize = MAX_SUGGEST_SHORT_LARGE;
391 } else {
392 mMaxSuggestionLongSize = MAX_SUGGEST_LONG_SMALL;
393 mMaxSuggestionShortSize = MAX_SUGGEST_SHORT_SMALL;
394 }
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700395 mOpenHelper = new DatabaseHelper(context);
Christopher Tate9c0dd8c2009-07-10 17:51:48 -0700396 mBackupManager = new BackupManager(context);
Satish Sampath565505b2009-05-29 15:37:27 +0100397 // we added "picasa web album" into default bookmarks for version 19.
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700398 // To avoid erasing the bookmark table, we added it explicitly for
399 // version 18 and 19 as in the other cases, we will erase the table.
400 if (DATABASE_VERSION == 18 || DATABASE_VERSION == 19) {
401 SharedPreferences p = PreferenceManager
402 .getDefaultSharedPreferences(context);
403 boolean fix = p.getBoolean("fix_picasa", true);
404 if (fix) {
405 fixPicasaBookmark();
406 Editor ed = p.edit();
407 ed.putBoolean("fix_picasa", false);
Brad Fitzpatrick1a6e0e82010-09-01 16:29:03 -0700408 ed.apply();
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700409 }
410 }
Bjorn Bringertd69f51d2010-09-13 14:06:41 +0100411 mSettings = BrowserSettings.getInstance();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800412 return true;
413 }
414
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700415 private void fixPicasaBookmark() {
416 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
417 Cursor cursor = db.rawQuery("SELECT _id FROM bookmarks WHERE " +
418 "bookmark = 1 AND url = ?", new String[] { PICASA_URL });
419 try {
420 if (!cursor.moveToFirst()) {
421 // set "created" so that it will be on the top of the list
422 db.execSQL("INSERT INTO bookmarks (title, url, visits, " +
423 "date, created, bookmark)" + " VALUES('" +
424 getContext().getString(R.string.picasa) + "', '"
425 + PICASA_URL + "', 0, 0, " + new Date().getTime()
426 + ", 1);");
427 }
428 } finally {
429 if (cursor != null) {
430 cursor.close();
431 }
432 }
433 }
434
The Android Open Source Project0c908882009-03-03 19:32:16 -0800435 /*
436 * Subclass AbstractCursor so we can combine multiple Cursors and add
Grace Kloba391df7c2010-03-01 19:51:49 -0800437 * "Search the web".
The Android Open Source Project0c908882009-03-03 19:32:16 -0800438 * Here are the rules.
Satish Sampath565505b2009-05-29 15:37:27 +0100439 * 1. We only have MAX_SUGGESTION_LONG_ENTRIES in the list plus
Grace Kloba391df7c2010-03-01 19:51:49 -0800440 * "Search the web";
441 * 2. If bookmark/history entries has a match, "Search the web" shows up at
442 * the second place. Otherwise, "Search the web" shows up at the first
443 * place.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800444 */
445 private class MySuggestionCursor extends AbstractCursor {
446 private Cursor mHistoryCursor;
447 private Cursor mSuggestCursor;
448 private int mHistoryCount;
449 private int mSuggestionCount;
Grace Klobad3992d42010-01-28 11:44:38 -0800450 private boolean mIncludeWebSearch;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800451 private String mString;
Satish Sampath565505b2009-05-29 15:37:27 +0100452 private int mSuggestText1Id;
453 private int mSuggestText2Id;
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000454 private int mSuggestText2UrlId;
Satish Sampath565505b2009-05-29 15:37:27 +0100455 private int mSuggestQueryId;
Bjorn Bringert04851702009-09-22 10:36:01 +0100456 private int mSuggestIntentExtraDataId;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800457
458 public MySuggestionCursor(Cursor hc, Cursor sc, String string) {
459 mHistoryCursor = hc;
460 mSuggestCursor = sc;
Grace Klobaf9b04272010-06-15 13:36:22 -0700461 mHistoryCount = hc != null ? hc.getCount() : 0;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800462 mSuggestionCount = sc != null ? sc.getCount() : 0;
Michael Kolbfe251992010-07-08 15:41:55 -0700463 if (mSuggestionCount > (mMaxSuggestionLongSize - mHistoryCount)) {
464 mSuggestionCount = mMaxSuggestionLongSize - mHistoryCount;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800465 }
466 mString = string;
Grace Klobad3992d42010-01-28 11:44:38 -0800467 mIncludeWebSearch = string.length() > 0;
Satish Sampath565505b2009-05-29 15:37:27 +0100468
469 // Some web suggest providers only give suggestions and have no description string for
470 // items. The order of the result columns may be different as well. So retrieve the
471 // column indices for the fields we need now and check before using below.
472 if (mSuggestCursor == null) {
473 mSuggestText1Id = -1;
474 mSuggestText2Id = -1;
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000475 mSuggestText2UrlId = -1;
Satish Sampath565505b2009-05-29 15:37:27 +0100476 mSuggestQueryId = -1;
Bjorn Bringert04851702009-09-22 10:36:01 +0100477 mSuggestIntentExtraDataId = -1;
Satish Sampath565505b2009-05-29 15:37:27 +0100478 } else {
479 mSuggestText1Id = mSuggestCursor.getColumnIndex(
480 SearchManager.SUGGEST_COLUMN_TEXT_1);
481 mSuggestText2Id = mSuggestCursor.getColumnIndex(
482 SearchManager.SUGGEST_COLUMN_TEXT_2);
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000483 mSuggestText2UrlId = mSuggestCursor.getColumnIndex(
484 SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
Satish Sampath565505b2009-05-29 15:37:27 +0100485 mSuggestQueryId = mSuggestCursor.getColumnIndex(
486 SearchManager.SUGGEST_COLUMN_QUERY);
Bjorn Bringert04851702009-09-22 10:36:01 +0100487 mSuggestIntentExtraDataId = mSuggestCursor.getColumnIndex(
488 SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
Satish Sampath565505b2009-05-29 15:37:27 +0100489 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800490 }
491
492 @Override
493 public boolean onMove(int oldPosition, int newPosition) {
494 if (mHistoryCursor == null) {
495 return false;
496 }
Grace Klobad3992d42010-01-28 11:44:38 -0800497 if (mIncludeWebSearch) {
Grace Kloba391df7c2010-03-01 19:51:49 -0800498 if (mHistoryCount == 0 && newPosition == 0) {
Grace Klobad3992d42010-01-28 11:44:38 -0800499 return true;
Grace Kloba391df7c2010-03-01 19:51:49 -0800500 } else if (mHistoryCount > 0) {
501 if (newPosition == 0) {
502 mHistoryCursor.moveToPosition(0);
503 return true;
504 } else if (newPosition == 1) {
505 return true;
506 }
Grace Klobad3992d42010-01-28 11:44:38 -0800507 }
Grace Kloba391df7c2010-03-01 19:51:49 -0800508 newPosition--;
Grace Klobad3992d42010-01-28 11:44:38 -0800509 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800510 if (mHistoryCount > newPosition) {
511 mHistoryCursor.moveToPosition(newPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800512 } else {
Grace Klobad3992d42010-01-28 11:44:38 -0800513 mSuggestCursor.moveToPosition(newPosition - mHistoryCount);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800514 }
515 return true;
516 }
517
518 @Override
519 public int getCount() {
Grace Klobad3992d42010-01-28 11:44:38 -0800520 if (mIncludeWebSearch) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800521 return mHistoryCount + mSuggestionCount + 1;
522 } else {
523 return mHistoryCount + mSuggestionCount;
524 }
525 }
526
527 @Override
528 public String[] getColumnNames() {
529 return COLUMNS;
530 }
Satish Sampath565505b2009-05-29 15:37:27 +0100531
The Android Open Source Project0c908882009-03-03 19:32:16 -0800532 @Override
533 public String getString(int columnIndex) {
534 if ((mPos != -1 && mHistoryCursor != null)) {
Grace Kloba391df7c2010-03-01 19:51:49 -0800535 int type = -1; // 0: web search; 1: history; 2: suggestion
536 if (mIncludeWebSearch) {
537 if (mHistoryCount == 0 && mPos == 0) {
538 type = 0;
539 } else if (mHistoryCount > 0) {
540 if (mPos == 0) {
541 type = 1;
542 } else if (mPos == 1) {
543 type = 0;
544 }
545 }
546 if (type == -1) type = (mPos - 1) < mHistoryCount ? 1 : 2;
547 } else {
548 type = mPos < mHistoryCount ? 1 : 2;
549 }
550
The Android Open Source Project0c908882009-03-03 19:32:16 -0800551 switch(columnIndex) {
552 case SUGGEST_COLUMN_INTENT_ACTION_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800553 if (type == 1) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800554 return Intent.ACTION_VIEW;
555 } else {
556 return Intent.ACTION_SEARCH;
557 }
558
559 case SUGGEST_COLUMN_INTENT_DATA_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800560 if (type == 1) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800561 return mHistoryCursor.getString(1);
562 } else {
563 return null;
564 }
565
566 case SUGGEST_COLUMN_TEXT_1_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800567 if (type == 0) {
Grace Klobad3992d42010-01-28 11:44:38 -0800568 return mString;
Grace Kloba391df7c2010-03-01 19:51:49 -0800569 } else if (type == 1) {
Mike LeBeau1ef26a32009-05-13 20:11:00 -0700570 return getHistoryTitle();
Grace Klobad3992d42010-01-28 11:44:38 -0800571 } else {
Satish Sampath565505b2009-05-29 15:37:27 +0100572 if (mSuggestText1Id == -1) return null;
573 return mSuggestCursor.getString(mSuggestText1Id);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800574 }
575
576 case SUGGEST_COLUMN_TEXT_2_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800577 if (type == 0) {
Grace Klobad3992d42010-01-28 11:44:38 -0800578 return getContext().getString(R.string.search_the_web);
Grace Kloba391df7c2010-03-01 19:51:49 -0800579 } else if (type == 1) {
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000580 return null; // Use TEXT_2_URL instead
Grace Klobad3992d42010-01-28 11:44:38 -0800581 } else {
Satish Sampath565505b2009-05-29 15:37:27 +0100582 if (mSuggestText2Id == -1) return null;
583 return mSuggestCursor.getString(mSuggestText2Id);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800584 }
585
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000586 case SUGGEST_COLUMN_TEXT_2_URL_ID:
587 if (type == 0) {
588 return null;
589 } else if (type == 1) {
590 return getHistoryUrl();
591 } else {
592 if (mSuggestText2UrlId == -1) return null;
593 return mSuggestCursor.getString(mSuggestText2UrlId);
594 }
595
The Android Open Source Project0c908882009-03-03 19:32:16 -0800596 case SUGGEST_COLUMN_ICON_1_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800597 if (type == 1) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800598 if (mHistoryCursor.getInt(3) == 1) {
Leon Scroggins31887fd2009-05-18 16:58:08 -0400599 return Integer.valueOf(
The Android Open Source Project0c908882009-03-03 19:32:16 -0800600 R.drawable.ic_search_category_bookmark)
601 .toString();
602 } else {
Leon Scroggins31887fd2009-05-18 16:58:08 -0400603 return Integer.valueOf(
The Android Open Source Project0c908882009-03-03 19:32:16 -0800604 R.drawable.ic_search_category_history)
605 .toString();
606 }
607 } else {
Leon Scroggins31887fd2009-05-18 16:58:08 -0400608 return Integer.valueOf(
The Android Open Source Project0c908882009-03-03 19:32:16 -0800609 R.drawable.ic_search_category_suggest)
610 .toString();
611 }
612
613 case SUGGEST_COLUMN_ICON_2_ID:
Leon Scroggins31887fd2009-05-18 16:58:08 -0400614 return "0";
The Android Open Source Project0c908882009-03-03 19:32:16 -0800615
616 case SUGGEST_COLUMN_QUERY_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800617 if (type == 0) {
Grace Klobad3992d42010-01-28 11:44:38 -0800618 return mString;
Grace Kloba391df7c2010-03-01 19:51:49 -0800619 } else if (type == 1) {
Mike LeBeau2af73052009-06-23 17:36:59 -0700620 // Return the url in the intent query column. This is ignored
621 // within the browser because our searchable is set to
622 // android:searchMode="queryRewriteFromData", but it is used by
623 // global search for query rewriting.
624 return mHistoryCursor.getString(1);
Grace Klobad3992d42010-01-28 11:44:38 -0800625 } else {
Satish Sampath565505b2009-05-29 15:37:27 +0100626 if (mSuggestQueryId == -1) return null;
627 return mSuggestCursor.getString(mSuggestQueryId);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800628 }
Satish Sampath565505b2009-05-29 15:37:27 +0100629
Bjorn Bringert04851702009-09-22 10:36:01 +0100630 case SUGGEST_COLUMN_INTENT_EXTRA_DATA:
Grace Kloba391df7c2010-03-01 19:51:49 -0800631 if (type == 0) {
Bjorn Bringert04851702009-09-22 10:36:01 +0100632 return null;
Grace Kloba391df7c2010-03-01 19:51:49 -0800633 } else if (type == 1) {
Grace Klobad3992d42010-01-28 11:44:38 -0800634 return null;
635 } else {
Bjorn Bringert04851702009-09-22 10:36:01 +0100636 if (mSuggestIntentExtraDataId == -1) return null;
637 return mSuggestCursor.getString(mSuggestIntentExtraDataId);
Bjorn Bringert04851702009-09-22 10:36:01 +0100638 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800639 }
640 }
641 return null;
642 }
643
644 @Override
645 public double getDouble(int column) {
646 throw new UnsupportedOperationException();
647 }
648
649 @Override
650 public float getFloat(int column) {
651 throw new UnsupportedOperationException();
652 }
653
654 @Override
655 public int getInt(int column) {
656 throw new UnsupportedOperationException();
657 }
658
659 @Override
660 public long getLong(int column) {
661 if ((mPos != -1) && column == 0) {
662 return mPos; // use row# as the _Id
663 }
664 throw new UnsupportedOperationException();
665 }
666
667 @Override
668 public short getShort(int column) {
669 throw new UnsupportedOperationException();
670 }
671
672 @Override
673 public boolean isNull(int column) {
674 throw new UnsupportedOperationException();
675 }
676
677 // TODO Temporary change, finalize after jq's changes go in
Michael Kolbfe251992010-07-08 15:41:55 -0700678 @Override
The Android Open Source Project0c908882009-03-03 19:32:16 -0800679 public void deactivate() {
680 if (mHistoryCursor != null) {
681 mHistoryCursor.deactivate();
682 }
683 if (mSuggestCursor != null) {
684 mSuggestCursor.deactivate();
685 }
686 super.deactivate();
687 }
688
Michael Kolbfe251992010-07-08 15:41:55 -0700689 @Override
The Android Open Source Project0c908882009-03-03 19:32:16 -0800690 public boolean requery() {
691 return (mHistoryCursor != null ? mHistoryCursor.requery() : false) |
692 (mSuggestCursor != null ? mSuggestCursor.requery() : false);
693 }
694
695 // TODO Temporary change, finalize after jq's changes go in
Michael Kolbfe251992010-07-08 15:41:55 -0700696 @Override
The Android Open Source Project0c908882009-03-03 19:32:16 -0800697 public void close() {
698 super.close();
699 if (mHistoryCursor != null) {
700 mHistoryCursor.close();
701 mHistoryCursor = null;
702 }
703 if (mSuggestCursor != null) {
704 mSuggestCursor.close();
705 mSuggestCursor = null;
706 }
707 }
Satish Sampath565505b2009-05-29 15:37:27 +0100708
Mike LeBeau21beb132009-05-13 14:57:50 -0700709 /**
710 * Provides the title (text line 1) for a browser suggestion, which should be the
711 * webpage title. If the webpage title is empty, returns the stripped url instead.
Satish Sampath565505b2009-05-29 15:37:27 +0100712 *
Mike LeBeau21beb132009-05-13 14:57:50 -0700713 * @return the title string to use
714 */
Mike LeBeau1ef26a32009-05-13 20:11:00 -0700715 private String getHistoryTitle() {
716 String title = mHistoryCursor.getString(2 /* webpage title */);
Mike LeBeau21beb132009-05-13 14:57:50 -0700717 if (TextUtils.isEmpty(title) || TextUtils.getTrimmedLength(title) == 0) {
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000718 title = stripUrl(mHistoryCursor.getString(1 /* url */));
Mike LeBeau21beb132009-05-13 14:57:50 -0700719 }
720 return title;
721 }
Satish Sampath565505b2009-05-29 15:37:27 +0100722
Mike LeBeau21beb132009-05-13 14:57:50 -0700723 /**
724 * Provides the subtitle (text line 2) for a browser suggestion, which should be the
725 * webpage url. If the webpage title is empty, then the url should go in the title
726 * instead, and the subtitle should be empty, so this would return null.
Satish Sampath565505b2009-05-29 15:37:27 +0100727 *
Mike LeBeau21beb132009-05-13 14:57:50 -0700728 * @return the subtitle string to use, or null if none
729 */
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000730 private String getHistoryUrl() {
Mike LeBeau1ef26a32009-05-13 20:11:00 -0700731 String title = mHistoryCursor.getString(2 /* webpage title */);
Mike LeBeau21beb132009-05-13 14:57:50 -0700732 if (TextUtils.isEmpty(title) || TextUtils.getTrimmedLength(title) == 0) {
733 return null;
734 } else {
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000735 return stripUrl(mHistoryCursor.getString(1 /* url */));
Mike LeBeau21beb132009-05-13 14:57:50 -0700736 }
737 }
Satish Sampath565505b2009-05-29 15:37:27 +0100738
The Android Open Source Project0c908882009-03-03 19:32:16 -0800739 }
740
Leon Scroggins58d56c62010-01-28 15:12:40 -0500741 private static class ResultsCursor extends AbstractCursor {
742 // Array indices for RESULTS_COLUMNS
743 private static final int RESULT_ACTION_ID = 1;
744 private static final int RESULT_DATA_ID = 2;
745 private static final int RESULT_TEXT_ID = 3;
746 private static final int RESULT_ICON_ID = 4;
747 private static final int RESULT_EXTRA_ID = 5;
748
749 private static final String[] RESULTS_COLUMNS = new String[] {
750 "_id",
751 SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
752 SearchManager.SUGGEST_COLUMN_INTENT_DATA,
753 SearchManager.SUGGEST_COLUMN_TEXT_1,
754 SearchManager.SUGGEST_COLUMN_ICON_1,
755 SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA
756 };
757 private final ArrayList<String> mResults;
758 public ResultsCursor(ArrayList<String> results) {
759 mResults = results;
760 }
Michael Kolbfe251992010-07-08 15:41:55 -0700761 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500762 public int getCount() { return mResults.size(); }
763
Michael Kolbfe251992010-07-08 15:41:55 -0700764 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500765 public String[] getColumnNames() {
766 return RESULTS_COLUMNS;
767 }
768
Michael Kolbfe251992010-07-08 15:41:55 -0700769 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500770 public String getString(int column) {
771 switch (column) {
772 case RESULT_ACTION_ID:
Leon Scrogginsa1cc3fd2010-02-01 16:14:11 -0500773 return RecognizerResultsIntent.ACTION_VOICE_SEARCH_RESULTS;
Leon Scroggins58d56c62010-01-28 15:12:40 -0500774 case RESULT_TEXT_ID:
775 // The data is used when the phone is in landscape mode. We
776 // still want to show the result string.
777 case RESULT_DATA_ID:
778 return mResults.get(mPos);
779 case RESULT_EXTRA_ID:
780 // The Intent's extra data will store the index into
781 // mResults so the BrowserActivity will know which result to
782 // use.
783 return Integer.toString(mPos);
784 case RESULT_ICON_ID:
785 return Integer.valueOf(R.drawable.magnifying_glass)
786 .toString();
787 default:
788 return null;
789 }
790 }
Michael Kolbfe251992010-07-08 15:41:55 -0700791 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500792 public short getShort(int column) {
793 throw new UnsupportedOperationException();
794 }
Michael Kolbfe251992010-07-08 15:41:55 -0700795 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500796 public int getInt(int column) {
797 throw new UnsupportedOperationException();
798 }
Michael Kolbfe251992010-07-08 15:41:55 -0700799 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500800 public long getLong(int column) {
801 if ((mPos != -1) && column == 0) {
802 return mPos; // use row# as the _id
803 }
804 throw new UnsupportedOperationException();
805 }
Michael Kolbfe251992010-07-08 15:41:55 -0700806 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500807 public float getFloat(int column) {
808 throw new UnsupportedOperationException();
809 }
Michael Kolbfe251992010-07-08 15:41:55 -0700810 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500811 public double getDouble(int column) {
812 throw new UnsupportedOperationException();
813 }
Michael Kolbfe251992010-07-08 15:41:55 -0700814 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500815 public boolean isNull(int column) {
816 throw new UnsupportedOperationException();
817 }
818 }
819
Jeff Hamilton8b139742010-07-29 16:06:53 -0500820 /** Contains custom suggestions results set by the UI */
Leon Scroggins58d56c62010-01-28 15:12:40 -0500821 private ResultsCursor mResultsCursor;
Jeff Hamilton8b139742010-07-29 16:06:53 -0500822 /** Locks access to {@link #mResultsCursor} */
823 private Object mResultsCursorLock = new Object();
Leon Scroggins58d56c62010-01-28 15:12:40 -0500824
825 /**
826 * Provide a set of results to be returned to query, intended to be used
827 * by the SearchDialog when the BrowserActivity is in voice search mode.
828 * @param results Strings to display in the dropdown from the SearchDialog
829 */
830 /* package */ void setQueryResults(ArrayList<String> results) {
Jeff Hamilton8b139742010-07-29 16:06:53 -0500831 synchronized (mResultsCursorLock) {
832 if (results == null) {
833 mResultsCursor = null;
834 } else {
835 mResultsCursor = new ResultsCursor(results);
836 }
Leon Scroggins58d56c62010-01-28 15:12:40 -0500837 }
838 }
839
The Android Open Source Project0c908882009-03-03 19:32:16 -0800840 @Override
841 public Cursor query(Uri url, String[] projectionIn, String selection,
Satish Sampath565505b2009-05-29 15:37:27 +0100842 String[] selectionArgs, String sortOrder)
The Android Open Source Project0c908882009-03-03 19:32:16 -0800843 throws IllegalStateException {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800844 int match = URI_MATCHER.match(url);
845 if (match == -1) {
846 throw new IllegalArgumentException("Unknown URL");
847 }
Jeff Hamilton8b139742010-07-29 16:06:53 -0500848
849 // If results for the suggestion are already ready just return them directly
850 synchronized (mResultsCursorLock) {
851 if (match == URI_MATCH_SUGGEST && mResultsCursor != null) {
852 Cursor results = mResultsCursor;
853 mResultsCursor = null;
854 return results;
855 }
Leon Scroggins58d56c62010-01-28 15:12:40 -0500856 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800857
Bjorn Bringert346dafb2009-04-29 21:41:47 +0100858 if (match == URI_MATCH_SUGGEST || match == URI_MATCH_BOOKMARKS_SUGGEST) {
Jeff Hamilton8b139742010-07-29 16:06:53 -0500859 // Handle suggestions
860 return doSuggestQuery(selection, selectionArgs, match == URI_MATCH_BOOKMARKS_SUGGEST);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800861 }
862
863 String[] projection = null;
864 if (projectionIn != null && projectionIn.length > 0) {
865 projection = new String[projectionIn.length + 1];
866 System.arraycopy(projectionIn, 0, projection, 0, projectionIn.length);
867 projection[projectionIn.length] = "_id AS _id";
868 }
869
Jeff Hamilton8b139742010-07-29 16:06:53 -0500870 String whereClause = null;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800871 if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) {
Jeff Hamilton8b139742010-07-29 16:06:53 -0500872 whereClause = "_id = " + url.getPathSegments().get(1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800873 }
874
Jeff Hamilton8b139742010-07-29 16:06:53 -0500875 Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_NAMES[match % 10], projection,
876 DatabaseUtils.concatenateWhere(whereClause, selection), selectionArgs,
877 null, null, sortOrder, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800878 c.setNotificationUri(getContext().getContentResolver(), url);
879 return c;
880 }
881
Jeff Hamilton8b139742010-07-29 16:06:53 -0500882 private Cursor doSuggestQuery(String selection, String[] selectionArgs, boolean bookmarksOnly) {
883 String suggestSelection;
884 String [] myArgs;
885 if (selectionArgs[0] == null || selectionArgs[0].equals("")) {
886 return new MySuggestionCursor(null, null, "");
887 } else {
888 String like = selectionArgs[0] + "%";
889 if (selectionArgs[0].startsWith("http")
890 || selectionArgs[0].startsWith("file")) {
891 myArgs = new String[1];
892 myArgs[0] = like;
893 suggestSelection = selection;
894 } else {
895 SUGGEST_ARGS[0] = "http://" + like;
896 SUGGEST_ARGS[1] = "http://www." + like;
897 SUGGEST_ARGS[2] = "https://" + like;
898 SUGGEST_ARGS[3] = "https://www." + like;
899 // To match against titles.
900 SUGGEST_ARGS[4] = like;
901 myArgs = SUGGEST_ARGS;
902 suggestSelection = SUGGEST_SELECTION;
903 }
904 }
905
906 Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_NAMES[URI_MATCH_BOOKMARKS],
907 SUGGEST_PROJECTION, suggestSelection, myArgs, null, null,
908 ORDER_BY, Integer.toString(mMaxSuggestionLongSize));
909
910 if (bookmarksOnly || Patterns.WEB_URL.matcher(selectionArgs[0]).matches()) {
911 return new MySuggestionCursor(c, null, "");
912 } else {
Bjorn Bringertd69f51d2010-09-13 14:06:41 +0100913 // get search suggestions if there is still space in the list
914 if (myArgs != null && myArgs.length > 1
Leon Scroggins III4fb6cc92010-09-17 15:01:28 -0400915 && c.getCount() < (MAX_SUGGEST_SHORT_SMALL - 1)) {
Bjorn Bringertd69f51d2010-09-13 14:06:41 +0100916 SearchEngine searchEngine = mSettings.getSearchEngine();
917 if (searchEngine != null && searchEngine.supportsSuggestions()) {
918 Cursor sc = searchEngine.getSuggestions(getContext(), selectionArgs[0]);
919 return new MySuggestionCursor(c, sc, selectionArgs[0]);
920 }
Jeff Hamilton8b139742010-07-29 16:06:53 -0500921 }
922 return new MySuggestionCursor(c, null, selectionArgs[0]);
923 }
924 }
925
The Android Open Source Project0c908882009-03-03 19:32:16 -0800926 @Override
927 public String getType(Uri url) {
928 int match = URI_MATCHER.match(url);
929 switch (match) {
930 case URI_MATCH_BOOKMARKS:
931 return "vnd.android.cursor.dir/bookmark";
932
933 case URI_MATCH_BOOKMARKS_ID:
934 return "vnd.android.cursor.item/bookmark";
935
936 case URI_MATCH_SEARCHES:
937 return "vnd.android.cursor.dir/searches";
938
939 case URI_MATCH_SEARCHES_ID:
940 return "vnd.android.cursor.item/searches";
941
942 case URI_MATCH_SUGGEST:
943 return SearchManager.SUGGEST_MIME_TYPE;
944
945 default:
946 throw new IllegalArgumentException("Unknown URL");
947 }
948 }
949
950 @Override
951 public Uri insert(Uri url, ContentValues initialValues) {
Christopher Tate9c0dd8c2009-07-10 17:51:48 -0700952 boolean isBookmarkTable = false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800953 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
954
955 int match = URI_MATCHER.match(url);
956 Uri uri = null;
957 switch (match) {
958 case URI_MATCH_BOOKMARKS: {
959 // Insert into the bookmarks table
960 long rowID = db.insert(TABLE_NAMES[URI_MATCH_BOOKMARKS], "url",
961 initialValues);
962 if (rowID > 0) {
963 uri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI,
964 rowID);
965 }
Christopher Tate9c0dd8c2009-07-10 17:51:48 -0700966 isBookmarkTable = true;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800967 break;
968 }
969
970 case URI_MATCH_SEARCHES: {
971 // Insert into the searches table
972 long rowID = db.insert(TABLE_NAMES[URI_MATCH_SEARCHES], "url",
973 initialValues);
974 if (rowID > 0) {
975 uri = ContentUris.withAppendedId(Browser.SEARCHES_URI,
976 rowID);
977 }
978 break;
979 }
980
981 default:
982 throw new IllegalArgumentException("Unknown URL");
983 }
984
985 if (uri == null) {
986 throw new IllegalArgumentException("Unknown URL");
987 }
988 getContext().getContentResolver().notifyChange(uri, null);
Christopher Tate9c0dd8c2009-07-10 17:51:48 -0700989
Christopher Tatef0c36f72009-07-28 15:24:05 -0700990 // Back up the new bookmark set if we just inserted one.
991 // A row created when bookmarks are added from scratch will have
992 // bookmark=1 in the initial value set.
993 if (isBookmarkTable
994 && initialValues.containsKey(BookmarkColumns.BOOKMARK)
995 && initialValues.getAsInteger(BookmarkColumns.BOOKMARK) != 0) {
Christopher Tate9c0dd8c2009-07-10 17:51:48 -0700996 mBackupManager.dataChanged();
997 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800998 return uri;
999 }
1000
1001 @Override
1002 public int delete(Uri url, String where, String[] whereArgs) {
1003 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1004
1005 int match = URI_MATCHER.match(url);
1006 if (match == -1 || match == URI_MATCH_SUGGEST) {
1007 throw new IllegalArgumentException("Unknown URL");
1008 }
1009
Christopher Tatef0c36f72009-07-28 15:24:05 -07001010 // need to know whether it's the bookmarks table for a couple of reasons
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001011 boolean isBookmarkTable = (match == URI_MATCH_BOOKMARKS_ID);
Christopher Tatef0c36f72009-07-28 15:24:05 -07001012 String id = null;
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001013
1014 if (isBookmarkTable || match == URI_MATCH_SEARCHES_ID) {
The Android Open Source Project0c908882009-03-03 19:32:16 -08001015 StringBuilder sb = new StringBuilder();
1016 if (where != null && where.length() > 0) {
1017 sb.append("( ");
1018 sb.append(where);
1019 sb.append(" ) AND ");
1020 }
Christopher Tatef0c36f72009-07-28 15:24:05 -07001021 id = url.getPathSegments().get(1);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001022 sb.append("_id = ");
Christopher Tatef0c36f72009-07-28 15:24:05 -07001023 sb.append(id);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001024 where = sb.toString();
1025 }
1026
Christopher Tatef0c36f72009-07-28 15:24:05 -07001027 ContentResolver cr = getContext().getContentResolver();
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001028
Christopher Tatef0c36f72009-07-28 15:24:05 -07001029 // we'lll need to back up the bookmark set if we are about to delete one
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001030 if (isBookmarkTable) {
Christopher Tatef0c36f72009-07-28 15:24:05 -07001031 Cursor cursor = cr.query(Browser.BOOKMARKS_URI,
1032 new String[] { BookmarkColumns.BOOKMARK },
1033 "_id = " + id, null, null);
1034 if (cursor.moveToNext()) {
1035 if (cursor.getInt(0) != 0) {
1036 // yep, this record is a bookmark
1037 mBackupManager.dataChanged();
1038 }
1039 }
1040 cursor.close();
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001041 }
Christopher Tatef0c36f72009-07-28 15:24:05 -07001042
1043 int count = db.delete(TABLE_NAMES[match % 10], where, whereArgs);
1044 cr.notifyChange(url, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001045 return count;
1046 }
1047
1048 @Override
1049 public int update(Uri url, ContentValues values, String where,
1050 String[] whereArgs) {
1051 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1052
1053 int match = URI_MATCHER.match(url);
1054 if (match == -1 || match == URI_MATCH_SUGGEST) {
1055 throw new IllegalArgumentException("Unknown URL");
1056 }
1057
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001058 if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) {
The Android Open Source Project0c908882009-03-03 19:32:16 -08001059 StringBuilder sb = new StringBuilder();
1060 if (where != null && where.length() > 0) {
1061 sb.append("( ");
1062 sb.append(where);
1063 sb.append(" ) AND ");
1064 }
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001065 String id = url.getPathSegments().get(1);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001066 sb.append("_id = ");
Christopher Tatef0c36f72009-07-28 15:24:05 -07001067 sb.append(id);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001068 where = sb.toString();
1069 }
1070
Christopher Tatef0c36f72009-07-28 15:24:05 -07001071 ContentResolver cr = getContext().getContentResolver();
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001072
Christopher Tatef0c36f72009-07-28 15:24:05 -07001073 // Not all bookmark-table updates should be backed up. Look to see
1074 // whether we changed the title, url, or "is a bookmark" state, and
1075 // request a backup if so.
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001076 if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_BOOKMARKS) {
1077 boolean changingBookmarks = false;
Christopher Tatef0c36f72009-07-28 15:24:05 -07001078 // Alterations to the bookmark field inherently change the bookmark
1079 // set, so we don't need to query the record; we know a priori that
1080 // we will need to back up this change.
1081 if (values.containsKey(BookmarkColumns.BOOKMARK)) {
1082 changingBookmarks = true;
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001083 } else if ((values.containsKey(BookmarkColumns.TITLE)
1084 || values.containsKey(BookmarkColumns.URL))
1085 && values.containsKey(BookmarkColumns._ID)) {
1086 // If a title or URL has been changed, check to see if it is to
1087 // a bookmark. The ID should have been included in the update,
1088 // so use it.
Christopher Tatef0c36f72009-07-28 15:24:05 -07001089 Cursor cursor = cr.query(Browser.BOOKMARKS_URI,
1090 new String[] { BookmarkColumns.BOOKMARK },
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001091 BookmarkColumns._ID + " = "
1092 + values.getAsString(BookmarkColumns._ID), null, null);
Christopher Tatef0c36f72009-07-28 15:24:05 -07001093 if (cursor.moveToNext()) {
1094 changingBookmarks = (cursor.getInt(0) != 0);
1095 }
1096 cursor.close();
1097 }
1098
1099 // if this *is* a bookmark row we're altering, we need to back it up.
1100 if (changingBookmarks) {
1101 mBackupManager.dataChanged();
1102 }
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001103 }
Christopher Tatef0c36f72009-07-28 15:24:05 -07001104
1105 int ret = db.update(TABLE_NAMES[match % 10], values, where, whereArgs);
1106 cr.notifyChange(url, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001107 return ret;
1108 }
Satish Sampath565505b2009-05-29 15:37:27 +01001109
Mike LeBeauc42f81b2009-05-14 15:04:19 -07001110 /**
1111 * Strips the provided url of preceding "http://" and any trailing "/". Does not
1112 * strip "https://". If the provided string cannot be stripped, the original string
1113 * is returned.
Satish Sampath565505b2009-05-29 15:37:27 +01001114 *
Mike LeBeauc42f81b2009-05-14 15:04:19 -07001115 * TODO: Put this in TextUtils to be used by other packages doing something similar.
Satish Sampath565505b2009-05-29 15:37:27 +01001116 *
Mike LeBeauc42f81b2009-05-14 15:04:19 -07001117 * @param url a url to strip, like "http://www.google.com/"
1118 * @return a stripped url like "www.google.com", or the original string if it could
1119 * not be stripped
1120 */
1121 private static String stripUrl(String url) {
1122 if (url == null) return null;
1123 Matcher m = STRIP_URL_PATTERN.matcher(url);
1124 if (m.matches() && m.groupCount() == 3) {
1125 return m.group(2);
1126 } else {
1127 return url;
1128 }
1129 }
1130
Michael Kolbfe251992010-07-08 15:41:55 -07001131 public static Cursor getBookmarksSuggestions(ContentResolver cr, String constraint) {
1132 Uri uri = Uri.parse("content://browser/" + SearchManager.SUGGEST_URI_PATH_QUERY);
1133 return cr.query(uri, SUGGEST_PROJECTION, SUGGEST_SELECTION,
1134 new String[] { constraint }, ORDER_BY);
1135 }
1136
The Android Open Source Project0c908882009-03-03 19:32:16 -08001137}