blob: bf74ba23abff33b5e98796977bed1e1d6aca7d28 [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
19import android.content.ContentResolver;
20import android.content.ContentUris;
21import android.content.ContentValues;
22import android.database.ContentObserver;
23import android.database.Cursor;
24import android.database.DataSetObserver;
25import android.graphics.Bitmap;
26import android.graphics.BitmapFactory;
27import android.net.Uri;
28import android.os.Bundle;
29import android.os.Handler;
30import android.provider.Browser;
31import android.provider.Browser.BookmarkColumns;
32import android.view.KeyEvent;
Leon Scroggins892df312009-07-14 14:48:02 -040033import android.view.LayoutInflater;
The Android Open Source Project0c908882009-03-03 19:32:16 -080034import android.view.View;
35import android.view.ViewGroup;
36import android.webkit.WebIconDatabase;
37import android.webkit.WebIconDatabase.IconListener;
Patrick Scott3918d442009-08-04 13:22:29 -040038import android.webkit.WebView;
The Android Open Source Project0c908882009-03-03 19:32:16 -080039import android.widget.BaseAdapter;
Leon Scroggins892df312009-07-14 14:48:02 -040040import android.widget.ImageView;
41import android.widget.TextView;
The Android Open Source Project0c908882009-03-03 19:32:16 -080042
43import java.io.ByteArrayOutputStream;
44
45class BrowserBookmarksAdapter extends BaseAdapter {
46
The Android Open Source Project0c908882009-03-03 19:32:16 -080047 private String mCurrentPage;
Leon Scroggins89c6d362009-07-15 16:54:37 -040048 private String mCurrentTitle;
The Android Open Source Project0c908882009-03-03 19:32:16 -080049 private Cursor mCursor;
50 private int mCount;
The Android Open Source Project0c908882009-03-03 19:32:16 -080051 private BrowserBookmarksPage mBookmarksPage;
52 private ContentResolver mContentResolver;
The Android Open Source Project0c908882009-03-03 19:32:16 -080053 private boolean mDataValid;
Leon Scroggins892df312009-07-14 14:48:02 -040054 private boolean mGridMode;
Leon Scrogginsa5d669e2009-08-05 14:07:58 -040055 private boolean mMostVisited;
56 private boolean mNeedsOffset;
57 private int mExtraOffset;
The Android Open Source Project0c908882009-03-03 19:32:16 -080058
59 // Implementation of WebIconDatabase.IconListener
60 private class IconReceiver implements IconListener {
61 public void onReceivedIcon(String url, Bitmap icon) {
Patrick Scott3918d442009-08-04 13:22:29 -040062 updateBookmarkFavicon(mContentResolver, null, url, icon);
The Android Open Source Project0c908882009-03-03 19:32:16 -080063 }
64 }
65
66 // Instance of IconReceiver
67 private final IconReceiver mIconReceiver = new IconReceiver();
68
69 /**
70 * Create a new BrowserBookmarksAdapter.
The Android Open Source Project0c908882009-03-03 19:32:16 -080071 * @param b BrowserBookmarksPage that instantiated this.
72 * Necessary so it will adjust its focus
73 * appropriately after a search.
74 */
75 public BrowserBookmarksAdapter(BrowserBookmarksPage b, String curPage,
Leon Scrogginsa5d669e2009-08-05 14:07:58 -040076 String curTitle, boolean createShortcut, boolean mostVisited) {
77 mNeedsOffset = !(createShortcut || mostVisited);
78 mMostVisited = mostVisited;
79 mExtraOffset = mNeedsOffset ? 1 : 0;
The Android Open Source Project0c908882009-03-03 19:32:16 -080080 mBookmarksPage = b;
Leon Scroggins89c6d362009-07-15 16:54:37 -040081 mCurrentPage = b.getResources().getString(R.string.current_page)
82 + curPage;
83 mCurrentTitle = curTitle;
The Android Open Source Project0c908882009-03-03 19:32:16 -080084 mContentResolver = b.getContentResolver();
Leon Scroggins892df312009-07-14 14:48:02 -040085 mGridMode = false;
86
Leon Scrogginsa5d669e2009-08-05 14:07:58 -040087 String whereClause;
The Android Open Source Project0c908882009-03-03 19:32:16 -080088 // FIXME: Should have a default sort order that the user selects.
Leon Scroggins892df312009-07-14 14:48:02 -040089 String orderBy = Browser.BookmarkColumns.VISITS + " DESC";
Leon Scrogginsa5d669e2009-08-05 14:07:58 -040090 if (mostVisited) {
91 whereClause = Browser.BookmarkColumns.VISITS + " != 0";
92 } else {
93 whereClause = Browser.BookmarkColumns.BOOKMARK + " != 0";
94 }
Leon Scroggins892df312009-07-14 14:48:02 -040095 mCursor = b.managedQuery(Browser.BOOKMARKS_URI,
96 Browser.HISTORY_PROJECTION, whereClause, null, orderBy);
97 mCursor.registerContentObserver(new ChangeObserver());
98 mCursor.registerDataSetObserver(new MyDataSetObserver());
99
100 mDataValid = true;
101 notifyDataSetChanged();
102
103 mCount = mCursor.getCount() + mExtraOffset;
104
The Android Open Source Project0c908882009-03-03 19:32:16 -0800105 // FIXME: This requires another query of the database after the
Leon Scroggins89c6d362009-07-15 16:54:37 -0400106 // managedQuery. Can we optimize this?
The Android Open Source Project0c908882009-03-03 19:32:16 -0800107 Browser.requestAllIcons(mContentResolver,
108 Browser.BookmarkColumns.FAVICON + " is NULL AND " +
109 Browser.BookmarkColumns.BOOKMARK + " == 1", mIconReceiver);
110 }
111
112 /**
113 * Return a hashmap with one row's Title, Url, and favicon.
114 * @param position Position in the list.
115 * @return Bundle Stores title, url of row position, favicon, and id
116 * for the url. Return a blank map if position is out of
117 * range.
118 */
119 public Bundle getRow(int position) {
120 Bundle map = new Bundle();
121 if (position < mExtraOffset || position >= mCount) {
122 return map;
123 }
124 mCursor.moveToPosition(position- mExtraOffset);
125 String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX);
126 map.putString(Browser.BookmarkColumns.TITLE,
127 mCursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX));
128 map.putString(Browser.BookmarkColumns.URL, url);
129 byte[] data = mCursor.getBlob(Browser.HISTORY_PROJECTION_FAVICON_INDEX);
130 if (data != null) {
131 map.putParcelable(Browser.BookmarkColumns.FAVICON,
132 BitmapFactory.decodeByteArray(data, 0, data.length));
133 }
134 map.putInt("id", mCursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX));
135 return map;
136 }
137
138 /**
139 * Update a row in the database with new information.
140 * Requeries the database if the information has changed.
141 * @param map Bundle storing id, title and url of new information
142 */
143 public void updateRow(Bundle map) {
144
145 // Find the record
146 int id = map.getInt("id");
147 int position = -1;
148 for (mCursor.moveToFirst(); !mCursor.isAfterLast(); mCursor.moveToNext()) {
149 if (mCursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX) == id) {
150 position = mCursor.getPosition();
151 break;
152 }
153 }
154 if (position < 0) {
155 return;
156 }
157
158 mCursor.moveToPosition(position);
159 ContentValues values = new ContentValues();
160 String title = map.getString(Browser.BookmarkColumns.TITLE);
161 if (!title.equals(mCursor
162 .getString(Browser.HISTORY_PROJECTION_TITLE_INDEX))) {
163 values.put(Browser.BookmarkColumns.TITLE, title);
164 }
165 String url = map.getString(Browser.BookmarkColumns.URL);
166 if (!url.equals(mCursor.
167 getString(Browser.HISTORY_PROJECTION_URL_INDEX))) {
168 values.put(Browser.BookmarkColumns.URL, url);
169 }
170 if (values.size() > 0
171 && mContentResolver.update(Browser.BOOKMARKS_URI, values,
172 "_id = " + id, null) != -1) {
173 refreshList();
174 }
175 }
176
177 /**
178 * Delete a row from the database. Requeries the database.
179 * Does nothing if the provided position is out of range.
180 * @param position Position in the list.
181 */
182 public void deleteRow(int position) {
183 if (position < mExtraOffset || position >= getCount()) {
184 return;
185 }
186 mCursor.moveToPosition(position- mExtraOffset);
187 String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX);
Leon Scrogginse372c022009-06-12 17:07:29 -0400188 Bookmarks.removeFromBookmarks(null, mContentResolver, url);
The Android Open Source Project0c908882009-03-03 19:32:16 -0800189 refreshList();
190 }
191
192 /**
193 * Delete all bookmarks from the db. Requeries the database.
194 * All bookmarks with become visited URLs or if never visited
195 * are removed
196 */
197 public void deleteAllRows() {
198 StringBuilder deleteIds = null;
199 StringBuilder convertIds = null;
200
201 for (mCursor.moveToFirst(); !mCursor.isAfterLast(); mCursor.moveToNext()) {
202 String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX);
203 WebIconDatabase.getInstance().releaseIconForPageUrl(url);
204 int id = mCursor.getInt(Browser.HISTORY_PROJECTION_ID_INDEX);
205 int numVisits = mCursor.getInt(Browser.HISTORY_PROJECTION_VISITS_INDEX);
206 if (0 == numVisits) {
207 if (deleteIds == null) {
208 deleteIds = new StringBuilder();
209 deleteIds.append("( ");
210 } else {
211 deleteIds.append(" OR ( ");
212 }
213 deleteIds.append(BookmarkColumns._ID);
214 deleteIds.append(" = ");
215 deleteIds.append(id);
216 deleteIds.append(" )");
217 } else {
218 // It is no longer a bookmark, but it is still a visited site.
219 if (convertIds == null) {
220 convertIds = new StringBuilder();
221 convertIds.append("( ");
222 } else {
223 convertIds.append(" OR ( ");
224 }
225 convertIds.append(BookmarkColumns._ID);
226 convertIds.append(" = ");
227 convertIds.append(id);
228 convertIds.append(" )");
229 }
230 }
231
232 if (deleteIds != null) {
233 mContentResolver.delete(Browser.BOOKMARKS_URI, deleteIds.toString(),
234 null);
235 }
236 if (convertIds != null) {
237 ContentValues values = new ContentValues();
238 values.put(Browser.BookmarkColumns.BOOKMARK, 0);
239 mContentResolver.update(Browser.BOOKMARKS_URI, values,
240 convertIds.toString(), null);
241 }
242 refreshList();
243 }
244
245 /**
246 * Refresh list to recognize a change in the database.
247 */
248 public void refreshList() {
Leon Scroggins892df312009-07-14 14:48:02 -0400249 mCursor.requery();
250 mCount = mCursor.getCount() + mExtraOffset;
251 notifyDataSetChanged();
The Android Open Source Project0c908882009-03-03 19:32:16 -0800252 }
253
254 /**
Patrick Scott3918d442009-08-04 13:22:29 -0400255 * Update the bookmark's favicon. This is a convenience method for updating
256 * a bookmark favicon for the originalUrl and url of the passed in WebView.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800257 * @param cr The ContentResolver to use.
Patrick Scott3918d442009-08-04 13:22:29 -0400258 * @param WebView The WebView containing the url to update.
The Android Open Source Project0c908882009-03-03 19:32:16 -0800259 * @param favicon The favicon bitmap to write to the db.
260 */
261 /* package */ static void updateBookmarkFavicon(ContentResolver cr,
Patrick Scott3918d442009-08-04 13:22:29 -0400262 WebView view, Bitmap favicon) {
263 if (view != null) {
264 updateBookmarkFavicon(cr, view.getOriginalUrl(), view.getUrl(),
265 favicon);
266 }
267 }
268
269 private static void updateBookmarkFavicon(ContentResolver cr,
270 String originalUrl, String url, Bitmap favicon) {
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400271 final Cursor c = queryBookmarksForUrl(cr, originalUrl, url, true);
Patrick Scott3918d442009-08-04 13:22:29 -0400272 if (c == null) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800273 return;
274 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800275 boolean succeed = c.moveToFirst();
276 ContentValues values = null;
277 while (succeed) {
278 if (values == null) {
279 final ByteArrayOutputStream os = new ByteArrayOutputStream();
280 favicon.compress(Bitmap.CompressFormat.PNG, 100, os);
281 values = new ContentValues();
282 values.put(Browser.BookmarkColumns.FAVICON, os.toByteArray());
283 }
284 cr.update(ContentUris.withAppendedId(Browser.BOOKMARKS_URI, c
285 .getInt(0)), values, null, null);
286 succeed = c.moveToNext();
287 }
288 c.close();
289 }
290
Patrick Scott3918d442009-08-04 13:22:29 -0400291 /* package */ static Cursor queryBookmarksForUrl(ContentResolver cr,
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400292 String originalUrl, String url, boolean onlyBookmarks) {
Patrick Scott3918d442009-08-04 13:22:29 -0400293 if (cr == null || url == null) {
294 return null;
295 }
296
297 // If originalUrl is null, just set it to url.
298 if (originalUrl == null) {
299 originalUrl = url;
300 }
301
302 // Look for both the original url and the actual url. This takes in to
303 // account redirects.
304 String originalUrlNoQuery = removeQuery(originalUrl);
305 String urlNoQuery = removeQuery(url);
306 originalUrl = originalUrlNoQuery + '?';
307 url = urlNoQuery + '?';
308
309 // Use NoQuery to search for the base url (i.e. if the url is
310 // http://www.yahoo.com/?rs=1, search for http://www.yahoo.com)
311 // Use url to match the base url with other queries (i.e. if the url is
312 // http://www.google.com/m, search for
313 // http://www.google.com/m?some_query)
314 final String[] selArgs = new String[] {
315 originalUrlNoQuery, urlNoQuery, originalUrl, url };
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400316 String where = BookmarkColumns.URL + " == ? OR "
Patrick Scott3918d442009-08-04 13:22:29 -0400317 + BookmarkColumns.URL + " == ? OR "
318 + BookmarkColumns.URL + " GLOB ? || '*' OR "
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400319 + BookmarkColumns.URL + " GLOB ? || '*'";
320 if (onlyBookmarks) {
321 where = "(" + where + ") AND " + BookmarkColumns.BOOKMARK + " == 1";
322 }
Patrick Scott3918d442009-08-04 13:22:29 -0400323 final String[] projection =
324 new String[] { Browser.BookmarkColumns._ID };
325 return cr.query(Browser.BOOKMARKS_URI, projection, where, selArgs,
326 null);
327 }
328
329 // Strip the query from the given url.
330 private static String removeQuery(String url) {
331 if (url == null) {
332 return null;
333 }
334 int query = url.indexOf('?');
335 String noQuery = url;
336 if (query != -1) {
337 noQuery = url.substring(0, query);
338 }
339 return noQuery;
340 }
341
The Android Open Source Project0c908882009-03-03 19:32:16 -0800342 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800343 * How many items should be displayed in the list.
344 * @return Count of items.
345 */
346 public int getCount() {
347 if (mDataValid) {
348 return mCount;
349 } else {
350 return 0;
351 }
352 }
353
354 public boolean areAllItemsEnabled() {
355 return true;
356 }
357
358 public boolean isEnabled(int position) {
359 return true;
360 }
361
362 /**
363 * Get the data associated with the specified position in the list.
364 * @param position Index of the item whose data we want.
365 * @return The data at the specified position.
366 */
367 public Object getItem(int position) {
368 return null;
369 }
370
371 /**
372 * Get the row id associated with the specified position in the list.
373 * @param position Index of the item whose row id we want.
374 * @return The id of the item at the specified position.
375 */
376 public long getItemId(int position) {
377 return position;
378 }
379
Leon Scroggins892df312009-07-14 14:48:02 -0400380 /* package */ void switchViewMode(boolean toGrid) {
381 mGridMode = toGrid;
382 }
383
384 /* package */ void populateBookmarkItem(BookmarkItem b, int position) {
385 mCursor.moveToPosition(position - mExtraOffset);
386 b.setUrl(mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX));
387 b.setName(mCursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX));
388 byte[] data = mCursor.getBlob(Browser.HISTORY_PROJECTION_FAVICON_INDEX);
389 Bitmap bitmap = (null == data) ? null :
390 BitmapFactory.decodeByteArray(data, 0, data.length);
391 b.setFavicon(bitmap);
392 }
393
The Android Open Source Project0c908882009-03-03 19:32:16 -0800394 /**
395 * Get a View that displays the data at the specified position
396 * in the list.
397 * @param position Index of the item whose view we want.
398 * @return A View corresponding to the data at the specified position.
399 */
400 public View getView(int position, View convertView, ViewGroup parent) {
401 if (!mDataValid) {
402 throw new IllegalStateException(
403 "this should only be called when the cursor is valid");
404 }
405 if (position < 0 || position > mCount) {
406 throw new AssertionError(
407 "BrowserBookmarksAdapter tried to get a view out of range");
408 }
Leon Scroggins892df312009-07-14 14:48:02 -0400409 if (mGridMode) {
410 if (convertView == null || convertView instanceof AddNewBookmark
411 || convertView instanceof BookmarkItem) {
412 LayoutInflater factory = LayoutInflater.from(mBookmarksPage);
413 convertView
414 = factory.inflate(R.layout.bookmark_thumbnail, null);
415 }
Leon Scroggins89c6d362009-07-15 16:54:37 -0400416 View holder = convertView.findViewById(R.id.holder);
Leon Scroggins892df312009-07-14 14:48:02 -0400417 ImageView thumb = (ImageView) convertView.findViewById(R.id.thumb);
Leon Scroggins892df312009-07-14 14:48:02 -0400418 TextView tv = (TextView) convertView.findViewById(R.id.label);
419
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400420 if (0 == position && mNeedsOffset) {
Leon Scroggins892df312009-07-14 14:48:02 -0400421 // This is to create a bookmark for the current page.
Leon Scroggins89c6d362009-07-15 16:54:37 -0400422 holder.setVisibility(View.VISIBLE);
Leon Scroggins89c6d362009-07-15 16:54:37 -0400423 tv.setText(mCurrentTitle);
424 // FIXME: Want to show the screenshot of the current page
425 thumb.setImageResource(R.drawable.blank);
Leon Scroggins892df312009-07-14 14:48:02 -0400426 return convertView;
427 }
Leon Scroggins89c6d362009-07-15 16:54:37 -0400428 holder.setVisibility(View.GONE);
Leon Scroggins892df312009-07-14 14:48:02 -0400429 mCursor.moveToPosition(position - mExtraOffset);
430 tv.setText(mCursor.getString(
431 Browser.HISTORY_PROJECTION_TITLE_INDEX));
432 byte[] data = mCursor.getBlob(
433 Browser.HISTORY_PROJECTION_THUMBNAIL_INDEX);
434 if (data == null) {
435 // Backup is to just show white
436 thumb.setImageResource(R.drawable.blank);
437 } else {
438 thumb.setImageBitmap(
439 BitmapFactory.decodeByteArray(data, 0, data.length));
440 }
Leon Scroggins89c6d362009-07-15 16:54:37 -0400441
Leon Scroggins892df312009-07-14 14:48:02 -0400442 return convertView;
443
444 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400445 if (position == 0 && mNeedsOffset) {
The Android Open Source Project0c908882009-03-03 19:32:16 -0800446 AddNewBookmark b;
447 if (convertView instanceof AddNewBookmark) {
448 b = (AddNewBookmark) convertView;
449 } else {
450 b = new AddNewBookmark(mBookmarksPage);
451 }
452 b.setUrl(mCurrentPage);
453 return b;
454 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400455 if (mMostVisited) {
456 if (convertView == null || !(convertView instanceof HistoryItem)) {
457 convertView = new HistoryItem(mBookmarksPage);
458 }
459 } else {
460 if (convertView == null || !(convertView instanceof BookmarkItem)) {
461 convertView = new BookmarkItem(mBookmarksPage);
462 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800463 }
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400464 bind((BookmarkItem) convertView, position);
465 if (mMostVisited) {
466 ((HistoryItem) convertView).setIsBookmark(
467 getIsBookmark(position));
468 }
The Android Open Source Project0c908882009-03-03 19:32:16 -0800469 return convertView;
470 }
471
472 /**
473 * Return the title for this item in the list.
474 */
475 public String getTitle(int position) {
476 return getString(Browser.HISTORY_PROJECTION_TITLE_INDEX, position);
477 }
478
479 /**
480 * Return the Url for this item in the list.
481 */
482 public String getUrl(int position) {
483 return getString(Browser.HISTORY_PROJECTION_URL_INDEX, position);
484 }
485
486 /**
Patrick Scotte09761e2009-03-24 20:43:37 -0700487 * Return the favicon for this item in the list.
488 */
489 public Bitmap getFavicon(int position) {
Patrick Scott3918d442009-08-04 13:22:29 -0400490 return getBitmap(Browser.HISTORY_PROJECTION_FAVICON_INDEX, position);
491 }
492
493 public Bitmap getTouchIcon(int position) {
494 return getBitmap(Browser.HISTORY_PROJECTION_TOUCH_ICON_INDEX, position);
495 }
496
497 private Bitmap getBitmap(int cursorIndex, int position) {
Patrick Scotte09761e2009-03-24 20:43:37 -0700498 if (position < mExtraOffset || position > mCount) {
499 return null;
500 }
501 mCursor.moveToPosition(position - mExtraOffset);
Patrick Scott3918d442009-08-04 13:22:29 -0400502 byte[] data = mCursor.getBlob(cursorIndex);
Patrick Scotte09761e2009-03-24 20:43:37 -0700503 if (data == null) {
504 return null;
505 }
506 return BitmapFactory.decodeByteArray(data, 0, data.length);
507 }
508
509 /**
Leon Scrogginsa5d669e2009-08-05 14:07:58 -0400510 * Return whether or not this item represents a bookmarked site.
511 */
512 public boolean getIsBookmark(int position) {
513 if (position < mExtraOffset || position > mCount) {
514 return false;
515 }
516 mCursor.moveToPosition(position - mExtraOffset);
517 return (1 == mCursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX));
518 }
519
520 /**
The Android Open Source Project0c908882009-03-03 19:32:16 -0800521 * Private helper function to return the title or url.
522 */
523 private String getString(int cursorIndex, int position) {
524 if (position < mExtraOffset || position > mCount) {
525 return "";
526 }
527 mCursor.moveToPosition(position- mExtraOffset);
528 return mCursor.getString(cursorIndex);
529 }
530
531 private void bind(BookmarkItem b, int position) {
532 mCursor.moveToPosition(position- mExtraOffset);
533
534 String title = mCursor.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX);
535 if (title.length() > BrowserSettings.MAX_TEXTVIEW_LEN) {
536 title = title.substring(0, BrowserSettings.MAX_TEXTVIEW_LEN);
537 }
538 b.setName(title);
539 String url = mCursor.getString(Browser.HISTORY_PROJECTION_URL_INDEX);
540 if (url.length() > BrowserSettings.MAX_TEXTVIEW_LEN) {
541 url = url.substring(0, BrowserSettings.MAX_TEXTVIEW_LEN);
542 }
543 b.setUrl(url);
544 byte[] data = mCursor.getBlob(Browser.HISTORY_PROJECTION_FAVICON_INDEX);
545 if (data != null) {
546 b.setFavicon(BitmapFactory.decodeByteArray(data, 0, data.length));
547 } else {
548 b.setFavicon(null);
549 }
550 }
551
552 private class ChangeObserver extends ContentObserver {
553 public ChangeObserver() {
554 super(new Handler());
555 }
556
557 @Override
558 public boolean deliverSelfNotifications() {
559 return true;
560 }
561
562 @Override
563 public void onChange(boolean selfChange) {
564 refreshList();
565 }
566 }
567
568 private class MyDataSetObserver extends DataSetObserver {
569 @Override
570 public void onChanged() {
571 mDataValid = true;
572 notifyDataSetChanged();
573 }
574
575 @Override
576 public void onInvalidated() {
577 mDataValid = false;
578 notifyDataSetInvalidated();
579 }
580 }
581}