1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.browser; 18 19 import android.app.Activity; 20 import android.app.Fragment; 21 import android.app.LoaderManager; 22 import android.content.ClipData; 23 import android.content.ClipboardManager; 24 import android.content.ContentUris; 25 import android.content.Context; 26 import android.content.CursorLoader; 27 import android.content.Intent; 28 import android.content.Loader; 29 import android.content.SharedPreferences; 30 import android.content.res.Configuration; 31 import android.content.res.Resources; 32 import android.database.Cursor; 33 import android.graphics.Bitmap; 34 import android.graphics.BitmapFactory; 35 import android.net.Uri; 36 import android.os.AsyncTask; 37 import android.os.Bundle; 38 import android.provider.BrowserContract; 39 import android.provider.BrowserContract.Accounts; 40 import android.provider.BrowserContract.ChromeSyncColumns; 41 import android.view.ActionMode; 42 import android.view.ContextMenu; 43 import android.view.ContextMenu.ContextMenuInfo; 44 import android.view.LayoutInflater; 45 import android.view.MenuInflater; 46 import android.view.MenuItem; 47 import android.view.View; 48 import android.view.ViewGroup; 49 import android.widget.ExpandableListView; 50 import android.widget.ExpandableListView.OnChildClickListener; 51 import android.widget.ImageView; 52 import android.widget.LinearLayout; 53 import android.widget.Toast; 54 55 import com.android.browser.BookmarkDragHandler.BookmarkDragController; 56 import com.android.browser.BookmarkDragHandler.BookmarkDragState; 57 import com.android.browser.provider.BrowserProvider2; 58 import com.android.browser.view.BookmarkExpandableView; 59 import com.android.browser.view.BookmarkExpandableView.BookmarkContextMenuInfo; 60 61 import org.json.JSONException; 62 import org.json.JSONObject; 63 64 import java.util.HashMap; 65 66 interface BookmarksPageCallbacks { 67 // Return true if handled 68 boolean onBookmarkSelected(Cursor c, boolean isFolder); 69 // Return true if handled 70 boolean onOpenInNewWindow(String... urls); 71 } 72 73 /** 74 * View showing the user's bookmarks in the browser. 75 */ 76 public class BrowserBookmarksPage extends Fragment implements View.OnCreateContextMenuListener, 77 LoaderManager.LoaderCallbacks<Cursor>, BreadCrumbView.Controller, 78 OnChildClickListener { 79 80 public static class ExtraDragState { 81 public int childPosition; 82 public int groupPosition; 83 } 84 85 static final String LOGTAG = "browser"; 86 87 static final int LOADER_ACCOUNTS = 1; 88 static final int LOADER_BOOKMARKS = 100; 89 90 static final String EXTRA_DISABLE_WINDOW = "disable_new_window"; 91 static final String PREF_GROUP_STATE = "bbp_group_state"; 92 93 static final String ACCOUNT_TYPE = "account_type"; 94 static final String ACCOUNT_NAME = "account_name"; 95 96 public static final int VIEW_THUMBNAILS = 1; 97 public static final int VIEW_LIST = 2; 98 99 BookmarksPageCallbacks mCallbacks; 100 View mRoot; 101 BookmarkExpandableView mGrid; 102 boolean mDisableNewWindow; 103 boolean mEnableContextMenu = true; 104 View mEmptyView; 105 View mHeader; 106 HashMap<Integer, BrowserBookmarksAdapter> mBookmarkAdapters = new HashMap<Integer, BrowserBookmarksAdapter>(); 107 BookmarkDragHandler mDragHandler; 108 JSONObject mState; 109 110 @Override 111 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 112 if (id == LOADER_ACCOUNTS) { 113 return new AccountsLoader(getActivity()); 114 } else if (id >= LOADER_BOOKMARKS) { 115 String accountType = args.getString(ACCOUNT_TYPE); 116 String accountName = args.getString(ACCOUNT_NAME); 117 BookmarksLoader bl = new BookmarksLoader(getActivity(), 118 accountType, accountName); 119 return bl; 120 } else { 121 throw new UnsupportedOperationException("Unknown loader id " + id); 122 } 123 } 124 125 @Override 126 public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 127 if (loader.getId() == LOADER_ACCOUNTS) { 128 LoaderManager lm = getLoaderManager(); 129 int id = LOADER_BOOKMARKS; 130 while (cursor.moveToNext()) { 131 String accountName = cursor.getString(0); 132 String accountType = cursor.getString(1); 133 Bundle args = new Bundle(); 134 args.putString(ACCOUNT_NAME, accountName); 135 args.putString(ACCOUNT_TYPE, accountType); 136 BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter( 137 getActivity(), VIEW_THUMBNAILS); 138 mBookmarkAdapters.put(id, adapter); 139 boolean expand = true; 140 try { 141 expand = mState.getBoolean(accountName != null ? accountName 142 : BookmarkExpandableView.LOCAL_ACCOUNT_NAME); 143 } catch (JSONException e) {} // no state for accountName 144 mGrid.addAccount(accountName, adapter, expand); 145 lm.restartLoader(id, args, this); 146 id++; 147 } 148 // TODO: Figure out what a reload of these means 149 // Currently, a reload is triggered whenever bookmarks change 150 // This is less than ideal 151 // It also causes UI flickering as a new adapter is created 152 // instead of re-using an existing one when the account_name is the 153 // same. 154 // For now, this is a one-shot load 155 getLoaderManager().destroyLoader(LOADER_ACCOUNTS); 156 } else if (loader.getId() >= LOADER_BOOKMARKS) { 157 BrowserBookmarksAdapter adapter = mBookmarkAdapters.get(loader.getId()); 158 adapter.changeCursor(cursor); 159 } 160 } 161 162 @Override 163 public void onLoaderReset(Loader<Cursor> loader) { 164 } 165 166 @Override 167 public boolean onContextItemSelected(MenuItem item) { 168 if (!(item.getMenuInfo() instanceof BookmarkContextMenuInfo)) { 169 return false; 170 } 171 BookmarkContextMenuInfo i = (BookmarkContextMenuInfo) item.getMenuInfo(); 172 // If we have no menu info, we can't tell which item was selected. 173 if (i == null) { 174 return false; 175 } 176 177 if (handleContextItem(item.getItemId(), i.groupPosition, i.childPosition)) { 178 return true; 179 } 180 return super.onContextItemSelected(item); 181 } 182 183 public boolean handleContextItem(int itemId, int groupPosition, 184 int childPosition) { 185 final Activity activity = getActivity(); 186 BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition); 187 188 switch (itemId) { 189 case R.id.open_context_menu_id: 190 loadUrl(adapter, childPosition); 191 break; 192 case R.id.edit_context_menu_id: 193 editBookmark(adapter, childPosition); 194 break; 195 case R.id.shortcut_context_menu_id: 196 Cursor c = adapter.getItem(childPosition); 197 activity.sendBroadcast(createShortcutIntent(getActivity(), c)); 198 break; 199 case R.id.delete_context_menu_id: 200 displayRemoveBookmarkDialog(adapter, childPosition); 201 break; 202 case R.id.new_window_context_menu_id: 203 openInNewWindow(adapter, childPosition); 204 break; 205 case R.id.share_link_context_menu_id: { 206 Cursor cursor = adapter.getItem(childPosition); 207 Controller.sharePage(activity, 208 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE), 209 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL), 210 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON), 211 getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_THUMBNAIL)); 212 break; 213 } 214 case R.id.copy_url_context_menu_id: 215 copy(getUrl(adapter, childPosition)); 216 break; 217 case R.id.homepage_context_menu_id: { 218 BrowserSettings.getInstance().setHomePage(getUrl(adapter, childPosition)); 219 Toast.makeText(activity, R.string.homepage_set, Toast.LENGTH_LONG).show(); 220 break; 221 } 222 // Only for the Most visited page 223 case R.id.save_to_bookmarks_menu_id: { 224 Cursor cursor = adapter.getItem(childPosition); 225 String name = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 226 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 227 // If the site is bookmarked, the item becomes remove from 228 // bookmarks. 229 Bookmarks.removeFromBookmarks(activity, activity.getContentResolver(), url, name); 230 break; 231 } 232 default: 233 return false; 234 } 235 return true; 236 } 237 238 static Bitmap getBitmap(Cursor cursor, int columnIndex) { 239 byte[] data = cursor.getBlob(columnIndex); 240 if (data == null) { 241 return null; 242 } 243 return BitmapFactory.decodeByteArray(data, 0, data.length); 244 } 245 246 private MenuItem.OnMenuItemClickListener mContextItemClickListener = 247 new MenuItem.OnMenuItemClickListener() { 248 @Override 249 public boolean onMenuItemClick(MenuItem item) { 250 return onContextItemSelected(item); 251 } 252 }; 253 254 @Override 255 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 256 BookmarkContextMenuInfo info = (BookmarkContextMenuInfo) menuInfo; 257 BrowserBookmarksAdapter adapter = getChildAdapter(info.groupPosition); 258 Cursor cursor = adapter.getItem(info.childPosition); 259 if (!canEdit(cursor)) { 260 return; 261 } 262 boolean isFolder 263 = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0; 264 265 final Activity activity = getActivity(); 266 MenuInflater inflater = activity.getMenuInflater(); 267 inflater.inflate(R.menu.bookmarkscontext, menu); 268 if (isFolder) { 269 menu.setGroupVisible(R.id.FOLDER_CONTEXT_MENU, true); 270 } else { 271 menu.setGroupVisible(R.id.BOOKMARK_CONTEXT_MENU, true); 272 if (mDisableNewWindow) { 273 menu.findItem(R.id.new_window_context_menu_id).setVisible(false); 274 } 275 } 276 BookmarkItem header = new BookmarkItem(activity); 277 header.setEnableScrolling(true); 278 populateBookmarkItem(cursor, header, isFolder); 279 menu.setHeaderView(header); 280 281 int count = menu.size(); 282 for (int i = 0; i < count; i++) { 283 menu.getItem(i).setOnMenuItemClickListener(mContextItemClickListener); 284 } 285 } 286 287 boolean canEdit(Cursor c) { 288 String unique = c.getString(BookmarksLoader.COLUMN_INDEX_SERVER_UNIQUE); 289 return !ChromeSyncColumns.FOLDER_NAME_OTHER_BOOKMARKS.equals(unique); 290 } 291 292 private void populateBookmarkItem(Cursor cursor, BookmarkItem item, boolean isFolder) { 293 item.setName(cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)); 294 if (isFolder) { 295 item.setUrl(null); 296 Bitmap bitmap = 297 BitmapFactory.decodeResource(getResources(), R.drawable.ic_folder_holo_dark); 298 item.setFavicon(bitmap); 299 new LookupBookmarkCount(getActivity(), item) 300 .execute(cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID)); 301 } else { 302 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 303 item.setUrl(url); 304 Bitmap bitmap = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON); 305 item.setFavicon(bitmap); 306 } 307 } 308 309 /** 310 * Create a new BrowserBookmarksPage. 311 */ 312 @Override 313 public void onCreate(Bundle icicle) { 314 super.onCreate(icicle); 315 SharedPreferences prefs = BrowserSettings.getInstance().getPreferences(); 316 try { 317 mState = new JSONObject(prefs.getString(PREF_GROUP_STATE, "{}")); 318 } catch (JSONException e) { 319 // Parse failed, clear preference and start with empty state 320 prefs.edit().remove(PREF_GROUP_STATE).apply(); 321 mState = new JSONObject(); 322 } 323 Bundle args = getArguments(); 324 mDisableNewWindow = args == null ? false : args.getBoolean(EXTRA_DISABLE_WINDOW, false); 325 setHasOptionsMenu(true); 326 if (mCallbacks == null && getActivity() instanceof CombinedBookmarksCallbacks) { 327 mCallbacks = new CombinedBookmarksCallbackWrapper( 328 (CombinedBookmarksCallbacks) getActivity()); 329 } 330 } 331 332 @Override 333 public void onPause() { 334 super.onPause(); 335 try { 336 mState = mGrid.saveGroupState(); 337 // Save state 338 SharedPreferences prefs = BrowserSettings.getInstance().getPreferences(); 339 prefs.edit() 340 .putString(PREF_GROUP_STATE, mState.toString()) 341 .apply(); 342 } catch (JSONException e) { 343 // Not critical, ignore 344 } 345 } 346 347 private static class CombinedBookmarksCallbackWrapper 348 implements BookmarksPageCallbacks { 349 350 private CombinedBookmarksCallbacks mCombinedCallback; 351 352 private CombinedBookmarksCallbackWrapper(CombinedBookmarksCallbacks cb) { 353 mCombinedCallback = cb; 354 } 355 356 @Override 357 public boolean onOpenInNewWindow(String... urls) { 358 mCombinedCallback.openInNewTab(urls); 359 return true; 360 } 361 362 @Override 363 public boolean onBookmarkSelected(Cursor c, boolean isFolder) { 364 if (isFolder) { 365 return false; 366 } 367 mCombinedCallback.openUrl(BrowserBookmarksPage.getUrl(c)); 368 return true; 369 } 370 }; 371 372 @Override 373 public View onCreateView(LayoutInflater inflater, ViewGroup container, 374 Bundle savedInstanceState) { 375 mRoot = inflater.inflate(R.layout.bookmarks, container, false); 376 mEmptyView = mRoot.findViewById(android.R.id.empty); 377 378 mGrid = (BookmarkExpandableView) mRoot.findViewById(R.id.grid); 379 mGrid.setOnChildClickListener(this); 380 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail); 381 mGrid.setBreadcrumbController(this); 382 setEnableContextMenu(mEnableContextMenu); 383 mDragHandler = new BookmarkDragHandler(getActivity(), mDragController, 384 mGrid.getDragAdapter()); 385 386 // Start the loaders 387 LoaderManager lm = getLoaderManager(); 388 lm.restartLoader(LOADER_ACCOUNTS, null, this); 389 390 return mRoot; 391 } 392 393 @Override 394 public void onDestroyView() { 395 super.onDestroyView(); 396 mGrid.setBreadcrumbController(null); 397 mGrid.clearAccounts(); 398 LoaderManager lm = getLoaderManager(); 399 lm.destroyLoader(LOADER_ACCOUNTS); 400 for (int id : mBookmarkAdapters.keySet()) { 401 lm.destroyLoader(id); 402 } 403 mBookmarkAdapters.clear(); 404 } 405 406 private BrowserBookmarksAdapter getChildAdapter(int groupPosition) { 407 return mGrid.getChildAdapter(groupPosition); 408 } 409 410 private BreadCrumbView getBreadCrumbs(int groupPosition) { 411 return mGrid.getBreadCrumbs(groupPosition); 412 } 413 414 @Override 415 public boolean onChildClick(ExpandableListView parent, View v, 416 int groupPosition, int childPosition, long id) { 417 BrowserBookmarksAdapter adapter = getChildAdapter(groupPosition); 418 Cursor cursor = adapter.getItem(childPosition); 419 boolean isFolder = cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0; 420 if (mCallbacks != null && 421 mCallbacks.onBookmarkSelected(cursor, isFolder)) { 422 return true; 423 } 424 425 if (isFolder) { 426 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 427 Uri uri = ContentUris.withAppendedId( 428 BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER, id); 429 BreadCrumbView crumbs = getBreadCrumbs(groupPosition); 430 if (crumbs != null) { 431 // update crumbs 432 crumbs.pushView(title, uri); 433 crumbs.setVisibility(View.VISIBLE); 434 } 435 loadFolder(groupPosition, uri); 436 } 437 return true; 438 } 439 440 /* package */ static Intent createShortcutIntent(Context context, Cursor cursor) { 441 String url = cursor.getString(BookmarksLoader.COLUMN_INDEX_URL); 442 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 443 Bitmap touchIcon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_TOUCH_ICON); 444 Bitmap favicon = getBitmap(cursor, BookmarksLoader.COLUMN_INDEX_FAVICON); 445 return BookmarkUtils.createAddToHomeIntent(context, url, title, touchIcon, favicon); 446 } 447 448 private void loadUrl(BrowserBookmarksAdapter adapter, int position) { 449 if (mCallbacks != null && adapter != null) { 450 mCallbacks.onBookmarkSelected(adapter.getItem(position), false); 451 } 452 } 453 454 private void openInNewWindow(BrowserBookmarksAdapter adapter, int position) { 455 if (mCallbacks != null) { 456 Cursor c = adapter.getItem(position); 457 boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1; 458 if (isFolder) { 459 long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID); 460 new OpenAllInTabsTask(id).execute(); 461 } else { 462 mCallbacks.onOpenInNewWindow(BrowserBookmarksPage.getUrl(c)); 463 } 464 } 465 } 466 467 class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> { 468 long mFolderId; 469 public OpenAllInTabsTask(long id) { 470 mFolderId = id; 471 } 472 473 @Override 474 protected Cursor doInBackground(Void... params) { 475 Context c = getActivity(); 476 if (c == null) return null; 477 return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c), 478 BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?", 479 new String[] { Long.toString(mFolderId) }, null); 480 } 481 482 @Override 483 protected void onPostExecute(Cursor result) { 484 if (mCallbacks != null && result.getCount() > 0) { 485 String[] urls = new String[result.getCount()]; 486 int i = 0; 487 while (result.moveToNext()) { 488 urls[i++] = BrowserBookmarksPage.getUrl(result); 489 } 490 mCallbacks.onOpenInNewWindow(urls); 491 } 492 } 493 494 } 495 496 private void editBookmark(BrowserBookmarksAdapter adapter, int position) { 497 Intent intent = new Intent(getActivity(), AddBookmarkPage.class); 498 Cursor cursor = adapter.getItem(position); 499 Bundle item = new Bundle(); 500 item.putString(BrowserContract.Bookmarks.TITLE, 501 cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE)); 502 item.putString(BrowserContract.Bookmarks.URL, 503 cursor.getString(BookmarksLoader.COLUMN_INDEX_URL)); 504 byte[] data = cursor.getBlob(BookmarksLoader.COLUMN_INDEX_FAVICON); 505 if (data != null) { 506 item.putParcelable(BrowserContract.Bookmarks.FAVICON, 507 BitmapFactory.decodeByteArray(data, 0, data.length)); 508 } 509 item.putLong(BrowserContract.Bookmarks._ID, 510 cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID)); 511 item.putLong(BrowserContract.Bookmarks.PARENT, 512 cursor.getLong(BookmarksLoader.COLUMN_INDEX_PARENT)); 513 intent.putExtra(AddBookmarkPage.EXTRA_EDIT_BOOKMARK, item); 514 intent.putExtra(AddBookmarkPage.EXTRA_IS_FOLDER, 515 cursor.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1); 516 startActivity(intent); 517 } 518 519 private void displayRemoveBookmarkDialog(BrowserBookmarksAdapter adapter, 520 int position) { 521 // Put up a dialog asking if the user really wants to 522 // delete the bookmark 523 Cursor cursor = adapter.getItem(position); 524 long id = cursor.getLong(BookmarksLoader.COLUMN_INDEX_ID); 525 String title = cursor.getString(BookmarksLoader.COLUMN_INDEX_TITLE); 526 Context context = getActivity(); 527 BookmarkUtils.displayRemoveBookmarkDialog(id, title, context, null); 528 } 529 530 private String getUrl(BrowserBookmarksAdapter adapter, int position) { 531 return getUrl(adapter.getItem(position)); 532 } 533 534 /* package */ static String getUrl(Cursor c) { 535 return c.getString(BookmarksLoader.COLUMN_INDEX_URL); 536 } 537 538 private void copy(CharSequence text) { 539 ClipboardManager cm = (ClipboardManager) getActivity().getSystemService( 540 Context.CLIPBOARD_SERVICE); 541 cm.setPrimaryClip(ClipData.newRawUri(null, Uri.parse(text.toString()))); 542 } 543 544 @Override 545 public void onConfigurationChanged(Configuration newConfig) { 546 super.onConfigurationChanged(newConfig); 547 Resources res = getActivity().getResources(); 548 mGrid.setColumnWidthFromLayout(R.layout.bookmark_thumbnail); 549 int paddingTop = (int) res.getDimension(R.dimen.combo_paddingTop); 550 mRoot.setPadding(0, paddingTop, 0, 0); 551 getActivity().invalidateOptionsMenu(); 552 } 553 554 /** 555 * BreadCrumb controller callback 556 */ 557 @Override 558 public void onTop(BreadCrumbView view, int level, Object data) { 559 int groupPosition = (Integer) view.getTag(R.id.group_position); 560 Uri uri = (Uri) data; 561 if (uri == null) { 562 // top level 563 uri = BrowserContract.Bookmarks.CONTENT_URI_DEFAULT_FOLDER; 564 } 565 loadFolder(groupPosition, uri); 566 if (level <= 1) { 567 view.setVisibility(View.GONE); 568 } else { 569 view.setVisibility(View.VISIBLE); 570 } 571 } 572 573 /** 574 * @param uri 575 */ 576 private void loadFolder(int groupPosition, Uri uri) { 577 LoaderManager manager = getLoaderManager(); 578 // This assumes groups are ordered the same as loaders 579 BookmarksLoader loader = (BookmarksLoader) ((Loader<?>) 580 manager.getLoader(LOADER_BOOKMARKS + groupPosition)); 581 loader.setUri(uri); 582 loader.forceLoad(); 583 } 584 585 public void setCallbackListener(BookmarksPageCallbacks callbackListener) { 586 mCallbacks = callbackListener; 587 } 588 589 public void setEnableContextMenu(boolean enable) { 590 mEnableContextMenu = enable; 591 if (mGrid != null) { 592 if (mEnableContextMenu) { 593 registerForContextMenu(mGrid); 594 } else { 595 unregisterForContextMenu(mGrid); 596 mGrid.setLongClickable(false); 597 } 598 } 599 } 600 601 private BookmarkDragController mDragController = new BookmarkDragController() { 602 603 @Override 604 public boolean startDrag(Cursor item) { 605 return canEdit(item); 606 } 607 608 @Override 609 public ViewGroup getActionModeView(ActionMode mode, 610 BookmarkDragState state) { 611 LayoutInflater inflater = LayoutInflater.from(getActivity()); 612 LinearLayout view = (LinearLayout) inflater.inflate( 613 R.layout.bookmarks_drag_actionmode, null); 614 view.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE); 615 ExtraDragState extraState = (ExtraDragState) state.extraState; 616 BrowserBookmarksAdapter adapter = getChildAdapter(extraState.groupPosition); 617 Cursor c = adapter.getItem(extraState.childPosition); 618 boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) != 0; 619 if (isFolder) { 620 view.findViewById(R.id.open_context_menu_id).setVisibility(View.GONE); 621 ImageView iv = (ImageView) view.findViewById( 622 R.id.new_window_context_menu_id); 623 iv.setImageResource(R.drawable.ic_windows_holo_dark); 624 } 625 return view; 626 } 627 628 @Override 629 public void actionItemClicked(View v, BookmarkDragState state) { 630 if (v.getId() == R.id.info) { 631 mGrid.showContextMenuForState(state); 632 } else { 633 ExtraDragState extraState = (ExtraDragState) state.extraState; 634 handleContextItem(v.getId(), extraState.groupPosition, 635 extraState.childPosition); 636 } 637 } 638 }; 639 640 private static class LookupBookmarkCount extends AsyncTask<Long, Void, Integer> { 641 Context mContext; 642 BookmarkItem mHeader; 643 644 public LookupBookmarkCount(Context context, BookmarkItem header) { 645 mContext = context.getApplicationContext(); 646 mHeader = header; 647 } 648 649 @Override 650 protected Integer doInBackground(Long... params) { 651 if (params.length != 1) { 652 throw new IllegalArgumentException("Missing folder id!"); 653 } 654 Uri uri = BookmarkUtils.getBookmarksUri(mContext); 655 Cursor c = mContext.getContentResolver().query(uri, 656 null, BrowserContract.Bookmarks.PARENT + "=?", 657 new String[] {params[0].toString()}, null); 658 return c.getCount(); 659 } 660 661 @Override 662 protected void onPostExecute(Integer result) { 663 if (result > 0) { 664 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_bookmarkcount, 665 result)); 666 } else if (result == 0) { 667 mHeader.setUrl(mContext.getString(R.string.contextheader_folder_empty)); 668 } 669 } 670 } 671 672 static class AccountsLoader extends CursorLoader { 673 674 static String[] ACCOUNTS_PROJECTION = new String[] { 675 Accounts.ACCOUNT_NAME, 676 Accounts.ACCOUNT_TYPE 677 }; 678 679 public AccountsLoader(Context context) { 680 super(context, Accounts.CONTENT_URI 681 .buildUpon() 682 .appendQueryParameter(BrowserProvider2.PARAM_ALLOW_EMPTY_ACCOUNTS, "false") 683 .build(), 684 ACCOUNTS_PROJECTION, null, null, null); 685 } 686 687 } 688 } 689