Browser.java revision d2334cb68aa4897a44ad33037c4c2e8657480466
1/* 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 android.provider; 18 19import android.content.ContentResolver; 20import android.content.ContentValues; 21import android.content.Context; 22import android.content.Intent; 23import android.database.Cursor; 24import android.database.DatabaseUtils; 25import android.net.Uri; 26import android.util.Log; 27import android.webkit.WebIconDatabase; 28 29import java.util.Date; 30 31public class Browser { 32 private static final String LOGTAG = "browser"; 33 public static final Uri BOOKMARKS_URI = 34 Uri.parse("content://browser/bookmarks"); 35 36 /** 37 * The name of extra data when starting Browser with ACTION_VIEW or 38 * ACTION_SEARCH intent. 39 * <p> 40 * The value should be an integer between 0 and 1000. If not set or set to 41 * 0, the Browser will use default. If set to 100, the Browser will start 42 * with 100%. 43 */ 44 public static final String INITIAL_ZOOM_LEVEL = "browser.initialZoomLevel"; 45 46 /** 47 * The name of the extra data when starting the Browser from another 48 * application. 49 * <p> 50 * The value is a unique identification string that will be used to 51 * indentify the calling application. The Browser will attempt to reuse the 52 * same window each time the application launches the Browser with the same 53 * identifier. 54 */ 55 public static final String EXTRA_APPLICATION_ID = 56 "com.android.browser.application_id"; 57 58 /** 59 * The name of the extra data in the VIEW intent. The data are key/value 60 * pairs in the format of Bundle. They will be sent in the HTTP request 61 * headers for the provided url. The keys can't be the standard HTTP headers 62 * as they are set by the WebView. The url's schema must be http(s). 63 * <p> 64 */ 65 public static final String EXTRA_HEADERS = "com.android.browser.headers"; 66 67 /* if you change column order you must also change indices 68 below */ 69 public static final String[] HISTORY_PROJECTION = new String[] { 70 BookmarkColumns._ID, BookmarkColumns.URL, BookmarkColumns.VISITS, 71 BookmarkColumns.DATE, BookmarkColumns.BOOKMARK, BookmarkColumns.TITLE, 72 BookmarkColumns.FAVICON, BookmarkColumns.THUMBNAIL, 73 BookmarkColumns.TOUCH_ICON, BookmarkColumns.USER_ENTERED }; 74 75 /* these indices dependent on HISTORY_PROJECTION */ 76 public static final int HISTORY_PROJECTION_ID_INDEX = 0; 77 public static final int HISTORY_PROJECTION_URL_INDEX = 1; 78 public static final int HISTORY_PROJECTION_VISITS_INDEX = 2; 79 public static final int HISTORY_PROJECTION_DATE_INDEX = 3; 80 public static final int HISTORY_PROJECTION_BOOKMARK_INDEX = 4; 81 public static final int HISTORY_PROJECTION_TITLE_INDEX = 5; 82 public static final int HISTORY_PROJECTION_FAVICON_INDEX = 6; 83 /** 84 * @hide 85 */ 86 public static final int HISTORY_PROJECTION_THUMBNAIL_INDEX = 7; 87 /** 88 * @hide 89 */ 90 public static final int HISTORY_PROJECTION_TOUCH_ICON_INDEX = 8; 91 92 /* columns needed to determine whether to truncate history */ 93 public static final String[] TRUNCATE_HISTORY_PROJECTION = new String[] { 94 BookmarkColumns._ID, BookmarkColumns.DATE, }; 95 public static final int TRUNCATE_HISTORY_PROJECTION_ID_INDEX = 0; 96 97 /* truncate this many history items at a time */ 98 public static final int TRUNCATE_N_OLDEST = 5; 99 100 public static final Uri SEARCHES_URI = 101 Uri.parse("content://browser/searches"); 102 103 /* if you change column order you must also change indices 104 below */ 105 public static final String[] SEARCHES_PROJECTION = new String[] { 106 SearchColumns._ID, SearchColumns.SEARCH, SearchColumns.DATE }; 107 108 /* these indices dependent on SEARCHES_PROJECTION */ 109 public static final int SEARCHES_PROJECTION_SEARCH_INDEX = 1; 110 public static final int SEARCHES_PROJECTION_DATE_INDEX = 2; 111 112 private static final String SEARCHES_WHERE_CLAUSE = "search = ?"; 113 114 /* Set a cap on the count of history items in the history/bookmark 115 table, to prevent db and layout operations from dragging to a 116 crawl. Revisit this cap when/if db/layout performance 117 improvements are made. Note: this does not affect bookmark 118 entries -- if the user wants more bookmarks than the cap, they 119 get them. */ 120 private static final int MAX_HISTORY_COUNT = 250; 121 122 /** 123 * URI for writing geolocation permissions. This requires the 124 * {@link android.Manifest.permission#WRITE_GEOLOCATION_PERMISSIONS}. 125 */ 126 public static final Uri GEOLOCATION_URI = 127 Uri.parse("content://browser/geolocation"); 128 129 private static final String GEOLOCATION_WHERE_CLAUSE = GeolocationColumns.ORIGIN + " = ?"; 130 131 /** 132 * Open the AddBookmark activity to save a bookmark. Launch with 133 * and/or url, which can be edited by the user before saving. 134 * @param c Context used to launch the AddBookmark activity. 135 * @param title Title for the bookmark. Can be null or empty string. 136 * @param url Url for the bookmark. Can be null or empty string. 137 */ 138 public static final void saveBookmark(Context c, 139 String title, 140 String url) { 141 Intent i = new Intent(Intent.ACTION_INSERT, Browser.BOOKMARKS_URI); 142 i.putExtra("title", title); 143 i.putExtra("url", url); 144 c.startActivity(i); 145 } 146 147 /** 148 * Stores a Bitmap extra in an {@link Intent} representing the screenshot of 149 * a page to share. When receiving an {@link Intent#ACTION_SEND} from the 150 * Browser, use this to access the screenshot. 151 * @hide 152 */ 153 public final static String EXTRA_SHARE_SCREENSHOT = "share_screenshot"; 154 155 /** 156 * Stores a Bitmap extra in an {@link Intent} representing the favicon of a 157 * page to share. When receiving an {@link Intent#ACTION_SEND} from the 158 * Browser, use this to access the favicon. 159 * @hide 160 */ 161 public final static String EXTRA_SHARE_FAVICON = "share_favicon"; 162 163 public static final void sendString(Context c, String s) { 164 sendString(c, s, c.getString(com.android.internal.R.string.sendText)); 165 } 166 167 /** 168 * Find an application to handle the given string and, if found, invoke 169 * it with the given string as a parameter. 170 * @param c Context used to launch the new activity. 171 * @param stringToSend The string to be handled. 172 * @param chooserDialogTitle The title of the dialog that allows the user 173 * to select between multiple applications that are all capable of handling 174 * the string. 175 * @hide pending API council approval 176 */ 177 public static final void sendString(Context c, 178 String stringToSend, 179 String chooserDialogTitle) { 180 Intent send = new Intent(Intent.ACTION_SEND); 181 send.setType("text/plain"); 182 send.putExtra(Intent.EXTRA_TEXT, stringToSend); 183 184 try { 185 c.startActivity(Intent.createChooser(send, chooserDialogTitle)); 186 } catch(android.content.ActivityNotFoundException ex) { 187 // if no app handles it, do nothing 188 } 189 } 190 191 /** 192 * Return a cursor pointing to a list of all the bookmarks. 193 * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} 194 * @param cr The ContentResolver used to access the database. 195 */ 196 public static final Cursor getAllBookmarks(ContentResolver cr) throws 197 IllegalStateException { 198 return cr.query(BOOKMARKS_URI, 199 new String[] { BookmarkColumns.URL }, 200 "bookmark = 1", null, null); 201 } 202 203 /** 204 * Return a cursor pointing to a list of all visited site urls. 205 * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} 206 * @param cr The ContentResolver used to access the database. 207 */ 208 public static final Cursor getAllVisitedUrls(ContentResolver cr) throws 209 IllegalStateException { 210 return cr.query(BOOKMARKS_URI, 211 new String[] { BookmarkColumns.URL }, null, null, null); 212 } 213 214 private static final void addOrUrlEquals(StringBuilder sb) { 215 sb.append(" OR " + BookmarkColumns.URL + " = "); 216 } 217 218 /** 219 * Return a Cursor with all history/bookmarks that are similar to url, 220 * where similar means 'http(s)://' and 'www.' are optional, but the rest 221 * of the url is the same. 222 * @param cr The ContentResolver used to access the database. 223 * @param url The url to compare to. 224 * @hide 225 */ 226 public static final Cursor getVisitedLike(ContentResolver cr, String url) { 227 boolean secure = false; 228 String compareString = url; 229 if (compareString.startsWith("http://")) { 230 compareString = compareString.substring(7); 231 } else if (compareString.startsWith("https://")) { 232 compareString = compareString.substring(8); 233 secure = true; 234 } 235 if (compareString.startsWith("www.")) { 236 compareString = compareString.substring(4); 237 } 238 StringBuilder whereClause = null; 239 if (secure) { 240 whereClause = new StringBuilder(BookmarkColumns.URL + " = "); 241 DatabaseUtils.appendEscapedSQLString(whereClause, 242 "https://" + compareString); 243 addOrUrlEquals(whereClause); 244 DatabaseUtils.appendEscapedSQLString(whereClause, 245 "https://www." + compareString); 246 } else { 247 whereClause = new StringBuilder(BookmarkColumns.URL + " = "); 248 DatabaseUtils.appendEscapedSQLString(whereClause, 249 compareString); 250 addOrUrlEquals(whereClause); 251 String wwwString = "www." + compareString; 252 DatabaseUtils.appendEscapedSQLString(whereClause, 253 wwwString); 254 addOrUrlEquals(whereClause); 255 DatabaseUtils.appendEscapedSQLString(whereClause, 256 "http://" + compareString); 257 addOrUrlEquals(whereClause); 258 DatabaseUtils.appendEscapedSQLString(whereClause, 259 "http://" + wwwString); 260 } 261 return cr.query(BOOKMARKS_URI, HISTORY_PROJECTION, 262 whereClause.toString(), null, null); 263 } 264 265 /** 266 * Update the visited history to acknowledge that a site has been 267 * visited. 268 * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} 269 * Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} 270 * @param cr The ContentResolver used to access the database. 271 * @param url The site being visited. 272 * @param real If true, this is an actual visit, and should add to the 273 * number of visits. If false, the user entered it manually. 274 */ 275 public static final void updateVisitedHistory(ContentResolver cr, 276 String url, boolean real) { 277 long now = new Date().getTime(); 278 try { 279 Cursor c = getVisitedLike(cr, url); 280 /* We should only get one answer that is exactly the same. */ 281 if (c.moveToFirst()) { 282 ContentValues map = new ContentValues(); 283 if (real) { 284 map.put(BookmarkColumns.VISITS, c 285 .getInt(HISTORY_PROJECTION_VISITS_INDEX) + 1); 286 } else { 287 map.put(BookmarkColumns.USER_ENTERED, 1); 288 } 289 map.put(BookmarkColumns.DATE, now); 290 cr.update(BOOKMARKS_URI, map, "_id = " + c.getInt(0), null); 291 } else { 292 truncateHistory(cr); 293 ContentValues map = new ContentValues(); 294 int visits; 295 int user_entered; 296 if (real) { 297 visits = 1; 298 user_entered = 0; 299 } else { 300 visits = 0; 301 user_entered = 1; 302 } 303 map.put(BookmarkColumns.URL, url); 304 map.put(BookmarkColumns.VISITS, visits); 305 map.put(BookmarkColumns.DATE, now); 306 map.put(BookmarkColumns.BOOKMARK, 0); 307 map.put(BookmarkColumns.TITLE, url); 308 map.put(BookmarkColumns.CREATED, 0); 309 map.put(BookmarkColumns.USER_ENTERED, user_entered); 310 cr.insert(BOOKMARKS_URI, map); 311 } 312 c.deactivate(); 313 } catch (IllegalStateException e) { 314 return; 315 } 316 } 317 318 /** 319 * Returns all the URLs in the history. 320 * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} 321 * @param cr The ContentResolver used to access the database. 322 * @hide pending API council approval 323 */ 324 public static final String[] getVisitedHistory(ContentResolver cr) { 325 try { 326 String[] projection = new String[] { 327 "url" 328 }; 329 Cursor c = cr.query(BOOKMARKS_URI, projection, "visits > 0", null, 330 null); 331 String[] str = new String[c.getCount()]; 332 int i = 0; 333 while (c.moveToNext()) { 334 str[i] = c.getString(0); 335 i++; 336 } 337 c.deactivate(); 338 return str; 339 } catch (IllegalStateException e) { 340 return new String[0]; 341 } 342 } 343 344 /** 345 * If there are more than MAX_HISTORY_COUNT non-bookmark history 346 * items in the bookmark/history table, delete TRUNCATE_N_OLDEST 347 * of them. This is used to keep our history table to a 348 * reasonable size. Note: it does not prune bookmarks. If the 349 * user wants 1000 bookmarks, the user gets 1000 bookmarks. 350 * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} 351 * Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} 352 * 353 * @param cr The ContentResolver used to access the database. 354 */ 355 public static final void truncateHistory(ContentResolver cr) { 356 try { 357 // Select non-bookmark history, ordered by date 358 Cursor c = cr.query( 359 BOOKMARKS_URI, 360 TRUNCATE_HISTORY_PROJECTION, 361 "bookmark = 0", 362 null, 363 BookmarkColumns.DATE); 364 // Log.v(LOGTAG, "history count " + c.count()); 365 if (c.moveToFirst() && c.getCount() >= MAX_HISTORY_COUNT) { 366 /* eliminate oldest history items */ 367 for (int i = 0; i < TRUNCATE_N_OLDEST; i++) { 368 // Log.v(LOGTAG, "truncate history " + 369 // c.getInt(TRUNCATE_HISTORY_PROJECTION_ID_INDEX)); 370 deleteHistoryWhere( 371 cr, "_id = " + 372 c.getInt(TRUNCATE_HISTORY_PROJECTION_ID_INDEX)); 373 if (!c.moveToNext()) break; 374 } 375 } 376 c.deactivate(); 377 } catch (IllegalStateException e) { 378 Log.e(LOGTAG, "truncateHistory", e); 379 return; 380 } 381 } 382 383 /** 384 * Returns whether there is any history to clear. 385 * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} 386 * @param cr The ContentResolver used to access the database. 387 * @return boolean True if the history can be cleared. 388 */ 389 public static final boolean canClearHistory(ContentResolver cr) { 390 try { 391 Cursor c = cr.query( 392 BOOKMARKS_URI, 393 new String [] { BookmarkColumns._ID, 394 BookmarkColumns.BOOKMARK, 395 BookmarkColumns.VISITS }, 396 "bookmark = 0 OR visits > 0", 397 null, 398 null 399 ); 400 boolean ret = c.moveToFirst(); 401 c.deactivate(); 402 return ret; 403 } catch (IllegalStateException e) { 404 return false; 405 } 406 } 407 408 /** 409 * Delete all entries from the bookmarks/history table which are 410 * not bookmarks. Also set all visited bookmarks to unvisited. 411 * Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} 412 * @param cr The ContentResolver used to access the database. 413 */ 414 public static final void clearHistory(ContentResolver cr) { 415 deleteHistoryWhere(cr, null); 416 } 417 418 /** 419 * Helper function to delete all history items and revert all 420 * bookmarks to zero visits which meet the criteria provided. 421 * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} 422 * Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} 423 * @param cr The ContentResolver used to access the database. 424 * @param whereClause String to limit the items affected. 425 * null means all items. 426 */ 427 private static final void deleteHistoryWhere(ContentResolver cr, 428 String whereClause) { 429 try { 430 Cursor c = cr.query(BOOKMARKS_URI, 431 HISTORY_PROJECTION, 432 whereClause, 433 null, 434 null); 435 if (!c.moveToFirst()) { 436 c.deactivate(); 437 return; 438 } 439 440 final WebIconDatabase iconDb = WebIconDatabase.getInstance(); 441 /* Delete favicons, and revert bookmarks which have been visited 442 * to simply bookmarks. 443 */ 444 StringBuffer sb = new StringBuffer(); 445 boolean firstTime = true; 446 do { 447 String url = c.getString(HISTORY_PROJECTION_URL_INDEX); 448 boolean isBookmark = 449 c.getInt(HISTORY_PROJECTION_BOOKMARK_INDEX) == 1; 450 if (isBookmark) { 451 if (firstTime) { 452 firstTime = false; 453 } else { 454 sb.append(" OR "); 455 } 456 sb.append("( _id = "); 457 sb.append(c.getInt(0)); 458 sb.append(" )"); 459 } else { 460 iconDb.releaseIconForPageUrl(url); 461 } 462 } while (c.moveToNext()); 463 c.deactivate(); 464 465 if (!firstTime) { 466 ContentValues map = new ContentValues(); 467 map.put(BookmarkColumns.VISITS, 0); 468 map.put(BookmarkColumns.DATE, 0); 469 /* FIXME: Should I also remove the title? */ 470 cr.update(BOOKMARKS_URI, map, sb.toString(), null); 471 } 472 473 String deleteWhereClause = BookmarkColumns.BOOKMARK + " = 0"; 474 if (whereClause != null) { 475 deleteWhereClause += " AND " + whereClause; 476 } 477 cr.delete(BOOKMARKS_URI, deleteWhereClause, null); 478 } catch (IllegalStateException e) { 479 return; 480 } 481 } 482 483 /** 484 * Delete all history items from begin to end. 485 * Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} 486 * @param cr The ContentResolver used to access the database. 487 * @param begin First date to remove. If -1, all dates before end. 488 * Inclusive. 489 * @param end Last date to remove. If -1, all dates after begin. 490 * Non-inclusive. 491 */ 492 public static final void deleteHistoryTimeFrame(ContentResolver cr, 493 long begin, long end) { 494 String whereClause; 495 String date = BookmarkColumns.DATE; 496 if (-1 == begin) { 497 if (-1 == end) { 498 clearHistory(cr); 499 return; 500 } 501 whereClause = date + " < " + Long.toString(end); 502 } else if (-1 == end) { 503 whereClause = date + " >= " + Long.toString(begin); 504 } else { 505 whereClause = date + " >= " + Long.toString(begin) + " AND " + date 506 + " < " + Long.toString(end); 507 } 508 deleteHistoryWhere(cr, whereClause); 509 } 510 511 /** 512 * Remove a specific url from the history database. 513 * Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} 514 * @param cr The ContentResolver used to access the database. 515 * @param url url to remove. 516 */ 517 public static final void deleteFromHistory(ContentResolver cr, 518 String url) { 519 StringBuilder sb = new StringBuilder(BookmarkColumns.URL + " = "); 520 DatabaseUtils.appendEscapedSQLString(sb, url); 521 String matchesUrl = sb.toString(); 522 deleteHistoryWhere(cr, matchesUrl); 523 } 524 525 /** 526 * Add a search string to the searches database. 527 * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} 528 * Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} 529 * @param cr The ContentResolver used to access the database. 530 * @param search The string to add to the searches database. 531 */ 532 public static final void addSearchUrl(ContentResolver cr, String search) { 533 long now = new Date().getTime(); 534 try { 535 Cursor c = cr.query( 536 SEARCHES_URI, 537 SEARCHES_PROJECTION, 538 SEARCHES_WHERE_CLAUSE, 539 new String [] { search }, 540 null); 541 ContentValues map = new ContentValues(); 542 map.put(SearchColumns.SEARCH, search); 543 map.put(SearchColumns.DATE, now); 544 /* We should only get one answer that is exactly the same. */ 545 if (c.moveToFirst()) { 546 cr.update(SEARCHES_URI, map, "_id = " + c.getInt(0), null); 547 } else { 548 cr.insert(SEARCHES_URI, map); 549 } 550 c.deactivate(); 551 } catch (IllegalStateException e) { 552 Log.e(LOGTAG, "addSearchUrl", e); 553 return; 554 } 555 } 556 /** 557 * Remove all searches from the search database. 558 * Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} 559 * @param cr The ContentResolver used to access the database. 560 */ 561 public static final void clearSearches(ContentResolver cr) { 562 // FIXME: Should this clear the urls to which these searches lead? 563 // (i.e. remove google.com/query= blah blah blah) 564 try { 565 cr.delete(SEARCHES_URI, null, null); 566 } catch (IllegalStateException e) { 567 Log.e(LOGTAG, "clearSearches", e); 568 } 569 } 570 571 /** 572 * Request all icons from the database. 573 * Requires {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} 574 * @param cr The ContentResolver used to access the database. 575 * @param where Clause to be used to limit the query from the database. 576 * Must be an allowable string to be passed into a database query. 577 * @param listener IconListener that gets the icons once they are 578 * retrieved. 579 */ 580 public static final void requestAllIcons(ContentResolver cr, String where, 581 WebIconDatabase.IconListener listener) { 582 try { 583 final Cursor c = cr.query( 584 BOOKMARKS_URI, 585 HISTORY_PROJECTION, 586 where, null, null); 587 if (c.moveToFirst()) { 588 final WebIconDatabase db = WebIconDatabase.getInstance(); 589 do { 590 db.requestIconForPageUrl( 591 c.getString(HISTORY_PROJECTION_URL_INDEX), 592 listener); 593 } while (c.moveToNext()); 594 } 595 c.deactivate(); 596 } catch (IllegalStateException e) { 597 Log.e(LOGTAG, "requestAllIcons", e); 598 } 599 } 600 601 /** 602 * Allows geolocation for the specified origin. 603 * This requires the {@link android.Manifest.permission#WRITE_GEOLOCATION_PERMISSIONS} 604 * permission. 605 * 606 * @param origin The origin to allow geolocation for, e.g. "http://www.google.com". The string 607 * should not include a trailing slash. 608 */ 609 public static void allowGeolocation(ContentResolver cr, String origin) { 610 try { 611 ContentValues map = new ContentValues(); 612 map.put(GeolocationColumns.ORIGIN, origin); 613 cr.insert(GEOLOCATION_URI, map); 614 } catch (IllegalStateException e) { 615 Log.e(LOGTAG, "allowGeolocation", e); 616 return; 617 } 618 } 619 620 /** 621 * Clears the geolocation permission state for the specified origin. 622 * This requires the {@link android.Manifest.permission#WRITE_GEOLOCATION_PERMISSIONS} 623 * permission. 624 * 625 * @param origin The origin to allow geolocation for, e.g. "http://www.google.com". The string 626 * should not include a trailing slash. 627 */ 628 public static void clearGeolocation(ContentResolver cr, String origin) { 629 try { 630 String[] whereArgs = { origin }; 631 cr.delete(GEOLOCATION_URI, GEOLOCATION_WHERE_CLAUSE, whereArgs); 632 } catch (IllegalStateException e) { 633 Log.e(LOGTAG, "clearGeolocation", e); 634 } 635 } 636 637 public static class BookmarkColumns implements BaseColumns { 638 public static final String URL = "url"; 639 public static final String VISITS = "visits"; 640 public static final String DATE = "date"; 641 public static final String BOOKMARK = "bookmark"; 642 public static final String TITLE = "title"; 643 public static final String CREATED = "created"; 644 public static final String FAVICON = "favicon"; 645 /** 646 * @hide 647 */ 648 public static final String THUMBNAIL = "thumbnail"; 649 /** 650 * @hide 651 */ 652 public static final String TOUCH_ICON = "touch_icon"; 653 /** 654 * @hide 655 */ 656 public static final String USER_ENTERED = "user_entered"; 657 } 658 659 public static class SearchColumns implements BaseColumns { 660 public static final String URL = "url"; 661 public static final String SEARCH = "search"; 662 public static final String DATE = "date"; 663 } 664 665 public static class GeolocationColumns { 666 public static final String ORIGIN = "origin"; 667 } 668} 669