BookmarkThumbnailWidgetService.java revision 99c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2
1df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck/* 2df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * Copyright (C) 2010 The Android Open Source Project 3df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * 4df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * Licensed under the Apache License, Version 2.0 (the "License"); 5df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * you may not use this file except in compliance with the License. 6df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * You may obtain a copy of the License at 7df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * 8df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * http://www.apache.org/licenses/LICENSE-2.0 9df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * 10df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * Unless required by applicable law or agreed to in writing, software 11df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * distributed under the License is distributed on an "AS IS" BASIS, 12df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * See the License for the specific language governing permissions and 14df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck * limitations under the License. 15df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck */ 16df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 17df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckpackage com.android.browser.widget; 18df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 1999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport com.android.browser.BookmarkUtils; 209291bd1c9b5d1398e14d80ddea91cebf574cc63eJohn Reckimport com.android.browser.BrowserActivity; 21df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport com.android.browser.R; 22df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 23df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.appwidget.AppWidgetManager; 246eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reckimport android.content.ContentUris; 25df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.content.Context; 26df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.content.Intent; 276eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reckimport android.content.SharedPreferences; 28df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.database.Cursor; 2999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport android.database.MergeCursor; 30df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.graphics.Bitmap; 31df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.graphics.Bitmap.Config; 32df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.graphics.BitmapFactory; 33df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.graphics.BitmapFactory.Options; 34df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.net.Uri; 3599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport android.os.Binder; 36df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.provider.BrowserContract; 37df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.provider.BrowserContract.Bookmarks; 38df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.text.TextUtils; 39df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.util.Log; 40df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.widget.RemoteViews; 41df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.widget.RemoteViewsService; 42df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 4399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.io.File; 4499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.io.FilenameFilter; 4599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.util.Arrays; 4699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.util.HashSet; 4799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.util.regex.Matcher; 4899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.util.regex.Pattern; 49df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 501537b774a62042a8b86100e1e6b0988bed70c385John Reckpublic class BookmarkThumbnailWidgetService extends RemoteViewsService { 51df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 521537b774a62042a8b86100e1e6b0988bed70c385John Reck static final String TAG = "BookmarkThumbnailWidgetService"; 53df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck static final String ACTION_CHANGE_FOLDER 54df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck = "com.android.browser.widget.CHANGE_FOLDER"; 55df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 5699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static final String STATE_CURRENT_FOLDER = "current_folder"; 5799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static final String STATE_ROOT_FOLDER = "root_folder"; 5899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 59df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck private static final String[] PROJECTION = new String[] { 60df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks._ID, 61df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks.TITLE, 62df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks.URL, 63df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks.FAVICON, 64df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks.IS_FOLDER, 651537b774a62042a8b86100e1e6b0988bed70c385John Reck BrowserContract.Bookmarks.POSITION, /* needed for order by */ 6699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck BrowserContract.Bookmarks.THUMBNAIL, 6799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck BrowserContract.Bookmarks.PARENT}; 68023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_ID = 0; 69023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_TITLE = 1; 70023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_URL = 2; 71023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_FAVICON = 3; 72023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_IS_FOLDER = 4; 7399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private static final int BOOKMARK_INDEX_THUMBNAIL = 6; 7499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private static final int BOOKMARK_INDEX_PARENT_ID = 7; 75df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 76df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 7799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck public RemoteViewsFactory onGetViewFactory(Intent intent) { 7899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 7999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (widgetId < 0) { 8099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Log.w(TAG, "Missing EXTRA_APPWIDGET_ID!"); 8199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return null; 8299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 8399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return new BookmarkFactory(getApplicationContext(), widgetId); 84df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 85df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 8699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static SharedPreferences getWidgetState(Context context, int widgetId) { 8799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return context.getSharedPreferences( 8899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String.format("widgetState-%d", widgetId), 8999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Context.MODE_PRIVATE); 90df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 91df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 9299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static void deleteWidgetState(Context context, int widgetId) { 9399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck File file = context.getSharedPrefsFile( 9499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String.format("widgetState-%d", widgetId)); 9599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (file.exists()) { 9699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (!file.delete()) { 9799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck file.deleteOnExit(); 9899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 9999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 100df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 101df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 10299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static void changeFolder(Context context, Intent intent) { 10399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck int wid = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 10499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck long fid = intent.getLongExtra(Bookmarks._ID, -1); 10599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (wid >= 0 && fid >= 0) { 10699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck SharedPreferences prefs = getWidgetState(context, wid); 10799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck prefs.edit().putLong(STATE_CURRENT_FOLDER, fid).commit(); 10899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck AppWidgetManager.getInstance(context) 10999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .notifyAppWidgetViewDataChanged(wid, R.id.bookmarks_list); 110df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 11199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 112df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 11399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static void clearWidgetState(Context context, int widgetId) { 11499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck SharedPreferences pref = getWidgetState(context, widgetId); 11599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck pref.edit() 11699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .remove(STATE_CURRENT_FOLDER) 11799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .remove(STATE_ROOT_FOLDER) 11899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .commit(); 11999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 120df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 12199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck /** 12299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck * Checks for any state files that may have not received onDeleted 12399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck */ 12499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static void removeOrphanedStates(Context context, int[] widgetIds) { 12599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck File prefsDirectory = context.getSharedPrefsFile("null").getParentFile(); 12699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck File[] widgetStates = prefsDirectory.listFiles(new StateFilter(widgetIds)); 12799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck for (File f : widgetStates) { 12899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Log.w(TAG, "Found orphaned state: " + f.getName()); 12999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (!f.delete()) { 13099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck f.deleteOnExit(); 1317c11d28643f571669b59ef0d700392c45256ce97John Reck } 132df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 133df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 134df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 13599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static class StateFilter implements FilenameFilter { 13699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 13799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static final Pattern sStatePattern = Pattern.compile("widgetState-(\\d+)\\.xml"); 13899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck HashSet<Integer> mWidgetIds; 13999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 14099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck StateFilter(int[] ids) { 14199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mWidgetIds = new HashSet<Integer>(); 14299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck for (int id : ids) { 14399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mWidgetIds.add(id); 1447c11d28643f571669b59ef0d700392c45256ce97John Reck } 145df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 146df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 14799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck @Override 14899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck public boolean accept(File dir, String filename) { 14999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Matcher m = sStatePattern.matcher(filename); 15099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (m.matches()) { 15199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck int id = Integer.parseInt(m.group(1)); 15299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (!mWidgetIds.contains(id)) { 15399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return true; 15499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 15599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 15699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return false; 1576eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck } 15899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 1596eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck } 1606eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck 16199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static class BookmarkFactory implements RemoteViewsService.RemoteViewsFactory { 16299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private Cursor mBookmarks; 163df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck private Context mContext; 164df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck private int mWidgetId; 16599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private long mCurrentFolder = -1; 16699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private long mRootFolder = -1; 16799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private SharedPreferences mPreferences = null; 168df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 169df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public BookmarkFactory(Context context, int widgetId) { 170df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck mContext = context; 171df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck mWidgetId = widgetId; 172df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 173df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 17499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck void syncState() { 17599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mPreferences == null) { 17699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mPreferences = getWidgetState(mContext, mWidgetId); 17799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 17899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck long currentFolder = mPreferences.getLong(STATE_CURRENT_FOLDER, -1); 17999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mRootFolder = mPreferences.getLong(STATE_ROOT_FOLDER, -1); 18099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (currentFolder != mCurrentFolder) { 18199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck resetBookmarks(); 18299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mCurrentFolder = currentFolder; 1836eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck } 18499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 1856eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck 18699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck void saveState() { 18799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mPreferences == null) { 18899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mPreferences = getWidgetState(mContext, mWidgetId); 1896eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck } 19099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mPreferences.edit() 19199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .putLong(STATE_CURRENT_FOLDER, mCurrentFolder) 19299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .putLong(STATE_ROOT_FOLDER, mRootFolder) 19399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .commit(); 194df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 195df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 196df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 197df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public int getCount() { 198df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck if (mBookmarks == null) 199df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return 0; 20099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return mBookmarks.getCount(); 201df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 202df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 203df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 204df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public long getItemId(int position) { 205df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return position; 206df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 207df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 208df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 209df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public RemoteViews getLoadingView() { 21099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return new RemoteViews( 21199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mContext.getPackageName(), R.layout.bookmarkthumbnailwidget_item); 212df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 213df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 214df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 215df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public RemoteViews getViewAt(int position) { 21699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (!mBookmarks.moveToPosition(position)) { 217df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return null; 218df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 219df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 22099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck long id = mBookmarks.getLong(BOOKMARK_INDEX_ID); 22199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String title = mBookmarks.getString(BOOKMARK_INDEX_TITLE); 22299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String url = mBookmarks.getString(BOOKMARK_INDEX_URL); 22399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck boolean isFolder = mBookmarks.getInt(BOOKMARK_INDEX_IS_FOLDER) != 0; 224df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 225df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck RemoteViews views = new RemoteViews( 2261537b774a62042a8b86100e1e6b0988bed70c385John Reck mContext.getPackageName(), R.layout.bookmarkthumbnailwidget_item); 227df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck // Set the title of the bookmark. Use the url as a backup. 22899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String displayTitle = title; 229df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck if (TextUtils.isEmpty(displayTitle)) { 230df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck // The browser always requires a title for bookmarks, but jic... 23199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck displayTitle = url; 232df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 233df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck views.setTextViewText(R.id.label, displayTitle); 23499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (isFolder) { 23599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (id == mCurrentFolder) { 23699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck id = mBookmarks.getLong(BOOKMARK_INDEX_PARENT_ID); 2371537b774a62042a8b86100e1e6b0988bed70c385John Reck views.setImageViewResource(R.id.thumb, R.drawable.thumb_bookmark_widget_folder_back_holo); 238df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } else { 2391537b774a62042a8b86100e1e6b0988bed70c385John Reck views.setImageViewResource(R.id.thumb, R.drawable.thumb_bookmark_widget_folder_holo); 240df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 2411537b774a62042a8b86100e1e6b0988bed70c385John Reck views.setImageViewResource(R.id.favicon, R.drawable.ic_bookmark_widget_bookmark_holo_dark); 242f95eb7410686ee1ea4b7f583f03b642c30551b79John Reck views.setDrawableParameters(R.id.thumb, true, 0, -1, null, -1); 243df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } else { 24499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck // RemoteViews require a valid bitmap config 24599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Options options = new Options(); 24699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck options.inPreferredConfig = Config.ARGB_8888; 24799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Bitmap thumbnail = null, favicon = null; 24899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck byte[] blob = mBookmarks.getBlob(BOOKMARK_INDEX_THUMBNAIL); 249f95eb7410686ee1ea4b7f583f03b642c30551b79John Reck views.setDrawableParameters(R.id.thumb, true, 255, -1, null, -1); 25099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (blob != null && blob.length > 0) { 25199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck thumbnail = BitmapFactory.decodeByteArray( 25299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck blob, 0, blob.length, options); 25399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck views.setImageViewBitmap(R.id.thumb, thumbnail); 254df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } else { 255df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck views.setImageViewResource(R.id.thumb, 256df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck R.drawable.browser_thumbnail); 257df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 25899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck blob = mBookmarks.getBlob(BOOKMARK_INDEX_FAVICON); 25999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (blob != null && blob.length > 0) { 26099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck favicon = BitmapFactory.decodeByteArray( 26199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck blob, 0, blob.length, options); 26299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck views.setImageViewBitmap(R.id.favicon, favicon); 2631537b774a62042a8b86100e1e6b0988bed70c385John Reck } else { 2641537b774a62042a8b86100e1e6b0988bed70c385John Reck views.setImageViewResource(R.id.favicon, 2651537b774a62042a8b86100e1e6b0988bed70c385John Reck R.drawable.app_web_browser_sm); 2661537b774a62042a8b86100e1e6b0988bed70c385John Reck } 267df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 26899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Intent fillin; 26999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (isFolder) { 27099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck fillin = new Intent(ACTION_CHANGE_FOLDER) 27199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId) 27299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .putExtra(Bookmarks._ID, id); 27399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } else { 27499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (!TextUtils.isEmpty(url)) { 27599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck fillin = new Intent(Intent.ACTION_VIEW) 27699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .addCategory(Intent.CATEGORY_BROWSABLE) 27799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .setData(Uri.parse(url)); 27899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } else { 27999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck fillin = new Intent(BrowserActivity.ACTION_SHOW_BROWSER); 28099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 28199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 28299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck views.setOnClickFillInIntent(R.id.list_item, fillin); 283df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return views; 284df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 285df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 286df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 287df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public int getViewTypeCount() { 288df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return 1; 289df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 290df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 291df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 292df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public boolean hasStableIds() { 293df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return false; 294df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 295df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 296df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 297df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public void onCreate() { 298df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 299df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 300df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 301df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public void onDestroy() { 30299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mBookmarks != null) { 30399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks.close(); 30499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks = null; 30573eb105e5bb53356e171837bd6b13b29661806e3John Reck } 30699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck deleteWidgetState(mContext, mWidgetId); 307df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 308df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 309df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 310df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public void onDataSetChanged() { 31199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck long token = Binder.clearCallingIdentity(); 31299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck syncState(); 31399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mRootFolder < 0 || mCurrentFolder < 0) { 31499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck // Our state has been zero'd, reset (account change most likely) 31599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mRootFolder = getRootFolder(); 31699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mCurrentFolder = mRootFolder; 31799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck saveState(); 3187c11d28643f571669b59ef0d700392c45256ce97John Reck } 31999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck loadBookmarks(); 32099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Binder.restoreCallingIdentity(token); 321df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 322df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 32399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private void resetBookmarks() { 32499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mBookmarks != null) { 32599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks.close(); 32699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks = null; 3277c11d28643f571669b59ef0d700392c45256ce97John Reck } 3287c11d28643f571669b59ef0d700392c45256ce97John Reck } 3297c11d28643f571669b59ef0d700392c45256ce97John Reck 33099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck long getRootFolder() { 33199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Uri uri = Uri.withAppendedPath( 33299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, "id"); 33399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck uri = BookmarkUtils.addAccountInfo(mContext, uri.buildUpon()).build(); 33499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Cursor c = mContext.getContentResolver().query( 33599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck uri, null, null, null, null); 336df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck try { 33799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck c.moveToFirst(); 33899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return c.getLong(0); 339df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } finally { 34099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck c.close(); 341df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 342df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 343df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 34499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck void loadBookmarks() { 34599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck resetBookmarks(); 34699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 34799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Uri uri = ContentUris.withAppendedId( 34899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, 34999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mCurrentFolder); 35099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck uri = BookmarkUtils.addAccountInfo(mContext, uri.buildUpon()).build(); 35199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks = mContext.getContentResolver().query(uri, PROJECTION, 35299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck null, null, null); 35399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mCurrentFolder != mRootFolder) { 35499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck uri = ContentUris.withAppendedId( 35599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck BrowserContract.Bookmarks.CONTENT_URI, 35699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mCurrentFolder); 35799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Cursor c = mContext.getContentResolver().query(uri, PROJECTION, 35899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck null, null, null); 35999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks = new MergeCursor(new Cursor[] { c, mBookmarks }); 3607c11d28643f571669b59ef0d700392c45256ce97John Reck } 3617c11d28643f571669b59ef0d700392c45256ce97John Reck } 362df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 363df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 364df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck} 365