/*
- * Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
*
import android.annotation.SuppressLint;
import android.app.Activity;
+import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.RadioButton;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar; // The AndroidX toolbar must be used until the minimum API is >= 21.
+import androidx.appcompat.widget.Toolbar;
import androidx.core.app.NavUtils;
import androidx.fragment.app.DialogFragment;
import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper;
import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
public class BookmarksActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener, EditBookmarkDialog.EditBookmarkListener,
EditBookmarkFolderDialog.EditBookmarkFolderListener, MoveToFolderDialog.MoveToFolderListener {
public static boolean restartFromBookmarksDatabaseViewActivity;
+ // Define the saved instance state constants.
+ private final String CHECKED_BOOKMARKS_ARRAY_LIST = "checked_bookmarks_array_list";
+
+ // Define the class menu items.
+ private MenuItem moveBookmarkUpMenuItem;
+ private MenuItem moveBookmarkDownMenuItem;
+
// `bookmarksDatabaseHelper` is used in `onCreate()`, `onOptionsItemSelected()`, `onBackPressed()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveBookmark()`, `onSaveBookmarkFolder()`,
// `onMoveToFolder()`, `deleteBookmarkFolderContents()`, `loadFolder()`, and `onDestroy()`.
private BookmarksDatabaseHelper bookmarksDatabaseHelper;
// `oldFolderName` is used in `onCreate()` and `onSaveBookmarkFolder()`.
private String oldFolderNameString;
- // `moveBookmarkUpMenuItem` is used in `onCreate()` and `updateMoveIcons()`.
- private MenuItem moveBookmarkUpMenuItem;
-
- // `moveBookmarkDownMenuItem` is used in `onCreate()` and `updateMoveIcons()`.
- private MenuItem moveBookmarkDownMenuItem;
-
// `bookmarksDeletedSnackbar` is used in `onCreate()`, `onOptionsItemSelected()`, and `onBackPressed()`.
private Snackbar bookmarksDeletedSnackbar;
// Get a handle for the shared preferences.
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
- // Get the theme and screenshot preferences.
- boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
+ // Get the screenshot preference.
boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
// Disable screenshots if not allowed.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
- // Set the activity theme.
- if (darkTheme) {
- setTheme(R.style.PrivacyBrowserDark_SecondaryActivity);
- } else {
- setTheme(R.style.PrivacyBrowserLight_SecondaryActivity);
- }
+ // Set the theme.
+ setTheme(R.style.PrivacyBrowser);
// Run the default commands.
super.onCreate(savedInstanceState);
// Get the favorite icon byte array.
favoriteIconByteArray = launchingIntent.getByteArrayExtra("favorite_icon_byte_array");
+ // Remove the incorrect lint warning that the favorite icon byte array might be null.
+ assert favoriteIconByteArray != null;
+
// Convert the favorite icon byte array to a bitmap.
Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length);
// Update the list view.
bookmarksCursorAdapter.changeCursor(bookmarksCursor);
- // Show a Snackbar with the number of deleted bookmarks.
+ // Create a Snackbar with the number of deleted bookmarks.
bookmarksDeletedSnackbar = Snackbar.make(findViewById(R.id.bookmarks_coordinatorlayout), getString(R.string.bookmarks_deleted) + " " + selectedBookmarksIdsLongArray.length,
Snackbar.LENGTH_LONG)
.setAction(R.string.undo, view -> {
@SuppressLint("SwitchIntDef") // Ignore the lint warning about not handling the other possible events as they are covered by `default:`.
@Override
public void onDismissed(Snackbar snackbar, int event) {
- switch (event) {
- // The user pushed the `Undo` button.
- case Snackbar.Callback.DISMISS_EVENT_ACTION:
- // Update the bookmarks cursor with the current contents of the bookmarks database, including the "deleted" bookmarks.
- bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder);
-
- // Update the list view.
- bookmarksCursorAdapter.changeCursor(bookmarksCursor);
-
- // Re-select the previously selected bookmarks.
- for (int i = 0; i < selectedBookmarksPositionsSparseBooleanArray.size(); i++) {
- bookmarksListView.setItemChecked(selectedBookmarksPositionsSparseBooleanArray.keyAt(i), true);
- }
- break;
-
- // The Snackbar was dismissed without the `Undo` button being pushed.
- default:
- // Delete each selected bookmark.
- for (long databaseIdLong : selectedBookmarksIdsLongArray) {
- // Convert `databaseIdLong` to an int.
- int databaseIdInt = (int) databaseIdLong;
-
- // Delete the contents of the folder if the selected bookmark is a folder.
- if (bookmarksDatabaseHelper.isFolder(databaseIdInt)) {
- deleteBookmarkFolderContents(databaseIdInt);
- }
-
- // Delete the selected bookmark.
- bookmarksDatabaseHelper.deleteBookmark(databaseIdInt);
+ if (event == Snackbar.Callback.DISMISS_EVENT_ACTION) { // The user pushed the undo button.
+ // Update the bookmarks cursor with the current contents of the bookmarks database, including the "deleted" bookmarks.
+ bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder);
+
+ // Update the list view.
+ bookmarksCursorAdapter.changeCursor(bookmarksCursor);
+
+ // Re-select the previously selected bookmarks.
+ for (int i = 0; i < selectedBookmarksPositionsSparseBooleanArray.size(); i++) {
+ bookmarksListView.setItemChecked(selectedBookmarksPositionsSparseBooleanArray.keyAt(i), true);
+ }
+ } else { // The snackbar was dismissed without the undo button being pushed.
+ // Delete each selected bookmark.
+ for (long databaseIdLong : selectedBookmarksIdsLongArray) {
+ // Convert `databaseIdLong` to an int.
+ int databaseIdInt = (int) databaseIdLong;
+
+ // Delete the contents of the folder if the selected bookmark is a folder.
+ if (bookmarksDatabaseHelper.isFolder(databaseIdInt)) {
+ deleteBookmarkFolderContents(databaseIdInt);
}
- // Update the display order.
- for (int i = 0; i < bookmarksListView.getCount(); i++) {
- // Get the database ID for the current bookmark.
- int currentBookmarkDatabaseId = (int) bookmarksListView.getItemIdAtPosition(i);
+ // Delete the selected bookmark.
+ bookmarksDatabaseHelper.deleteBookmark(databaseIdInt);
+ }
+
+ // Update the display order.
+ for (int i = 0; i < bookmarksListView.getCount(); i++) {
+ // Get the database ID for the current bookmark.
+ int currentBookmarkDatabaseId = (int) bookmarksListView.getItemIdAtPosition(i);
- // Move `bookmarksCursor` to the current bookmark position.
- bookmarksCursor.moveToPosition(i);
+ // Move `bookmarksCursor` to the current bookmark position.
+ bookmarksCursor.moveToPosition(i);
- // Update the display order only if it is not correct in the database.
- if (bookmarksCursor.getInt(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)) != i) {
- bookmarksDatabaseHelper.updateDisplayOrder(currentBookmarkDatabaseId, i);
- }
+ // Update the display order only if it is not correct in the database.
+ if (bookmarksCursor.getInt(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)) != i) {
+ bookmarksDatabaseHelper.updateDisplayOrder(currentBookmarkDatabaseId, i);
}
+ }
}
// Reset the deleting bookmarks flag.
// Set the create new bookmark FAB to display the `AlertDialog`.
createBookmarkFab.setOnClickListener(view -> {
+ // Remove the incorrect lint warning below.
+ assert currentUrl != null;
+ assert currentTitle != null;
+
// Instantiate the create bookmark dialog.
DialogFragment createBookmarkDialog = CreateBookmarkDialog.createBookmark(currentUrl, currentTitle, favoriteIconBitmap);
// Display the create bookmark dialog.
createBookmarkDialog.show(getSupportFragmentManager(), getResources().getString(R.string.create_bookmark));
});
+
+ // Restore the state if the app has been restarted.
+ if (savedInstanceState != null) {
+ // Update the bookmarks list view after it has loaded.
+ bookmarksListView.post(() -> {
+ // Get the checked bookmarks array list.
+ ArrayList<Integer> checkedBookmarksArrayList = savedInstanceState.getIntegerArrayList(CHECKED_BOOKMARKS_ARRAY_LIST);
+
+ // Check each previously checked bookmark in the list view. When the minimum API >= 24 a `forEach()` command can be used instead.
+ if (checkedBookmarksArrayList != null) {
+ for (int i = 0; i < checkedBookmarksArrayList.size(); i++) {
+ bookmarksListView.setItemChecked(checkedBookmarksArrayList.get(i), true);
+ }
+ }
+ });
+ }
}
@Override
}
}
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
+ // Run the default commands.
+ super.onSaveInstanceState(savedInstanceState);
+
+ // Get the array of the checked items.
+ SparseBooleanArray checkedBookmarksSparseBooleanArray = bookmarksListView.getCheckedItemPositions();
+
+ // Create a checked items array list.
+ ArrayList<Integer> checkedBookmarksArrayList = new ArrayList<>();
+
+ // Add each checked bookmark position to the array list.
+ for (int i = 0; i < checkedBookmarksSparseBooleanArray.size(); i++) {
+ // Check to see if the bookmark is currently checked. Bookmarks that have previously been checked but currently aren't will be populated in the sparse boolean array, but will return false.
+ if (checkedBookmarksSparseBooleanArray.valueAt(i)) {
+ // Add the bookmark position to the checked bookmarks array list.
+ checkedBookmarksArrayList.add(checkedBookmarksSparseBooleanArray.keyAt(i));
+ }
+ }
+
+ // Store the checked items array list in the saved instance state.
+ savedInstanceState.putIntegerArrayList(CHECKED_BOOKMARKS_ARRAY_LIST, checkedBookmarksArrayList);
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu.
@Override
public void onCreateBookmark(DialogFragment dialogFragment, Bitmap favoriteIconBitmap) {
+ // Get the alert dialog from the fragment.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
// Get the views from the dialog fragment.
- EditText createBookmarkNameEditText = dialogFragment.getDialog().findViewById(R.id.create_bookmark_name_edittext);
- EditText createBookmarkUrlEditText = dialogFragment.getDialog().findViewById(R.id.create_bookmark_url_edittext);
+ EditText createBookmarkNameEditText = dialog.findViewById(R.id.create_bookmark_name_edittext);
+ EditText createBookmarkUrlEditText = dialog.findViewById(R.id.create_bookmark_url_edittext);
// Extract the strings from the edit texts.
String bookmarkNameString = createBookmarkNameEditText.getText().toString();
}
@Override
- public void onCreateBookmarkFolder(DialogFragment dialogFragment, Bitmap favoriteIconBitmap) {
+ public void onCreateBookmarkFolder(DialogFragment dialogFragment, @NonNull Bitmap favoriteIconBitmap) {
+ // Get the dialog from the dialog fragment.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
// Get handles for the views in the dialog fragment.
- EditText createFolderNameEditText = dialogFragment.getDialog().findViewById(R.id.create_folder_name_edittext);
- RadioButton defaultFolderIconRadioButton = dialogFragment.getDialog().findViewById(R.id.create_folder_default_icon_radiobutton);
- ImageView folderIconImageView = dialogFragment.getDialog().findViewById(R.id.create_folder_default_icon);
+ EditText createFolderNameEditText = dialog.findViewById(R.id.create_folder_name_edittext);
+ RadioButton defaultFolderIconRadioButton = dialog.findViewById(R.id.create_folder_default_icon_radiobutton);
+ ImageView folderIconImageView = dialog.findViewById(R.id.create_folder_default_icon);
// Get new folder name string.
String folderNameString = createFolderNameEditText.getText().toString();
}
@Override
- public void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, Bitmap favoriteIconBitmap) {
+ public void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, @NonNull Bitmap favoriteIconBitmap) {
+ // Get the dialog from the dialog fragment.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
// Get handles for the views from `dialogFragment`.
- EditText editBookmarkNameEditText = dialogFragment.getDialog().findViewById(R.id.edit_bookmark_name_edittext);
- EditText editBookmarkUrlEditText = dialogFragment.getDialog().findViewById(R.id.edit_bookmark_url_edittext);
- RadioButton currentBookmarkIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_bookmark_current_icon_radiobutton);
+ EditText editBookmarkNameEditText = dialog.findViewById(R.id.edit_bookmark_name_edittext);
+ EditText editBookmarkUrlEditText = dialog.findViewById(R.id.edit_bookmark_url_edittext);
+ RadioButton currentBookmarkIconRadioButton = dialog.findViewById(R.id.edit_bookmark_current_icon_radiobutton);
// Store the bookmark strings.
String bookmarkNameString = editBookmarkNameEditText.getText().toString();
@Override
public void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId, Bitmap favoriteIconBitmap) {
+ // Get the dialog from the dialog fragment.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
// Get handles for the views from `dialogFragment`.
- RadioButton currentFolderIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_folder_current_icon_radiobutton);
- RadioButton defaultFolderIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_folder_default_icon_radiobutton);
- ImageView defaultFolderIconImageView = dialogFragment.getDialog().findViewById(R.id.edit_folder_default_icon_imageview);
- EditText editFolderNameEditText = dialogFragment.getDialog().findViewById(R.id.edit_folder_name_edittext);
+ RadioButton currentFolderIconRadioButton = dialog.findViewById(R.id.edit_folder_current_icon_radiobutton);
+ RadioButton defaultFolderIconRadioButton = dialog.findViewById(R.id.edit_folder_default_icon_radiobutton);
+ ImageView defaultFolderIconImageView = dialog.findViewById(R.id.edit_folder_default_icon_imageview);
+ EditText editFolderNameEditText = dialog.findViewById(R.id.edit_folder_name_edittext);
// Get the new folder name.
String newFolderNameString = editFolderNameEditText.getText().toString();
@Override
public void onMoveToFolder(DialogFragment dialogFragment) {
- // Get a handle for the `ListView` from `dialogFragment`.
- ListView folderListView = dialogFragment.getDialog().findViewById(R.id.move_to_folder_listview);
+ // Get the dialog from the dialog fragment.
+ Dialog dialog = dialogFragment.getDialog();
+
+ // Remove the incorrect lint warning below that the dialog might be null.
+ assert dialog != null;
+
+ // Get a handle for the list view from the dialog.
+ ListView folderListView = dialog.findViewById(R.id.move_to_folder_listview);
// Store a long array of the selected folders.
long[] newFolderLongArray = folderListView.getCheckedItemIds();
}
private void updateMoveIcons() {
- // Get a handle for the shared preferences.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
-
- // Get the theme and screenshot preferences.
- boolean darkTheme = sharedPreferences.getBoolean("dark_theme", false);
-
// Get a long array of the selected bookmarks.
long[] selectedBookmarksLongArray = bookmarksListView.getCheckedItemIds();
// bookmarksListView is 0 indexed.
int lastBookmarkDatabaseId = (int) bookmarksListView.getItemIdAtPosition(bookmarksListView.getCount() - 1);
+ // Get the current theme status.
+ int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+
// Update the move bookmark up `MenuItem`.
if (selectedBookmarkDatabaseId == firstBookmarkDatabaseId) { // The selected bookmark is in the first position.
// Disable the move bookmark up `MenuItem`.
// Set the move bookmark up icon to be ghosted.
moveBookmarkUpMenuItem.setIcon(R.drawable.move_up_disabled);
} else { // The selected bookmark is not in the first position.
- // Enable the move bookmark up `MenuItem`.
+ // Enable the move bookmark up menu item.
moveBookmarkUpMenuItem.setEnabled(true);
// Set the icon according to the theme.
- if (darkTheme) {
- moveBookmarkUpMenuItem.setIcon(R.drawable.move_up_enabled_dark);
+ if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
+ moveBookmarkUpMenuItem.setIcon(R.drawable.move_up_enabled_night);
} else {
- moveBookmarkUpMenuItem.setIcon(R.drawable.move_up_enabled_light);
+ moveBookmarkUpMenuItem.setIcon(R.drawable.move_up_enabled_day);
}
}
moveBookmarkDownMenuItem.setEnabled(true);
// Set the icon according to the theme.
- if (darkTheme) {
- moveBookmarkDownMenuItem.setIcon(R.drawable.move_down_enabled_dark);
+ if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
+ moveBookmarkDownMenuItem.setIcon(R.drawable.move_down_enabled_night);
} else {
- moveBookmarkDownMenuItem.setIcon(R.drawable.move_down_enabled_light);
+ moveBookmarkDownMenuItem.setIcon(R.drawable.move_down_enabled_day);
}
}
}