diff options
author | John Reck <jreck@google.com> | 2011-02-01 12:57:06 -0800 |
---|---|---|
committer | John Reck <jreck@google.com> | 2011-02-04 13:37:17 -0800 |
commit | 99c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2 (patch) | |
tree | f60a6aa9058be7028ef089b27e5c132545d0d96d /src/com | |
parent | 4daecf299171596ff8d1c2f1b845be810fd87fb1 (diff) | |
download | packages_apps_Browser-99c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2.zip packages_apps_Browser-99c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2.tar.gz packages_apps_Browser-99c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2.tar.bz2 |
Get the widget off of startservice
Bug: 3379120
Now with drastically lower memory usage as well!
Change-Id: Iff16d2acceba3c8a983a51ec03a31a39ac6a12ed
Diffstat (limited to 'src/com')
6 files changed, 312 insertions, 332 deletions
diff --git a/src/com/android/browser/AccountsChangedReceiver.java b/src/com/android/browser/AccountsChangedReceiver.java index 92d6ad0..a34180a 100644 --- a/src/com/android/browser/AccountsChangedReceiver.java +++ b/src/com/android/browser/AccountsChangedReceiver.java @@ -16,6 +16,8 @@ package com.android.browser; +import com.android.browser.widget.BookmarkThumbnailWidgetProvider; + import android.accounts.Account; import android.accounts.AccountManager; import android.content.BroadcastReceiver; @@ -55,6 +57,7 @@ public class AccountsChangedReceiver extends BroadcastReceiver { ContentResolver.setSyncAutomatically(a, BrowserContract.AUTHORITY, false); ContentResolver.setIsSyncable(a, BrowserContract.AUTHORITY, 0); } + BookmarkThumbnailWidgetProvider.refreshWidgets(context, true); } } diff --git a/src/com/android/browser/preferences/GeneralPreferencesFragment.java b/src/com/android/browser/preferences/GeneralPreferencesFragment.java index b6228dc..33bfd9c 100644 --- a/src/com/android/browser/preferences/GeneralPreferencesFragment.java +++ b/src/com/android/browser/preferences/GeneralPreferencesFragment.java @@ -21,6 +21,7 @@ import com.android.browser.BrowserHomepagePreference; import com.android.browser.BrowserPreferencesPage; import com.android.browser.BrowserSettings; import com.android.browser.R; +import com.android.browser.widget.BookmarkThumbnailWidgetProvider; import android.accounts.Account; import android.accounts.AccountManager; @@ -125,6 +126,7 @@ public class GeneralPreferencesFragment extends PreferenceFragment if (BrowserBookmarksPage.PREF_ACCOUNT_NAME.equals(key) || BrowserBookmarksPage.PREF_ACCOUNT_TYPE.equals(key)) { refreshUi(); + BookmarkThumbnailWidgetProvider.refreshWidgets(getActivity(), true); } } diff --git a/src/com/android/browser/provider/BrowserProvider2.java b/src/com/android/browser/provider/BrowserProvider2.java index a51635c..74cb773 100644 --- a/src/com/android/browser/provider/BrowserProvider2.java +++ b/src/com/android/browser/provider/BrowserProvider2.java @@ -19,6 +19,7 @@ package com.android.browser.provider; import com.android.browser.BookmarkUtils; import com.android.browser.BrowserBookmarksPage; import com.android.browser.R; +import com.android.browser.widget.BookmarkThumbnailWidgetProvider; import com.android.common.content.SyncStateContentProviderHelper; import android.accounts.Account; @@ -35,6 +36,7 @@ import android.content.res.TypedArray; import android.database.AbstractCursor; import android.database.Cursor; import android.database.DatabaseUtils; +import android.database.MatrixCursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; @@ -106,6 +108,7 @@ public class BrowserProvider2 extends SQLiteContentProvider { static final int BOOKMARKS_FOLDER = 1002; static final int BOOKMARKS_FOLDER_ID = 1003; static final int BOOKMARKS_SUGGESTIONS = 1004; + static final int BOOKMARKS_DEFAULT_FOLDER_ID = 1005; static final int HISTORY = 2000; static final int HISTORY_ID = 2001; @@ -159,6 +162,7 @@ public class BrowserProvider2 extends SQLiteContentProvider { matcher.addURI(authority, "bookmarks/#", BOOKMARKS_ID); matcher.addURI(authority, "bookmarks/folder", BOOKMARKS_FOLDER); matcher.addURI(authority, "bookmarks/folder/#", BOOKMARKS_FOLDER_ID); + matcher.addURI(authority, "bookmarks/folder/id", BOOKMARKS_DEFAULT_FOLDER_ID); matcher.addURI(authority, SearchManager.SUGGEST_URI_PATH_QUERY, BOOKMARKS_SUGGESTIONS); @@ -758,6 +762,15 @@ public class BrowserProvider2 extends SQLiteContentProvider { return cursor; } + case BOOKMARKS_DEFAULT_FOLDER_ID: { + String accountName = uri.getQueryParameter(Bookmarks.PARAM_ACCOUNT_NAME); + String accountType = uri.getQueryParameter(Bookmarks.PARAM_ACCOUNT_TYPE); + long id = queryDefaultFolderId(accountName, accountType); + MatrixCursor c = new MatrixCursor(new String[] {Bookmarks._ID}); + c.newRow().add(id); + return c; + } + case BOOKMARKS_SUGGESTIONS: { return doSuggestQuery(selection, selectionArgs, limit); } @@ -973,6 +986,9 @@ public class BrowserProvider2 extends SQLiteContentProvider { selectionArgs = (String[]) withAccount[1]; int deleted = deleteBookmarks(selection, selectionArgs, callerIsSyncAdapter); pruneImages(); + if (deleted > 0) { + BookmarkThumbnailWidgetProvider.refreshWidgets(getContext()); + } return deleted; } @@ -1054,7 +1070,7 @@ public class BrowserProvider2 extends SQLiteContentProvider { } long queryDefaultFolderId(String accountName, String accountType) { - if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) { + if (!isNullAccount(accountName) && !isNullAccount(accountType)) { final SQLiteDatabase db = mOpenHelper.getReadableDatabase(); Cursor c = db.query(TABLE_BOOKMARKS, new String[] { Bookmarks._ID }, ChromeSyncColumns.SERVER_UNIQUE + " = ?" + @@ -1134,6 +1150,7 @@ public class BrowserProvider2 extends SQLiteContentProvider { } id = db.insertOrThrow(TABLE_BOOKMARKS, Bookmarks.DIRTY, values); + BookmarkThumbnailWidgetProvider.refreshWidgets(getContext()); break; } @@ -1302,6 +1319,9 @@ public class BrowserProvider2 extends SQLiteContentProvider { int updated = updateBookmarksInTransaction(values, selection, selectionArgs, callerIsSyncAdapter); pruneImages(); + if (updated > 0) { + BookmarkThumbnailWidgetProvider.refreshWidgets(getContext()); + } return updated; } @@ -1342,6 +1362,9 @@ public class BrowserProvider2 extends SQLiteContentProvider { db.insertOrThrow(TABLE_IMAGES, Images.FAVICON, values); count = 1; } + if (count > 0) { + BookmarkThumbnailWidgetProvider.refreshWidgets(getContext()); + } return count; } diff --git a/src/com/android/browser/widget/BookmarkThumbnailWidgetProvider.java b/src/com/android/browser/widget/BookmarkThumbnailWidgetProvider.java index b991abd..48d7123 100644 --- a/src/com/android/browser/widget/BookmarkThumbnailWidgetProvider.java +++ b/src/com/android/browser/widget/BookmarkThumbnailWidgetProvider.java @@ -32,12 +32,9 @@ import android.widget.RemoteViews; * Widget that shows a preview of the user's bookmarks. */ public class BookmarkThumbnailWidgetProvider extends AppWidgetProvider { - static final String ACTION_BOOKMARK_APPWIDGET_UPDATE = + public static final String ACTION_BOOKMARK_APPWIDGET_UPDATE = "com.android.browser.BOOKMARK_APPWIDGET_UPDATE"; - /** - * {@inheritDoc} - */ @Override public void onReceive(Context context, Intent intent) { // Handle bookmark-specific updates ourselves because they might be @@ -58,23 +55,27 @@ public class BookmarkThumbnailWidgetProvider extends AppWidgetProvider { } @Override - public void onEnabled(Context context) { - // Start the backing service - context.startService(new Intent(context, BookmarkThumbnailWidgetService.class)); + public void onDeleted(Context context, int[] appWidgetIds) { + super.onDeleted(context, appWidgetIds); + for (int widgetId : appWidgetIds) { + BookmarkThumbnailWidgetService.deleteWidgetState(context, widgetId); + } + removeOrphanedFiles(context); } @Override public void onDisabled(Context context) { - // Stop the backing service - context.stopService(new Intent(context, BookmarkThumbnailWidgetService.class)); + super.onDisabled(context); + removeOrphanedFiles(context); } - @Override - public void onDeleted(Context context, int[] appWidgetIds) { - super.onDeleted(context, appWidgetIds); - context.startService(new Intent(BookmarkThumbnailWidgetService.ACTION_REMOVE_FACTORIES, - null, context, BookmarkThumbnailWidgetService.class) - .putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)); + /** + * Checks for any state files that may have not received onDeleted + */ + void removeOrphanedFiles(Context context) { + AppWidgetManager wm = AppWidgetManager.getInstance(context); + int[] ids = wm.getAppWidgetIds(getComponentName(context)); + BookmarkThumbnailWidgetService.removeOrphanedStates(context, ids); } private void performUpdate(Context context, @@ -92,9 +93,9 @@ public class BookmarkThumbnailWidgetProvider extends AppWidgetProvider { views.setOnClickPendingIntent(R.id.app_shortcut, launchBrowser); views.setRemoteAdapter(appWidgetId, R.id.bookmarks_list, updateIntent); appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.bookmarks_list); - Intent ic = new Intent(context, BookmarkThumbnailWidgetService.class); + Intent ic = new Intent(context, BookmarkWidgetProxy.class); views.setPendingIntentTemplate(R.id.bookmarks_list, - PendingIntent.getService(context, 0, ic, + PendingIntent.getBroadcast(context, 0, ic, PendingIntent.FLAG_UPDATE_CURRENT)); appWidgetManager.updateAppWidget(appWidgetId, views); } @@ -107,4 +108,29 @@ public class BookmarkThumbnailWidgetProvider extends AppWidgetProvider { static ComponentName getComponentName(Context context) { return new ComponentName(context, BookmarkThumbnailWidgetProvider.class); } + + public static void refreshWidgets(Context context) { + refreshWidgets(context, false); + } + + public static void refreshWidgets(Context context, boolean zeroState) { + if (zeroState) { + final Context appContext = context.getApplicationContext(); + new Thread() { + @Override + public void run() { + AppWidgetManager wm = AppWidgetManager.getInstance(appContext); + int[] ids = wm.getAppWidgetIds(getComponentName(appContext)); + for (int id : ids) { + BookmarkThumbnailWidgetService.clearWidgetState(appContext, id); + } + refreshWidgets(appContext, false); + } + }.start(); + } else { + context.sendBroadcast(new Intent( + BookmarkThumbnailWidgetProvider.ACTION_BOOKMARK_APPWIDGET_UPDATE, + null, context, BookmarkThumbnailWidgetProvider.class)); + } + } } diff --git a/src/com/android/browser/widget/BookmarkThumbnailWidgetService.java b/src/com/android/browser/widget/BookmarkThumbnailWidgetService.java index e525159..675cdd9 100644 --- a/src/com/android/browser/widget/BookmarkThumbnailWidgetService.java +++ b/src/com/android/browser/widget/BookmarkThumbnailWidgetService.java @@ -16,8 +16,8 @@ package com.android.browser.widget; +import com.android.browser.BookmarkUtils; import com.android.browser.BrowserActivity; -import com.android.browser.BrowserBookmarksPage; import com.android.browser.R; import android.appwidget.AppWidgetManager; @@ -25,17 +25,14 @@ import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.database.ContentObserver; import android.database.Cursor; +import android.database.MergeCursor; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.preference.PreferenceManager; +import android.os.Binder; import android.provider.BrowserContract; import android.provider.BrowserContract.Bookmarks; import android.text.TextUtils; @@ -43,185 +40,164 @@ import android.util.Log; import android.widget.RemoteViews; import android.widget.RemoteViewsService; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Stack; +import java.io.File; +import java.io.FilenameFilter; +import java.util.Arrays; +import java.util.HashSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class BookmarkThumbnailWidgetService extends RemoteViewsService { static final String TAG = "BookmarkThumbnailWidgetService"; - static final boolean USE_FOLDERS = true; - - static final String ACTION_REMOVE_FACTORIES - = "com.android.browser.widget.REMOVE_FACTORIES"; static final String ACTION_CHANGE_FOLDER = "com.android.browser.widget.CHANGE_FOLDER"; + static final String STATE_CURRENT_FOLDER = "current_folder"; + static final String STATE_ROOT_FOLDER = "root_folder"; + private static final String[] PROJECTION = new String[] { BrowserContract.Bookmarks._ID, BrowserContract.Bookmarks.TITLE, BrowserContract.Bookmarks.URL, BrowserContract.Bookmarks.FAVICON, BrowserContract.Bookmarks.IS_FOLDER, - BrowserContract.Bookmarks.TOUCH_ICON, BrowserContract.Bookmarks.POSITION, /* needed for order by */ - BrowserContract.Bookmarks.THUMBNAIL}; + BrowserContract.Bookmarks.THUMBNAIL, + BrowserContract.Bookmarks.PARENT}; private static final int BOOKMARK_INDEX_ID = 0; private static final int BOOKMARK_INDEX_TITLE = 1; private static final int BOOKMARK_INDEX_URL = 2; private static final int BOOKMARK_INDEX_FAVICON = 3; private static final int BOOKMARK_INDEX_IS_FOLDER = 4; - private static final int BOOKMARK_INDEX_TOUCH_ICON = 5; - private static final int BOOKMARK_INDEX_THUMBNAIL = 7; - - // The service will likely be destroyed at any time, so we need to keep references to the - // factories across services connections. - private static final Map<Integer, BookmarkFactory> mFactories = - new HashMap<Integer, BookmarkFactory>(); - private Handler mUiHandler; - private BookmarksObserver mBookmarksObserver; + private static final int BOOKMARK_INDEX_THUMBNAIL = 6; + private static final int BOOKMARK_INDEX_PARENT_ID = 7; @Override - public void onCreate() { - super.onCreate(); - mUiHandler = new Handler(); - mBookmarksObserver = new BookmarksObserver(mUiHandler); - getContentResolver().registerContentObserver( - BrowserContract.Bookmarks.CONTENT_URI, true, mBookmarksObserver); + public RemoteViewsFactory onGetViewFactory(Intent intent) { + int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); + if (widgetId < 0) { + Log.w(TAG, "Missing EXTRA_APPWIDGET_ID!"); + return null; + } + return new BookmarkFactory(getApplicationContext(), widgetId); } - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - String action = intent.getAction(); - if (Intent.ACTION_VIEW.equals(action)) { - if (intent.getData() == null) { - startActivity(new Intent(BrowserActivity.ACTION_SHOW_BROWSER, null, - this, BrowserActivity.class) - .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); - } else { - Intent view = new Intent(intent); - view.setComponent(null); - startActivity(view); - } - } else if (ACTION_REMOVE_FACTORIES.equals(action)) { - int[] ids = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); - if (ids != null) { - for (int id : ids) { - BookmarkFactory bf = mFactories.remove(id); - if (bf != null) { - // Workaround a known framework bug - // onDestroy is currently never called - bf.onDestroy(); - } - } - } - } else if (ACTION_CHANGE_FOLDER.equals(action)) { - int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - long folderId = intent.getLongExtra(Bookmarks._ID, -1); - BookmarkFactory fac = mFactories.get(widgetId); - if (fac != null && folderId >= 0) { - fac.changeFolder(folderId); - } else { - // This a workaround to the issue when the Browser process crashes, after which - // mFactories is not populated (due to onBind() not being called). Calling - // notifyDataSetChanged() will trigger a connection to be made. - AppWidgetManager.getInstance(getApplicationContext()) - .notifyAppWidgetViewDataChanged(widgetId, R.id.bookmarks_list); - } - } - return START_STICKY; + static SharedPreferences getWidgetState(Context context, int widgetId) { + return context.getSharedPreferences( + String.format("widgetState-%d", widgetId), + Context.MODE_PRIVATE); } - @Override - public void onDestroy() { - super.onDestroy(); - getContentResolver().unregisterContentObserver(mBookmarksObserver); + static void deleteWidgetState(Context context, int widgetId) { + File file = context.getSharedPrefsFile( + String.format("widgetState-%d", widgetId)); + if (file.exists()) { + if (!file.delete()) { + file.deleteOnExit(); + } + } } - private class BookmarksObserver extends ContentObserver { - public BookmarksObserver(Handler handler) { - super(handler); + static void changeFolder(Context context, Intent intent) { + int wid = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); + long fid = intent.getLongExtra(Bookmarks._ID, -1); + if (wid >= 0 && fid >= 0) { + SharedPreferences prefs = getWidgetState(context, wid); + prefs.edit().putLong(STATE_CURRENT_FOLDER, fid).commit(); + AppWidgetManager.getInstance(context) + .notifyAppWidgetViewDataChanged(wid, R.id.bookmarks_list); } + } - @Override - public void onChange(boolean selfChange) { - super.onChange(selfChange); + static void clearWidgetState(Context context, int widgetId) { + SharedPreferences pref = getWidgetState(context, widgetId); + pref.edit() + .remove(STATE_CURRENT_FOLDER) + .remove(STATE_ROOT_FOLDER) + .commit(); + } - // Update all the bookmark widgets - if (mFactories != null) { - for (BookmarkFactory fac : mFactories.values()) { - fac.loadData(); - } + /** + * Checks for any state files that may have not received onDeleted + */ + static void removeOrphanedStates(Context context, int[] widgetIds) { + File prefsDirectory = context.getSharedPrefsFile("null").getParentFile(); + File[] widgetStates = prefsDirectory.listFiles(new StateFilter(widgetIds)); + for (File f : widgetStates) { + Log.w(TAG, "Found orphaned state: " + f.getName()); + if (!f.delete()) { + f.deleteOnExit(); } } } - @Override - public RemoteViewsFactory onGetViewFactory(Intent intent) { - int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); - if (widgetId < 0) { - Log.w(TAG, "Missing EXTRA_APPWIDGET_ID!"); - return null; - } else { - BookmarkFactory fac = mFactories.get(widgetId); - if (fac == null) { - fac = new BookmarkFactory(getApplicationContext(), widgetId); + static class StateFilter implements FilenameFilter { + + static final Pattern sStatePattern = Pattern.compile("widgetState-(\\d+)\\.xml"); + HashSet<Integer> mWidgetIds; + + StateFilter(int[] ids) { + mWidgetIds = new HashSet<Integer>(); + for (int id : ids) { + mWidgetIds.add(id); } - mFactories.put(widgetId, fac); - return fac; } - } - private static class Breadcrumb { - long mId; - String mTitle; - public Breadcrumb(long id, String title) { - mId = id; - mTitle = title; + @Override + public boolean accept(File dir, String filename) { + Matcher m = sStatePattern.matcher(filename); + if (m.matches()) { + int id = Integer.parseInt(m.group(1)); + if (!mWidgetIds.contains(id)) { + return true; + } + } + return false; } + } - static class BookmarkFactory implements RemoteViewsService.RemoteViewsFactory, - OnSharedPreferenceChangeListener { - private List<RenderResult> mBookmarks; + static class BookmarkFactory implements RemoteViewsService.RemoteViewsFactory { + private Cursor mBookmarks; private Context mContext; private int mWidgetId; - private String mAccountType; - private String mAccountName; - private Stack<Breadcrumb> mBreadcrumbs; - private LoadBookmarksTask mLoadTask; + private long mCurrentFolder = -1; + private long mRootFolder = -1; + private SharedPreferences mPreferences = null; public BookmarkFactory(Context context, int widgetId) { - mBreadcrumbs = new Stack<Breadcrumb>(); mContext = context; mWidgetId = widgetId; } - void changeFolder(long folderId) { - if (mBookmarks == null) return; - - if (!mBreadcrumbs.empty() && mBreadcrumbs.peek().mId == folderId) { - mBreadcrumbs.pop(); - loadData(); - return; + void syncState() { + if (mPreferences == null) { + mPreferences = getWidgetState(mContext, mWidgetId); + } + long currentFolder = mPreferences.getLong(STATE_CURRENT_FOLDER, -1); + mRootFolder = mPreferences.getLong(STATE_ROOT_FOLDER, -1); + if (currentFolder != mCurrentFolder) { + resetBookmarks(); + mCurrentFolder = currentFolder; } + } - for (RenderResult res : mBookmarks) { - if (res.mId == folderId) { - mBreadcrumbs.push(new Breadcrumb(res.mId, res.mTitle)); - loadData(); - break; - } + void saveState() { + if (mPreferences == null) { + mPreferences = getWidgetState(mContext, mWidgetId); } + mPreferences.edit() + .putLong(STATE_CURRENT_FOLDER, mCurrentFolder) + .putLong(STATE_ROOT_FOLDER, mRootFolder) + .commit(); } @Override public int getCount() { if (mBookmarks == null) return 0; - return mBookmarks.size(); + return mBookmarks.getCount(); } @Override @@ -231,44 +207,33 @@ public class BookmarkThumbnailWidgetService extends RemoteViewsService { @Override public RemoteViews getLoadingView() { - return null; + return new RemoteViews( + mContext.getPackageName(), R.layout.bookmarkthumbnailwidget_item); } @Override public RemoteViews getViewAt(int position) { - if (position < 0 || position >= getCount()) { + if (!mBookmarks.moveToPosition(position)) { return null; } - RenderResult res = mBookmarks.get(position); - Breadcrumb folder = mBreadcrumbs.empty() ? null : mBreadcrumbs.peek(); + long id = mBookmarks.getLong(BOOKMARK_INDEX_ID); + String title = mBookmarks.getString(BOOKMARK_INDEX_TITLE); + String url = mBookmarks.getString(BOOKMARK_INDEX_URL); + boolean isFolder = mBookmarks.getInt(BOOKMARK_INDEX_IS_FOLDER) != 0; RemoteViews views = new RemoteViews( mContext.getPackageName(), R.layout.bookmarkthumbnailwidget_item); - Intent fillin; - if (res.mIsFolder) { - long nfi = res.mId; - fillin = new Intent(ACTION_CHANGE_FOLDER, null, - mContext, BookmarkThumbnailWidgetService.class) - .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId) - .putExtra(Bookmarks._ID, nfi); - } else { - fillin = new Intent(Intent.ACTION_VIEW) - .addCategory(Intent.CATEGORY_BROWSABLE); - if (!TextUtils.isEmpty(res.mUrl)) { - fillin.setData(Uri.parse(res.mUrl)); - } - } - views.setOnClickFillInIntent(R.id.list_item, fillin); // Set the title of the bookmark. Use the url as a backup. - String displayTitle = res.mTitle; + String displayTitle = title; if (TextUtils.isEmpty(displayTitle)) { // The browser always requires a title for bookmarks, but jic... - displayTitle = res.mUrl; + displayTitle = url; } views.setTextViewText(R.id.label, displayTitle); - if (res.mIsFolder) { - if (folder != null && res.mId == folder.mId) { + if (isFolder) { + if (id == mCurrentFolder) { + id = mBookmarks.getLong(BOOKMARK_INDEX_PARENT_ID); views.setImageViewResource(R.id.thumb, R.drawable.thumb_bookmark_widget_folder_back_holo); } else { views.setImageViewResource(R.id.thumb, R.drawable.thumb_bookmark_widget_folder_holo); @@ -276,20 +241,45 @@ public class BookmarkThumbnailWidgetService extends RemoteViewsService { views.setImageViewResource(R.id.favicon, R.drawable.ic_bookmark_widget_bookmark_holo_dark); views.setDrawableParameters(R.id.thumb, true, 0, -1, null, -1); } else { + // RemoteViews require a valid bitmap config + Options options = new Options(); + options.inPreferredConfig = Config.ARGB_8888; + Bitmap thumbnail = null, favicon = null; + byte[] blob = mBookmarks.getBlob(BOOKMARK_INDEX_THUMBNAIL); views.setDrawableParameters(R.id.thumb, true, 255, -1, null, -1); - if (res.mThumbnail != null) { - views.setImageViewBitmap(R.id.thumb, res.mThumbnail); + if (blob != null && blob.length > 0) { + thumbnail = BitmapFactory.decodeByteArray( + blob, 0, blob.length, options); + views.setImageViewBitmap(R.id.thumb, thumbnail); } else { views.setImageViewResource(R.id.thumb, R.drawable.browser_thumbnail); } - if (res.mIcon != null) { - views.setImageViewBitmap(R.id.favicon, res.mIcon); + blob = mBookmarks.getBlob(BOOKMARK_INDEX_FAVICON); + if (blob != null && blob.length > 0) { + favicon = BitmapFactory.decodeByteArray( + blob, 0, blob.length, options); + views.setImageViewBitmap(R.id.favicon, favicon); } else { views.setImageViewResource(R.id.favicon, R.drawable.app_web_browser_sm); } } + Intent fillin; + if (isFolder) { + fillin = new Intent(ACTION_CHANGE_FOLDER) + .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId) + .putExtra(Bookmarks._ID, id); + } else { + if (!TextUtils.isEmpty(url)) { + fillin = new Intent(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_BROWSABLE) + .setData(Uri.parse(url)); + } else { + fillin = new Intent(BrowserActivity.ACTION_SHOW_BROWSER); + } + } + views.setOnClickFillInIntent(R.id.list_item, fillin); return views; } @@ -305,187 +295,70 @@ public class BookmarkThumbnailWidgetService extends RemoteViewsService { @Override public void onCreate() { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); - mAccountType = prefs.getString(BrowserBookmarksPage.PREF_ACCOUNT_TYPE, null); - mAccountName = prefs.getString(BrowserBookmarksPage.PREF_ACCOUNT_NAME, null); - prefs.registerOnSharedPreferenceChangeListener(this); - loadData(); } @Override public void onDestroy() { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); - prefs.unregisterOnSharedPreferenceChangeListener(this); - - // Workaround known framework bug - // This class currently leaks, so free as much memory as we can - recycleBitmaps(); - mBookmarks.clear(); - mBreadcrumbs.clear(); - if (mLoadTask != null) { - mLoadTask.cancel(false); - mLoadTask = null; + if (mBookmarks != null) { + mBookmarks.close(); + mBookmarks = null; } + deleteWidgetState(mContext, mWidgetId); } @Override public void onDataSetChanged() { - } - - void loadData() { - if (mLoadTask != null) { - mLoadTask.cancel(false); + long token = Binder.clearCallingIdentity(); + syncState(); + if (mRootFolder < 0 || mCurrentFolder < 0) { + // Our state has been zero'd, reset (account change most likely) + mRootFolder = getRootFolder(); + mCurrentFolder = mRootFolder; + saveState(); } - mLoadTask = new LoadBookmarksTask(); - mLoadTask.execute(); + loadBookmarks(); + Binder.restoreCallingIdentity(token); } - class LoadBookmarksTask extends AsyncTask<Void, Void, List<RenderResult>> { - private Breadcrumb mFolder; - - @Override - protected void onPreExecute() { - mFolder = mBreadcrumbs.empty() ? null : mBreadcrumbs.peek(); - } - - @Override - protected List<RenderResult> doInBackground(Void... params) { - return loadBookmarks(mFolder); - } - - @Override - protected void onPostExecute(List<RenderResult> result) { - if (!isCancelled() && result != null) { - recycleBitmaps(); - mBookmarks = result; - AppWidgetManager.getInstance(mContext) - .notifyAppWidgetViewDataChanged(mWidgetId, R.id.bookmarks_list); - } + private void resetBookmarks() { + if (mBookmarks != null) { + mBookmarks.close(); + mBookmarks = null; } } - List<RenderResult> loadBookmarks(Breadcrumb folder) { - String where = null; - Uri uri; - if (USE_FOLDERS) { - uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER; - if (folder != null) { - uri = ContentUris.withAppendedId(uri, folder.mId); - } - } else { - uri = BrowserContract.Bookmarks.CONTENT_URI; - where = Bookmarks.IS_FOLDER + " == 0"; - } - uri = uri.buildUpon() - .appendQueryParameter(Bookmarks.PARAM_ACCOUNT_TYPE, mAccountType) - .appendQueryParameter(Bookmarks.PARAM_ACCOUNT_NAME, mAccountName) - .build(); - Cursor c = null; + long getRootFolder() { + Uri uri = Uri.withAppendedPath( + BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, "id"); + uri = BookmarkUtils.addAccountInfo(mContext, uri.buildUpon()).build(); + Cursor c = mContext.getContentResolver().query( + uri, null, null, null, null); try { - c = mContext.getContentResolver().query(uri, PROJECTION, - where, null, null); - if (c != null) { - ArrayList<RenderResult> bookmarks - = new ArrayList<RenderResult>(c.getCount() + 1); - if (folder != null) { - RenderResult res = new RenderResult( - folder.mId, folder.mTitle, null); - res.mIsFolder = true; - bookmarks.add(res); - } - while (c.moveToNext()) { - long id = c.getLong(BOOKMARK_INDEX_ID); - String title = c.getString(BOOKMARK_INDEX_TITLE); - String url = c.getString(BOOKMARK_INDEX_URL); - RenderResult res = new RenderResult(id, title, url); - res.mIsFolder = c.getInt(BOOKMARK_INDEX_IS_FOLDER) != 0; - if (!res.mIsFolder) { - // RemoteViews require a valid bitmap config - Options options = new Options(); - options.inPreferredConfig = Config.ARGB_8888; - Bitmap thumbnail = null, favicon = null; - byte[] blob = c.getBlob(BOOKMARK_INDEX_THUMBNAIL); - if (blob != null && blob.length > 0) { - thumbnail = BitmapFactory.decodeByteArray( - blob, 0, blob.length, options); - } - blob = c.getBlob(BOOKMARK_INDEX_FAVICON); - if (blob != null && blob.length > 0) { - favicon = BitmapFactory.decodeByteArray( - blob, 0, blob.length, options); - } - res.mThumbnail = thumbnail; - res.mIcon = favicon; - } - bookmarks.add(res); - } - if (bookmarks.size() == 0) { - RenderResult res = new RenderResult(0, "", ""); - Bitmap thumbnail = BitmapFactory.decodeResource( - mContext.getResources(), - R.drawable.thumbnail_bookmarks_widget_no_bookmark_holo); - Bitmap favicon = Bitmap.createBitmap(1, 1, Config.ALPHA_8); - res.mThumbnail = thumbnail; - res.mIcon = favicon; - for (int i = 0; i < 6; i++) { - bookmarks.add(res); - } - } - return bookmarks; - } - } catch (IllegalStateException e) { - Log.e(TAG, "update bookmark widget", e); + c.moveToFirst(); + return c.getLong(0); } finally { - if (c != null) { - c.close(); - } + c.close(); } - return null; } - private void recycleBitmaps() { - // Do a bit of house cleaning for the system - if (mBookmarks != null) { - for (RenderResult res : mBookmarks) { - if (res.mThumbnail != null) { - res.mThumbnail.recycle(); - res.mThumbnail = null; - } - } - } - } - - @Override - public void onSharedPreferenceChanged( - SharedPreferences prefs, String key) { - if (BrowserBookmarksPage.PREF_ACCOUNT_TYPE.equals(key)) { - mAccountType = prefs.getString(BrowserBookmarksPage.PREF_ACCOUNT_TYPE, null); - mBreadcrumbs.clear(); - loadData(); - } - if (BrowserBookmarksPage.PREF_ACCOUNT_NAME.equals(key)) { - mAccountName = prefs.getString(BrowserBookmarksPage.PREF_ACCOUNT_NAME, null); - mBreadcrumbs.clear(); - loadData(); + void loadBookmarks() { + resetBookmarks(); + + Uri uri = ContentUris.withAppendedId( + BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, + mCurrentFolder); + uri = BookmarkUtils.addAccountInfo(mContext, uri.buildUpon()).build(); + mBookmarks = mContext.getContentResolver().query(uri, PROJECTION, + null, null, null); + if (mCurrentFolder != mRootFolder) { + uri = ContentUris.withAppendedId( + BrowserContract.Bookmarks.CONTENT_URI, + mCurrentFolder); + Cursor c = mContext.getContentResolver().query(uri, PROJECTION, + null, null, null); + mBookmarks = new MergeCursor(new Cursor[] { c, mBookmarks }); } } } - // Class containing the rendering information for a specific bookmark. - private static class RenderResult { - final String mTitle; - final String mUrl; - Bitmap mThumbnail; - Bitmap mIcon; - boolean mIsFolder; - long mId; - - RenderResult(long id, String title, String url) { - mId = id; - mTitle = title; - mUrl = url; - } - - } - } diff --git a/src/com/android/browser/widget/BookmarkWidgetProxy.java b/src/com/android/browser/widget/BookmarkWidgetProxy.java new file mode 100644 index 0000000..8ab57fc --- /dev/null +++ b/src/com/android/browser/widget/BookmarkWidgetProxy.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 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.widget; + +import com.android.browser.BrowserActivity; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +public class BookmarkWidgetProxy extends BroadcastReceiver { + + private static final String TAG = "BookmarkWidgetProxy"; + + @Override + public void onReceive(Context context, Intent intent) { + if (BookmarkThumbnailWidgetService.ACTION_CHANGE_FOLDER.equals(intent.getAction())) { + BookmarkThumbnailWidgetService.changeFolder(context, intent); + } else if (BrowserActivity.ACTION_SHOW_BROWSER.equals(intent.getAction())) { + startActivity(context, + new Intent(BrowserActivity.ACTION_SHOW_BROWSER, + null, context, BrowserActivity.class)); + } else { + Intent view = new Intent(intent); + view.setComponent(null); + startActivity(context, view); + } + } + + void startActivity(Context context, Intent intent) { + try { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } catch (Exception e) { + Log.w(TAG, "Failed to start intent activity", e); + } + } +} |