blob: f69665cc625912cae3b1354b507a3055dfffe7e0 [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";
Reena Leef59fc9b2011-03-04 16:44:54 -0800184 Cursor legacyClientIdCursor = null;
185 Cursor searchClientIdCursor = null;
186
187 // search_client_id includes search prefix, legacy client_id does not include prefix
Patrick Scott43914692010-02-19 10:10:10 -0500188 try {
Reena Leef59fc9b2011-03-04 16:44:54 -0800189 searchClientIdCursor = cr.query(Uri.parse("content://com.google.settings/partner"),
190 new String[] { "value" }, "name='search_client_id'", null, null);
191 if (searchClientIdCursor != null && searchClientIdCursor.moveToNext()) {
192 ret = searchClientIdCursor.getString(0);
193 } else {
194 legacyClientIdCursor = cr.query(Uri.parse("content://com.google.settings/partner"),
Patrick Scott43914692010-02-19 10:10:10 -0500195 new String[] { "value" }, "name='client_id'", null, null);
Reena Leef59fc9b2011-03-04 16:44:54 -0800196 if (legacyClientIdCursor != null && legacyClientIdCursor.moveToNext()) {
197 ret = "ms-" + legacyClientIdCursor.getString(0);
198 }
Patrick Scott43914692010-02-19 10:10:10 -0500199 }
200 } catch (RuntimeException ex) {
201 // fall through to return the default
202 } finally {
Reena Leef59fc9b2011-03-04 16:44:54 -0800203 if (legacyClientIdCursor != null) {
204 legacyClientIdCursor.close();
205 }
206 if (searchClientIdCursor != null) {
207 searchClientIdCursor.close();
Patrick Scott43914692010-02-19 10:10:10 -0500208 }
209 }
210 return ret;
211 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800212
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700213 private static CharSequence replaceSystemPropertyInString(Context context, CharSequence srcString) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800214 StringBuffer sb = new StringBuffer();
215 int lastCharLoc = 0;
Satish Sampath565505b2009-05-29 15:37:27 +0100216
Patrick Scott43914692010-02-19 10:10:10 -0500217 final String client_id = getClientId(context.getContentResolver());
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700218
The Android Open Source Project0c908882009-03-03 19:32:16 -0800219 for (int i = 0; i < srcString.length(); ++i) {
220 char c = srcString.charAt(i);
221 if (c == '{') {
222 sb.append(srcString.subSequence(lastCharLoc, i));
223 lastCharLoc = i;
224 inner:
225 for (int j = i; j < srcString.length(); ++j) {
226 char k = srcString.charAt(j);
227 if (k == '}') {
228 String propertyKeyValue = srcString.subSequence(i + 1, j).toString();
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700229 if (propertyKeyValue.equals("CLIENT_ID")) {
230 sb.append(client_id);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800231 } else {
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700232 sb.append("unknown");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800233 }
234 lastCharLoc = j + 1;
235 i = j;
236 break inner;
237 }
238 }
239 }
240 }
241 if (srcString.length() - lastCharLoc > 0) {
242 // Put on the tail, if there is one
243 sb.append(srcString.subSequence(lastCharLoc, srcString.length()));
244 }
245 return sb;
246 }
247
248 private static class DatabaseHelper extends SQLiteOpenHelper {
249 private Context mContext;
250
251 public DatabaseHelper(Context context) {
252 super(context, sDatabaseName, null, DATABASE_VERSION);
253 mContext = context;
254 }
255
256 @Override
257 public void onCreate(SQLiteDatabase db) {
258 db.execSQL("CREATE TABLE bookmarks (" +
259 "_id INTEGER PRIMARY KEY," +
260 "title TEXT," +
Magnus Lindhult655e8672010-09-29 18:36:07 +0200261 "url TEXT NOT NULL," +
The Android Open Source Project0c908882009-03-03 19:32:16 -0800262 "visits INTEGER," +
263 "date LONG," +
264 "created LONG," +
265 "description TEXT," +
266 "bookmark INTEGER," +
Leon Scrogginsb6b7f9e2009-06-18 12:05:28 -0400267 "favicon BLOB DEFAULT NULL," +
Patrick Scott3918d442009-08-04 13:22:29 -0400268 "thumbnail BLOB DEFAULT NULL," +
Leon Scrogginsb4464432009-11-25 12:37:50 -0500269 "touch_icon BLOB DEFAULT NULL," +
270 "user_entered INTEGER" +
The Android Open Source Project0c908882009-03-03 19:32:16 -0800271 ");");
272
273 final CharSequence[] bookmarks = mContext.getResources()
274 .getTextArray(R.array.bookmarks);
275 int size = bookmarks.length;
276 try {
277 for (int i = 0; i < size; i = i + 2) {
Ramanan Rajeswarandd4f4292009-03-24 20:41:19 -0700278 CharSequence bookmarkDestination = replaceSystemPropertyInString(mContext, bookmarks[i + 1]);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800279 db.execSQL("INSERT INTO bookmarks (title, url, visits, " +
280 "date, created, bookmark)" + " VALUES('" +
Satish Sampath565505b2009-05-29 15:37:27 +0100281 bookmarks[i] + "', '" + bookmarkDestination +
The Android Open Source Project0c908882009-03-03 19:32:16 -0800282 "', 0, 0, 0, 1);");
283 }
284 } catch (ArrayIndexOutOfBoundsException e) {
285 }
286
287 db.execSQL("CREATE TABLE searches (" +
288 "_id INTEGER PRIMARY KEY," +
289 "search TEXT," +
290 "date LONG" +
291 ");");
292 }
293
294 @Override
295 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
296 Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
Leon Scrogginsb6b7f9e2009-06-18 12:05:28 -0400297 + newVersion);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800298 if (oldVersion == 18) {
299 db.execSQL("DROP TABLE IF EXISTS labels");
Leon Scrogginsb6b7f9e2009-06-18 12:05:28 -0400300 }
301 if (oldVersion <= 19) {
302 db.execSQL("ALTER TABLE bookmarks ADD COLUMN thumbnail BLOB DEFAULT NULL;");
Patrick Scott3918d442009-08-04 13:22:29 -0400303 }
304 if (oldVersion < 21) {
305 db.execSQL("ALTER TABLE bookmarks ADD COLUMN touch_icon BLOB DEFAULT NULL;");
Grace Kloba6b52a552009-09-03 16:29:56 -0700306 }
307 if (oldVersion < 22) {
308 db.execSQL("DELETE FROM bookmarks WHERE (bookmark = 0 AND url LIKE \"%.google.%client=ms-%\")");
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100309 removeGears();
Leon Scrogginsb4464432009-11-25 12:37:50 -0500310 }
311 if (oldVersion < 23) {
312 db.execSQL("ALTER TABLE bookmarks ADD COLUMN user_entered INTEGER;");
Magnus Lindhult655e8672010-09-29 18:36:07 +0200313 }
314 if (oldVersion < 24) {
315 /* SQLite does not support ALTER COLUMN, hence the lengthy code. */
316 db.execSQL("DELETE FROM bookmarks WHERE url IS NULL;");
317 db.execSQL("ALTER TABLE bookmarks RENAME TO bookmarks_temp;");
318 db.execSQL("CREATE TABLE bookmarks (" +
319 "_id INTEGER PRIMARY KEY," +
320 "title TEXT," +
321 "url TEXT NOT NULL," +
322 "visits INTEGER," +
323 "date LONG," +
324 "created LONG," +
325 "description TEXT," +
326 "bookmark INTEGER," +
327 "favicon BLOB DEFAULT NULL," +
328 "thumbnail BLOB DEFAULT NULL," +
329 "touch_icon BLOB DEFAULT NULL," +
330 "user_entered INTEGER" +
331 ");");
332 db.execSQL("INSERT INTO bookmarks SELECT * FROM bookmarks_temp;");
333 db.execSQL("DROP TABLE bookmarks_temp;");
The Android Open Source Project0c908882009-03-03 19:32:16 -0800334 } else {
335 db.execSQL("DROP TABLE IF EXISTS bookmarks");
336 db.execSQL("DROP TABLE IF EXISTS searches");
337 onCreate(db);
338 }
339 }
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100340
341 private void removeGears() {
Andrei Popescu93bea962010-03-23 15:04:36 +0000342 new Thread() {
343 @Override
344 public void run() {
345 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100346 String browserDataDirString = mContext.getApplicationInfo().dataDir;
347 final String appPluginsDirString = "app_plugins";
348 final String gearsPrefix = "gears";
349 File appPluginsDir = new File(browserDataDirString + File.separator
350 + appPluginsDirString);
351 if (!appPluginsDir.exists()) {
Andrei Popescu93bea962010-03-23 15:04:36 +0000352 return;
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100353 }
354 // Delete the Gears plugin files
355 File[] gearsFiles = appPluginsDir.listFiles(new FilenameFilter() {
356 public boolean accept(File dir, String filename) {
357 return filename.startsWith(gearsPrefix);
358 }
359 });
360 for (int i = 0; i < gearsFiles.length; ++i) {
361 if (gearsFiles[i].isDirectory()) {
362 deleteDirectory(gearsFiles[i]);
363 } else {
364 gearsFiles[i].delete();
365 }
366 }
367 // Delete the Gears data files
368 File gearsDataDir = new File(browserDataDirString + File.separator
369 + gearsPrefix);
370 if (!gearsDataDir.exists()) {
Andrei Popescu93bea962010-03-23 15:04:36 +0000371 return;
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100372 }
373 deleteDirectory(gearsDataDir);
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100374 }
375
376 private void deleteDirectory(File currentDir) {
377 File[] files = currentDir.listFiles();
378 for (int i = 0; i < files.length; ++i) {
379 if (files[i].isDirectory()) {
380 deleteDirectory(files[i]);
381 }
382 files[i].delete();
383 }
384 currentDir.delete();
385 }
Andrei Popescu93bea962010-03-23 15:04:36 +0000386 }.start();
Andrei Popescu1b20b9d2009-09-21 18:49:42 +0100387 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800388 }
389
390 @Override
391 public boolean onCreate() {
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700392 final Context context = getContext();
Michael Kolbfe251992010-07-08 15:41:55 -0700393 boolean xlargeScreenSize = (context.getResources().getConfiguration().screenLayout
394 & Configuration.SCREENLAYOUT_SIZE_MASK)
395 == Configuration.SCREENLAYOUT_SIZE_XLARGE;
396 boolean isPortrait = (context.getResources().getConfiguration().orientation
397 == Configuration.ORIENTATION_PORTRAIT);
398
399
400 if (xlargeScreenSize && isPortrait) {
401 mMaxSuggestionLongSize = MAX_SUGGEST_LONG_LARGE;
402 mMaxSuggestionShortSize = MAX_SUGGEST_SHORT_LARGE;
403 } else {
404 mMaxSuggestionLongSize = MAX_SUGGEST_LONG_SMALL;
405 mMaxSuggestionShortSize = MAX_SUGGEST_SHORT_SMALL;
406 }
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700407 mOpenHelper = new DatabaseHelper(context);
Christopher Tate9c0dd8c2009-07-10 17:51:48 -0700408 mBackupManager = new BackupManager(context);
Satish Sampath565505b2009-05-29 15:37:27 +0100409 // we added "picasa web album" into default bookmarks for version 19.
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700410 // To avoid erasing the bookmark table, we added it explicitly for
411 // version 18 and 19 as in the other cases, we will erase the table.
412 if (DATABASE_VERSION == 18 || DATABASE_VERSION == 19) {
413 SharedPreferences p = PreferenceManager
414 .getDefaultSharedPreferences(context);
415 boolean fix = p.getBoolean("fix_picasa", true);
416 if (fix) {
417 fixPicasaBookmark();
418 Editor ed = p.edit();
419 ed.putBoolean("fix_picasa", false);
Brad Fitzpatrick1a6e0e82010-09-01 16:29:03 -0700420 ed.apply();
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700421 }
422 }
Bjorn Bringertd69f51d2010-09-13 14:06:41 +0100423 mSettings = BrowserSettings.getInstance();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800424 return true;
425 }
426
The Android Open Source Projecta3c0aab2009-03-18 17:39:48 -0700427 private void fixPicasaBookmark() {
428 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
429 Cursor cursor = db.rawQuery("SELECT _id FROM bookmarks WHERE " +
430 "bookmark = 1 AND url = ?", new String[] { PICASA_URL });
431 try {
432 if (!cursor.moveToFirst()) {
433 // set "created" so that it will be on the top of the list
434 db.execSQL("INSERT INTO bookmarks (title, url, visits, " +
435 "date, created, bookmark)" + " VALUES('" +
436 getContext().getString(R.string.picasa) + "', '"
437 + PICASA_URL + "', 0, 0, " + new Date().getTime()
438 + ", 1);");
439 }
440 } finally {
441 if (cursor != null) {
442 cursor.close();
443 }
444 }
445 }
446
The Android Open Source Project0c908882009-03-03 19:32:16 -0800447 /*
448 * Subclass AbstractCursor so we can combine multiple Cursors and add
Grace Kloba391df7c2010-03-01 19:51:49 -0800449 * "Search the web".
The Android Open Source Project0c908882009-03-03 19:32:16 -0800450 * Here are the rules.
Satish Sampath565505b2009-05-29 15:37:27 +0100451 * 1. We only have MAX_SUGGESTION_LONG_ENTRIES in the list plus
Grace Kloba391df7c2010-03-01 19:51:49 -0800452 * "Search the web";
453 * 2. If bookmark/history entries has a match, "Search the web" shows up at
454 * the second place. Otherwise, "Search the web" shows up at the first
455 * place.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800456 */
457 private class MySuggestionCursor extends AbstractCursor {
458 private Cursor mHistoryCursor;
459 private Cursor mSuggestCursor;
460 private int mHistoryCount;
461 private int mSuggestionCount;
Grace Klobad3992d42010-01-28 11:44:38 -0800462 private boolean mIncludeWebSearch;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800463 private String mString;
Satish Sampath565505b2009-05-29 15:37:27 +0100464 private int mSuggestText1Id;
465 private int mSuggestText2Id;
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000466 private int mSuggestText2UrlId;
Satish Sampath565505b2009-05-29 15:37:27 +0100467 private int mSuggestQueryId;
Bjorn Bringert04851702009-09-22 10:36:01 +0100468 private int mSuggestIntentExtraDataId;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800469
470 public MySuggestionCursor(Cursor hc, Cursor sc, String string) {
471 mHistoryCursor = hc;
472 mSuggestCursor = sc;
Grace Klobaf9b04272010-06-15 13:36:22 -0700473 mHistoryCount = hc != null ? hc.getCount() : 0;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800474 mSuggestionCount = sc != null ? sc.getCount() : 0;
Michael Kolbfe251992010-07-08 15:41:55 -0700475 if (mSuggestionCount > (mMaxSuggestionLongSize - mHistoryCount)) {
476 mSuggestionCount = mMaxSuggestionLongSize - mHistoryCount;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800477 }
478 mString = string;
Grace Klobad3992d42010-01-28 11:44:38 -0800479 mIncludeWebSearch = string.length() > 0;
Satish Sampath565505b2009-05-29 15:37:27 +0100480
481 // Some web suggest providers only give suggestions and have no description string for
482 // items. The order of the result columns may be different as well. So retrieve the
483 // column indices for the fields we need now and check before using below.
484 if (mSuggestCursor == null) {
485 mSuggestText1Id = -1;
486 mSuggestText2Id = -1;
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000487 mSuggestText2UrlId = -1;
Satish Sampath565505b2009-05-29 15:37:27 +0100488 mSuggestQueryId = -1;
Bjorn Bringert04851702009-09-22 10:36:01 +0100489 mSuggestIntentExtraDataId = -1;
Satish Sampath565505b2009-05-29 15:37:27 +0100490 } else {
491 mSuggestText1Id = mSuggestCursor.getColumnIndex(
492 SearchManager.SUGGEST_COLUMN_TEXT_1);
493 mSuggestText2Id = mSuggestCursor.getColumnIndex(
494 SearchManager.SUGGEST_COLUMN_TEXT_2);
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000495 mSuggestText2UrlId = mSuggestCursor.getColumnIndex(
496 SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
Satish Sampath565505b2009-05-29 15:37:27 +0100497 mSuggestQueryId = mSuggestCursor.getColumnIndex(
498 SearchManager.SUGGEST_COLUMN_QUERY);
Bjorn Bringert04851702009-09-22 10:36:01 +0100499 mSuggestIntentExtraDataId = mSuggestCursor.getColumnIndex(
500 SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
Satish Sampath565505b2009-05-29 15:37:27 +0100501 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800502 }
503
504 @Override
505 public boolean onMove(int oldPosition, int newPosition) {
506 if (mHistoryCursor == null) {
507 return false;
508 }
Grace Klobad3992d42010-01-28 11:44:38 -0800509 if (mIncludeWebSearch) {
Grace Kloba391df7c2010-03-01 19:51:49 -0800510 if (mHistoryCount == 0 && newPosition == 0) {
Grace Klobad3992d42010-01-28 11:44:38 -0800511 return true;
Grace Kloba391df7c2010-03-01 19:51:49 -0800512 } else if (mHistoryCount > 0) {
513 if (newPosition == 0) {
514 mHistoryCursor.moveToPosition(0);
515 return true;
516 } else if (newPosition == 1) {
517 return true;
518 }
Grace Klobad3992d42010-01-28 11:44:38 -0800519 }
Grace Kloba391df7c2010-03-01 19:51:49 -0800520 newPosition--;
Grace Klobad3992d42010-01-28 11:44:38 -0800521 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800522 if (mHistoryCount > newPosition) {
523 mHistoryCursor.moveToPosition(newPosition);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800524 } else {
Grace Klobad3992d42010-01-28 11:44:38 -0800525 mSuggestCursor.moveToPosition(newPosition - mHistoryCount);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800526 }
527 return true;
528 }
529
530 @Override
531 public int getCount() {
Grace Klobad3992d42010-01-28 11:44:38 -0800532 if (mIncludeWebSearch) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800533 return mHistoryCount + mSuggestionCount + 1;
534 } else {
535 return mHistoryCount + mSuggestionCount;
536 }
537 }
538
539 @Override
540 public String[] getColumnNames() {
541 return COLUMNS;
542 }
Satish Sampath565505b2009-05-29 15:37:27 +0100543
The Android Open Source Project0c908882009-03-03 19:32:16 -0800544 @Override
545 public String getString(int columnIndex) {
546 if ((mPos != -1 && mHistoryCursor != null)) {
Grace Kloba391df7c2010-03-01 19:51:49 -0800547 int type = -1; // 0: web search; 1: history; 2: suggestion
548 if (mIncludeWebSearch) {
549 if (mHistoryCount == 0 && mPos == 0) {
550 type = 0;
551 } else if (mHistoryCount > 0) {
552 if (mPos == 0) {
553 type = 1;
554 } else if (mPos == 1) {
555 type = 0;
556 }
557 }
558 if (type == -1) type = (mPos - 1) < mHistoryCount ? 1 : 2;
559 } else {
560 type = mPos < mHistoryCount ? 1 : 2;
561 }
562
The Android Open Source Project0c908882009-03-03 19:32:16 -0800563 switch(columnIndex) {
564 case SUGGEST_COLUMN_INTENT_ACTION_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800565 if (type == 1) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800566 return Intent.ACTION_VIEW;
567 } else {
568 return Intent.ACTION_SEARCH;
569 }
570
571 case SUGGEST_COLUMN_INTENT_DATA_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800572 if (type == 1) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800573 return mHistoryCursor.getString(1);
574 } else {
575 return null;
576 }
577
578 case SUGGEST_COLUMN_TEXT_1_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800579 if (type == 0) {
Grace Klobad3992d42010-01-28 11:44:38 -0800580 return mString;
Grace Kloba391df7c2010-03-01 19:51:49 -0800581 } else if (type == 1) {
Mike LeBeau1ef26a32009-05-13 20:11:00 -0700582 return getHistoryTitle();
Grace Klobad3992d42010-01-28 11:44:38 -0800583 } else {
Satish Sampath565505b2009-05-29 15:37:27 +0100584 if (mSuggestText1Id == -1) return null;
585 return mSuggestCursor.getString(mSuggestText1Id);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800586 }
587
588 case SUGGEST_COLUMN_TEXT_2_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800589 if (type == 0) {
Grace Klobad3992d42010-01-28 11:44:38 -0800590 return getContext().getString(R.string.search_the_web);
Grace Kloba391df7c2010-03-01 19:51:49 -0800591 } else if (type == 1) {
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000592 return null; // Use TEXT_2_URL instead
Grace Klobad3992d42010-01-28 11:44:38 -0800593 } else {
Satish Sampath565505b2009-05-29 15:37:27 +0100594 if (mSuggestText2Id == -1) return null;
595 return mSuggestCursor.getString(mSuggestText2Id);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800596 }
597
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000598 case SUGGEST_COLUMN_TEXT_2_URL_ID:
599 if (type == 0) {
600 return null;
601 } else if (type == 1) {
602 return getHistoryUrl();
603 } else {
604 if (mSuggestText2UrlId == -1) return null;
605 return mSuggestCursor.getString(mSuggestText2UrlId);
606 }
607
The Android Open Source Project0c908882009-03-03 19:32:16 -0800608 case SUGGEST_COLUMN_ICON_1_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800609 if (type == 1) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800610 if (mHistoryCursor.getInt(3) == 1) {
Leon Scroggins31887fd2009-05-18 16:58:08 -0400611 return Integer.valueOf(
The Android Open Source Project0c908882009-03-03 19:32:16 -0800612 R.drawable.ic_search_category_bookmark)
613 .toString();
614 } else {
Leon Scroggins31887fd2009-05-18 16:58:08 -0400615 return Integer.valueOf(
The Android Open Source Project0c908882009-03-03 19:32:16 -0800616 R.drawable.ic_search_category_history)
617 .toString();
618 }
619 } else {
Leon Scroggins31887fd2009-05-18 16:58:08 -0400620 return Integer.valueOf(
The Android Open Source Project0c908882009-03-03 19:32:16 -0800621 R.drawable.ic_search_category_suggest)
622 .toString();
623 }
624
625 case SUGGEST_COLUMN_ICON_2_ID:
Leon Scroggins31887fd2009-05-18 16:58:08 -0400626 return "0";
The Android Open Source Project0c908882009-03-03 19:32:16 -0800627
628 case SUGGEST_COLUMN_QUERY_ID:
Grace Kloba391df7c2010-03-01 19:51:49 -0800629 if (type == 0) {
Grace Klobad3992d42010-01-28 11:44:38 -0800630 return mString;
Grace Kloba391df7c2010-03-01 19:51:49 -0800631 } else if (type == 1) {
Mike LeBeau2af73052009-06-23 17:36:59 -0700632 // Return the url in the intent query column. This is ignored
633 // within the browser because our searchable is set to
634 // android:searchMode="queryRewriteFromData", but it is used by
635 // global search for query rewriting.
636 return mHistoryCursor.getString(1);
Grace Klobad3992d42010-01-28 11:44:38 -0800637 } else {
Satish Sampath565505b2009-05-29 15:37:27 +0100638 if (mSuggestQueryId == -1) return null;
639 return mSuggestCursor.getString(mSuggestQueryId);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800640 }
Satish Sampath565505b2009-05-29 15:37:27 +0100641
Bjorn Bringert04851702009-09-22 10:36:01 +0100642 case SUGGEST_COLUMN_INTENT_EXTRA_DATA:
Grace Kloba391df7c2010-03-01 19:51:49 -0800643 if (type == 0) {
Bjorn Bringert04851702009-09-22 10:36:01 +0100644 return null;
Grace Kloba391df7c2010-03-01 19:51:49 -0800645 } else if (type == 1) {
Grace Klobad3992d42010-01-28 11:44:38 -0800646 return null;
647 } else {
Bjorn Bringert04851702009-09-22 10:36:01 +0100648 if (mSuggestIntentExtraDataId == -1) return null;
649 return mSuggestCursor.getString(mSuggestIntentExtraDataId);
Bjorn Bringert04851702009-09-22 10:36:01 +0100650 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800651 }
652 }
653 return null;
654 }
655
656 @Override
657 public double getDouble(int column) {
658 throw new UnsupportedOperationException();
659 }
660
661 @Override
662 public float getFloat(int column) {
663 throw new UnsupportedOperationException();
664 }
665
666 @Override
667 public int getInt(int column) {
668 throw new UnsupportedOperationException();
669 }
670
671 @Override
672 public long getLong(int column) {
673 if ((mPos != -1) && column == 0) {
674 return mPos; // use row# as the _Id
675 }
676 throw new UnsupportedOperationException();
677 }
678
679 @Override
680 public short getShort(int column) {
681 throw new UnsupportedOperationException();
682 }
683
684 @Override
685 public boolean isNull(int column) {
686 throw new UnsupportedOperationException();
687 }
688
689 // TODO Temporary change, finalize after jq's changes go in
Michael Kolbfe251992010-07-08 15:41:55 -0700690 @Override
The Android Open Source Project0c908882009-03-03 19:32:16 -0800691 public void deactivate() {
692 if (mHistoryCursor != null) {
693 mHistoryCursor.deactivate();
694 }
695 if (mSuggestCursor != null) {
696 mSuggestCursor.deactivate();
697 }
698 super.deactivate();
699 }
700
Michael Kolbfe251992010-07-08 15:41:55 -0700701 @Override
The Android Open Source Project0c908882009-03-03 19:32:16 -0800702 public boolean requery() {
703 return (mHistoryCursor != null ? mHistoryCursor.requery() : false) |
704 (mSuggestCursor != null ? mSuggestCursor.requery() : false);
705 }
706
707 // TODO Temporary change, finalize after jq's changes go in
Michael Kolbfe251992010-07-08 15:41:55 -0700708 @Override
The Android Open Source Project0c908882009-03-03 19:32:16 -0800709 public void close() {
710 super.close();
711 if (mHistoryCursor != null) {
712 mHistoryCursor.close();
713 mHistoryCursor = null;
714 }
715 if (mSuggestCursor != null) {
716 mSuggestCursor.close();
717 mSuggestCursor = null;
718 }
719 }
Satish Sampath565505b2009-05-29 15:37:27 +0100720
Mike LeBeau21beb132009-05-13 14:57:50 -0700721 /**
722 * Provides the title (text line 1) for a browser suggestion, which should be the
723 * webpage title. If the webpage title is empty, returns the stripped url instead.
Satish Sampath565505b2009-05-29 15:37:27 +0100724 *
Mike LeBeau21beb132009-05-13 14:57:50 -0700725 * @return the title string to use
726 */
Mike LeBeau1ef26a32009-05-13 20:11:00 -0700727 private String getHistoryTitle() {
728 String title = mHistoryCursor.getString(2 /* webpage title */);
Mike LeBeau21beb132009-05-13 14:57:50 -0700729 if (TextUtils.isEmpty(title) || TextUtils.getTrimmedLength(title) == 0) {
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000730 title = stripUrl(mHistoryCursor.getString(1 /* url */));
Mike LeBeau21beb132009-05-13 14:57:50 -0700731 }
732 return title;
733 }
Satish Sampath565505b2009-05-29 15:37:27 +0100734
Mike LeBeau21beb132009-05-13 14:57:50 -0700735 /**
736 * Provides the subtitle (text line 2) for a browser suggestion, which should be the
737 * webpage url. If the webpage title is empty, then the url should go in the title
738 * instead, and the subtitle should be empty, so this would return null.
Satish Sampath565505b2009-05-29 15:37:27 +0100739 *
Mike LeBeau21beb132009-05-13 14:57:50 -0700740 * @return the subtitle string to use, or null if none
741 */
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000742 private String getHistoryUrl() {
Mike LeBeau1ef26a32009-05-13 20:11:00 -0700743 String title = mHistoryCursor.getString(2 /* webpage title */);
Mike LeBeau21beb132009-05-13 14:57:50 -0700744 if (TextUtils.isEmpty(title) || TextUtils.getTrimmedLength(title) == 0) {
745 return null;
746 } else {
Bjorn Bringertc7c0fce2010-03-02 11:20:29 +0000747 return stripUrl(mHistoryCursor.getString(1 /* url */));
Mike LeBeau21beb132009-05-13 14:57:50 -0700748 }
749 }
Satish Sampath565505b2009-05-29 15:37:27 +0100750
The Android Open Source Project0c908882009-03-03 19:32:16 -0800751 }
752
Leon Scroggins58d56c62010-01-28 15:12:40 -0500753 private static class ResultsCursor extends AbstractCursor {
754 // Array indices for RESULTS_COLUMNS
755 private static final int RESULT_ACTION_ID = 1;
756 private static final int RESULT_DATA_ID = 2;
757 private static final int RESULT_TEXT_ID = 3;
758 private static final int RESULT_ICON_ID = 4;
759 private static final int RESULT_EXTRA_ID = 5;
760
761 private static final String[] RESULTS_COLUMNS = new String[] {
762 "_id",
763 SearchManager.SUGGEST_COLUMN_INTENT_ACTION,
764 SearchManager.SUGGEST_COLUMN_INTENT_DATA,
765 SearchManager.SUGGEST_COLUMN_TEXT_1,
766 SearchManager.SUGGEST_COLUMN_ICON_1,
767 SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA
768 };
769 private final ArrayList<String> mResults;
770 public ResultsCursor(ArrayList<String> results) {
771 mResults = results;
772 }
Michael Kolbfe251992010-07-08 15:41:55 -0700773 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500774 public int getCount() { return mResults.size(); }
775
Michael Kolbfe251992010-07-08 15:41:55 -0700776 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500777 public String[] getColumnNames() {
778 return RESULTS_COLUMNS;
779 }
780
Michael Kolbfe251992010-07-08 15:41:55 -0700781 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500782 public String getString(int column) {
783 switch (column) {
784 case RESULT_ACTION_ID:
Leon Scrogginsa1cc3fd2010-02-01 16:14:11 -0500785 return RecognizerResultsIntent.ACTION_VOICE_SEARCH_RESULTS;
Leon Scroggins58d56c62010-01-28 15:12:40 -0500786 case RESULT_TEXT_ID:
787 // The data is used when the phone is in landscape mode. We
788 // still want to show the result string.
789 case RESULT_DATA_ID:
790 return mResults.get(mPos);
791 case RESULT_EXTRA_ID:
792 // The Intent's extra data will store the index into
793 // mResults so the BrowserActivity will know which result to
794 // use.
795 return Integer.toString(mPos);
796 case RESULT_ICON_ID:
797 return Integer.valueOf(R.drawable.magnifying_glass)
798 .toString();
799 default:
800 return null;
801 }
802 }
Michael Kolbfe251992010-07-08 15:41:55 -0700803 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500804 public short getShort(int column) {
805 throw new UnsupportedOperationException();
806 }
Michael Kolbfe251992010-07-08 15:41:55 -0700807 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500808 public int getInt(int column) {
809 throw new UnsupportedOperationException();
810 }
Michael Kolbfe251992010-07-08 15:41:55 -0700811 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500812 public long getLong(int column) {
813 if ((mPos != -1) && column == 0) {
814 return mPos; // use row# as the _id
815 }
816 throw new UnsupportedOperationException();
817 }
Michael Kolbfe251992010-07-08 15:41:55 -0700818 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500819 public float getFloat(int column) {
820 throw new UnsupportedOperationException();
821 }
Michael Kolbfe251992010-07-08 15:41:55 -0700822 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500823 public double getDouble(int column) {
824 throw new UnsupportedOperationException();
825 }
Michael Kolbfe251992010-07-08 15:41:55 -0700826 @Override
Leon Scroggins58d56c62010-01-28 15:12:40 -0500827 public boolean isNull(int column) {
828 throw new UnsupportedOperationException();
829 }
830 }
831
Jeff Hamilton8b139742010-07-29 16:06:53 -0500832 /** Contains custom suggestions results set by the UI */
Leon Scroggins58d56c62010-01-28 15:12:40 -0500833 private ResultsCursor mResultsCursor;
Jeff Hamilton8b139742010-07-29 16:06:53 -0500834 /** Locks access to {@link #mResultsCursor} */
835 private Object mResultsCursorLock = new Object();
Leon Scroggins58d56c62010-01-28 15:12:40 -0500836
837 /**
838 * Provide a set of results to be returned to query, intended to be used
839 * by the SearchDialog when the BrowserActivity is in voice search mode.
840 * @param results Strings to display in the dropdown from the SearchDialog
841 */
842 /* package */ void setQueryResults(ArrayList<String> results) {
Jeff Hamilton8b139742010-07-29 16:06:53 -0500843 synchronized (mResultsCursorLock) {
844 if (results == null) {
845 mResultsCursor = null;
846 } else {
847 mResultsCursor = new ResultsCursor(results);
848 }
Leon Scroggins58d56c62010-01-28 15:12:40 -0500849 }
850 }
851
The Android Open Source Project0c908882009-03-03 19:32:16 -0800852 @Override
853 public Cursor query(Uri url, String[] projectionIn, String selection,
Satish Sampath565505b2009-05-29 15:37:27 +0100854 String[] selectionArgs, String sortOrder)
The Android Open Source Project0c908882009-03-03 19:32:16 -0800855 throws IllegalStateException {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800856 int match = URI_MATCHER.match(url);
857 if (match == -1) {
858 throw new IllegalArgumentException("Unknown URL");
859 }
Jeff Hamilton8b139742010-07-29 16:06:53 -0500860
861 // If results for the suggestion are already ready just return them directly
862 synchronized (mResultsCursorLock) {
863 if (match == URI_MATCH_SUGGEST && mResultsCursor != null) {
864 Cursor results = mResultsCursor;
865 mResultsCursor = null;
866 return results;
867 }
Leon Scroggins58d56c62010-01-28 15:12:40 -0500868 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800869
Bjorn Bringert346dafb2009-04-29 21:41:47 +0100870 if (match == URI_MATCH_SUGGEST || match == URI_MATCH_BOOKMARKS_SUGGEST) {
Jeff Hamilton8b139742010-07-29 16:06:53 -0500871 // Handle suggestions
872 return doSuggestQuery(selection, selectionArgs, match == URI_MATCH_BOOKMARKS_SUGGEST);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800873 }
874
875 String[] projection = null;
876 if (projectionIn != null && projectionIn.length > 0) {
877 projection = new String[projectionIn.length + 1];
878 System.arraycopy(projectionIn, 0, projection, 0, projectionIn.length);
879 projection[projectionIn.length] = "_id AS _id";
880 }
881
Jeff Hamilton8b139742010-07-29 16:06:53 -0500882 String whereClause = null;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800883 if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) {
Jeff Hamilton8b139742010-07-29 16:06:53 -0500884 whereClause = "_id = " + url.getPathSegments().get(1);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800885 }
886
Jeff Hamilton8b139742010-07-29 16:06:53 -0500887 Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_NAMES[match % 10], projection,
888 DatabaseUtils.concatenateWhere(whereClause, selection), selectionArgs,
889 null, null, sortOrder, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800890 c.setNotificationUri(getContext().getContentResolver(), url);
891 return c;
892 }
893
Jeff Hamilton8b139742010-07-29 16:06:53 -0500894 private Cursor doSuggestQuery(String selection, String[] selectionArgs, boolean bookmarksOnly) {
895 String suggestSelection;
896 String [] myArgs;
897 if (selectionArgs[0] == null || selectionArgs[0].equals("")) {
898 return new MySuggestionCursor(null, null, "");
899 } else {
900 String like = selectionArgs[0] + "%";
901 if (selectionArgs[0].startsWith("http")
902 || selectionArgs[0].startsWith("file")) {
903 myArgs = new String[1];
904 myArgs[0] = like;
905 suggestSelection = selection;
906 } else {
907 SUGGEST_ARGS[0] = "http://" + like;
908 SUGGEST_ARGS[1] = "http://www." + like;
909 SUGGEST_ARGS[2] = "https://" + like;
910 SUGGEST_ARGS[3] = "https://www." + like;
911 // To match against titles.
912 SUGGEST_ARGS[4] = like;
913 myArgs = SUGGEST_ARGS;
914 suggestSelection = SUGGEST_SELECTION;
915 }
916 }
917
918 Cursor c = mOpenHelper.getReadableDatabase().query(TABLE_NAMES[URI_MATCH_BOOKMARKS],
919 SUGGEST_PROJECTION, suggestSelection, myArgs, null, null,
920 ORDER_BY, Integer.toString(mMaxSuggestionLongSize));
921
922 if (bookmarksOnly || Patterns.WEB_URL.matcher(selectionArgs[0]).matches()) {
923 return new MySuggestionCursor(c, null, "");
924 } else {
Bjorn Bringertd69f51d2010-09-13 14:06:41 +0100925 // get search suggestions if there is still space in the list
926 if (myArgs != null && myArgs.length > 1
Leon Scroggins III4fb6cc92010-09-17 15:01:28 -0400927 && c.getCount() < (MAX_SUGGEST_SHORT_SMALL - 1)) {
Bjorn Bringertd69f51d2010-09-13 14:06:41 +0100928 SearchEngine searchEngine = mSettings.getSearchEngine();
929 if (searchEngine != null && searchEngine.supportsSuggestions()) {
930 Cursor sc = searchEngine.getSuggestions(getContext(), selectionArgs[0]);
931 return new MySuggestionCursor(c, sc, selectionArgs[0]);
932 }
Jeff Hamilton8b139742010-07-29 16:06:53 -0500933 }
934 return new MySuggestionCursor(c, null, selectionArgs[0]);
935 }
936 }
937
The Android Open Source Project0c908882009-03-03 19:32:16 -0800938 @Override
939 public String getType(Uri url) {
940 int match = URI_MATCHER.match(url);
941 switch (match) {
942 case URI_MATCH_BOOKMARKS:
943 return "vnd.android.cursor.dir/bookmark";
944
945 case URI_MATCH_BOOKMARKS_ID:
946 return "vnd.android.cursor.item/bookmark";
947
948 case URI_MATCH_SEARCHES:
949 return "vnd.android.cursor.dir/searches";
950
951 case URI_MATCH_SEARCHES_ID:
952 return "vnd.android.cursor.item/searches";
953
954 case URI_MATCH_SUGGEST:
955 return SearchManager.SUGGEST_MIME_TYPE;
956
957 default:
958 throw new IllegalArgumentException("Unknown URL");
959 }
960 }
961
962 @Override
963 public Uri insert(Uri url, ContentValues initialValues) {
Christopher Tate9c0dd8c2009-07-10 17:51:48 -0700964 boolean isBookmarkTable = false;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800965 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
966
967 int match = URI_MATCHER.match(url);
968 Uri uri = null;
969 switch (match) {
970 case URI_MATCH_BOOKMARKS: {
971 // Insert into the bookmarks table
972 long rowID = db.insert(TABLE_NAMES[URI_MATCH_BOOKMARKS], "url",
973 initialValues);
974 if (rowID > 0) {
975 uri = ContentUris.withAppendedId(Browser.BOOKMARKS_URI,
976 rowID);
977 }
Christopher Tate9c0dd8c2009-07-10 17:51:48 -0700978 isBookmarkTable = true;
The Android Open Source Project0c908882009-03-03 19:32:16 -0800979 break;
980 }
981
982 case URI_MATCH_SEARCHES: {
983 // Insert into the searches table
984 long rowID = db.insert(TABLE_NAMES[URI_MATCH_SEARCHES], "url",
985 initialValues);
986 if (rowID > 0) {
987 uri = ContentUris.withAppendedId(Browser.SEARCHES_URI,
988 rowID);
989 }
990 break;
991 }
992
993 default:
994 throw new IllegalArgumentException("Unknown URL");
995 }
996
997 if (uri == null) {
998 throw new IllegalArgumentException("Unknown URL");
999 }
1000 getContext().getContentResolver().notifyChange(uri, null);
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001001
Christopher Tatef0c36f72009-07-28 15:24:05 -07001002 // Back up the new bookmark set if we just inserted one.
1003 // A row created when bookmarks are added from scratch will have
1004 // bookmark=1 in the initial value set.
1005 if (isBookmarkTable
1006 && initialValues.containsKey(BookmarkColumns.BOOKMARK)
1007 && initialValues.getAsInteger(BookmarkColumns.BOOKMARK) != 0) {
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001008 mBackupManager.dataChanged();
1009 }
The Android Open Source Project0c908882009-03-03 19:32:16 -08001010 return uri;
1011 }
1012
1013 @Override
1014 public int delete(Uri url, String where, String[] whereArgs) {
1015 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1016
1017 int match = URI_MATCHER.match(url);
1018 if (match == -1 || match == URI_MATCH_SUGGEST) {
1019 throw new IllegalArgumentException("Unknown URL");
1020 }
1021
Christopher Tatef0c36f72009-07-28 15:24:05 -07001022 // need to know whether it's the bookmarks table for a couple of reasons
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001023 boolean isBookmarkTable = (match == URI_MATCH_BOOKMARKS_ID);
Christopher Tatef0c36f72009-07-28 15:24:05 -07001024 String id = null;
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001025
1026 if (isBookmarkTable || match == URI_MATCH_SEARCHES_ID) {
The Android Open Source Project0c908882009-03-03 19:32:16 -08001027 StringBuilder sb = new StringBuilder();
1028 if (where != null && where.length() > 0) {
1029 sb.append("( ");
1030 sb.append(where);
1031 sb.append(" ) AND ");
1032 }
Christopher Tatef0c36f72009-07-28 15:24:05 -07001033 id = url.getPathSegments().get(1);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001034 sb.append("_id = ");
Christopher Tatef0c36f72009-07-28 15:24:05 -07001035 sb.append(id);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001036 where = sb.toString();
1037 }
1038
Christopher Tatef0c36f72009-07-28 15:24:05 -07001039 ContentResolver cr = getContext().getContentResolver();
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001040
Christopher Tatef0c36f72009-07-28 15:24:05 -07001041 // we'lll need to back up the bookmark set if we are about to delete one
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001042 if (isBookmarkTable) {
Christopher Tatef0c36f72009-07-28 15:24:05 -07001043 Cursor cursor = cr.query(Browser.BOOKMARKS_URI,
1044 new String[] { BookmarkColumns.BOOKMARK },
1045 "_id = " + id, null, null);
1046 if (cursor.moveToNext()) {
1047 if (cursor.getInt(0) != 0) {
1048 // yep, this record is a bookmark
1049 mBackupManager.dataChanged();
1050 }
1051 }
1052 cursor.close();
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001053 }
Christopher Tatef0c36f72009-07-28 15:24:05 -07001054
1055 int count = db.delete(TABLE_NAMES[match % 10], where, whereArgs);
1056 cr.notifyChange(url, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001057 return count;
1058 }
1059
1060 @Override
1061 public int update(Uri url, ContentValues values, String where,
1062 String[] whereArgs) {
1063 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1064
1065 int match = URI_MATCHER.match(url);
1066 if (match == -1 || match == URI_MATCH_SUGGEST) {
1067 throw new IllegalArgumentException("Unknown URL");
1068 }
1069
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001070 if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) {
The Android Open Source Project0c908882009-03-03 19:32:16 -08001071 StringBuilder sb = new StringBuilder();
1072 if (where != null && where.length() > 0) {
1073 sb.append("( ");
1074 sb.append(where);
1075 sb.append(" ) AND ");
1076 }
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001077 String id = url.getPathSegments().get(1);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001078 sb.append("_id = ");
Christopher Tatef0c36f72009-07-28 15:24:05 -07001079 sb.append(id);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001080 where = sb.toString();
1081 }
1082
Christopher Tatef0c36f72009-07-28 15:24:05 -07001083 ContentResolver cr = getContext().getContentResolver();
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001084
Christopher Tatef0c36f72009-07-28 15:24:05 -07001085 // Not all bookmark-table updates should be backed up. Look to see
1086 // whether we changed the title, url, or "is a bookmark" state, and
1087 // request a backup if so.
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001088 if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_BOOKMARKS) {
1089 boolean changingBookmarks = false;
Christopher Tatef0c36f72009-07-28 15:24:05 -07001090 // Alterations to the bookmark field inherently change the bookmark
1091 // set, so we don't need to query the record; we know a priori that
1092 // we will need to back up this change.
1093 if (values.containsKey(BookmarkColumns.BOOKMARK)) {
1094 changingBookmarks = true;
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001095 } else if ((values.containsKey(BookmarkColumns.TITLE)
1096 || values.containsKey(BookmarkColumns.URL))
1097 && values.containsKey(BookmarkColumns._ID)) {
1098 // If a title or URL has been changed, check to see if it is to
1099 // a bookmark. The ID should have been included in the update,
1100 // so use it.
Christopher Tatef0c36f72009-07-28 15:24:05 -07001101 Cursor cursor = cr.query(Browser.BOOKMARKS_URI,
1102 new String[] { BookmarkColumns.BOOKMARK },
Leon Scrogginsf2463ae2010-02-23 14:28:51 -05001103 BookmarkColumns._ID + " = "
1104 + values.getAsString(BookmarkColumns._ID), null, null);
Christopher Tatef0c36f72009-07-28 15:24:05 -07001105 if (cursor.moveToNext()) {
1106 changingBookmarks = (cursor.getInt(0) != 0);
1107 }
1108 cursor.close();
1109 }
1110
1111 // if this *is* a bookmark row we're altering, we need to back it up.
1112 if (changingBookmarks) {
1113 mBackupManager.dataChanged();
1114 }
Christopher Tate9c0dd8c2009-07-10 17:51:48 -07001115 }
Christopher Tatef0c36f72009-07-28 15:24:05 -07001116
1117 int ret = db.update(TABLE_NAMES[match % 10], values, where, whereArgs);
1118 cr.notifyChange(url, null);
The Android Open Source Project0c908882009-03-03 19:32:16 -08001119 return ret;
1120 }
Satish Sampath565505b2009-05-29 15:37:27 +01001121
Mike LeBeauc42f81b2009-05-14 15:04:19 -07001122 /**
1123 * Strips the provided url of preceding "http://" and any trailing "/". Does not
1124 * strip "https://". If the provided string cannot be stripped, the original string
1125 * is returned.
Satish Sampath565505b2009-05-29 15:37:27 +01001126 *
Mike LeBeauc42f81b2009-05-14 15:04:19 -07001127 * TODO: Put this in TextUtils to be used by other packages doing something similar.
Satish Sampath565505b2009-05-29 15:37:27 +01001128 *
Mike LeBeauc42f81b2009-05-14 15:04:19 -07001129 * @param url a url to strip, like "http://www.google.com/"
1130 * @return a stripped url like "www.google.com", or the original string if it could
1131 * not be stripped
1132 */
1133 private static String stripUrl(String url) {
1134 if (url == null) return null;
1135 Matcher m = STRIP_URL_PATTERN.matcher(url);
1136 if (m.matches() && m.groupCount() == 3) {
1137 return m.group(2);
1138 } else {
1139 return url;
1140 }
1141 }
1142
Michael Kolbfe251992010-07-08 15:41:55 -07001143 public static Cursor getBookmarksSuggestions(ContentResolver cr, String constraint) {
1144 Uri uri = Uri.parse("content://browser/" + SearchManager.SUGGEST_URI_PATH_QUERY);
1145 return cr.query(uri, SUGGEST_PROJECTION, SUGGEST_SELECTION,
1146 new String[] { constraint }, ORDER_BY);
1147 }
1148
The Android Open Source Project0c908882009-03-03 19:32:16 -08001149}