diff options
author | Patrick Scott <phanna@android.com> | 2009-08-04 13:22:29 -0400 |
---|---|---|
committer | Patrick Scott <phanna@android.com> | 2009-08-05 10:52:30 -0400 |
commit | 3918d4443ff38ef1870e02aa51a8b29f8352bb1a (patch) | |
tree | 72751daaca11780acba4f57c73619f4f37f6964c /src/com/android/browser | |
parent | 13feaed9ab1b9a3b8cc5ac1b33e36005802b9fc3 (diff) | |
download | packages_apps_Browser-3918d4443ff38ef1870e02aa51a8b29f8352bb1a.zip packages_apps_Browser-3918d4443ff38ef1870e02aa51a8b29f8352bb1a.tar.gz packages_apps_Browser-3918d4443ff38ef1870e02aa51a8b29f8352bb1a.tar.bz2 |
Implement onReceivedTouchIconUrl.
Add DownloadTouchIcon, an AsyncTask that downloads the apple-touch-icon for urls
that are marked as bookmarks. The touch icon is stored in the bookmark database
similar to favicons and thumbnails. If a shortcut is created for a bookmark
containing a touch icon, the touch icon is used (with rounded corners).
Refactor the bookmarks query to be a static function. The function uses the
original url and new url to look for matching bookmarks. This takes care of
redirects as well as bookmarks containing queries.
Diffstat (limited to 'src/com/android/browser')
-rw-r--r-- | src/com/android/browser/AddBookmarkPage.java | 13 | ||||
-rw-r--r-- | src/com/android/browser/BrowserActivity.java | 45 | ||||
-rw-r--r-- | src/com/android/browser/BrowserBookmarksAdapter.java | 99 | ||||
-rw-r--r-- | src/com/android/browser/BrowserBookmarksPage.java | 108 | ||||
-rw-r--r-- | src/com/android/browser/BrowserProvider.java | 9 | ||||
-rw-r--r-- | src/com/android/browser/DownloadTouchIcon.java | 118 |
6 files changed, 305 insertions, 87 deletions
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java index 191659a..d269546 100644 --- a/src/com/android/browser/AddBookmarkPage.java +++ b/src/com/android/browser/AddBookmarkPage.java @@ -20,6 +20,7 @@ import android.app.Activity; import android.content.ContentResolver; import android.content.Intent; import android.content.res.Resources; +import android.database.Cursor; import android.net.ParseException; import android.net.WebAddress; import android.os.Bundle; @@ -42,6 +43,7 @@ public class AddBookmarkPage extends Activity { private View mCancelButton; private boolean mEditingExisting; private Bundle mMap; + private String mTouchIconUrl; private View.OnClickListener mSaveBookmark = new View.OnClickListener() { public void onClick(View v) { @@ -78,6 +80,7 @@ public class AddBookmarkPage extends Activity { } title = mMap.getString("title"); url = mMap.getString("url"); + mTouchIconUrl = mMap.getString("touch_icon_url"); } mTitle = (EditText) findViewById(R.id.title); @@ -142,7 +145,15 @@ public class AddBookmarkPage extends Activity { setResult(RESULT_OK, (new Intent()).setAction( getIntent().toString()).putExtras(mMap)); } else { - Bookmarks.addBookmark(null, getContentResolver(), url, title, true); + final ContentResolver cr = getContentResolver(); + Bookmarks.addBookmark(null, cr, url, title, true); + if (mTouchIconUrl != null) { + final Cursor c = + BrowserBookmarksAdapter.queryBookmarksForUrl( + cr, null, url); + new DownloadTouchIcon(cr, c, url) + .execute(mTouchIconUrl); + } setResult(RESULT_OK); } } catch (IllegalStateException e) { diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java index c20c5a3..8117961 100644 --- a/src/com/android/browser/BrowserActivity.java +++ b/src/com/android/browser/BrowserActivity.java @@ -2926,23 +2926,10 @@ public class BrowserActivity extends Activity // FIXME: Would like to make sure there is actually something to // draw, but the API for that (WebViewCore.pictureReady()) is not // currently accessible here. - String original = view.getOriginalUrl(); - if (original != null) { - // copied from BrowserBookmarksAdapter - int query = original.indexOf('?'); - String noQuery = original; - if (query != -1) { - noQuery = original.substring(0, query); - } - String URL = noQuery + '?'; - String[] selArgs = new String[] { noQuery, URL }; - final String where - = "(url == ? OR url GLOB ? || '*') AND bookmark == 1"; - final String[] projection - = new String[] { Browser.BookmarkColumns._ID }; - ContentResolver cr = getContentResolver(); - final Cursor c = cr.query(Browser.BOOKMARKS_URI, projection, - where, selArgs, null); + ContentResolver cr = getContentResolver(); + final Cursor c = BrowserBookmarksAdapter.queryBookmarksForUrl( + cr, view.getOriginalUrl(), view.getUrl()); + if (c != null) { boolean succeed = c.moveToFirst(); ContentValues values = null; while (succeed) { @@ -2986,10 +2973,10 @@ public class BrowserActivity extends Activity return mWebViewClient; } - private void updateIcon(String url, Bitmap icon) { + private void updateIcon(WebView view, Bitmap icon) { if (icon != null) { BrowserBookmarksAdapter.updateBookmarkFavicon(mResolver, - url, icon); + view, icon); } setFavicon(icon); } @@ -3010,7 +2997,7 @@ public class BrowserActivity extends Activity // Call updateIcon instead of setFavicon so the bookmark // database can be updated. - updateIcon(url, favicon); + updateIcon(view, favicon); if (mSettings.isTracing() == true) { // FIXME: we should save the trace file somewhere other than data. @@ -3794,7 +3781,22 @@ public class BrowserActivity extends Activity @Override public void onReceivedIcon(WebView view, Bitmap icon) { - updateIcon(view.getUrl(), icon); + updateIcon(view, icon); + } + + @Override + public void onReceivedTouchIconUrl(WebView view, String url) { + final ContentResolver cr = getContentResolver(); + final Cursor c = + BrowserBookmarksAdapter.queryBookmarksForUrl(cr, + view.getOriginalUrl(), view.getUrl()); + if (c != null) { + if (c.getCount() > 0) { + new DownloadTouchIcon(cr, c, view).execute(url); + } else { + c.close(); + } + } } @Override @@ -4830,6 +4832,7 @@ public class BrowserActivity extends Activity intent.putExtra("url", url); intent.putExtra("maxTabsOpen", mTabControl.getTabCount() >= TabControl.MAX_TABS); + intent.putExtra("touch_icon_url", current.getTouchIconUrl()); if (startWithHistory) { intent.putExtra(CombinedBookmarkHistoryActivity.STARTING_TAB, CombinedBookmarkHistoryActivity.HISTORY_TAB); diff --git a/src/com/android/browser/BrowserBookmarksAdapter.java b/src/com/android/browser/BrowserBookmarksAdapter.java index 764daea..c3ccdfd 100644 --- a/src/com/android/browser/BrowserBookmarksAdapter.java +++ b/src/com/android/browser/BrowserBookmarksAdapter.java @@ -35,6 +35,7 @@ import android.view.View; import android.view.ViewGroup; import android.webkit.WebIconDatabase; import android.webkit.WebIconDatabase.IconListener; +import android.webkit.WebView; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; @@ -59,7 +60,7 @@ class BrowserBookmarksAdapter extends BaseAdapter { // Implementation of WebIconDatabase.IconListener private class IconReceiver implements IconListener { public void onReceivedIcon(String url, Bitmap icon) { - updateBookmarkFavicon(mContentResolver, url, icon); + updateBookmarkFavicon(mContentResolver, null, url, icon); } } @@ -247,35 +248,26 @@ class BrowserBookmarksAdapter extends BaseAdapter { } /** - * Update the bookmark's favicon. + * Update the bookmark's favicon. This is a convenience method for updating + * a bookmark favicon for the originalUrl and url of the passed in WebView. * @param cr The ContentResolver to use. - * @param url The url of the bookmark to update. + * @param WebView The WebView containing the url to update. * @param favicon The favicon bitmap to write to the db. */ /* package */ static void updateBookmarkFavicon(ContentResolver cr, - String url, Bitmap favicon) { - if (url == null || favicon == null) { - return; + WebView view, Bitmap favicon) { + if (view != null) { + updateBookmarkFavicon(cr, view.getOriginalUrl(), view.getUrl(), + favicon); } - // Strip the query. - int query = url.indexOf('?'); - String noQuery = url; - if (query != -1) { - noQuery = url.substring(0, query); + } + + private static void updateBookmarkFavicon(ContentResolver cr, + String originalUrl, String url, Bitmap favicon) { + final Cursor c = queryBookmarksForUrl(cr, originalUrl, url); + if (c == null) { + return; } - url = noQuery + '?'; - // Use noQuery to search for the base url (i.e. if the url is - // http://www.yahoo.com/?rs=1, search for http://www.yahoo.com) - // Use url to match the base url with other queries (i.e. if the url is - // http://www.google.com/m, search for - // http://www.google.com/m?some_query) - final String[] selArgs = new String[] { noQuery, url }; - final String where = "(" + Browser.BookmarkColumns.URL + " == ? OR " - + Browser.BookmarkColumns.URL + " GLOB ? || '*') AND " - + Browser.BookmarkColumns.BOOKMARK + " == 1"; - final String[] projection = new String[] { Browser.BookmarkColumns._ID }; - final Cursor c = cr.query(Browser.BOOKMARKS_URI, projection, where, - selArgs, null); boolean succeed = c.moveToFirst(); ContentValues values = null; while (succeed) { @@ -292,6 +284,55 @@ class BrowserBookmarksAdapter extends BaseAdapter { c.close(); } + /* package */ static Cursor queryBookmarksForUrl(ContentResolver cr, + String originalUrl, String url) { + if (cr == null || url == null) { + return null; + } + + // If originalUrl is null, just set it to url. + if (originalUrl == null) { + originalUrl = url; + } + + // Look for both the original url and the actual url. This takes in to + // account redirects. + String originalUrlNoQuery = removeQuery(originalUrl); + String urlNoQuery = removeQuery(url); + originalUrl = originalUrlNoQuery + '?'; + url = urlNoQuery + '?'; + + // Use NoQuery to search for the base url (i.e. if the url is + // http://www.yahoo.com/?rs=1, search for http://www.yahoo.com) + // Use url to match the base url with other queries (i.e. if the url is + // http://www.google.com/m, search for + // http://www.google.com/m?some_query) + final String[] selArgs = new String[] { + originalUrlNoQuery, urlNoQuery, originalUrl, url }; + final String where = "(" + BookmarkColumns.URL + " == ? OR " + + BookmarkColumns.URL + " == ? OR " + + BookmarkColumns.URL + " GLOB ? || '*' OR " + + BookmarkColumns.URL + " GLOB ? || '*') AND " + + BookmarkColumns.BOOKMARK + " == 1"; + final String[] projection = + new String[] { Browser.BookmarkColumns._ID }; + return cr.query(Browser.BOOKMARKS_URI, projection, where, selArgs, + null); + } + + // Strip the query from the given url. + private static String removeQuery(String url) { + if (url == null) { + return null; + } + int query = url.indexOf('?'); + String noQuery = url; + if (query != -1) { + noQuery = url.substring(0, query); + } + return noQuery; + } + /** * How many items should be displayed in the list. * @return Count of items. @@ -430,11 +471,19 @@ class BrowserBookmarksAdapter extends BaseAdapter { * Return the favicon for this item in the list. */ public Bitmap getFavicon(int position) { + return getBitmap(Browser.HISTORY_PROJECTION_FAVICON_INDEX, position); + } + + public Bitmap getTouchIcon(int position) { + return getBitmap(Browser.HISTORY_PROJECTION_TOUCH_ICON_INDEX, position); + } + + private Bitmap getBitmap(int cursorIndex, int position) { if (position < mExtraOffset || position > mCount) { return null; } mCursor.moveToPosition(position - mExtraOffset); - byte[] data = mCursor.getBlob(Browser.HISTORY_PROJECTION_FAVICON_INDEX); + byte[] data = mCursor.getBlob(cursorIndex); if (data == null) { return null; } diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java index 5abdbb3..0fc2643 100644 --- a/src/com/android/browser/BrowserBookmarksPage.java +++ b/src/com/android/browser/BrowserBookmarksPage.java @@ -25,6 +25,9 @@ import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.net.Uri; import android.os.Bundle; @@ -97,8 +100,7 @@ public class BrowserBookmarksPage extends Activity implements editBookmark(i.position); break; case R.id.shortcut_context_menu_id: - final Intent send = createShortcutIntent(getUrl(i.position), - getBookmarkTitle(i.position), getFavicon(i.position)); + final Intent send = createShortcutIntent(i.position); send.setAction(INSTALL_SHORTCUT); sendBroadcast(send); break; @@ -259,16 +261,18 @@ public class BrowserBookmarksPage extends Activity implements loadUrl(position); } } else { - final Intent intent = createShortcutIntent(getUrl(position), - getBookmarkTitle(position), getFavicon(position)); + final Intent intent = createShortcutIntent(position); setResultToParent(RESULT_OK, intent); finish(); } } }; - private Intent createShortcutIntent(String url, String title, - Bitmap favicon) { + private Intent createShortcutIntent(int position) { + String url = getUrl(position); + String title = getBookmarkTitle(position); + Bitmap touchIcon = getTouchIcon(position); + final Intent i = new Intent(); final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); @@ -278,41 +282,65 @@ public class BrowserBookmarksPage extends Activity implements Long.toString(uniqueId)); i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title); - if (favicon == null) { - i.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, - Intent.ShortcutIconResource.fromContext( - BrowserBookmarksPage.this, - R.drawable.ic_launcher_shortcut_browser_bookmark)); - } else { - Bitmap icon = BitmapFactory.decodeResource(getResources(), - R.drawable.ic_launcher_shortcut_browser_bookmark); - - // Make a copy of the regular icon so we can modify the pixels. - Bitmap copy = icon.copy(Bitmap.Config.ARGB_8888, true); + // Use the apple-touch-icon if available + if (touchIcon != null) { + // Make a copy so we can modify the pixels. + Bitmap copy = touchIcon.copy(Bitmap.Config.ARGB_8888, true); Canvas canvas = new Canvas(copy); - // Make a Paint for the white background rectangle and for - // filtering the favicon. - Paint p = new Paint(Paint.ANTI_ALIAS_FLAG - | Paint.FILTER_BITMAP_FLAG); - p.setStyle(Paint.Style.FILL_AND_STROKE); - p.setColor(Color.WHITE); - - // Create a rectangle that is slightly wider than the favicon - final float iconSize = 16; // 16x16 favicon - final float padding = 2; // white padding around icon - final float rectSize = iconSize + 2 * padding; - final float y = icon.getHeight() - rectSize; - RectF r = new RectF(0, y, rectSize, y + rectSize); - - // Draw a white rounded rectangle behind the favicon - canvas.drawRoundRect(r, 2, 2, p); - - // Draw the favicon in the same rectangle as the rounded rectangle - // but inset by the padding (results in a 16x16 favicon). - r.inset(padding, padding); - canvas.drawBitmap(favicon, null, r, p); + // Construct a path from a round rect. This will allow drawing with + // an inverse fill so we can punch a hole using the round rect. + Path path = new Path(); + path.setFillType(Path.FillType.INVERSE_WINDING); + path.addRoundRect(new RectF(0, 0, touchIcon.getWidth(), + touchIcon.getHeight()), 8f, 8f, Path.Direction.CW); + + // Construct a paint that clears the outside of the rectangle and + // draw. + Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + canvas.drawPath(path, paint); + i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy); + } else { + Bitmap favicon = getFavicon(position); + if (favicon == null) { + i.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, + Intent.ShortcutIconResource.fromContext( + BrowserBookmarksPage.this, + R.drawable.ic_launcher_shortcut_browser_bookmark)); + } else { + Bitmap icon = BitmapFactory.decodeResource(getResources(), + R.drawable.ic_launcher_shortcut_browser_bookmark); + + // Make a copy of the regular icon so we can modify the pixels. + Bitmap copy = icon.copy(Bitmap.Config.ARGB_8888, true); + Canvas canvas = new Canvas(copy); + + // Make a Paint for the white background rectangle and for + // filtering the favicon. + Paint p = new Paint(Paint.ANTI_ALIAS_FLAG + | Paint.FILTER_BITMAP_FLAG); + p.setStyle(Paint.Style.FILL_AND_STROKE); + p.setColor(Color.WHITE); + + // Create a rectangle that is slightly wider than the favicon + final float iconSize = 16; // 16x16 favicon + final float padding = 2; // white padding around icon + final float rectSize = iconSize + 2 * padding; + final float y = icon.getHeight() - rectSize; + RectF r = new RectF(0, y, rectSize, y + rectSize); + + // Draw a white rounded rectangle behind the favicon + canvas.drawRoundRect(r, 2, 2, p); + + // Draw the favicon in the same rectangle as the rounded + // rectangle but inset by the padding + // (results in a 16x16 favicon). + r.inset(padding, padding); + canvas.drawBitmap(favicon, null, r, p); + i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy); + } } // Do not allow duplicate items i.putExtra("duplicate", false); @@ -459,6 +487,10 @@ public class BrowserBookmarksPage extends Activity implements return mBookmarksAdapter.getFavicon(position); } + private Bitmap getTouchIcon(int position) { + return mBookmarksAdapter.getTouchIcon(position); + } + private void copy(CharSequence text) { try { IClipboard clip = IClipboard.Stub.asInterface(ServiceManager.getService("clipboard")); diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java index cdab3a3..75a98b6 100644 --- a/src/com/android/browser/BrowserProvider.java +++ b/src/com/android/browser/BrowserProvider.java @@ -150,7 +150,8 @@ public class BrowserProvider extends ContentProvider { // 17 -> 18 Added favicon in bookmarks table for Home shortcuts // 18 -> 19 Remove labels table // 19 -> 20 Added thumbnail - private static final int DATABASE_VERSION = 20; + // 20 -> 21 Added touch_icon + private static final int DATABASE_VERSION = 21; // Regular expression which matches http://, followed by some stuff, followed by // optionally a trailing slash, all matched as separate groups. @@ -223,7 +224,8 @@ public class BrowserProvider extends ContentProvider { "description TEXT," + "bookmark INTEGER," + "favicon BLOB DEFAULT NULL," + - "thumbnail BLOB DEFAULT NULL" + + "thumbnail BLOB DEFAULT NULL," + + "touch_icon BLOB DEFAULT NULL" + ");"); final CharSequence[] bookmarks = mContext.getResources() @@ -256,6 +258,9 @@ public class BrowserProvider extends ContentProvider { } if (oldVersion <= 19) { db.execSQL("ALTER TABLE bookmarks ADD COLUMN thumbnail BLOB DEFAULT NULL;"); + } + if (oldVersion < 21) { + db.execSQL("ALTER TABLE bookmarks ADD COLUMN touch_icon BLOB DEFAULT NULL;"); } else { db.execSQL("DROP TABLE IF EXISTS bookmarks"); db.execSQL("DROP TABLE IF EXISTS searches"); diff --git a/src/com/android/browser/DownloadTouchIcon.java b/src/com/android/browser/DownloadTouchIcon.java new file mode 100644 index 0000000..6662e09 --- /dev/null +++ b/src/com/android/browser/DownloadTouchIcon.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.browser; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.http.AndroidHttpClient; +import android.os.AsyncTask; +import android.provider.Browser; +import android.webkit.WebView; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.params.HttpClientParams; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +class DownloadTouchIcon extends AsyncTask<String, Void, Bitmap> { + private final ContentResolver mContentResolver; + private final Cursor mCursor; + private final String mOriginalUrl; + private final String mUrl; + private final String mUserAgent; + + public DownloadTouchIcon(ContentResolver cr, Cursor c, WebView view) { + mContentResolver = cr; + mCursor = c; + // Store these in case they change. + mOriginalUrl = view.getOriginalUrl(); + mUrl = view.getUrl(); + mUserAgent = view.getSettings().getUserAgentString(); + } + + public DownloadTouchIcon(ContentResolver cr, Cursor c, String url) { + mContentResolver = cr; + mCursor = c; + mOriginalUrl = null; + mUrl = url; + mUserAgent = null; + } + + @Override + public Bitmap doInBackground(String... values) { + String url = values[0]; + + AndroidHttpClient client = AndroidHttpClient.newInstance( + mUserAgent); + HttpGet request = new HttpGet(url); + + // Follow redirects + HttpClientParams.setRedirecting(client.getParams(), true); + + try { + HttpResponse response = client.execute(request); + + if (response.getStatusLine().getStatusCode() == 200) { + HttpEntity entity = response.getEntity(); + if (entity != null) { + InputStream content = entity.getContent(); + if (content != null) { + Bitmap icon = BitmapFactory.decodeStream( + content, null, null); + return icon; + } + } + } + } catch (IllegalArgumentException ex) { + request.abort(); + } catch (IOException ex) { + request.abort(); + } finally { + client.close(); + } + return null; + } + + @Override + public void onPostExecute(Bitmap icon) { + if (icon == null || mCursor == null) { + return; + } + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + icon.compress(Bitmap.CompressFormat.PNG, 100, os); + ContentValues values = new ContentValues(); + values.put(Browser.BookmarkColumns.TOUCH_ICON, + os.toByteArray()); + + if (mCursor.moveToFirst()) { + do { + mContentResolver.update(ContentUris.withAppendedId( + Browser.BOOKMARKS_URI, mCursor.getInt(0)), + values, null, null); + } while (mCursor.moveToNext()); + } + mCursor.close(); + } +} |