+ // `MultiChoiceModeListener` handles long clicks.
+ bookmarksListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
+ // `editBookmarkMenuItem` is used in `onCreateActionMode()` and `onItemCheckedStateChanged`.
+ MenuItem editBookmarkMenuItem;
+
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ // Inflate the menu for the contextual app bar and set the title.
+ getMenuInflater().inflate(R.menu.bookmarks_context_menu, menu);
+ mode.setTitle(R.string.bookmarks);
+
+ // Get a handle for `R.id.edit_bookmark`.
+ editBookmarkMenuItem = menu.findItem(R.id.edit_bookmark);
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
+ // Get an array of the selected bookmarks.
+ long[] selectedBookmarksLongArray = bookmarksListView.getCheckedItemIds();
+
+ // Calculate the number of selected bookmarks.
+ int numberOfSelectedBookmarks = selectedBookmarksLongArray.length;
+
+ // List the number of selected bookmarks in the subtitle.
+ mode.setSubtitle(numberOfSelectedBookmarks + " " + getString(R.string.selected));
+
+ // Show the `Edit` option only if 1 bookmark is selected.
+ if (numberOfSelectedBookmarks == 1) {
+ editBookmarkMenuItem.setVisible(true);
+ } else {
+ editBookmarkMenuItem.setVisible(false);
+ }
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ int menuItemId = item.getItemId();
+
+ switch (menuItemId) {
+ case R.id.edit_bookmark:
+ // Show the `EditBookmark` `AlertDialog` and name the instance `@string/edit_bookmark`.
+ DialogFragment editBookmarkDialog = new EditBookmark();
+ editBookmarkDialog.show(getFragmentManager(), "@string/edit_bookmark");
+
+ contextualActionMode = mode;
+ break;
+
+ case R.id.delete_bookmark:
+ // Get an array of the selected rows.
+ final long[] selectedBookmarksLongArray = bookmarksListView.getCheckedItemIds();
+
+ String snackbarMessage;
+
+ // Determine how many items are in the array and prepare an appropriate Snackbar message.
+ if (selectedBookmarksLongArray.length == 1) {
+ snackbarMessage = getString(R.string.one_bookmark_deleted);
+ } else {
+ snackbarMessage = selectedBookmarksLongArray.length + " " + getString(R.string.bookmarks_deleted);
+ }
+
+ updateBookmarksListViewExcept(selectedBookmarksLongArray);
+
+ // Show a SnackBar.
+ Snackbar.make(findViewById(R.id.bookmarks_coordinatorlayout), snackbarMessage, Snackbar.LENGTH_LONG)
+ .setAction(R.string.undo, new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ // Do nothing because everything will be handled by `onDismissed()` below.
+ }
+ })
+ .setCallback(new Snackbar.Callback() {
+ @Override
+ public void onDismissed(Snackbar snackbar, int event) {
+ switch (event) {
+ // The user pushed the "Undo" button.
+ case Snackbar.Callback.DISMISS_EVENT_ACTION:
+ // Refresh the ListView to show the rows again.
+ updateBookmarksListView();
+
+ break;
+
+ // The Snackbar was dismissed without the "Undo" button being pushed.
+ default:
+ // Delete each selected row.
+ for (long databaseIdLong : selectedBookmarksLongArray) {
+ // Convert `databaseIdLong` to an int.
+ int databaseIdInt = (int) databaseIdLong;
+
+ // Delete the database row.
+ bookmarksDatabaseHandler.deleteBookmark(databaseIdInt);
+ }
+ break;
+ }
+ }
+ })
+ .show();
+
+ // Close the contextual app bar.
+ mode.finish();
+ break;
+ }
+ // Consume the click.
+ return true;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+
+ }
+ });
+