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 19df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.appwidget.AppWidgetManager; 206eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reckimport android.content.ContentUris; 21df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.content.Context; 22df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.content.Intent; 236eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reckimport android.content.SharedPreferences; 24df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.database.Cursor; 2599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport android.database.MergeCursor; 26df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.graphics.Bitmap; 27df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.graphics.Bitmap.Config; 28df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.graphics.BitmapFactory; 29df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.graphics.BitmapFactory.Options; 30df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.net.Uri; 3199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport android.os.Binder; 32df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.provider.BrowserContract; 33df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.provider.BrowserContract.Bookmarks; 34df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.text.TextUtils; 35df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.util.Log; 36df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.widget.RemoteViews; 37df63d2ff2e9881706eef78796d05078d0ffb7f60John Reckimport android.widget.RemoteViewsService; 38df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 399b8cd1e564984874f2a6f5cc9bdc68cda8aa15ceJohn Reckimport com.android.browser.BrowserActivity; 409b8cd1e564984874f2a6f5cc9bdc68cda8aa15ceJohn Reckimport com.android.browser.R; 419b8cd1e564984874f2a6f5cc9bdc68cda8aa15ceJohn Reckimport com.android.browser.provider.BrowserProvider2; 429b8cd1e564984874f2a6f5cc9bdc68cda8aa15ceJohn Reck 4399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.io.File; 4499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.io.FilenameFilter; 4599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.util.HashSet; 4699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.util.regex.Matcher; 4799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reckimport java.util.regex.Pattern; 48df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 491537b774a62042a8b86100e1e6b0988bed70c385John Reckpublic class BookmarkThumbnailWidgetService extends RemoteViewsService { 50df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 511537b774a62042a8b86100e1e6b0988bed70c385John Reck static final String TAG = "BookmarkThumbnailWidgetService"; 52df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck static final String ACTION_CHANGE_FOLDER 53df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck = "com.android.browser.widget.CHANGE_FOLDER"; 54df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 5599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static final String STATE_CURRENT_FOLDER = "current_folder"; 5699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static final String STATE_ROOT_FOLDER = "root_folder"; 5799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 58df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck private static final String[] PROJECTION = new String[] { 59df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks._ID, 60df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks.TITLE, 61df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks.URL, 62df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks.FAVICON, 63df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck BrowserContract.Bookmarks.IS_FOLDER, 641537b774a62042a8b86100e1e6b0988bed70c385John Reck BrowserContract.Bookmarks.POSITION, /* needed for order by */ 6599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck BrowserContract.Bookmarks.THUMBNAIL, 6699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck BrowserContract.Bookmarks.PARENT}; 67023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_ID = 0; 68023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_TITLE = 1; 69023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_URL = 2; 70023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_FAVICON = 3; 71023a60e37c0f3374aed57531ab11b7f20ece232bJohn Reck private static final int BOOKMARK_INDEX_IS_FOLDER = 4; 7299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private static final int BOOKMARK_INDEX_THUMBNAIL = 6; 7399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private static final int BOOKMARK_INDEX_PARENT_ID = 7; 74df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 75df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 7699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck public RemoteViewsFactory onGetViewFactory(Intent intent) { 7799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck int widgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 7899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (widgetId < 0) { 7999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Log.w(TAG, "Missing EXTRA_APPWIDGET_ID!"); 8099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return null; 8199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 8299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return new BookmarkFactory(getApplicationContext(), widgetId); 83df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 84df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 8599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static SharedPreferences getWidgetState(Context context, int widgetId) { 8699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return context.getSharedPreferences( 8799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String.format("widgetState-%d", widgetId), 8899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Context.MODE_PRIVATE); 89df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 90df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 9199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static void deleteWidgetState(Context context, int widgetId) { 9299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck File file = context.getSharedPrefsFile( 9399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String.format("widgetState-%d", widgetId)); 9499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (file.exists()) { 9599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (!file.delete()) { 9699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck file.deleteOnExit(); 9799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 9899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 99df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 100df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 10199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static void changeFolder(Context context, Intent intent) { 10299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck int wid = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1); 10399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck long fid = intent.getLongExtra(Bookmarks._ID, -1); 10499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (wid >= 0 && fid >= 0) { 10599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck SharedPreferences prefs = getWidgetState(context, wid); 10699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck prefs.edit().putLong(STATE_CURRENT_FOLDER, fid).commit(); 10799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck AppWidgetManager.getInstance(context) 10899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .notifyAppWidgetViewDataChanged(wid, R.id.bookmarks_list); 109df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 11099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 111df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 1129b8cd1e564984874f2a6f5cc9bdc68cda8aa15ceJohn Reck static void setupWidgetState(Context context, int widgetId, long rootFolder) { 11399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck SharedPreferences pref = getWidgetState(context, widgetId); 11499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck pref.edit() 1159b8cd1e564984874f2a6f5cc9bdc68cda8aa15ceJohn Reck .putLong(STATE_CURRENT_FOLDER, rootFolder) 1169b8cd1e564984874f2a6f5cc9bdc68cda8aa15ceJohn Reck .putLong(STATE_ROOT_FOLDER, rootFolder) 11732a915b47ece86b8fa6026e5917eaa9cf651d64bBen Murdoch .apply(); 11899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 119df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 12099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck /** 12199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck * Checks for any state files that may have not received onDeleted 12299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck */ 12399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static void removeOrphanedStates(Context context, int[] widgetIds) { 12499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck File prefsDirectory = context.getSharedPrefsFile("null").getParentFile(); 12599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck File[] widgetStates = prefsDirectory.listFiles(new StateFilter(widgetIds)); 126728abd38d05820cf1a3329d7b5513cf92eef5644John Reck if (widgetStates != null) { 127728abd38d05820cf1a3329d7b5513cf92eef5644John Reck for (File f : widgetStates) { 128728abd38d05820cf1a3329d7b5513cf92eef5644John Reck Log.w(TAG, "Found orphaned state: " + f.getName()); 129728abd38d05820cf1a3329d7b5513cf92eef5644John Reck if (!f.delete()) { 130728abd38d05820cf1a3329d7b5513cf92eef5644John Reck f.deleteOnExit(); 131728abd38d05820cf1a3329d7b5513cf92eef5644John Reck } 1327c11d28643f571669b59ef0d700392c45256ce97John Reck } 133df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 134df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 135df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 13699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static class StateFilter implements FilenameFilter { 13799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 13899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static final Pattern sStatePattern = Pattern.compile("widgetState-(\\d+)\\.xml"); 13999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck HashSet<Integer> mWidgetIds; 14099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 14199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck StateFilter(int[] ids) { 14299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mWidgetIds = new HashSet<Integer>(); 14399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck for (int id : ids) { 14499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mWidgetIds.add(id); 1457c11d28643f571669b59ef0d700392c45256ce97John Reck } 146df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 147df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 14899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck @Override 14999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck public boolean accept(File dir, String filename) { 15099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Matcher m = sStatePattern.matcher(filename); 15199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (m.matches()) { 15299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck int id = Integer.parseInt(m.group(1)); 15399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (!mWidgetIds.contains(id)) { 15499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return true; 15599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 15699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 15799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return false; 1586eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck } 15999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 1606eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck } 1616eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck 16299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck static class BookmarkFactory implements RemoteViewsService.RemoteViewsFactory { 16399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private Cursor mBookmarks; 164df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck private Context mContext; 165df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck private int mWidgetId; 16699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private long mCurrentFolder = -1; 16799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private long mRootFolder = -1; 16899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private SharedPreferences mPreferences = null; 169df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 170df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public BookmarkFactory(Context context, int widgetId) { 171914c5591baeb86bf30a5bc28930071442a822d60Ben Murdoch mContext = context.getApplicationContext(); 172df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck mWidgetId = widgetId; 173df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 174df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 17599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck void syncState() { 17699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mPreferences == null) { 17799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mPreferences = getWidgetState(mContext, mWidgetId); 17899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 17999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck long currentFolder = mPreferences.getLong(STATE_CURRENT_FOLDER, -1); 18099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mRootFolder = mPreferences.getLong(STATE_ROOT_FOLDER, -1); 18199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (currentFolder != mCurrentFolder) { 18299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck resetBookmarks(); 18399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mCurrentFolder = currentFolder; 1846eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck } 18599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 1866eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck 18799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck void saveState() { 18899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mPreferences == null) { 18999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mPreferences = getWidgetState(mContext, mWidgetId); 1906eb77c79f9a88ea0e76eb07ea0412bbd2446a110John Reck } 19199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mPreferences.edit() 19299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .putLong(STATE_CURRENT_FOLDER, mCurrentFolder) 19399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .putLong(STATE_ROOT_FOLDER, mRootFolder) 19499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .commit(); 195df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 196df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 197df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 198df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public int getCount() { 199df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck if (mBookmarks == null) 200df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return 0; 20199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return mBookmarks.getCount(); 202df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 203df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 204df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 205df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public long getItemId(int position) { 206df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return position; 207df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 208df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 209df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 210df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public RemoteViews getLoadingView() { 21199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck return new RemoteViews( 21299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mContext.getPackageName(), R.layout.bookmarkthumbnailwidget_item); 213df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 214df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 215df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 216df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public RemoteViews getViewAt(int position) { 21799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (!mBookmarks.moveToPosition(position)) { 218df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return null; 219df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 220df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 22199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck long id = mBookmarks.getLong(BOOKMARK_INDEX_ID); 22299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String title = mBookmarks.getString(BOOKMARK_INDEX_TITLE); 22399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String url = mBookmarks.getString(BOOKMARK_INDEX_URL); 22499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck boolean isFolder = mBookmarks.getInt(BOOKMARK_INDEX_IS_FOLDER) != 0; 225df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 22623c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck RemoteViews views; 22723c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck // Two layouts are needed because of b/5387153 22823c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck if (isFolder) { 22923c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck views = new RemoteViews(mContext.getPackageName(), 23023c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck R.layout.bookmarkthumbnailwidget_item_folder); 23123c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck } else { 23223c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck views = new RemoteViews(mContext.getPackageName(), 23323c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck R.layout.bookmarkthumbnailwidget_item); 23423c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck } 235df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck // Set the title of the bookmark. Use the url as a backup. 23699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck String displayTitle = title; 237df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck if (TextUtils.isEmpty(displayTitle)) { 238df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck // The browser always requires a title for bookmarks, but jic... 23999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck displayTitle = url; 240df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 241df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck views.setTextViewText(R.id.label, displayTitle); 24299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (isFolder) { 24399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (id == mCurrentFolder) { 24499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck id = mBookmarks.getLong(BOOKMARK_INDEX_PARENT_ID); 2451537b774a62042a8b86100e1e6b0988bed70c385John Reck views.setImageViewResource(R.id.thumb, R.drawable.thumb_bookmark_widget_folder_back_holo); 246df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } else { 2471537b774a62042a8b86100e1e6b0988bed70c385John Reck views.setImageViewResource(R.id.thumb, R.drawable.thumb_bookmark_widget_folder_holo); 248df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 2491537b774a62042a8b86100e1e6b0988bed70c385John Reck views.setImageViewResource(R.id.favicon, R.drawable.ic_bookmark_widget_bookmark_holo_dark); 250f95eb7410686ee1ea4b7f583f03b642c30551b79John Reck views.setDrawableParameters(R.id.thumb, true, 0, -1, null, -1); 251df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } else { 25299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck // RemoteViews require a valid bitmap config 25399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Options options = new Options(); 25499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck options.inPreferredConfig = Config.ARGB_8888; 25599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Bitmap thumbnail = null, favicon = null; 25699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck byte[] blob = mBookmarks.getBlob(BOOKMARK_INDEX_THUMBNAIL); 257f95eb7410686ee1ea4b7f583f03b642c30551b79John Reck views.setDrawableParameters(R.id.thumb, true, 255, -1, null, -1); 25899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (blob != null && blob.length > 0) { 25999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck thumbnail = BitmapFactory.decodeByteArray( 26099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck blob, 0, blob.length, options); 26199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck views.setImageViewBitmap(R.id.thumb, thumbnail); 262df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } else { 263df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck views.setImageViewResource(R.id.thumb, 264df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck R.drawable.browser_thumbnail); 265df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 26699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck blob = mBookmarks.getBlob(BOOKMARK_INDEX_FAVICON); 26799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (blob != null && blob.length > 0) { 26899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck favicon = BitmapFactory.decodeByteArray( 26999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck blob, 0, blob.length, options); 27099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck views.setImageViewBitmap(R.id.favicon, favicon); 2711537b774a62042a8b86100e1e6b0988bed70c385John Reck } else { 2721537b774a62042a8b86100e1e6b0988bed70c385John Reck views.setImageViewResource(R.id.favicon, 2731537b774a62042a8b86100e1e6b0988bed70c385John Reck R.drawable.app_web_browser_sm); 2741537b774a62042a8b86100e1e6b0988bed70c385John Reck } 275df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 27699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Intent fillin; 27799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (isFolder) { 27899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck fillin = new Intent(ACTION_CHANGE_FOLDER) 27999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId) 28099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .putExtra(Bookmarks._ID, id); 28199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } else { 28299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (!TextUtils.isEmpty(url)) { 28399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck fillin = new Intent(Intent.ACTION_VIEW) 28499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .addCategory(Intent.CATEGORY_BROWSABLE) 28599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck .setData(Uri.parse(url)); 28699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } else { 28799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck fillin = new Intent(BrowserActivity.ACTION_SHOW_BROWSER); 28899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 28999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck } 29099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck views.setOnClickFillInIntent(R.id.list_item, fillin); 291df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return views; 292df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 293df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 294df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 295df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public int getViewTypeCount() { 29623c61dd30cd2f4a96ab2b01a5878badc79380c6aJohn Reck return 2; 297df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 298df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 299df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 300df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public boolean hasStableIds() { 301df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck return false; 302df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 303df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 304df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 305df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public void onCreate() { 306df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 307df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 308df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 309df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public void onDestroy() { 31099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mBookmarks != null) { 31199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks.close(); 31299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks = null; 31373eb105e5bb53356e171837bd6b13b29661806e3John Reck } 31499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck deleteWidgetState(mContext, mWidgetId); 315df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 316df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 317df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck @Override 318df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck public void onDataSetChanged() { 31999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck long token = Binder.clearCallingIdentity(); 32099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck syncState(); 32199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mRootFolder < 0 || mCurrentFolder < 0) { 3229b8cd1e564984874f2a6f5cc9bdc68cda8aa15ceJohn Reck // This shouldn't happen, but JIC default to the local account 3239b8cd1e564984874f2a6f5cc9bdc68cda8aa15ceJohn Reck mRootFolder = BrowserProvider2.FIXED_ID_ROOT; 32499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mCurrentFolder = mRootFolder; 32599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck saveState(); 3267c11d28643f571669b59ef0d700392c45256ce97John Reck } 32799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck loadBookmarks(); 32899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Binder.restoreCallingIdentity(token); 329df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 330df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 33199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck private void resetBookmarks() { 33299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mBookmarks != null) { 33399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks.close(); 33499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks = null; 3357c11d28643f571669b59ef0d700392c45256ce97John Reck } 3367c11d28643f571669b59ef0d700392c45256ce97John Reck } 3377c11d28643f571669b59ef0d700392c45256ce97John Reck 33899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck void loadBookmarks() { 33999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck resetBookmarks(); 34099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck 34199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Uri uri = ContentUris.withAppendedId( 34299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, 34399c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mCurrentFolder); 34499c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks = mContext.getContentResolver().query(uri, PROJECTION, 34599c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck null, null, null); 34699c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck if (mCurrentFolder != mRootFolder) { 34799c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck uri = ContentUris.withAppendedId( 34899c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck BrowserContract.Bookmarks.CONTENT_URI, 34999c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mCurrentFolder); 35099c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck Cursor c = mContext.getContentResolver().query(uri, PROJECTION, 35199c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck null, null, null); 35299c6d333106cc0fb3c028b5f8d1ff1f5cf726ca2John Reck mBookmarks = new MergeCursor(new Cursor[] { c, mBookmarks }); 3537c11d28643f571669b59ef0d700392c45256ce97John Reck } 3547c11d28643f571669b59ef0d700392c45256ce97John Reck } 355df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck } 356df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck 357df63d2ff2e9881706eef78796d05078d0ffb7f60John Reck} 358