diff options
-rw-r--r-- | AndroidManifest.xml | 33 | ||||
-rw-r--r-- | res/layout/bookmark_thumbnail.xml | 42 | ||||
-rw-r--r-- | src/com/android/browser/BookmarkGridPage.java | 243 | ||||
-rw-r--r-- | src/com/android/browser/BrowserActivity.java | 43 | ||||
-rw-r--r-- | src/com/android/browser/BrowserProvider.java | 11 | ||||
-rw-r--r-- | src/com/android/browser/CombinedBookmarkHistoryActivity.java | 2 |
6 files changed, 354 insertions, 20 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 0403dfe..88c414b 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,20 +1,19 @@ <!-- -/* //device/apps/Browser/AndroidManifest.xml -** -** Copyright 2006, 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. -*/ +/* + * Copyright 2006, 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. + */ --> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.browser"> @@ -131,6 +130,8 @@ <activity android:name="BrowserBookmarksPage" android:label="@string/bookmarks" android:launchMode="singleTop" android:configChanges="orientation|keyboardHidden"> </activity> + <activity android:name="BookmarkGridPage" android:label="@string/bookmarks" + android:launchMode="singleTop" android:configChanges="orientation|keyboardHidden"/> <activity android:name="MostVisitedActivity" android:label="" android:launchMode="singleTop" android:configChanges="orientation|keyboardHidden"/> diff --git a/res/layout/bookmark_thumbnail.xml b/res/layout/bookmark_thumbnail.xml new file mode 100644 index 0000000..439145a --- /dev/null +++ b/res/layout/bookmark_thumbnail.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:orientation="vertical" + android:padding="4dip" + android:background="@color/white"> + + <ImageView android:id="@+id/thumb" + android:src="@android:drawable/app_web_browser_sm" + android:scaleType="center" + android:layout_width="fill_parent" + android:layout_height="fill_parent" /> + + <TextView android:id="@+id/label" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="@color/white" + android:maxLines="1" + android:paddingTop="3dip" + android:paddingBottom="3dip" + android:paddingLeft="2dip" + android:paddingRight="2dip" + android:scrollHorizontally="true" + android:background="#CC000000"/> +</LinearLayout> diff --git a/src/com/android/browser/BookmarkGridPage.java b/src/com/android/browser/BookmarkGridPage.java new file mode 100644 index 0000000..a9db7ac --- /dev/null +++ b/src/com/android/browser/BookmarkGridPage.java @@ -0,0 +1,243 @@ +/* + * 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.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.ContentObserver; +import android.database.DataSetObserver; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.os.Handler; +import android.provider.Browser; +import android.provider.Browser.BookmarkColumns; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.ListAdapter; +import android.widget.TextView; + +import java.util.ArrayList; + +public class BookmarkGridPage extends Activity { + private final static int SPACING = 10; + private BookmarkGrid mGridView; + private BookmarkGridAdapter mAdapter; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mGridView = new BookmarkGrid(this); + mGridView.setNumColumns(3); + mAdapter = new BookmarkGridAdapter(this); + mGridView.setAdapter(mAdapter); + mGridView.setFocusable(true); + mGridView.setFocusableInTouchMode(true); + mGridView.setSelector(android.R.drawable.gallery_thumb); + mGridView.setVerticalSpacing(SPACING); + mGridView.setHorizontalSpacing(SPACING); + setContentView(mGridView); + mGridView.requestFocus(); + } + + private class BookmarkGrid extends GridView { + public BookmarkGrid(Context context) { + super(context); + } + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + int thumbHeight = (h - 2 * (SPACING + getListPaddingTop() + + getListPaddingBottom())) / 3; + mAdapter.heightChanged(thumbHeight); + super.onSizeChanged(w, h, oldw, oldh); + } + } + + private class BookmarkGridAdapter implements ListAdapter { + private ArrayList<DataSetObserver> mDataObservers; + private Context mContext; // Context to use to inflate views + private Cursor mCursor; + private int mThumbHeight; + + public BookmarkGridAdapter(Context context) { + mContext = context; + mDataObservers = new ArrayList<DataSetObserver>(); + String whereClause = Browser.BookmarkColumns.BOOKMARK + " != 0"; + String orderBy = Browser.BookmarkColumns.VISITS + " DESC"; + mCursor = managedQuery(Browser.BOOKMARKS_URI, + Browser.HISTORY_PROJECTION, whereClause, null, orderBy); + mCursor.registerContentObserver(new ChangeObserver()); + mGridView.setOnItemClickListener( + new AdapterView.OnItemClickListener() { + public void onItemClick(AdapterView parent, View v, + int position, long id) { + mCursor.moveToPosition(position); + String url = mCursor.getString( + Browser.HISTORY_PROJECTION_URL_INDEX); + Intent intent = (new Intent()).setAction(url); + getParent().setResult(RESULT_OK, intent); + finish(); + }}); + } + + void heightChanged(int newHeight) { + mThumbHeight = newHeight; + } + + private class ChangeObserver extends ContentObserver { + public ChangeObserver() { + super(new Handler()); + } + + @Override + public boolean deliverSelfNotifications() { + return true; + } + + @Override + public void onChange(boolean selfChange) { + BookmarkGridAdapter.this.refreshData(); + } + } + + void refreshData() { + mCursor.requery(); + for (DataSetObserver o : mDataObservers) { + o.onChanged(); + } + } + + /* (non-Javadoc) + * @see android.widget.ListAdapter#areAllItemsSelectable() + */ + public boolean areAllItemsEnabled() { + return true; + } + + /* (non-Javadoc) + * @see android.widget.ListAdapter#isSelectable(int) + */ + public boolean isEnabled(int position) { + if (position >= 0 && position < mCursor.getCount()) { + return true; + } + return false; + } + + /* (non-Javadoc) + * @see android.widget.Adapter#getCount() + */ + public int getCount() { + return mCursor.getCount(); + } + + /* (non-Javadoc) + * @see android.widget.Adapter#getItem(int) + */ + public Object getItem(int position) { + return null; + } + + /* (non-Javadoc) + * @see android.widget.Adapter#getItemId(int) + */ + public long getItemId(int position) { + return position; + } + + /* (non-Javadoc) + * @see android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup) + */ + public View getView(int position, View convertView, ViewGroup parent) { + View v = null; + if (convertView != null) { + v = convertView; + } else { + LayoutInflater factory = LayoutInflater.from(mContext); + v = factory.inflate(R.layout.bookmark_thumbnail, null); + } + ImageView thumb = (ImageView) v.findViewById(R.id.thumb); + TextView tv = (TextView) v.findViewById(R.id.label); + + mCursor.moveToPosition(position); + tv.setText(mCursor.getString( + Browser.HISTORY_PROJECTION_TITLE_INDEX)); + byte[] data = mCursor.getBlob( + Browser.HISTORY_PROJECTION_THUMBNAIL_INDEX); + if (data == null) { + // Backup is to show the favicon + data = mCursor.getBlob( + Browser.HISTORY_PROJECTION_FAVICON_INDEX); + thumb.setScaleType(ImageView.ScaleType.CENTER); + } else { + thumb.setScaleType(ImageView.ScaleType.FIT_XY); + } + if (data != null) { + thumb.setImageBitmap( + BitmapFactory.decodeByteArray(data, 0, data.length)); + } else { + thumb.setImageResource(R.drawable.app_web_browser_sm); + thumb.setScaleType(ImageView.ScaleType.CENTER); + } + ViewGroup.LayoutParams lp = thumb.getLayoutParams(); + if (lp.height != mThumbHeight) { + lp.height = mThumbHeight; + thumb.requestLayout(); + } + return v; + } + + /* (non-Javadoc) + * @see android.widget.Adapter#registerDataSetObserver(android.database.DataSetObserver) + */ + public void registerDataSetObserver(DataSetObserver observer) { + mDataObservers.add(observer); + } + + /* (non-Javadoc) + * @see android.widget.Adapter#hasStableIds() + */ + public boolean hasStableIds() { + return true; + } + + /* (non-Javadoc) + * @see android.widget.Adapter#unregisterDataSetObserver(android.database.DataSetObserver) + */ + public void unregisterDataSetObserver(DataSetObserver observer) { + mDataObservers.remove(observer); + } + + public int getItemViewType(int position) { + return 0; + } + + public int getViewTypeCount() { + return 1; + } + + public boolean isEmpty() { + return getCount() == 0; + } + } +} diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java index 363c6d7..d1d8d15 100644 --- a/src/com/android/browser/BrowserActivity.java +++ b/src/com/android/browser/BrowserActivity.java @@ -29,6 +29,7 @@ import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; +import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; @@ -130,6 +131,7 @@ import android.widget.TextView; import android.widget.Toast; import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -2989,6 +2991,47 @@ public class BrowserActivity extends Activity // Update the lock icon image only once we are done loading updateLockIconImage(mLockIconType); + // If this is a bookmarked site, add a screenshot to the database. + // FIXME: When should we update? Every time? + if (url != null) { + // copied from BrowserBookmarksAdapter + int query = url.indexOf('?'); + String noQuery = url; + if (query != -1) { + noQuery = url.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); + boolean succeed = c.moveToFirst(); + ContentValues values = null; + while (succeed) { + if (values == null) { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + Picture thumbnail = view.capturePicture(); + // Height was arbitrarily chosen + Bitmap bm = Bitmap.createBitmap(100, 100, + Bitmap.Config.ARGB_4444); + Canvas canvas = new Canvas(bm); + // Scale chosen to be about one third, since we want + // roughly three rows/columns for bookmark page + canvas.scale(.3f, .3f); + thumbnail.draw(canvas); + bm.compress(Bitmap.CompressFormat.PNG, 100, os); + values = new ContentValues(); + values.put(Browser.BookmarkColumns.THUMBNAIL, + os.toByteArray()); + } + cr.update(ContentUris.withAppendedId(Browser.BOOKMARKS_URI, + c.getInt(0)), values, null, null); + succeed = c.moveToNext(); + } + c.close(); + } + // Performance probe if (false) { long[] sysCpu = new long[7]; diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java index 8743254..a3f249b 100644 --- a/src/com/android/browser/BrowserProvider.java +++ b/src/com/android/browser/BrowserProvider.java @@ -145,7 +145,8 @@ public class BrowserProvider extends ContentProvider { // 15 -> 17 Set it up for the SearchManager // 17 -> 18 Added favicon in bookmarks table for Home shortcuts // 18 -> 19 Remove labels table - private static final int DATABASE_VERSION = 19; + // 19 -> 20 Added thumbnail + private static final int DATABASE_VERSION = 20; // Regular expression which matches http://, followed by some stuff, followed by // optionally a trailing slash, all matched as separate groups. @@ -214,7 +215,8 @@ public class BrowserProvider extends ContentProvider { "created LONG," + "description TEXT," + "bookmark INTEGER," + - "favicon BLOB DEFAULT NULL" + + "favicon BLOB DEFAULT NULL," + + "thumbnail BLOB DEFAULT NULL" + ");"); final CharSequence[] bookmarks = mContext.getResources() @@ -241,9 +243,12 @@ public class BrowserProvider extends ContentProvider { @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Log.w(TAG, "Upgrading database from version " + oldVersion + " to " - + newVersion + ", which will destroy all old data"); + + newVersion); if (oldVersion == 18) { db.execSQL("DROP TABLE IF EXISTS labels"); + } + if (oldVersion <= 19) { + db.execSQL("ALTER TABLE bookmarks ADD COLUMN thumbnail 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/CombinedBookmarkHistoryActivity.java b/src/com/android/browser/CombinedBookmarkHistoryActivity.java index 963f179..6926c8f 100644 --- a/src/com/android/browser/CombinedBookmarkHistoryActivity.java +++ b/src/com/android/browser/CombinedBookmarkHistoryActivity.java @@ -84,7 +84,7 @@ public class CombinedBookmarkHistoryActivity extends TabActivity Resources resources = getResources(); getIconListenerSet(getContentResolver()); - Intent bookmarksIntent = new Intent(this, BrowserBookmarksPage.class); + Intent bookmarksIntent = new Intent(this, BookmarkGridPage.class); bookmarksIntent.putExtras(extras); tabHost.addTab(tabHost.newTabSpec(BOOKMARKS_TAB) .setIndicator(resources.getString(R.string.tab_bookmarks), |