From: Soren Stoutner Date: Wed, 10 Apr 2019 00:23:02 +0000 (-0700) Subject: Make the favorite icon tab aware. X-Git-Tag: v3.0~13 X-Git-Url: https://gitweb.stoutner.com/?a=commitdiff_plain;h=ff636c77836983a078f33e60616204518dab61d1;p=PrivacyBrowserAndroid.git Make the favorite icon tab aware. --- diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java index bd274ec2..daed7937 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java @@ -120,6 +120,9 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // `closeActivityAfterDismissingSnackbar` is used in `onCreate()`, `onOptionsItemSelected()`, and `onBackPressed()`. private boolean closeActivityAfterDismissingSnackbar; + // The favorite icon byte array is populated in `onCreate()` and used in `onOptionsItemSelected()`. + private byte[] favoriteIconByteArray; + @Override protected void onCreate(Bundle savedInstanceState) { // Disable screenshots if not allowed. @@ -141,12 +144,18 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma Intent launchingIntent = getIntent(); // Set the current folder variable. - if (launchingIntent.getStringExtra("Current Folder") != null) { // Set the current folder from the intent. - currentFolder = launchingIntent.getStringExtra("Current Folder"); + if (launchingIntent.getStringExtra("current_folder") != null) { // Set the current folder from the intent. + currentFolder = launchingIntent.getStringExtra("current_folder"); } else { // Set the current folder to be `""`, which is the home folder. currentFolder = ""; } + // Get the favorite icon byte array. + favoriteIconByteArray = launchingIntent.getByteArrayExtra("favorite_icon_byte_array"); + + // Convert the favorite icon byte array to a bitmap. + Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length); + // Set the content view. setContentView(R.layout.bookmarks_coordinatorlayout); @@ -425,11 +434,11 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma oldFolderNameString = bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); // Show the edit bookmark folder dialog. - DialogFragment editFolderDialog = EditBookmarkFolderDialog.folderDatabaseId(databaseId); + DialogFragment editFolderDialog = EditBookmarkFolderDialog.folderDatabaseId(databaseId, favoriteIconBitmap); editFolderDialog.show(getSupportFragmentManager(), getResources().getString(R.string.edit_folder)); } else { // Show the edit bookmark dialog. - DialogFragment editBookmarkDialog = EditBookmarkDialog.bookmarkDatabaseId(databaseId); + DialogFragment editBookmarkDialog = EditBookmarkDialog.bookmarkDatabaseId(databaseId, favoriteIconBitmap); editBookmarkDialog.show(getSupportFragmentManager(), getResources().getString(R.string.edit_bookmark)); } break; @@ -550,15 +559,17 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Set the create new bookmark folder FAB to display the `AlertDialog`. createBookmarkFolderFab.setOnClickListener(v -> { - // Show the `CreateBookmarkFolderDialog` `AlertDialog` and name the instance `@string/create_folder`. - DialogFragment createBookmarkFolderDialog = new CreateBookmarkFolderDialog(); - createBookmarkFolderDialog.show(getSupportFragmentManager(), getResources().getString(R.string.create_folder)); + // Create a create bookmark folder dialog. + DialogFragment createBookmarkFolderDialog = CreateBookmarkFolderDialog.createBookmarkFolder(favoriteIconBitmap); + + // Show the create bookmark folder dialog. + createBookmarkFolderDialog.show(getSupportFragmentManager(), getString(R.string.create_folder)); }); // Set the create new bookmark FAB to display the `AlertDialog`. createBookmarkFab.setOnClickListener(view -> { // Instantiate the create bookmark dialog. - DialogFragment createBookmarkDialog = CreateBookmarkDialog.createBookmark(currentWebViewUrl, currentWebViewTitle, MainWebViewActivity.favoriteIconBitmap); + DialogFragment createBookmarkDialog = CreateBookmarkDialog.createBookmark(currentWebViewUrl, currentWebViewTitle, favoriteIconBitmap); // Display the create bookmark dialog. createBookmarkDialog.show(getSupportFragmentManager(), getResources().getString(R.string.create_bookmark)); @@ -616,8 +627,13 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma break; case R.id.bookmarks_database_view: - // Launch `BookmarksDatabaseViewActivity`. + // Create an intent to launch the bookmarks database view activity. Intent bookmarksDatabaseViewIntent = new Intent(this, BookmarksDatabaseViewActivity.class); + + // Include the favorite icon byte array to the intent. + bookmarksDatabaseViewIntent.putExtra("favorite_icon_byte_array", favoriteIconByteArray); + + // Make it so. startActivity(bookmarksDatabaseViewIntent); break; } @@ -646,7 +662,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma } @Override - public void onCreateBookmark(DialogFragment dialogFragment) { + public void onCreateBookmark(DialogFragment dialogFragment, Bitmap favoriteIconBitmap) { // 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); @@ -655,19 +671,11 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma String bookmarkNameString = createBookmarkNameEditText.getText().toString(); String bookmarkUrlString = createBookmarkUrlEditText.getText().toString(); - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIcon = MainWebViewActivity.favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIcon.getHeight() > 256) || (favoriteIcon.getWidth() > 256)) { - favoriteIcon = Bitmap.createScaledBitmap(favoriteIcon, 256, 256, true); - } - // Create a favorite icon byte array output stream. ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); // Convert the favorite icon bitmap to a byte array. `0` is for lossless compression (the only option for a PNG). - favoriteIcon.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); // Convert the favorite icon byte array stream to a byte array. byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); @@ -689,7 +697,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma } @Override - public void onCreateBookmarkFolder(DialogFragment dialogFragment) { + public void onCreateBookmarkFolder(DialogFragment dialogFragment, Bitmap favoriteIconBitmap) { // 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); @@ -712,13 +720,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Convert the folder icon bitmap drawable to a bitmap. folderIconBitmap = folderIconBitmapDrawable.getBitmap(); } else { // Use the WebView favorite icon. - // Get a copy of the favorite icon bitmap. - folderIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the folder icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((folderIconBitmap.getHeight() > 256) || (folderIconBitmap.getWidth() > 256)) { - folderIconBitmap = Bitmap.createScaledBitmap(folderIconBitmap, 256, 256, true); - } + // Copy the favorite icon bitmap to the folder icon bitmap. + folderIconBitmap = favoriteIconBitmap; } // Create a folder icon byte array output stream. @@ -750,7 +753,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma } @Override - public void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId) { + public void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, Bitmap favoriteIconBitmap) { // 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); @@ -763,15 +766,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Update the bookmark. if (currentBookmarkIconRadioButton.isChecked()) { // Update the bookmark without changing the favorite icon. bookmarksDatabaseHelper.updateBookmark(selectedBookmarkDatabaseId, bookmarkNameString, bookmarkUrlString); - } else { // Update the bookmark using the `WebView` favorite icon. - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIconBitmap.getHeight() > 256) || (favoriteIconBitmap.getWidth() > 256)) { - favoriteIconBitmap = Bitmap.createScaledBitmap(favoriteIconBitmap, 256, 256, true); - } - + } else { // Update the bookmark using the WebView favorite icon. // Create a favorite icon byte array output stream. ByteArrayOutputStream newFavoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); @@ -796,7 +791,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma } @Override - public void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId) { + public void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId, Bitmap favoriteIconBitmap) { // 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); @@ -825,13 +820,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Convert the folder icon bitmap drawable to a bitmap. folderIconBitmap = folderIconBitmapDrawable.getBitmap(); } else { // Use the WebView favorite icon. - // Get a copy of the favorite icon bitmap. - folderIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the folder icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((folderIconBitmap.getHeight() > 256) || (folderIconBitmap.getWidth() > 256)) { - folderIconBitmap = Bitmap.createScaledBitmap(folderIconBitmap, 256, 256, true); - } + // Copy the favorite icon bitmap to the folder icon bitmap. + folderIconBitmap = favoriteIconBitmap; } // Create a folder icon byte array output stream. @@ -860,13 +850,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Convert the folder icon bitmap drawable to a bitmap. folderIconBitmap = folderIconBitmapDrawable.getBitmap(); } else { // Use the WebView favorite icon. - // Get a copy of the favorite icon bitmap. - folderIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the folder icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((folderIconBitmap.getHeight() > 256) || (folderIconBitmap.getWidth() > 256)) { - folderIconBitmap = Bitmap.createScaledBitmap(folderIconBitmap, 256, 256, true); - } + // Copy the favorite icon bitmap to the folder icon bitmap. + folderIconBitmap = favoriteIconBitmap; } // Create a folder icon byte array output stream. diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java index 4645f3dc..abff4632 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java @@ -21,6 +21,7 @@ package com.stoutner.privacybrowser.activities; import android.annotation.SuppressLint; import android.content.Context; +import android.content.Intent; import android.database.Cursor; import android.database.MatrixCursor; import android.database.MergeCursor; @@ -114,6 +115,18 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements // Run the default commands. super.onCreate(savedInstanceState); + // Get the intent that launched the activity. + Intent launchingIntent = getIntent(); + + // Get the favorite icon byte array. + byte[] favoriteIconByteArray = launchingIntent.getByteArrayExtra("favorite_icon_byte_array"); + + // Remove the incorrect lint warning below that the favorite icon byte array might be null. + assert favoriteIconByteArray != null; + + // Convert the favorite icon byte array to a bitmap and store it in a class variable. + Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length); + // Set the content view. setContentView(R.layout.bookmarks_databaseview_coordinatorlayout); @@ -121,7 +134,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements Toolbar toolbar = findViewById(R.id.bookmarks_databaseview_toolbar); setSupportActionBar(toolbar); - // Get a handle for the `AppBar`. + // Get a handle for the action bar. ActionBar actionBar = getSupportActionBar(); // Remove the incorrect lint warning that the action bar might be null. @@ -337,11 +350,11 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements oldFolderNameString = bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); // Show the edit bookmark folder dialog. - DialogFragment editBookmarkFolderDatabaseViewDialog = EditBookmarkFolderDatabaseViewDialog.folderDatabaseId(databaseId); + DialogFragment editBookmarkFolderDatabaseViewDialog = EditBookmarkFolderDatabaseViewDialog.folderDatabaseId(databaseId, favoriteIconBitmap); editBookmarkFolderDatabaseViewDialog.show(getSupportFragmentManager(), getResources().getString(R.string.edit_folder)); } else { // Show the edit bookmark dialog. - DialogFragment editBookmarkDatabaseViewDialog = EditBookmarkDatabaseViewDialog.bookmarkDatabaseId(databaseId); + DialogFragment editBookmarkDatabaseViewDialog = EditBookmarkDatabaseViewDialog.bookmarkDatabaseId(databaseId, favoriteIconBitmap); editBookmarkDatabaseViewDialog.show(getSupportFragmentManager(), getResources().getString(R.string.edit_bookmark)); } }); @@ -736,7 +749,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements } @Override - public void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId) { + public void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, Bitmap favoriteIconBitmap) { // Get handles for the views from dialog fragment. RadioButton currentBookmarkIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_bookmark_current_icon_radiobutton); EditText editBookmarkNameEditText = dialogFragment.getDialog().findViewById(R.id.edit_bookmark_name_edittext); @@ -764,14 +777,6 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements if (currentBookmarkIconRadioButton.isChecked()) { // Update the bookmark without changing the favorite icon. bookmarksDatabaseHelper.updateBookmark(selectedBookmarkDatabaseId, bookmarkNameString, bookmarkUrlString, parentFolderNameString, displayOrderInt); } else { // Update the bookmark using the `WebView` favorite icon. - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIconBitmap.getHeight() > 256) || (favoriteIconBitmap.getWidth() > 256)) { - favoriteIconBitmap = Bitmap.createScaledBitmap(favoriteIconBitmap, 256, 256, true); - } - // Create a favorite icon byte array output stream. ByteArrayOutputStream newFavoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); @@ -790,7 +795,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements } @Override - public void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedBookmarkDatabaseId) { + public void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, Bitmap favoriteIconBitmap) { // Get handles for the views from dialog fragment. RadioButton currentBookmarkIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_folder_current_icon_radiobutton); RadioButton defaultFolderIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_folder_default_icon_radiobutton); @@ -833,12 +838,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements folderIconBitmap = folderIconBitmapDrawable.getBitmap(); } else { // Use the `WebView` favorite icon. // Get a copy of the favorite icon bitmap. - folderIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the folder icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((folderIconBitmap.getHeight() > 256) || (folderIconBitmap.getWidth() > 256)) { - folderIconBitmap = Bitmap.createScaledBitmap(folderIconBitmap, 256, 256, true); - } + folderIconBitmap = favoriteIconBitmap; } // Create a folder icon byte array output stream. diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index e39b54a4..c0f2b824 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -168,14 +168,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `allowScreenshots` is public static so it can be accessed from everywhere. It is also used in `onCreate()`. public static boolean allowScreenshots; - // `favoriteIconBitmap` is public static so it can be accessed from `BookmarksActivity`, `BookmarksDatabaseViewActivity`, `CreateBookmarkFolderDialog`, - // `EditBookmarkDialog`, `EditBookmarkFolderDialog`, `EditBookmarkDatabaseViewDialog`, and `ViewSslCertificateDialog`. It is also used in `onCreate()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, - // `onCreateHomeScreenShortcut()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `applyDomainSettings()`. - public static Bitmap favoriteIconBitmap; - - // `favoriteIconDefaultBitmap` public static so it can be accessed from `PinnedMismatchDialog`. It is also used in `onCreate()` and `applyDomainSettings`. - public static Bitmap favoriteIconDefaultBitmap; - // TODO Remove. // `formattedUrlString` is public static so it can be accessed from `AddDomainDialog`, `BookmarksActivity`, `DomainSettingsFragment`, and `PinnedMismatchDialog`. // It is also used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onCreateHomeScreenShortcutCreate()`, `loadUrlFromTextBox()`, and `applyProxyThroughOrbot()`. @@ -218,18 +210,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `navigatingHistory` is used in `onCreate()`, `onNavigationItemSelected()`, `onSslMismatchBack()`, and `applyDomainSettings()`. - private boolean navigatingHistory; + private boolean navigatingHistory; // TODO. // The current WebView is used in `onCreate()`, `onPrepareOptionsMenu()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, `onCreateContextMenu()`, `findPreviousOnPage()`, // `findNextOnPage()`, `closeFindOnPage()`, `loadUrlFromTextBox()`, `onSslMismatchBack()`, `applyProxyThroughOrbot()`, and `applyDomainSettings()`. private NestedScrollWebView currentWebView; - // `fullScreenVideoFrameLayout` is used in `onCreate()` and `onConfigurationChanged()`. - private FrameLayout fullScreenVideoFrameLayout; - - // `cookieManager` is used in `onCreate()`, `onOptionsItemSelected()`, and `onNavigationItemSelected()`, `loadUrlFromTextBox()`, `onDownloadImage()`, `onDownloadFile()`, and `onRestart()`. - private CookieManager cookieManager; - // `customHeader` is used in `onCreate()`, `onOptionsItemSelected()`, `onCreateContextMenu()`, and `loadUrl()`. private final Map customHeaders = new HashMap<>(); @@ -244,20 +230,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private boolean nightMode; // 'homepage' is used in `onCreate()`, `onNavigationItemSelected()`, and `applyProxyThroughOrbot()`. - private String homepage; + private String homepage; // TODO ? // `searchURL` is used in `loadURLFromTextBox()` and `applyProxyThroughOrbot()`. - private String searchURL; + private String searchURL; // TODO ? // The options menu is set in `onCreateOptionsMenu()` and used in `onOptionsItemSelected()` and `updatePrivacyIcons()`. private Menu optionsMenu; // The refresh menu item is set in `onCreateOptionsMenu()` and accessed from `initializeWebView()`. // It must be this way because `initializeWebView()` runs before the menu is created but doesn't actually modify the menu until later. - private MenuItem refreshMenuItem; - - // The navigation requests menu item is used in `onCreate()` and accessed from `WebViewPagerAdapter`. - private MenuItem navigationRequestsMenuItem; // TODO. + private MenuItem refreshMenuItem; // TODO. Create it from `optionsMenu`. // TODO. This could probably be removed. // The blocklist helper is used in `onCreate()` and `WebViewPagerAdapter`. @@ -270,7 +253,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private ArrayList> fanboysSocialList; private ArrayList> ultraPrivacy; - // The blocklist menu items are used in `onCreateOptionsMenu()`, `onPrepareOptionsMenu()`, and `initializeWebView()`. + // The blocklist menu items are used in `onCreateOptionsMenu()`, `onPrepareOptionsMenu()`, and `initializeWebView()`. // TODO. private MenuItem blocklistsMenuItem; private MenuItem easyListMenuItem; private MenuItem easyPrivacyMenuItem; @@ -282,23 +265,20 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // `webViewDefaultUserAgent` is used in `onCreate()` and `onPrepareOptionsMenu()`. private String webViewDefaultUserAgent; - // `privacyBrowserRuntime` is used in `onCreate()`, `onOptionsItemSelected()`, and `applyAppSettings()`. - private Runtime privacyBrowserRuntime; - // `proxyThroughOrbot` is used in `onRestart()`, `onOptionsItemSelected()`, `applyAppSettings()`, and `applyProxyThroughOrbot()`. private boolean proxyThroughOrbot; // `incognitoModeEnabled` is used in `onCreate()` and `applyAppSettings()`. - private boolean incognitoModeEnabled; + private boolean incognitoModeEnabled; // TODO. // `fullScreenBrowsingModeEnabled` is used in `onCreate()` and `applyAppSettings()`. - private boolean fullScreenBrowsingModeEnabled; + private boolean fullScreenBrowsingModeEnabled; // TODO. // `inFullScreenBrowsingMode` is used in `onCreate()`, `onConfigurationChanged()`, and `applyAppSettings()`. private boolean inFullScreenBrowsingMode; // Hide app bar is used in `onCreate()` and `applyAppSettings()`. - private boolean hideAppBar; + private boolean hideAppBar; // TODO. // `reapplyDomainSettingsOnRestart` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onRestart()`, and `onAddDomain()`, . private boolean reapplyDomainSettingsOnRestart; @@ -310,7 +290,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private boolean displayingFullScreenVideo; // `downloadWithExternalApp` is used in `onCreate()`, `onCreateContextMenu()`, and `applyDomainSettings()`. - private boolean downloadWithExternalApp; + private boolean downloadWithExternalApp; // TODO. // `orbotStatusBroadcastReceiver` is used in `onCreate()` and `onDestroy()`. private BroadcastReceiver orbotStatusBroadcastReceiver; @@ -319,22 +299,22 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private boolean waitingForOrbot; // `domainSettingsJavaScriptEnabled` is used in `onOptionsItemSelected()` and `applyDomainSettings()`. - private Boolean domainSettingsJavaScriptEnabled; + private Boolean domainSettingsJavaScriptEnabled; // TODO. // `waitingForOrbotHtmlString` is used in `onCreate()` and `applyProxyThroughOrbot()`. - private String waitingForOrbotHtmlString; + private String waitingForOrbotHtmlString; // TODO. // `privateDataDirectoryString` is used in `onCreate()`, `onOptionsItemSelected()`, and `onNavigationItemSelected()`. - private String privateDataDirectoryString; + private String privateDataDirectoryString; // TODO. // `findOnPageEditText` is used in `onCreate()`, `onOptionsItemSelected()`, and `closeFindOnPage()`. - private EditText findOnPageEditText; + private EditText findOnPageEditText; // TODO. // `displayAdditionalAppBarIcons` is used in `onCreate()` and `onCreateOptionsMenu()`. - private boolean displayAdditionalAppBarIcons; + private boolean displayAdditionalAppBarIcons; // TODO. // The action bar drawer toggle is initialized in `onCreate()` and used in `onResume()`. - private ActionBarDrawerToggle actionBarDrawerToggle; + private ActionBarDrawerToggle actionBarDrawerToggle; // TODO. // The color spans are used in `onCreate()` and `highlightUrlText()`. private ForegroundColorSpan redColorSpan; @@ -347,23 +327,23 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private int drawerHeaderPaddingBottom; // `sslErrorHandler` is used in `onCreate()`, `onSslErrorCancel()`, and `onSslErrorProceed`. - private SslErrorHandler sslErrorHandler; + private SslErrorHandler sslErrorHandler; // TODO. // `httpAuthHandler` is used in `onCreate()`, `onHttpAuthenticationCancel()`, and `onHttpAuthenticationProceed()`. - private static HttpAuthHandler httpAuthHandler; + private static HttpAuthHandler httpAuthHandler; // TODO. // `inputMethodManager` is used in `onOptionsItemSelected()`, `loadUrlFromTextBox()`, and `closeFindOnPage()`. - private InputMethodManager inputMethodManager; + private InputMethodManager inputMethodManager; // TODO. // `bookmarksDatabaseHelper` is used in `onCreate()`, `onDestroy`, `onOptionsItemSelected()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, // and `loadBookmarksFolder()`. - private BookmarksDatabaseHelper bookmarksDatabaseHelper; + private BookmarksDatabaseHelper bookmarksDatabaseHelper; // TODO. // `bookmarksListView` is used in `onCreate()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, and `loadBookmarksFolder()`. - private ListView bookmarksListView; + private ListView bookmarksListView; // TODO. // `bookmarksTitleTextView` is used in `onCreate()` and `loadBookmarksFolder()`. - private TextView bookmarksTitleTextView; + private TextView bookmarksTitleTextView; // TODO. // `bookmarksCursor` is used in `onDestroy()`, `onOptionsItemSelected()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`. private Cursor bookmarksCursor; @@ -443,7 +423,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook finalGrayColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_500)); // Get handles for the URL views. - RelativeLayout urlRelativeLayout = findViewById(R.id.url_relativelayout); EditText urlEditText = findViewById(R.id.url_edittext); // Remove the formatting from `urlTextBar` when the user is editing the text. @@ -524,7 +503,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get handles for views that need to be modified. DrawerLayout drawerLayout = findViewById(R.id.drawerlayout); - final NavigationView navigationView = findViewById(R.id.navigationview); + NavigationView navigationView = findViewById(R.id.navigationview); TabLayout tabLayout = findViewById(R.id.tablayout); SwipeRefreshLayout swipeRefreshLayout = findViewById(R.id.swiperefreshlayout); ViewPager webViewPager = findViewById(R.id.webviewpager); @@ -534,18 +513,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook FloatingActionButton createBookmarkFolderFab = findViewById(R.id.create_bookmark_folder_fab); FloatingActionButton createBookmarkFab = findViewById(R.id.create_bookmark_fab); findOnPageEditText = findViewById(R.id.find_on_page_edittext); - fullScreenVideoFrameLayout = findViewById(R.id.full_screen_video_framelayout); // Listen for touches on the navigation menu. navigationView.setNavigationItemSelectedListener(this); // Get handles for the navigation menu and the back and forward menu items. The menu is zero-based. - final Menu navigationMenu = navigationView.getMenu(); - final MenuItem navigationCloseTabMenuItem = navigationMenu.getItem(0); - final MenuItem navigationBackMenuItem = navigationMenu.getItem(3); - final MenuItem navigationForwardMenuItem = navigationMenu.getItem(4); - final MenuItem navigationHistoryMenuItem = navigationMenu.getItem(5); - navigationRequestsMenuItem = navigationMenu.getItem(6); + Menu navigationMenu = navigationView.getMenu(); + MenuItem navigationCloseTabMenuItem = navigationMenu.getItem(0); + MenuItem navigationBackMenuItem = navigationMenu.getItem(3); + MenuItem navigationForwardMenuItem = navigationMenu.getItem(4); + MenuItem navigationHistoryMenuItem = navigationMenu.getItem(5); + MenuItem navigationRequestsMenuItem = navigationMenu.getItem(6); // Initialize the web view pager adapter. webViewPagerAdapter = new WebViewPagerAdapter(getSupportFragmentManager()); @@ -565,47 +543,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @Override public void onPageSelected(int position) { - // Get the WebView tab fragment. - WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(position); - - // Get the fragment view. - View fragmentView = webViewTabFragment.getView(); - - // Remove the incorrect lint warning below that the fragment view might be null. - assert fragmentView != null; - - // Store the current WebView. - currentWebView = fragmentView.findViewById(R.id.nestedscroll_webview); - - // Update the privacy icons. `true` redraws the icons in the app bar. - updatePrivacyIcons(true); - - // Store the current formatted URL string. - formattedUrlString = currentWebView.getUrl(); - - // Clear the focus from the URL text box. - urlEditText.clearFocus(); - - // Hide the soft keyboard. - inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); - - // Display the current URL in the URL text box. - urlEditText.setText(formattedUrlString); - - // Highlight the URL text. - highlightUrlText(); - - // Set the background to indicate the domain settings status. - if (currentWebView.getDomainSettingsApplied()) { - // Set a green background on the URL relative layout to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. - if (darkTheme) { - urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); - } else { - urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); - } - } else { - urlRelativeLayout.setBackground(getResources().getDrawable(R.color.transparent)); - } + // Set the current WebView. + setCurrentWebView(position); // Select the corresponding tab if it does not match the currently selected page. This will happen if the page was scrolled via swiping in the view pager. if (tabLayout.getSelectedTabPosition() != position) { @@ -642,7 +581,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @Override public void onTabReselected(TabLayout.Tab tab) { // Instantiate the View SSL Certificate dialog. - DialogFragment viewSslCertificateDialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView.getWebViewFragmentId()); + DialogFragment viewSslCertificateDialogFragment = ViewSslCertificateDialog.displayDialog(currentWebView.getWebViewFragmentId(), currentWebView.getFavoriteOrDefaultIcon()); // Display the View SSL Certificate dialog. viewSslCertificateDialogFragment.show(getSupportFragmentManager(), getString(R.string.view_ssl_certificate)); @@ -668,15 +607,28 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the launch bookmarks activity FAB to launch the bookmarks activity. launchBookmarksActivityFab.setOnClickListener(v -> { - // Store the current WebView url and title in the bookmarks activity. + // Store the current WebView url and title in the bookmarks activity. // TODO. BookmarksActivity.currentWebViewUrl = currentWebView.getUrl(); BookmarksActivity.currentWebViewTitle = currentWebView.getTitle(); + // Get a copy of the favorite icon bitmap. + Bitmap favoriteIconBitmap = currentWebView.getFavoriteOrDefaultIcon(); + + // Create a favorite icon byte array output stream. + ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the favorite icon bitmap to a byte array. `0` is for lossless compression (the only option for a PNG). + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + + // Convert the favorite icon byte array stream to a byte array. + byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); + // Create an intent to launch the bookmarks activity. Intent bookmarksIntent = new Intent(getApplicationContext(), BookmarksActivity.class); - // Include the current folder with the `Intent`. - bookmarksIntent.putExtra("Current Folder", currentBookmarksFolder); + // Add the extra information to the intent. + bookmarksIntent.putExtra("current_folder", currentBookmarksFolder); + bookmarksIntent.putExtra("favorite_icon_byte_array", favoriteIconByteArray); // Make it so. startActivity(bookmarksIntent); @@ -684,15 +636,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Set the create new bookmark folder FAB to display an alert dialog. createBookmarkFolderFab.setOnClickListener(v -> { - // Show the create bookmark folder dialog and name the instance `@string/create_folder`. - DialogFragment createBookmarkFolderDialog = new CreateBookmarkFolderDialog(); + // Create a create bookmark folder dialog. + DialogFragment createBookmarkFolderDialog = CreateBookmarkFolderDialog.createBookmarkFolder(currentWebView.getFavoriteOrDefaultIcon()); + + // Show the create bookmark folder dialog. createBookmarkFolderDialog.show(getSupportFragmentManager(), getString(R.string.create_folder)); }); // Set the create new bookmark FAB to display an alert dialog. createBookmarkFab.setOnClickListener(view -> { // Instantiate the create bookmark dialog. - DialogFragment createBookmarkDialog = CreateBookmarkDialog.createBookmark(currentWebView.getUrl(), currentWebView.getTitle(), favoriteIconBitmap); + DialogFragment createBookmarkDialog = CreateBookmarkDialog.createBookmark(currentWebView.getUrl(), currentWebView.getTitle(), currentWebView.getFavoriteOrDefaultIcon()); // Display the create bookmark dialog. createBookmarkDialog.show(getSupportFragmentManager(), getString(R.string.create_bookmark)); @@ -797,11 +751,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook oldFolderNameString = bookmarksCursor.getString(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); // Show the edit bookmark folder `AlertDialog` and name the instance `@string/edit_folder`. - DialogFragment editBookmarkFolderDialog = EditBookmarkFolderDialog.folderDatabaseId(databaseId); + DialogFragment editBookmarkFolderDialog = EditBookmarkFolderDialog.folderDatabaseId(databaseId, currentWebView.getFavoriteOrDefaultIcon()); editBookmarkFolderDialog.show(getSupportFragmentManager(), getString(R.string.edit_folder)); } else { // Show the edit bookmark `AlertDialog` and name the instance `@string/edit_bookmark`. - DialogFragment editBookmarkDialog = EditBookmarkDialog.bookmarkDatabaseId(databaseId); + DialogFragment editBookmarkDialog = EditBookmarkDialog.bookmarkDatabaseId(databaseId, currentWebView.getFavoriteOrDefaultIcon()); editBookmarkDialog.show(getSupportFragmentManager(), getString(R.string.edit_bookmark)); } @@ -872,18 +826,12 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Create the hamburger icon at the start of the AppBar. actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.open_navigation_drawer, R.string.close_navigation_drawer); - // Initialize cookieManager. - cookieManager = CookieManager.getInstance(); - // Replace the header that `WebView` creates for `X-Requested-With` with a null value. The default value is the application ID (com.stoutner.privacybrowser.standard). customHeaders.put("X-Requested-With", ""); // Initialize the default preference values the first time the program is run. `false` keeps this command from resetting any current preferences back to default. PreferenceManager.setDefaultValues(this, R.xml.preferences, false); - // Get a handle for the `Runtime`. - privacyBrowserRuntime = Runtime.getRuntime(); - // Store the application's private data directory. privateDataDirectoryString = getApplicationInfo().dataDir; // `dataDir` will vary, but will be something like `/data/user/0/com.stoutner.privacybrowser.standard`, which links to `/data/data/com.stoutner.privacybrowser.standard`. @@ -908,17 +856,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Destroy the bare WebView. bareWebView.destroy(); - // Initialize the favorite icon bitmap. `ContextCompat` must be used until API >= 21. - Drawable favoriteIconDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.world); - BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable; - assert favoriteIconBitmapDrawable != null; - favoriteIconDefaultBitmap = favoriteIconBitmapDrawable.getBitmap(); - - // If the favorite icon is null, load the default. - if (favoriteIconBitmap == null) { - favoriteIconBitmap = favoriteIconDefaultBitmap; - } - // Initialize the user agent array adapter and string array. userAgentNamesArray = ArrayAdapter.createFromResource(this, R.array.user_agent_names, R.layout.spinner_item); userAgentDataArray = getResources().getStringArray(R.array.user_agent_data); @@ -952,53 +889,56 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @Override protected void onNewIntent(Intent intent) { - // Add a new tab. - addTab(null); - - // Sets the new intent as the activity intent, so that any future `getIntent()`s pick up this one instead of creating a new activity. - setIntent(intent); - // Get the information from the intent. String intentAction = intent.getAction(); Uri intentUriData = intent.getData(); - // If the intent action is a web search, perform the search. - if ((intentAction != null) && intentAction.equals(Intent.ACTION_WEB_SEARCH)) { - // Create an encoded URL string. - String encodedUrlString; + // Only process the URI if it contains data. If the user pressed the desktop icon after the app was already running the URI will be null. + if (intentUriData != null) { + // Sets the new intent as the activity intent, which replaces the one that originally started the app. + setIntent(intent); - // Sanitize the search input and convert it to a search. - try { - encodedUrlString = URLEncoder.encode(intent.getStringExtra(SearchManager.QUERY), "UTF-8"); - } catch (UnsupportedEncodingException exception) { - encodedUrlString = ""; + // Add a new tab. + addTab(null); + + // If the intent action is a web search, perform the search. + if ((intentAction != null) && intentAction.equals(Intent.ACTION_WEB_SEARCH)) { + // Create an encoded URL string. + String encodedUrlString; + + // Sanitize the search input and convert it to a search. + try { + encodedUrlString = URLEncoder.encode(intent.getStringExtra(SearchManager.QUERY), "UTF-8"); + } catch (UnsupportedEncodingException exception) { + encodedUrlString = ""; + } + + // Add the base search URL. + formattedUrlString = searchURL + encodedUrlString; + } else { // The intent should contain a URL. + // Set the formatted URL string. + formattedUrlString = intentUriData.toString(); } - // Add the base search URL. - formattedUrlString = searchURL + encodedUrlString; - } else if (intentUriData != null){ // Check to see if the intent contains a new URL. - // Set the formatted URL string. - formattedUrlString = intentUriData.toString(); - } + // Load the URL. + loadUrl(formattedUrlString); - // Load the URL. - loadUrl(formattedUrlString); + // Get a handle for the drawer layout. + DrawerLayout drawerLayout = findViewById(R.id.drawerlayout); - // Get a handle for the drawer layout. - DrawerLayout drawerLayout = findViewById(R.id.drawerlayout); + // Close the navigation drawer if it is open. + if (drawerLayout.isDrawerVisible(GravityCompat.START)) { + drawerLayout.closeDrawer(GravityCompat.START); + } - // Close the navigation drawer if it is open. - if (drawerLayout.isDrawerVisible(GravityCompat.START)) { - drawerLayout.closeDrawer(GravityCompat.START); - } + // Close the bookmarks drawer if it is open. + if (drawerLayout.isDrawerVisible(GravityCompat.END)) { + drawerLayout.closeDrawer(GravityCompat.END); + } - // Close the bookmarks drawer if it is open. - if (drawerLayout.isDrawerVisible(GravityCompat.END)) { - drawerLayout.closeDrawer(GravityCompat.END); + // Clear the keyboard if displayed and remove the focus on the urlTextBar if it has it. + currentWebView.requestFocus(); } - - // Clear the keyboard if displayed and remove the focus on the urlTextBar if it has it. - currentWebView.requestFocus(); } @Override @@ -1283,6 +1223,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook MenuItem nightModeMenuItem = menu.findItem(R.id.night_mode); MenuItem proxyThroughOrbotMenuItem = menu.findItem(R.id.proxy_through_orbot); + // Get a handle for the cookie manager. + CookieManager cookieManager = CookieManager.getInstance(); + // Initialize the current user agent string and the font size. String currentUserAgent = getString(R.string.user_agent_privacy_browser); int fontSize = 100; @@ -1497,6 +1440,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + // Get a handle for the cookie manager. + CookieManager cookieManager = CookieManager.getInstance(); + // Run the commands that correlate to the selected menu item. switch (menuItemId) { case R.id.toggle_javascript: @@ -1719,14 +1665,17 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Setup a runnable to manually delete the DOM storage files and directories. Runnable deleteDomStorageRunnable = () -> { try { + // Get a handle for the runtime. + Runtime runtime = Runtime.getRuntime(); + // A string array must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly. - Process deleteLocalStorageProcess = privacyBrowserRuntime.exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"}); + Process deleteLocalStorageProcess = runtime.exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"}); // Multiple commands must be used because `Runtime.exec()` does not like `*`. - Process deleteIndexProcess = privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB"); - Process deleteQuotaManagerProcess = privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager"); - Process deleteQuotaManagerJournalProcess = privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal"); - Process deleteDatabasesProcess = privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases"); + Process deleteIndexProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB"); + Process deleteQuotaManagerProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager"); + Process deleteQuotaManagerJournalProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal"); + Process deleteDatabasesProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases"); // Wait for the processes to finish. deleteLocalStorageProcess.waitFor(); @@ -2094,7 +2043,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook case R.id.add_to_homescreen: // Instantiate the create home screen shortcut dialog. - DialogFragment createHomeScreenShortcutDialogFragment = CreateHomeScreenShortcutDialog.createDialog(currentWebView.getTitle(), formattedUrlString, favoriteIconBitmap); + DialogFragment createHomeScreenShortcutDialogFragment = CreateHomeScreenShortcutDialog.createDialog(currentWebView.getTitle(), formattedUrlString, currentWebView.getFavoriteOrDefaultIcon()); // Show the create home screen shortcut dialog. createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getString(R.string.create_shortcut)); @@ -2140,8 +2089,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Run the commands that correspond to the selected menu item. switch (menuItemId) { case R.id.close_tab: - // Get a handle for the tab layout. + // Get a handle for the tab layout and the view pager. TabLayout tabLayout = findViewById(R.id.tablayout); + ViewPager webViewPager = findViewById(R.id.webviewpager); // Get the current tab number. int currentTabNumber = tabLayout.getSelectedTabPosition(); @@ -2149,8 +2099,10 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Delete the current tab. tabLayout.removeTabAt(currentTabNumber); - // Delete the current page. - webViewPagerAdapter.deletePage(currentTabNumber); + // Delete the current page. If the selected page number did not change during the delete, it will return true, meaning that the current WebView must be reset. + if (webViewPagerAdapter.deletePage(currentTabNumber, webViewPager)) { + setCurrentWebView(currentTabNumber); + } break; case R.id.clear_and_exit: @@ -2164,20 +2116,23 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the status of the clear everything preference. boolean clearEverything = sharedPreferences.getBoolean("clear_everything", true); + // Get a handle for the runtime. + Runtime runtime = Runtime.getRuntime(); + // Clear cookies. if (clearEverything || sharedPreferences.getBoolean("clear_cookies", true)) { // The command to remove cookies changed slightly in API 21. if (Build.VERSION.SDK_INT >= 21) { - cookieManager.removeAllCookies(null); + CookieManager.getInstance().removeAllCookies(null); } else { - cookieManager.removeAllCookie(); + CookieManager.getInstance().removeAllCookie(); } // Manually delete the cookies database, as `CookieManager` sometimes will not flush its changes to disk before `System.exit(0)` is run. try { // Two commands must be used because `Runtime.exec()` does not like `*`. - Process deleteCookiesProcess = privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/Cookies"); - Process deleteCookiesJournalProcess = privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/Cookies-journal"); + Process deleteCookiesProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/Cookies"); + Process deleteCookiesJournalProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/Cookies-journal"); // Wait until the processes have finished. deleteCookiesProcess.waitFor(); @@ -2196,13 +2151,13 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Manually delete the DOM storage files and directories, as `WebStorage` sometimes will not flush its changes to disk before `System.exit(0)` is run. try { // A `String[]` must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly. - Process deleteLocalStorageProcess = privacyBrowserRuntime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"}); + Process deleteLocalStorageProcess = runtime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Local Storage/"}); // Multiple commands must be used because `Runtime.exec()` does not like `*`. - Process deleteIndexProcess = privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB"); - Process deleteQuotaManagerProcess = privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager"); - Process deleteQuotaManagerJournalProcess = privacyBrowserRuntime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal"); - Process deleteDatabaseProcess = privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases"); + Process deleteIndexProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/IndexedDB"); + Process deleteQuotaManagerProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager"); + Process deleteQuotaManagerJournalProcess = runtime.exec("rm -f " + privateDataDirectoryString + "/app_webview/QuotaManager-journal"); + Process deleteDatabaseProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview/databases"); // Wait until the processes have finished. deleteLocalStorageProcess.waitFor(); @@ -2223,8 +2178,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Manually delete the form data database, as `WebViewDatabase` sometimes will not flush its changes to disk before `System.exit(0)` is run. try { // A string array must be used because the database contains a space and `Runtime.exec` will not otherwise escape the string correctly. - Process deleteWebDataProcess = privacyBrowserRuntime.exec(new String[] {"rm", "-f", privateDataDirectoryString + "/app_webview/Web Data"}); - Process deleteWebDataJournalProcess = privacyBrowserRuntime.exec(new String[] {"rm", "-f", privateDataDirectoryString + "/app_webview/Web Data-journal"}); + Process deleteWebDataProcess = runtime.exec(new String[] {"rm", "-f", privateDataDirectoryString + "/app_webview/Web Data"}); + Process deleteWebDataJournalProcess = runtime.exec(new String[] {"rm", "-f", privateDataDirectoryString + "/app_webview/Web Data-journal"}); // Wait until the processes have finished. deleteWebDataProcess.waitFor(); @@ -2257,11 +2212,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Manually delete the cache directories. try { // Delete the main cache directory. - Process deleteCacheProcess = privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache"); + Process deleteCacheProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/cache"); // Delete the secondary `Service Worker` cache directory. // A string array must be used because the directory contains a space and `Runtime.exec` will otherwise not escape the string correctly. - Process deleteServiceWorkerProcess = privacyBrowserRuntime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"}); + Process deleteServiceWorkerProcess = runtime.exec(new String[] {"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"}); // Wait until the processes have finished. deleteCacheProcess.waitFor(); @@ -2306,7 +2261,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook if (clearEverything) { try { // Delete the folder. - Process deleteAppWebviewProcess = privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/app_webview"); + Process deleteAppWebviewProcess = runtime.exec("rm -rf " + privateDataDirectoryString + "/app_webview"); // Wait until the process has finished. deleteAppWebviewProcess.waitFor(); @@ -2766,7 +2721,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } @Override - public void onCreateBookmark(DialogFragment dialogFragment) { + public void onCreateBookmark(DialogFragment dialogFragment, Bitmap favoriteIconBitmap) { // 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); @@ -2775,19 +2730,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook String bookmarkNameString = createBookmarkNameEditText.getText().toString(); String bookmarkUrlString = createBookmarkUrlEditText.getText().toString(); - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIcon = favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIcon.getHeight() > 256) || (favoriteIcon.getWidth() > 256)) { - favoriteIcon = Bitmap.createScaledBitmap(favoriteIcon, 256, 256, true); - } - // Create a favorite icon byte array output stream. ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); // Convert the favorite icon bitmap to a byte array. `0` is for lossless compression (the only option for a PNG). - favoriteIcon.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); // Convert the favorite icon byte array stream to a byte array. byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); @@ -2809,7 +2756,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } @Override - public void onCreateBookmarkFolder(DialogFragment dialogFragment) { + public void onCreateBookmarkFolder(DialogFragment dialogFragment, Bitmap favoriteIconBitmap) { // 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); @@ -2832,13 +2779,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Convert the folder icon bitmap drawable to a bitmap. folderIconBitmap = folderIconBitmapDrawable.getBitmap(); } else { // Use the WebView favorite icon. - // Get a copy of the favorite icon bitmap. + // Copy the favorite icon bitmap to the folder icon bitmap. folderIconBitmap = favoriteIconBitmap; - - // Scale the folder icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((folderIconBitmap.getHeight() > 256) || (folderIconBitmap.getWidth() > 256)) { - folderIconBitmap = Bitmap.createScaledBitmap(folderIconBitmap, 256, 256, true); - } } // Create a folder icon byte array output stream. @@ -2870,7 +2812,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } @Override - public void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId) { + public void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, Bitmap favoriteIconBitmap) { // 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); @@ -2884,19 +2826,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook if (currentBookmarkIconRadioButton.isChecked()) { // Update the bookmark without changing the favorite icon. bookmarksDatabaseHelper.updateBookmark(selectedBookmarkDatabaseId, bookmarkNameString, bookmarkUrlString); } else { // Update the bookmark using the `WebView` favorite icon. - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIcon = favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIcon.getHeight() > 256) || (favoriteIcon.getWidth() > 256)) { - favoriteIcon = Bitmap.createScaledBitmap(favoriteIcon, 256, 256, true); - } - // Create a favorite icon byte array output stream. ByteArrayOutputStream newFavoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); // Convert the favorite icon bitmap to a byte array. `0` is for lossless compression (the only option for a PNG). - favoriteIcon.compress(Bitmap.CompressFormat.PNG, 0, newFavoriteIconByteArrayOutputStream); + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, newFavoriteIconByteArrayOutputStream); // Convert the favorite icon byte array stream to a byte array. byte[] newFavoriteIconByteArray = newFavoriteIconByteArrayOutputStream.toByteArray(); @@ -2913,7 +2847,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook } @Override - public void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId) { + public void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId, Bitmap favoriteIconBitmap) { // Get handles for the views from `dialogFragment`. EditText editFolderNameEditText = dialogFragment.getDialog().findViewById(R.id.edit_folder_name_edittext); RadioButton currentFolderIconRadioButton = dialogFragment.getDialog().findViewById(R.id.edit_folder_current_icon_radiobutton); @@ -2942,13 +2876,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Convert the folder icon bitmap drawable to a bitmap. folderIconBitmap = folderIconBitmapDrawable.getBitmap(); } else { // Use the `WebView` favorite icon. - // Get a copy of the favorite icon bitmap. - folderIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the folder icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((folderIconBitmap.getHeight() > 256) || (folderIconBitmap.getWidth() > 256)) { - folderIconBitmap = Bitmap.createScaledBitmap(folderIconBitmap, 256, 256, true); - } + // Copy the favorite icon bitmap to the folder icon bitmap. + folderIconBitmap = favoriteIconBitmap; } // Create a folder icon byte array output stream. @@ -2975,13 +2904,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Convert the folder icon bitmap drawable to a bitmap. folderIconBitmap = folderIconBitmapDrawable.getBitmap(); } else { // Use the `WebView` favorite icon. - // Get a copy of the favorite icon bitmap. - folderIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the folder icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((folderIconBitmap.getHeight() > 256) || (folderIconBitmap.getWidth() > 256)) { - folderIconBitmap = Bitmap.createScaledBitmap(folderIconBitmap, 256, 256, true); - } + // Copy the favorite icon bitmap to the folder icon bitmap. + folderIconBitmap = favoriteIconBitmap; } // Create a folder icon byte array output stream. @@ -3073,7 +2997,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Code contributed 2017 Hendrik Knackstedt. Copyright assigned to Soren Stoutner . if (firstPartyCookiesEnabled) { // Get the cookies for `imageUrl`. - String cookies = cookieManager.getCookie(imageUrl); + String cookies = CookieManager.getInstance().getCookie(imageUrl); // Add the cookies to `downloadRequest`. In the HTTP request header, cookies are named `Cookie`. downloadRequest.addRequestHeader("Cookie", cookies); @@ -3125,7 +3049,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Code contributed 2017 Hendrik Knackstedt. Copyright assigned to Soren Stoutner . if (firstPartyCookiesEnabled) { // Get the cookies for `downloadUrl`. - String cookies = cookieManager.getCookie(downloadUrl); + String cookies = CookieManager.getInstance().getCookie(downloadUrl); // Add the cookies to `downloadRequest`. In the HTTP request header, cookies are named `Cookie`. downloadRequest.addRequestHeader("Cookie", cookies); @@ -3517,8 +3441,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Reset the favorite icon if specified. if (resetFavoriteIcon) { - // Store the favorite icon bitmap. - favoriteIconBitmap = favoriteIconDefaultBitmap; // TODO. + // Initialize the favorite icon. + currentWebView.initializeFavoriteIcon(); // Get a handle for the tab layout. TabLayout tabLayout = findViewById(R.id.tablayout); @@ -3539,7 +3463,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook ImageView currentTabFavoriteIconImageView = currentTabCustomView.findViewById(R.id.favorite_icon_imageview); // Set the default favorite icon as the favorite icon for this tab. - currentTabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(favoriteIconBitmap, 64, 64, true)); + currentTabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(nestedScrollWebView.getFavoriteOrDefaultIcon(), 64, 64, true)); } // Get a handle for the swipe refresh layout. @@ -3609,6 +3533,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook nightMode = sharedPreferences.getBoolean("night_mode", false); // TODO. boolean displayWebpageImages = sharedPreferences.getBoolean("display_webpage_images", true); + // Get a handle for the cookie manager. + CookieManager cookieManager = CookieManager.getInstance(); + if (nestedScrollWebView.getDomainSettingsApplied()) { // The url has custom domain settings. // Get a cursor for the current host and move it to the first position. Cursor currentDomainSettingsCursor = domainsDatabaseHelper.getCursorForDomainName(domainNameInDatabase); @@ -4259,6 +4186,54 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook webViewPagerAdapter.addPage(newTabNumber, webViewPager); } + private void setCurrentWebView(int pageNumber) { + // Get handles for the URL views. + RelativeLayout urlRelativeLayout = findViewById(R.id.url_relativelayout); + EditText urlEditText = findViewById(R.id.url_edittext); + + // Get the WebView tab fragment. + WebViewTabFragment webViewTabFragment = webViewPagerAdapter.getPageFragment(pageNumber); + + // Get the fragment view. + View fragmentView = webViewTabFragment.getView(); + + // Remove the incorrect lint warning below that the fragment view might be null. + assert fragmentView != null; + + // Store the current WebView. + currentWebView = fragmentView.findViewById(R.id.nestedscroll_webview); + + // Update the privacy icons. `true` redraws the icons in the app bar. + updatePrivacyIcons(true); + + // Store the current formatted URL string. + formattedUrlString = currentWebView.getUrl(); + + // Clear the focus from the URL text box. + urlEditText.clearFocus(); + + // Hide the soft keyboard. + inputMethodManager.hideSoftInputFromWindow(currentWebView.getWindowToken(), 0); + + // Display the current URL in the URL text box. + urlEditText.setText(formattedUrlString); + + // Highlight the URL text. + highlightUrlText(); + + // Set the background to indicate the domain settings status. + if (currentWebView.getDomainSettingsApplied()) { + // Set a green background on the URL relative layout to indicate that custom domain settings are being used. The deprecated `.getDrawable()` must be used until the minimum API >= 21. + if (darkTheme) { + urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_dark_blue)); + } else { + urlRelativeLayout.setBackground(getResources().getDrawable(R.drawable.url_bar_background_light_green)); + } + } else { + urlRelativeLayout.setBackground(getResources().getDrawable(R.color.transparent)); + } + } + @Override public void initializeWebView(NestedScrollWebView nestedScrollWebView, int pageNumber, ProgressBar progressBar) { // Get handles for the activity views. @@ -4282,6 +4257,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the relevant preferences. boolean downloadWithExternalApp = sharedPreferences.getBoolean("download_with_external_app", false); + // Initialize the favorite icon. + nestedScrollWebView.initializeFavoriteIcon(); + // Set the app bar scrolling. nestedScrollWebView.setNestedScrollingEnabled(sharedPreferences.getBoolean("scroll_app_bar", true)); @@ -4501,8 +4479,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook public void onReceivedIcon(WebView view, Bitmap icon) { // Only update the favorite icon if the website has finished loading. if (progressBar.getVisibility() == View.GONE) { - // Save a copy of the favorite icon. - favoriteIconBitmap = icon; + // Store the new favorite icon. + nestedScrollWebView.setFavoriteOrDefaultIcon(icon); // Get the current page position. int currentPosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId()); @@ -4536,25 +4514,28 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Get the current tab. TabLayout.Tab tab = tabLayout.getTabAt(currentPosition); - // Remove the lint warning below that the current tab might be null. - assert tab != null; - - // Get the custom view from the tab. - View tabView = tab.getCustomView(); + // Only populate the title text view if the tab has been fully created. + if (tab != null) { + // Get the custom view from the tab. + View tabView = tab.getCustomView(); - // Remove the incorrect warning below that the current tab view might be null. - assert tabView != null; + // Remove the incorrect warning below that the current tab view might be null. + assert tabView != null; - // Get the title text view from the tab. - TextView tabTitleTextView = tabView.findViewById(R.id.title_textview); + // Get the title text view from the tab. + TextView tabTitleTextView = tabView.findViewById(R.id.title_textview); - // Set the title as the tab text. - tabTitleTextView.setText(title); + // Set the title as the tab text. + tabTitleTextView.setText(title); + } } // Enter full screen video. @Override public void onShowCustomView(View video, CustomViewCallback callback) { + // Get a handle for the full screen video frame layout. + FrameLayout fullScreenVideoFrameLayout = findViewById(R.id.full_screen_video_framelayout); + // Set the full screen video flag. displayingFullScreenVideo = true; @@ -4598,6 +4579,9 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Exit full screen video. @Override public void onHideCustomView() { + // Get a handle for the full screen video frame layout. + FrameLayout fullScreenVideoFrameLayout = findViewById(R.id.full_screen_video_framelayout); + // Unset the full screen video flag. displayingFullScreenVideo = false; @@ -4752,6 +4736,15 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @SuppressWarnings("deprecation") @Override public WebResourceResponse shouldInterceptRequest(WebView view, String url) { + // Get a handle for the navigation view. + NavigationView navigationView = findViewById(R.id.navigationview); + + // Get a handle for the navigation menu. + Menu navigationMenu = navigationView.getMenu(); + + // Get a handle for the navigation requests menu item. The menu is 0 based. + MenuItem navigationRequestsMenuItem = navigationMenu.getItem(6); + // Create an empty web resource response to be used if the resource request is blocked. WebResourceResponse emptyWebResourceResponse = new WebResourceResponse("text/plain", "utf8", new ByteArrayInputStream("".getBytes())); @@ -4906,7 +4899,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Process the EasyPrivacy results. if (easyPrivacyResults[0].equals(BlockListHelper.REQUEST_BLOCKED)) { // The resource request matched EasyPrivacy's blacklist. // Add the result to the resource requests. - nestedScrollWebView.addResourceRequest(new String[] {easyPrivacyResults[0], easyPrivacyResults[1], easyPrivacyResults[2], easyPrivacyResults[3], easyPrivacyResults[5], + nestedScrollWebView.addResourceRequest(new String[] {easyPrivacyResults[0], easyPrivacyResults[1], easyPrivacyResults[2], easyPrivacyResults[3], easyPrivacyResults[4], easyPrivacyResults[5]}); // Increment the blocked requests counters. @@ -5101,7 +5094,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Flush any cookies to persistent storage. `CookieManager` has become very lazy about flushing cookies in recent versions. if (firstPartyCookiesEnabled && Build.VERSION.SDK_INT >= 21) { - cookieManager.flush(); + CookieManager.getInstance().flush(); } // Update the Refresh menu item if it has been created. @@ -5131,11 +5124,11 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Manually delete cache folders. try { // Delete the main cache directory. - privacyBrowserRuntime.exec("rm -rf " + privateDataDirectoryString + "/cache"); + Runtime.getRuntime().exec("rm -rf " + privateDataDirectoryString + "/cache"); // Delete the secondary `Service Worker` cache directory. // A `String[]` must be used because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise. - privacyBrowserRuntime.exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"}); + Runtime.getRuntime().exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"}); } catch (IOException e) { // Do nothing if an error is thrown. } diff --git a/app/src/main/java/com/stoutner/privacybrowser/adapters/WebViewPagerAdapter.java b/app/src/main/java/com/stoutner/privacybrowser/adapters/WebViewPagerAdapter.java index 7c6aaf35..0a5aff1f 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/adapters/WebViewPagerAdapter.java +++ b/app/src/main/java/com/stoutner/privacybrowser/adapters/WebViewPagerAdapter.java @@ -106,12 +106,15 @@ public class WebViewPagerAdapter extends FragmentPagerAdapter { } } - public void deletePage(int pageNumber) { + public boolean deletePage(int pageNumber, ViewPager webViewPager) { // Delete the page. webViewFragmentsList.remove(pageNumber); // Update the view pager. notifyDataSetChanged(); + + // Return true if the selected page number did not change after the delete. This will cause the calling method to reset the current WebView to the new contents of this page number. + return (webViewPager.getCurrentItem() == pageNumber); } public WebViewTabFragment getPageFragment(int pageNumber) { diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkDialog.java index 00e604e0..a524d266 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkDialog.java @@ -44,14 +44,9 @@ import com.stoutner.privacybrowser.R; import java.io.ByteArrayOutputStream; public class CreateBookmarkDialog extends DialogFragment { - // Create the class variables. - String url; - String title; - Bitmap favoriteIconBitmap; - // The public interface is used to send information back to the parent activity. public interface CreateBookmarkListener { - void onCreateBookmark(DialogFragment dialogFragment); + void onCreateBookmark(DialogFragment dialogFragment, Bitmap favoriteIconBitmap); } // The create bookmark listener is initialized in `onAttach()` and used in `onCreateDialog()`. @@ -66,11 +61,6 @@ public class CreateBookmarkDialog extends DialogFragment { } public static CreateBookmarkDialog createBookmark(String url, String title, Bitmap favoriteIconBitmap) { - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIconBitmap.getHeight() > 256) || (favoriteIconBitmap.getWidth() > 256)) { - favoriteIconBitmap = Bitmap.createScaledBitmap(favoriteIconBitmap, 256, 256, true); - } - // Create a favorite icon byte array output stream. ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); @@ -80,38 +70,38 @@ public class CreateBookmarkDialog extends DialogFragment { // Convert the byte array output stream to a byte array. byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); - // Create a bundle. - Bundle bundle = new Bundle(); + // Create an arguments bundle. + Bundle argumentsBundle = new Bundle(); - // Store the variables in the bundle - bundle.putString("url", url); - bundle.putString("title", title); - bundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray); + // Store the variables in the bundle. + argumentsBundle.putString("url", url); + argumentsBundle.putString("title", title); + argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray); // Create a new instance of the dialog. CreateBookmarkDialog createBookmarkDialog = new CreateBookmarkDialog(); // Add the bundle to the dialog. - createBookmarkDialog.setArguments(bundle); + createBookmarkDialog.setArguments(argumentsBundle); // Return the new dialog. return createBookmarkDialog; } + // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. + @SuppressLint("InflateParams") @Override - public void onCreate(Bundle savedInstanceState) { - // Run the default commands. - super.onCreate(savedInstanceState); - + @NonNull + public Dialog onCreateDialog(Bundle savedInstanceState) { // Get the arguments. Bundle arguments = getArguments(); // Remove the incorrect lint warning below that the arguments might be null. assert arguments != null; - // Store the contents of the arguments in class variables. - url = arguments.getString("url"); - title = arguments.getString("title"); + // Get the strings from the arguments. + String url = arguments.getString("url"); + String title = arguments.getString("title"); // Get the favorite icon byte array. byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array"); @@ -119,15 +109,9 @@ public class CreateBookmarkDialog extends DialogFragment { // Remove the incorrect lint warning below that the favorite icon byte array might be null. assert favoriteIconByteArray != null; - // Convert the favorite icon byte array to a bitmap and store it in a class variable. - favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length); - } + // Convert the favorite icon byte array to a bitmap. + Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length); - // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. - @SuppressLint("InflateParams") - @Override - @NonNull - public Dialog onCreateDialog(Bundle savedInstanceState) { // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); @@ -166,11 +150,11 @@ public class CreateBookmarkDialog extends DialogFragment { // Set an `onClick()` listener for the positive button. dialogBuilder.setPositiveButton(R.string.create, (DialogInterface dialog, int which) -> { // Return the `DialogFragment` to the parent activity. - createBookmarkListener.onCreateBookmark(CreateBookmarkDialog.this); + createBookmarkListener.onCreateBookmark(this, favoriteIconBitmap); }); // Create an `AlertDialog` from the `AlertDialog.Builder`. - final AlertDialog alertDialog = dialogBuilder.create(); + AlertDialog alertDialog = dialogBuilder.create(); // Remove the warning below that `getWindow()` might be null. assert alertDialog.getWindow() != null; @@ -197,7 +181,7 @@ public class CreateBookmarkDialog extends DialogFragment { // If the event is a key-down on the `enter` key, select the `PositiveButton` `Create`. if ((keyCode == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) { // Trigger `createBookmarkListener` and return the `DialogFragment` to the parent activity. - createBookmarkListener.onCreateBookmark(CreateBookmarkDialog.this); + createBookmarkListener.onCreateBookmark(this, favoriteIconBitmap); // Manually dismiss the `AlertDialog`. alertDialog.dismiss(); @@ -218,7 +202,7 @@ public class CreateBookmarkDialog extends DialogFragment { // If the event is a key-down on the "enter" key, select the PositiveButton "Create". if ((keyCode == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) { // Trigger `createBookmarkListener` and return the DialogFragment to the parent activity. - createBookmarkListener.onCreateBookmark(CreateBookmarkDialog.this); + createBookmarkListener.onCreateBookmark(this, favoriteIconBitmap); // Manually dismiss the `AlertDialog`. alertDialog.dismiss(); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java index 2e9532aa..9c8411b1 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.DialogInterface; import android.database.Cursor; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; @@ -43,10 +44,12 @@ import com.stoutner.privacybrowser.R; import com.stoutner.privacybrowser.activities.MainWebViewActivity; import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; +import java.io.ByteArrayOutputStream; + public class CreateBookmarkFolderDialog extends DialogFragment { // The public interface is used to send information back to the parent activity. public interface CreateBookmarkFolderListener { - void onCreateBookmarkFolder(DialogFragment dialogFragment); + void onCreateBookmarkFolder(DialogFragment dialogFragment, Bitmap favoriteIconBitmap); } // `createBookmarkFolderListener` is used in `onAttach()` and `onCreateDialog`. @@ -59,11 +62,52 @@ public class CreateBookmarkFolderDialog extends DialogFragment { createBookmarkFolderListener = (CreateBookmarkFolderListener) context; } + public static CreateBookmarkFolderDialog createBookmarkFolder(Bitmap favoriteIconBitmap) { + // Create a favorite icon byte array output stream. + ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG). + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + + // Convert the byte array output stream to a byte array. + byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); + + // Create an arguments bundle. + Bundle argumentsBundle = new Bundle(); + + // Store the favorite icon in the bundle. + argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray); + + // Create a new instance of the dialog. + CreateBookmarkFolderDialog createBookmarkFolderDialog = new CreateBookmarkFolderDialog(); + + // Add the bundle to the dialog. + createBookmarkFolderDialog.setArguments(argumentsBundle); + + // Return the new dialog. + return createBookmarkFolderDialog; + } + // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. @SuppressLint("InflateParams") @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { + // Get the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning below that the arguments might be null. + assert arguments != null; + + // Get the favorite icon byte array. + byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array"); + + // Remove the incorrect lint warning below 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); + // Use an alert dialog builder to create the alert dialog. AlertDialog.Builder dialogBuilder; @@ -91,7 +135,7 @@ public class CreateBookmarkFolderDialog extends DialogFragment { // Set an `onClick()` listener fo the positive button. dialogBuilder.setPositiveButton(R.string.create, (DialogInterface dialog, int which) -> { // Return the `DialogFragment` to the parent activity on create. - createBookmarkFolderListener.onCreateBookmarkFolder(CreateBookmarkFolderDialog.this); + createBookmarkFolderListener.onCreateBookmarkFolder(this, favoriteIconBitmap); }); @@ -150,7 +194,7 @@ public class CreateBookmarkFolderDialog extends DialogFragment { // If the event is a key-down on the `enter` key, select the `PositiveButton` `Create`. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && createButton.isEnabled()) { // The enter key was pressed and the create button is enabled. // Trigger `createBookmarkFolderListener` and return the `DialogFragment` to the parent activity. - createBookmarkFolderListener.onCreateBookmarkFolder(CreateBookmarkFolderDialog.this); + createBookmarkFolderListener.onCreateBookmarkFolder(this, favoriteIconBitmap); // Manually dismiss the `AlertDialog`. alertDialog.dismiss(); // Consume the event. @@ -160,14 +204,6 @@ public class CreateBookmarkFolderDialog extends DialogFragment { } }); - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIconBitmap.getHeight() > 256) || (favoriteIconBitmap.getWidth() > 256)) { - favoriteIconBitmap = Bitmap.createScaledBitmap(favoriteIconBitmap, 256, 256, true); - } - // Display the current favorite icon. webPageIconImageView.setImageBitmap(favoriteIconBitmap); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateHomeScreenShortcutDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateHomeScreenShortcutDialog.java index b82f4bbf..dc4b2f8f 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateHomeScreenShortcutDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateHomeScreenShortcutDialog.java @@ -56,14 +56,10 @@ import com.stoutner.privacybrowser.R; import java.io.ByteArrayOutputStream; public class CreateHomeScreenShortcutDialog extends DialogFragment { - // Create the class variables. - private String initialShortcutName; - private String initialUrlString; - private Bitmap favoriteIconBitmap; + // Define the class variables. private EditText shortcutNameEditText; private EditText urlEditText; private RadioButton openWithPrivacyBrowserRadioButton; - private Button createButton; public static CreateHomeScreenShortcutDialog createDialog(String shortcutName, String urlString, Bitmap favoriteIconBitmap) { // Create a favorite icon byte array output stream. @@ -93,20 +89,20 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { return createHomeScreenShortcutDialog; } + // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. + @SuppressLint("InflateParams") @Override - public void onCreate(Bundle savedInstanceState) { - // Run the default commands. - super.onCreate(savedInstanceState); - + @NonNull + public Dialog onCreateDialog(Bundle savedInstanceState) { // Get the arguments. Bundle arguments = getArguments(); // Remove the incorrect lint warning below that the arguments might be null. assert arguments != null; - // Store the strings in class variables. - initialShortcutName = arguments.getString("shortcut_name"); - initialUrlString = arguments.getString("url_string"); + // Get the strings from the arguments. + String initialShortcutName = arguments.getString("shortcut_name"); + String initialUrlString = arguments.getString("url_string"); // Get the favorite icon byte array. byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array"); @@ -115,14 +111,8 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { assert favoriteIconByteArray != null; // Convert the favorite icon byte array to a bitmap and store it in a class variable. - favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length); - } + Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length); - // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. - @SuppressLint("InflateParams") - @Override - @NonNull - public Dialog onCreateDialog(Bundle savedInstanceState) { // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); @@ -162,7 +152,7 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { // Set an `onClick` listener on the create button. dialogBuilder.setPositiveButton(R.string.create, (DialogInterface dialog, int which) -> { // Create the home screen shortcut. - createHomeScreenShortcut(); + createHomeScreenShortcut(favoriteIconBitmap); }); // Create an alert dialog from the alert dialog builder. @@ -183,7 +173,7 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { shortcutNameEditText = alertDialog.findViewById(R.id.shortcut_name_edittext); urlEditText = alertDialog.findViewById(R.id.url_edittext); openWithPrivacyBrowserRadioButton = alertDialog.findViewById(R.id.open_with_privacy_browser_radiobutton); - createButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + Button createButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); // Populate the edit texts. shortcutNameEditText.setText(initialShortcutName); @@ -204,7 +194,7 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { @Override public void afterTextChanged(Editable s) { // Update the create button. - updateCreateButton(); + updateCreateButton(createButton); } }); @@ -223,7 +213,7 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { @Override public void afterTextChanged(Editable s) { // Update the create button. - updateCreateButton(); + updateCreateButton(createButton); } }); @@ -234,7 +224,7 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { // Check the status of the create button. if (createButton.isEnabled()) { // The create button is enabled. // Create the home screen shortcut. - createHomeScreenShortcut(); + createHomeScreenShortcut(favoriteIconBitmap); // Manually dismiss the alert dialog. alertDialog.dismiss(); @@ -258,7 +248,7 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { // Check the status of the create button. if (createButton.isEnabled()) { // The create button is enabled. // Create the home screen shortcut. - createHomeScreenShortcut(); + createHomeScreenShortcut(favoriteIconBitmap); // Manually dismiss the alert dialog. alertDialog.dismiss(); @@ -279,7 +269,7 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { return alertDialog; } - private void updateCreateButton() { + private void updateCreateButton(Button createButton) { // Get the contents of the edit texts. String shortcutName = shortcutNameEditText.getText().toString(); String urlString = urlEditText.getText().toString(); @@ -288,7 +278,7 @@ public class CreateHomeScreenShortcutDialog extends DialogFragment { createButton.setEnabled(!shortcutName.isEmpty() && !urlString.isEmpty()); } - private void createHomeScreenShortcut() { + private void createHomeScreenShortcut(Bitmap favoriteIconBitmap) { // Get a handle for the context. Context context = getContext(); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java index b0d401bb..d58ae113 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java @@ -49,30 +49,23 @@ import com.stoutner.privacybrowser.R; import com.stoutner.privacybrowser.activities.MainWebViewActivity; import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; +import java.io.ByteArrayOutputStream; + import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import androidx.fragment.app.DialogFragment; // The AndroidX dialog fragment must be used or an error is produced on API <=22. public class EditBookmarkDatabaseViewDialog extends DialogFragment { - // Instantiate the constants. + // Define the home folder database ID constant. public static final int HOME_FOLDER_DATABASE_ID = -1; - // Instantiate the class variables. + // Define the edit bookmark database view listener. private EditBookmarkDatabaseViewListener editBookmarkDatabaseViewListener; - private String currentBookmarkName; - private String currentUrl; - private int currentFolderDatabaseId; - private String currentDisplayOrder; - private RadioButton newIconRadioButton; - private EditText nameEditText; - private EditText urlEditText; - private Spinner folderSpinner; - private EditText displayOrderEditText; - private Button editButton; + // The public interface is used to send information back to the parent activity. public interface EditBookmarkDatabaseViewListener { - void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId); + void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, Bitmap favoriteIconBitmap); } @Override @@ -84,17 +77,29 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { editBookmarkDatabaseViewListener = (EditBookmarkDatabaseViewListener) context; } - // Store the database ID in the arguments bundle. - public static EditBookmarkDatabaseViewDialog bookmarkDatabaseId(int databaseId) { - // Create a bundle. - Bundle bundle = new Bundle(); - // Store the bookmark database ID in the bundle. - bundle.putInt("Database ID", databaseId); + public static EditBookmarkDatabaseViewDialog bookmarkDatabaseId(int databaseId, Bitmap favoriteIconBitmap) { + // Create a favorite icon byte array output stream. + ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG). + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + + // Convert the byte array output stream to a byte array. + byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); - // Add the bundle to the dialog. + // Create an arguments bundle. + Bundle argumentsBundle = new Bundle(); + + // Store the variables in the bundle. + argumentsBundle.putInt("database_id", databaseId); + argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray); + + // Create a new instance of the dialog. EditBookmarkDatabaseViewDialog editBookmarkDatabaseViewDialog = new EditBookmarkDatabaseViewDialog(); - editBookmarkDatabaseViewDialog.setArguments(bundle); + + // Add the arguments bundle to the dialog. + editBookmarkDatabaseViewDialog.setArguments(argumentsBundle); // Return the new dialog. return editBookmarkDatabaseViewDialog; @@ -105,11 +110,23 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { - // Remove the incorrect lint warning below that `getInt()` might be null. - assert getArguments() != null; + // Get the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning below that the arguments might be null. + assert arguments != null; // Get the bookmark database ID from the bundle. - int bookmarkDatabaseId = getArguments().getInt("Database ID"); + int bookmarkDatabaseId = getArguments().getInt("database_id"); + + // Get the favorite icon byte array. + byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array"); + + // Remove the incorrect lint warning below 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); // Initialize the database helper. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`. BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); @@ -142,10 +159,10 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { // Do nothing. The `AlertDialog` will close automatically. }); - // Set the listener fo the positive button. + // Set the listener for the positive button. dialogBuilder.setPositiveButton(R.string.save, (DialogInterface dialog, int which) -> { // Return the `DialogFragment` to the parent activity on save. - editBookmarkDatabaseViewListener.onSaveBookmark(EditBookmarkDatabaseViewDialog.this, bookmarkDatabaseId); + editBookmarkDatabaseViewListener.onSaveBookmark(this, bookmarkDatabaseId, favoriteIconBitmap); }); // Create an alert dialog from the alert dialog builder`. @@ -167,17 +184,17 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { RadioGroup iconRadioGroup = alertDialog.findViewById(R.id.edit_bookmark_icon_radiogroup); ImageView currentIconImageView = alertDialog.findViewById(R.id.edit_bookmark_current_icon); ImageView newFavoriteIconImageView = alertDialog.findViewById(R.id.edit_bookmark_webpage_favorite_icon); - newIconRadioButton = alertDialog.findViewById(R.id.edit_bookmark_webpage_favorite_icon_radiobutton); - nameEditText = alertDialog.findViewById(R.id.edit_bookmark_name_edittext); - urlEditText = alertDialog.findViewById(R.id.edit_bookmark_url_edittext); - folderSpinner = alertDialog.findViewById(R.id.edit_bookmark_folder_spinner); - displayOrderEditText = alertDialog.findViewById(R.id.edit_bookmark_display_order_edittext); - editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + RadioButton newIconRadioButton = alertDialog.findViewById(R.id.edit_bookmark_webpage_favorite_icon_radiobutton); + EditText nameEditText = alertDialog.findViewById(R.id.edit_bookmark_name_edittext); + EditText urlEditText = alertDialog.findViewById(R.id.edit_bookmark_url_edittext); + Spinner folderSpinner = alertDialog.findViewById(R.id.edit_bookmark_folder_spinner); + EditText displayOrderEditText = alertDialog.findViewById(R.id.edit_bookmark_display_order_edittext); + Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); // Store the current bookmark values. - currentBookmarkName = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); - currentUrl = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL)); - currentDisplayOrder = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)); + String currentBookmarkName = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); + String currentUrl = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL)); + int currentDisplayOrder = bookmarkCursor.getInt(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)); // Set the database ID. databaseIdTextView.setText(String.valueOf(bookmarkCursor.getInt(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper._ID)))); @@ -191,14 +208,6 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { // Display `currentIconBitmap` in `edit_bookmark_current_icon`. currentIconImageView.setImageBitmap(currentIconBitmap); - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIconBitmap.getHeight() > 256) || (favoriteIconBitmap.getWidth() > 256)) { - favoriteIconBitmap = Bitmap.createScaledBitmap(favoriteIconBitmap, 256, 256, true); - } - // Set the new favorite icon bitmap. newFavoriteIconImageView.setImageBitmap(favoriteIconBitmap); @@ -283,7 +292,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { } // Store the current folder database ID. - currentFolderDatabaseId = (int) folderSpinner.getSelectedItemId(); + int currentFolderDatabaseId = (int) folderSpinner.getSelectedItemId(); // Populate the display order `EditText`. displayOrderEditText.setText(String.valueOf(bookmarkCursor.getInt(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)))); @@ -294,7 +303,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { // Update the edit button if the icon selection changes. iconRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { // Update the edit button. - updateEditButton(); + updateEditButton(nameEditText, urlEditText, displayOrderEditText, folderSpinner, newIconRadioButton, editButton, currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder); }); // Update the edit button if the bookmark name changes. @@ -312,7 +321,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { @Override public void afterTextChanged(Editable s) { // Update the edit button. - updateEditButton(); + updateEditButton(nameEditText, urlEditText, displayOrderEditText, folderSpinner, newIconRadioButton, editButton, currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder); } }); @@ -331,7 +340,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { @Override public void afterTextChanged(Editable s) { // Update the edit button. - updateEditButton(); + updateEditButton(nameEditText, urlEditText, displayOrderEditText, folderSpinner, newIconRadioButton, editButton, currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder); } }); @@ -340,7 +349,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { // Update the edit button. - updateEditButton(); + updateEditButton(nameEditText, urlEditText, displayOrderEditText, folderSpinner, newIconRadioButton, editButton, currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder); } @Override @@ -364,7 +373,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { @Override public void afterTextChanged(Editable s) { // Update the edit button. - updateEditButton(); + updateEditButton(nameEditText, urlEditText, displayOrderEditText, folderSpinner, newIconRadioButton, editButton, currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder); } }); @@ -373,7 +382,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { // Save the bookmark if the event is a key-down on the "enter" button. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled. // Trigger the `Listener` and return the `DialogFragment` to the parent activity. - editBookmarkDatabaseViewListener.onSaveBookmark(EditBookmarkDatabaseViewDialog.this, bookmarkDatabaseId); + editBookmarkDatabaseViewListener.onSaveBookmark(EditBookmarkDatabaseViewDialog.this, bookmarkDatabaseId, favoriteIconBitmap); // Manually dismiss `alertDialog`. alertDialog.dismiss(); @@ -390,7 +399,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { // Save the bookmark if the event is a key-down on the "enter" button. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled. // Trigger the `Listener` and return the `DialogFragment` to the parent activity. - editBookmarkDatabaseViewListener.onSaveBookmark(EditBookmarkDatabaseViewDialog.this, bookmarkDatabaseId); + editBookmarkDatabaseViewListener.onSaveBookmark(EditBookmarkDatabaseViewDialog.this, bookmarkDatabaseId, favoriteIconBitmap); // Manually dismiss the `AlertDialog`. alertDialog.dismiss(); @@ -407,7 +416,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { // Save the bookmark if the event is a key-down on the "enter" button. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled. // Trigger the `Listener` and return the `DialogFragment` to the parent activity. - editBookmarkDatabaseViewListener.onSaveBookmark(EditBookmarkDatabaseViewDialog.this, bookmarkDatabaseId); + editBookmarkDatabaseViewListener.onSaveBookmark(EditBookmarkDatabaseViewDialog.this, bookmarkDatabaseId, favoriteIconBitmap); // Manually dismiss the `AlertDialog`. alertDialog.dismiss(); @@ -423,7 +432,8 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { return alertDialog; } - private void updateEditButton() { + private void updateEditButton(EditText nameEditText, EditText urlEditText, EditText displayOrderEditText, Spinner folderSpinner, RadioButton newIconRadioButton, Button editButton, + String currentBookmarkName, String currentUrl, int currentFolderDatabaseId, int currentDisplayOrder) { // Get the values from the dialog. String newName = nameEditText.getText().toString(); String newUrl = urlEditText.getText().toString(); @@ -443,7 +453,7 @@ public class EditBookmarkDatabaseViewDialog extends DialogFragment { boolean folderChanged = newFolderDatabaseId != currentFolderDatabaseId; // Has the display order changed? - boolean displayOrderChanged = !newDisplayOrder.equals(currentDisplayOrder); + boolean displayOrderChanged = !newDisplayOrder.equals(String.valueOf(currentDisplayOrder)); // Is the display order empty? boolean displayOrderNotEmpty = !newDisplayOrder.isEmpty(); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDialog.java index 6eddfc94..daeb1d64 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDialog.java @@ -46,19 +46,15 @@ import com.stoutner.privacybrowser.R; import com.stoutner.privacybrowser.activities.MainWebViewActivity; import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; +import java.io.ByteArrayOutputStream; + public class EditBookmarkDialog extends DialogFragment { - // Instantiate the class variables. + // Define the edit bookmark listener. private EditBookmarkListener editBookmarkListener; - private EditText nameEditText; - private EditText urlEditText; - private RadioButton newIconRadioButton; - private Button editButton; - private String currentName; - private String currentUrl; // The public interface is used to send information back to the parent activity. public interface EditBookmarkListener { - void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId); + void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, Bitmap favoriteIconBitmap); } public void onAttach(Context context) { @@ -70,16 +66,28 @@ public class EditBookmarkDialog extends DialogFragment { } // Store the database ID in the arguments bundle. - public static EditBookmarkDialog bookmarkDatabaseId(int databaseId) { - // Create a bundle. - Bundle bundle = new Bundle(); + public static EditBookmarkDialog bookmarkDatabaseId(int databaseId, Bitmap favoriteIconBitmap) { + // Create a favorite icon byte array output stream. + ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG). + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + + // Convert the byte array output stream to a byte array. + byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); + + // Create an arguments bundle. + Bundle argumentsBundle = new Bundle(); - // Store the bookmark database ID in the bundle. - bundle.putInt("Database ID", databaseId); + // Store the variables in the bundle. + argumentsBundle.putInt("database_id", databaseId); + argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray); - // Add the bundle to the dialog. + // Create a new instance of the dialog. EditBookmarkDialog editBookmarkDialog = new EditBookmarkDialog(); - editBookmarkDialog.setArguments(bundle); + + // Add the arguments bundle to the dialog. + editBookmarkDialog.setArguments(argumentsBundle); // Return the new dialog. return editBookmarkDialog; @@ -90,11 +98,23 @@ public class EditBookmarkDialog extends DialogFragment { @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { - // Remove the incorrect lint warning that `getInt()` might be null. - assert getArguments() != null; + // Get the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning below that the arguments might be null. + assert arguments != null; // Store the bookmark database ID in the class variable. - int selectedBookmarkDatabaseId = getArguments().getInt("Database ID"); + int selectedBookmarkDatabaseId = arguments.getInt("database_id"); + + // Get the favorite icon byte array. + byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array"); + + // Remove the incorrect lint warning below 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); // Initialize the database helper. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`. BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); @@ -130,7 +150,7 @@ public class EditBookmarkDialog extends DialogFragment { // Set the save button listener. dialogBuilder.setPositiveButton(R.string.save, (DialogInterface dialog, int which) -> { // Return the dialog fragment to the parent activity. - editBookmarkListener.onSaveBookmark(EditBookmarkDialog.this, selectedBookmarkDatabaseId); + editBookmarkListener.onSaveBookmark(this, selectedBookmarkDatabaseId, favoriteIconBitmap); }); // Create an alert dialog from the builder. @@ -151,10 +171,9 @@ public class EditBookmarkDialog extends DialogFragment { RadioGroup iconRadioGroup = alertDialog.findViewById(R.id.edit_bookmark_icon_radiogroup); ImageView currentIconImageView = alertDialog.findViewById(R.id.edit_bookmark_current_icon); ImageView newFavoriteIconImageView = alertDialog.findViewById(R.id.edit_bookmark_webpage_favorite_icon); - newIconRadioButton = alertDialog.findViewById(R.id.edit_bookmark_webpage_favorite_icon_radiobutton); - nameEditText = alertDialog.findViewById(R.id.edit_bookmark_name_edittext); - urlEditText = alertDialog.findViewById(R.id.edit_bookmark_url_edittext); - editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + EditText nameEditText = alertDialog.findViewById(R.id.edit_bookmark_name_edittext); + EditText urlEditText = alertDialog.findViewById(R.id.edit_bookmark_url_edittext); + Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); // Get the current favorite icon byte array from the cursor. byte[] currentIconByteArray = bookmarkCursor.getBlob(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON)); @@ -165,20 +184,12 @@ public class EditBookmarkDialog extends DialogFragment { // Display the current icon bitmap. currentIconImageView.setImageBitmap(currentIconBitmap); - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIconBitmap.getHeight() > 256) || (favoriteIconBitmap.getWidth() > 256)) { - favoriteIconBitmap = Bitmap.createScaledBitmap(favoriteIconBitmap, 256, 256, true); - } - // Set the new favorite icon bitmap. newFavoriteIconImageView.setImageBitmap(favoriteIconBitmap); // Store the current bookmark name and URL. - currentName = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); - currentUrl = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL)); + String currentName = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); + String currentUrl = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL)); // Populate the edit texts. nameEditText.setText(currentName); @@ -190,7 +201,7 @@ public class EditBookmarkDialog extends DialogFragment { // Update the edit button if the icon selection changes. iconRadioGroup.setOnCheckedChangeListener((RadioGroup group, int checkedId) -> { // Update the edit button. - updateEditButton(); + updateEditButton(alertDialog, currentName, currentUrl); }); // Update the edit button if the bookmark name changes. @@ -208,7 +219,7 @@ public class EditBookmarkDialog extends DialogFragment { @Override public void afterTextChanged(Editable s) { // Update the edit button. - updateEditButton(); + updateEditButton(alertDialog, currentName, currentUrl); } }); @@ -227,7 +238,7 @@ public class EditBookmarkDialog extends DialogFragment { @Override public void afterTextChanged(Editable s) { // Update the edit button. - updateEditButton(); + updateEditButton(alertDialog, currentName, currentUrl); } }); @@ -236,7 +247,7 @@ public class EditBookmarkDialog extends DialogFragment { // Save the bookmark if the event is a key-down on the "enter" button. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled. // Trigger the `Listener` and return the `DialogFragment` to the parent activity. - editBookmarkListener.onSaveBookmark(EditBookmarkDialog.this, selectedBookmarkDatabaseId); + editBookmarkListener.onSaveBookmark(this, selectedBookmarkDatabaseId, favoriteIconBitmap); // Manually dismiss `alertDialog`. alertDialog.dismiss(); @@ -253,7 +264,7 @@ public class EditBookmarkDialog extends DialogFragment { // Save the bookmark if the event is a key-down on the "enter" button. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled. // Trigger the `Listener` and return the DialogFragment to the parent activity. - editBookmarkListener.onSaveBookmark(EditBookmarkDialog.this, selectedBookmarkDatabaseId); + editBookmarkListener.onSaveBookmark(this, selectedBookmarkDatabaseId, favoriteIconBitmap); // Manually dismiss the alert dialog. alertDialog.dismiss(); @@ -269,8 +280,14 @@ public class EditBookmarkDialog extends DialogFragment { return alertDialog; } - private void updateEditButton() { - // Get the text from the `EditTexts`. + private void updateEditButton(AlertDialog alertdialog, String currentName, String currentUrl) { + // Get handles for the views. + EditText nameEditText = alertdialog.findViewById(R.id.edit_bookmark_name_edittext); + EditText urlEditText = alertdialog.findViewById(R.id.edit_bookmark_url_edittext); + RadioButton newIconRadioButton = alertdialog.findViewById(R.id.edit_bookmark_webpage_favorite_icon_radiobutton); + Button editButton = alertdialog.getButton(AlertDialog.BUTTON_POSITIVE); + + // Get the text from the edit texts. String newName = nameEditText.getText().toString(); String newUrl = urlEditText.getText().toString(); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java index bb02fda2..5033ece8 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java @@ -33,6 +33,7 @@ import android.graphics.BitmapFactory; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; +import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.WindowManager; @@ -54,26 +55,19 @@ import com.stoutner.privacybrowser.R; import com.stoutner.privacybrowser.activities.MainWebViewActivity; import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; +import java.io.ByteArrayOutputStream; + public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { - // Instantiate the constants. + // Define the home folder database ID constant. public static final int HOME_FOLDER_DATABASE_ID = -1; - // Instantiate the class variables. + // Define the edit bookmark folder database view listener. private EditBookmarkFolderDatabaseViewListener editBookmarkFolderDatabaseViewListener; - private BookmarksDatabaseHelper bookmarksDatabaseHelper; - private StringBuilder exceptFolders; - private String currentFolderName; - private int currentParentFolderDatabaseId; - private String currentDisplayOrder; - private RadioButton currentIconRadioButton; - private EditText nameEditText; - private Spinner folderSpinner; - private EditText displayOrderEditText; - private Button editButton; + // The public interface is used to send information back to the parent activity. public interface EditBookmarkFolderDatabaseViewListener { - void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId); + void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId, Bitmap favoriteIconBitmap); } public void onAttach(Context context) { @@ -84,17 +78,29 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { editBookmarkFolderDatabaseViewListener = (EditBookmarkFolderDatabaseViewListener) context; } - // Store the database ID in the arguments bundle. - public static EditBookmarkFolderDatabaseViewDialog folderDatabaseId(int databaseId) { - // Create a bundle. - Bundle bundle = new Bundle(); - // Store the bookmark database ID in the bundle. - bundle.putInt("Database ID", databaseId); + public static EditBookmarkFolderDatabaseViewDialog folderDatabaseId(int databaseId, Bitmap favoriteIconBitmap) { + // Create a favorite icon byte array output stream. + ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG). + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + + // Convert the byte array output stream to a byte array. + byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); + + // Create an arguments bundle. + Bundle argumentsBundle = new Bundle(); + + // Store the variables in the bundle. + argumentsBundle.putInt("database_id", databaseId); + argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray); - // Add the bundle to the dialog. + // Create a new instance of the dialog. EditBookmarkFolderDatabaseViewDialog editBookmarkFolderDatabaseViewDialog = new EditBookmarkFolderDatabaseViewDialog(); - editBookmarkFolderDatabaseViewDialog.setArguments(bundle); + + // Add the arguments bundle to the dialog. + editBookmarkFolderDatabaseViewDialog.setArguments(argumentsBundle); // Return the new dialog. return editBookmarkFolderDatabaseViewDialog; @@ -105,14 +111,26 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { - // Remove the incorrect lint warning that `getInt()` might be null. - assert getArguments() != null; + // Get the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning below that the arguments might be null. + assert arguments != null; // Get the bookmark database ID from the bundle. - int folderDatabaseId = getArguments().getInt("Database ID"); + int folderDatabaseId = getArguments().getInt("database_id"); + + // Get the favorite icon byte array. + byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array"); + + // Remove the incorrect lint warning below 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); - // Initialize the database helper. The two `nulls` do not specify the database name or a `CursorFactory`. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`. - bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); + // Initialize the database helper. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`. + BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); // Get a `Cursor` with the selected bookmark and move it to the first position. Cursor folderCursor = bookmarksDatabaseHelper.getBookmark(folderDatabaseId); @@ -145,7 +163,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { // Set the listener fo the positive button. dialogBuilder.setPositiveButton(R.string.save, (DialogInterface dialog, int which) -> { // Return the `DialogFragment` to the parent activity on save. - editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(EditBookmarkFolderDatabaseViewDialog.this, folderDatabaseId); + editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(this, folderDatabaseId, favoriteIconBitmap); }); // Create an alert dialog from the alert dialog builder. @@ -167,15 +185,14 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { RadioGroup iconRadioGroup = alertDialog.findViewById(R.id.edit_folder_icon_radiogroup); ImageView currentIconImageView = alertDialog.findViewById(R.id.edit_folder_current_icon_imageview); ImageView newFavoriteIconImageView = alertDialog.findViewById(R.id.edit_folder_webpage_favorite_icon_imageview); - currentIconRadioButton = alertDialog.findViewById(R.id.edit_folder_current_icon_radiobutton); - nameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext); - folderSpinner = alertDialog.findViewById(R.id.edit_folder_parent_folder_spinner); - displayOrderEditText = alertDialog.findViewById(R.id.edit_folder_display_order_edittext); - editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + EditText nameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext); + Spinner folderSpinner = alertDialog.findViewById(R.id.edit_folder_parent_folder_spinner); + EditText displayOrderEditText = alertDialog.findViewById(R.id.edit_folder_display_order_edittext); + Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); // Store the current folder values. - currentFolderName = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); - currentDisplayOrder = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)); + String currentFolderName = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); + int currentDisplayOrder = folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)); String parentFolder = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER)); // Set the database ID. @@ -190,14 +207,6 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { // Display the current icon bitmap in `edit_bookmark_current_icon`. currentIconImageView.setImageBitmap(currentIconBitmap); - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIconBitmap.getHeight() > 256) || (favoriteIconBitmap.getWidth() > 256)) { - favoriteIconBitmap = Bitmap.createScaledBitmap(favoriteIconBitmap, 256, 256, true); - } - // Set the new favorite icon bitmap. newFavoriteIconImageView.setImageBitmap(favoriteIconBitmap); @@ -209,14 +218,13 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { MatrixCursor matrixCursor = new MatrixCursor(matrixCursorColumnNames); matrixCursor.addRow(new Object[]{HOME_FOLDER_DATABASE_ID, getString(R.string.home_folder)}); - // Initialize a string builder to track the folders not to display in the spinner and populate it with the current folder. - exceptFolders = new StringBuilder(DatabaseUtils.sqlEscapeString(currentFolderName)); - // Add all subfolders of the current folder to the list of folders not to display. - addSubfoldersToExceptFolders(currentFolderName); + String exceptFolders = getStringOfSubfolders(currentFolderName, bookmarksDatabaseHelper); + + Log.i("Folders", "String of Folders Not To Display: " + exceptFolders); // Get a cursor with the list of all the folders. - Cursor foldersCursor = bookmarksDatabaseHelper.getFoldersExcept(exceptFolders.toString()); + Cursor foldersCursor = bookmarksDatabaseHelper.getFoldersExcept(exceptFolders); // Combine the matrix cursor and the folders cursor. MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{matrixCursor, foldersCursor}); @@ -284,7 +292,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { } // Store the current folder database ID. - currentParentFolderDatabaseId = (int) folderSpinner.getSelectedItemId(); + int currentParentFolderDatabaseId = (int) folderSpinner.getSelectedItemId(); // Populate the display order `EditText`. displayOrderEditText.setText(String.valueOf(folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)))); @@ -295,7 +303,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { // Update the edit button if the icon selection changes. iconRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { // Update the edit button. - updateEditButton(); + updateEditButton(alertDialog, bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder); }); // Update the edit button if the bookmark name changes. @@ -313,7 +321,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { @Override public void afterTextChanged(Editable s) { // Update the edit button. - updateEditButton(); + updateEditButton(alertDialog, bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder); } }); @@ -322,7 +330,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { // Update the edit button. - updateEditButton(); + updateEditButton(alertDialog, bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder); } @Override @@ -346,7 +354,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { @Override public void afterTextChanged(Editable s) { // Update the edit button. - updateEditButton(); + updateEditButton(alertDialog, bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder); } }); @@ -355,7 +363,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { // Save the bookmark if the event is a key-down on the "enter" button. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled. // Trigger the `Listener` and return the `DialogFragment` to the parent activity. - editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(EditBookmarkFolderDatabaseViewDialog.this, folderDatabaseId); + editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(this, folderDatabaseId, favoriteIconBitmap); // Manually dismiss `alertDialog`. alertDialog.dismiss(); @@ -372,7 +380,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { // Save the bookmark if the event is a key-down on the "enter" button. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled. // Trigger the `Listener` and return the `DialogFragment` to the parent activity. - editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(EditBookmarkFolderDatabaseViewDialog.this, folderDatabaseId); + editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(this, folderDatabaseId, favoriteIconBitmap); // Manually dismiss the `AlertDialog`. alertDialog.dismiss(); @@ -388,7 +396,14 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { return alertDialog; } - private void updateEditButton() { + private void updateEditButton(AlertDialog alertDialog, BookmarksDatabaseHelper bookmarksDatabaseHelper, String currentFolderName, int currentParentFolderDatabaseId, int currentDisplayOrder) { + // Get handles for the views. + EditText nameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext); + Spinner folderSpinner = alertDialog.findViewById(R.id.edit_folder_parent_folder_spinner); + EditText displayOrderEditText = alertDialog.findViewById(R.id.edit_folder_display_order_edittext); + RadioButton currentIconRadioButton = alertDialog.findViewById(R.id.edit_folder_current_icon_radiobutton); + Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + // Get the values from the dialog. String newFolderName = nameEditText.getText().toString(); int newParentFolderDatabaseId = (int) folderSpinner.getSelectedItemId(); @@ -413,7 +428,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { boolean parentFolderChanged = newParentFolderDatabaseId != currentParentFolderDatabaseId; // Has the display order changed? - boolean displayOrderChanged = !newDisplayOrder.equals(currentDisplayOrder); + boolean displayOrderChanged = !newDisplayOrder.equals(String.valueOf(currentDisplayOrder)); // Is the display order empty? boolean displayOrderNotEmpty = !newDisplayOrder.isEmpty(); @@ -422,23 +437,31 @@ public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment { editButton.setEnabled((iconChanged || folderRenamed || parentFolderChanged || displayOrderChanged) && folderNameNotEmpty && displayOrderNotEmpty); } - private void addSubfoldersToExceptFolders(String folderName) { - // Get a `Cursor` will all the immediate subfolders. + private String getStringOfSubfolders(String folderName, BookmarksDatabaseHelper bookmarksDatabaseHelper) { + // Get a cursor will all the immediate subfolders. Cursor subfoldersCursor = bookmarksDatabaseHelper.getSubfolders(folderName); + // Initialize a string builder to track the folders not to display in the spinner and populate it with the current folder. + StringBuilder exceptFoldersStringBuilder = new StringBuilder(DatabaseUtils.sqlEscapeString(folderName)); + for (int i = 0; i < subfoldersCursor.getCount(); i++) { - // Move `subfolderCursor` to the current item. + // Move the subfolder cursor to the current item. subfoldersCursor.moveToPosition(i); // Get the name of the subfolder. String subfolderName = subfoldersCursor.getString(subfoldersCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); - // Add the subfolder to `exceptFolders`. - exceptFolders.append(","); - exceptFolders.append(DatabaseUtils.sqlEscapeString(subfolderName)); + // Add a comma to the end of the existing string. + exceptFoldersStringBuilder.append(","); - // Run the same tasks for any subfolders of the subfolder. - addSubfoldersToExceptFolders(subfolderName); + // Get the folder name and run the task for any subfolders. + String subfolderString = getStringOfSubfolders(subfolderName, bookmarksDatabaseHelper); + + // Add the folder name to the string builder. + exceptFoldersStringBuilder.append(subfolderString); } + + // Return the string of folders. + return exceptFoldersStringBuilder.toString(); } } \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDialog.java index 984cdee1..4e606f0d 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDialog.java @@ -46,13 +46,15 @@ import com.stoutner.privacybrowser.R; import com.stoutner.privacybrowser.activities.MainWebViewActivity; import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; +import java.io.ByteArrayOutputStream; + public class EditBookmarkFolderDialog extends DialogFragment { // Instantiate the class variable. private EditBookmarkFolderListener editBookmarkFolderListener; // The public interface is used to send information back to the parent activity. public interface EditBookmarkFolderListener { - void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId); + void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId, Bitmap favoriteIconBitmap); } public void onAttach(Context context) { @@ -64,16 +66,28 @@ public class EditBookmarkFolderDialog extends DialogFragment { } // Store the database ID in the arguments bundle. - public static EditBookmarkFolderDialog folderDatabaseId(int databaseId) { - // Create a bundle - Bundle bundle = new Bundle(); + public static EditBookmarkFolderDialog folderDatabaseId(int databaseId, Bitmap favoriteIconBitmap) { + // Create a favorite icon byte array output stream. + ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG). + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + + // Convert the byte array output stream to a byte array. + byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); - // Store the folder database ID in the bundle. - bundle.putInt("Database ID", databaseId); + // Create an arguments bundle + Bundle argumentsBundle = new Bundle(); - // Add the bundle to the dialog. + // Store the variables in the bundle. + argumentsBundle.putInt("database_id", databaseId); + argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray); + + // Create a new instance of the dialog. EditBookmarkFolderDialog editBookmarkFolderDialog = new EditBookmarkFolderDialog(); - editBookmarkFolderDialog.setArguments(bundle); + + // Add the arguments bundle to the dialog. + editBookmarkFolderDialog.setArguments(argumentsBundle); // Return the new dialog. return editBookmarkFolderDialog; @@ -84,14 +98,26 @@ public class EditBookmarkFolderDialog extends DialogFragment { @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { - // Remove the incorrect lint warning that `getInt()` might be null. - assert getArguments() != null; + // Get the arguments. + Bundle arguments = getArguments(); + + // Remove the incorrect lint warning below that the arguments might be null. + assert arguments != null; // Store the folder database ID in the class variable. - int selectedFolderDatabaseId = getArguments().getInt("Database ID"); + int selectedFolderDatabaseId = arguments.getInt("database_id"); + + // Get the favorite icon byte array. + byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array"); + + // Remove the incorrect lint warning below 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); // Initialize the database helper. The two `nulls` do not specify the database name or a `CursorFactory`. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`. - final BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); + BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); // Get a cursor with the selected folder and move it to the first position. Cursor folderCursor = bookmarksDatabaseHelper.getBookmark(selectedFolderDatabaseId); @@ -124,11 +150,11 @@ public class EditBookmarkFolderDialog extends DialogFragment { // Set the listener fo the positive button. dialogBuilder.setPositiveButton(R.string.save, (DialogInterface dialog, int which) -> { // Return the `DialogFragment` to the parent activity on save. - editBookmarkFolderListener.onSaveBookmarkFolder(EditBookmarkFolderDialog.this, selectedFolderDatabaseId); + editBookmarkFolderListener.onSaveBookmarkFolder(this, selectedFolderDatabaseId, favoriteIconBitmap); }); // Create an alert dialog from the alert dialog builder. - final AlertDialog alertDialog = dialogBuilder.create(); + AlertDialog alertDialog = dialogBuilder.create(); // Remove the warning below that `getWindow()` might be null. assert alertDialog.getWindow() != null; @@ -143,11 +169,11 @@ public class EditBookmarkFolderDialog extends DialogFragment { // Get handles for the views in the alert dialog. RadioGroup iconRadioGroup = alertDialog.findViewById(R.id.edit_folder_icon_radio_group); - final RadioButton currentIconRadioButton = alertDialog.findViewById(R.id.edit_folder_current_icon_radiobutton); + RadioButton currentIconRadioButton = alertDialog.findViewById(R.id.edit_folder_current_icon_radiobutton); ImageView currentIconImageView = alertDialog.findViewById(R.id.edit_folder_current_icon_imageview); ImageView webPageFavoriteIconImageView = alertDialog.findViewById(R.id.edit_folder_web_page_favorite_icon_imageview); - final EditText folderNameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext); - final Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); + EditText folderNameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext); + Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); // Initially disable the edit button. editButton.setEnabled(false); @@ -161,19 +187,11 @@ public class EditBookmarkFolderDialog extends DialogFragment { // Display the current icon bitmap. currentIconImageView.setImageBitmap(currentIconBitmap); - // Get a copy of the favorite icon bitmap. - Bitmap favoriteIconBitmap = MainWebViewActivity.favoriteIconBitmap; - - // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. - if ((favoriteIconBitmap.getHeight() > 256) || (favoriteIconBitmap.getWidth() > 256)) { - favoriteIconBitmap = Bitmap.createScaledBitmap(favoriteIconBitmap, 256, 256, true); - } - // Set the new favorite icon bitmap. webPageFavoriteIconImageView.setImageBitmap(favoriteIconBitmap); // Get the current folder name. - final String currentFolderName = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); + String currentFolderName = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)); // Display the current folder name in `edit_folder_name_edittext`. folderNameEditText.setText(currentFolderName); @@ -244,7 +262,7 @@ public class EditBookmarkFolderDialog extends DialogFragment { // If the event is a key-down on the "enter" button, select the PositiveButton `Save`. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled. // Trigger `editBookmarkListener` and return the DialogFragment to the parent activity. - editBookmarkFolderListener.onSaveBookmarkFolder(EditBookmarkFolderDialog.this, selectedFolderDatabaseId); + editBookmarkFolderListener.onSaveBookmarkFolder(this, selectedFolderDatabaseId, favoriteIconBitmap); // Manually dismiss the `AlertDialog`. alertDialog.dismiss(); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java index c8a0a788..25dd5412 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/PinnedMismatchDialog.java @@ -24,6 +24,8 @@ import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -46,11 +48,13 @@ import com.stoutner.privacybrowser.views.NestedScrollWebView; import com.stoutner.privacybrowser.views.WrapVerticalContentViewPager; import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper; +import java.io.ByteArrayOutputStream; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.fragment.app.DialogFragment; // The AndroidX dialog fragment must be used or an error is produced on API <=22. import androidx.viewpager.widget.PagerAdapter; @@ -83,12 +87,22 @@ public class PinnedMismatchDialog extends DialogFragment { pinnedMismatchListener = (PinnedMismatchListener) context; } - public static PinnedMismatchDialog displayDialog(long webViewFragmentId) { + public static PinnedMismatchDialog displayDialog(long webViewFragmentId, Bitmap favoriteIconBitmap) { + // Create a favorite icon byte array output stream. + ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG). + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + + // Convert the byte array output stream to a byte array. + byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); + // Create an arguments bundle. Bundle argumentsBundle = new Bundle(); - // Store the WebView position in the bundle. + // Store the variables in the bundle. argumentsBundle.putLong("webview_fragment_id", webViewFragmentId); + argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray); // Create a new instance of the pinned mismatch dialog. PinnedMismatchDialog pinnedMismatchDialog = new PinnedMismatchDialog(); @@ -105,11 +119,23 @@ public class PinnedMismatchDialog extends DialogFragment { @Override @NonNull public Dialog onCreateDialog(Bundle savedInstanceState) { + // Get the arguments. + Bundle arguments = getArguments(); + // Remove the incorrect lint warning below that `.getArguments().getInt()` might be null. - assert getArguments() != null; + assert arguments != null; // Get the current position of this WebView fragment. - int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(getArguments().getLong("webview_fragment_id")); + int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(arguments.getLong("webview_fragment_id")); + + // Get the favorite icon byte array. + byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array"); + + // Remove the incorrect lint warning below 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); // Get the WebView tab fragment. WebViewTabFragment webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition); @@ -135,8 +161,26 @@ public class PinnedMismatchDialog extends DialogFragment { dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight); } + // Get the context. + Context context = getContext(); + + // Remove the incorrect lint warning below that the context might be null. + assert context != null; + + // Get the default favorite icon drawable. `ContextCompat` must be used until API >= 21. + Drawable defaultFavoriteIconDrawable = ContextCompat.getDrawable(context, R.drawable.world); + + // Cast the favorite icon drawable to a bitmap drawable. + BitmapDrawable defaultFavoriteIconBitmapDrawable = (BitmapDrawable) defaultFavoriteIconDrawable; + + // Remove the incorrect warning below that the favorite icon bitmap drawable might be null. + assert defaultFavoriteIconBitmapDrawable != null; + + // Store the default icon bitmap. + Bitmap defaultFavoriteIconBitmap = defaultFavoriteIconBitmapDrawable.getBitmap(); + // Set the favorite icon as the dialog icon if it exists. - if (MainWebViewActivity.favoriteIconBitmap.equals(MainWebViewActivity.favoriteIconDefaultBitmap)) { // There is no favorite icon. + if (favoriteIconBitmap.sameAs(defaultFavoriteIconBitmap)) { // There is no website favorite icon. // Set the icon according to the theme. if (MainWebViewActivity.darkTheme) { dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_dark); @@ -145,7 +189,7 @@ public class PinnedMismatchDialog extends DialogFragment { } } else { // There is a favorite icon. // Create a drawable version of the favorite icon. - Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIconBitmap); + Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), favoriteIconBitmap); // Set the icon. dialogBuilder.setIcon(favoriteIconDrawable); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewRequestDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewRequestDialog.java index fd8d68e1..87719ea0 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewRequestDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewRequestDialog.java @@ -62,9 +62,9 @@ public class ViewRequestDialog extends DialogFragment { Bundle bundle = new Bundle(); // Store the request details. - bundle.putInt("ID", id); - bundle.putBoolean("Is Last Request", isLastRequest); - bundle.putStringArray("Request Details", requestDetails); + bundle.putInt("id", id); + bundle.putBoolean("is_last_request", isLastRequest); + bundle.putStringArray("request_details", requestDetails); // Add the bundle to the dialog. ViewRequestDialog viewRequestDialog = new ViewRequestDialog(); @@ -90,9 +90,9 @@ public class ViewRequestDialog extends DialogFragment { assert getArguments() != null; // Get the info from the bundle. - int id = getArguments().getInt("ID"); - boolean isLastRequest = getArguments().getBoolean("Is Last Request"); - String[] requestDetails = getArguments().getStringArray("Request Details"); + int id = getArguments().getInt("id"); + boolean isLastRequest = getArguments().getBoolean("is_last_request"); + String[] requestDetails = getArguments().getStringArray("request_details"); // Use an alert dialog builder to create the alert dialog. AlertDialog.Builder dialogBuilder; diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.java index d1ff91c2..5004f231 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.java @@ -22,6 +22,8 @@ package com.stoutner.privacybrowser.dialogs; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -43,6 +45,7 @@ import com.stoutner.privacybrowser.R; import com.stoutner.privacybrowser.fragments.WebViewTabFragment; import com.stoutner.privacybrowser.views.NestedScrollWebView; +import java.io.ByteArrayOutputStream; import java.text.DateFormat; import java.util.Calendar; import java.util.Date; @@ -50,12 +53,22 @@ import java.util.Date; // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. @SuppressLint("InflateParams") public class ViewSslCertificateDialog extends DialogFragment { - public static ViewSslCertificateDialog displayDialog(long webViewFragmentId) { + public static ViewSslCertificateDialog displayDialog(long webViewFragmentId, Bitmap favoriteIconBitmap) { + // Create a favorite icon byte array output stream. + ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG). + favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream); + + // Convert the byte array output stream to a byte array. + byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray(); + // Create an arguments bundle. Bundle argumentsBundle = new Bundle(); - // Store the WebView fragment ID in the bundle. + // Store the variables in the bundle. argumentsBundle.putLong("webview_fragment_id", webViewFragmentId); + argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray); // Create a new instance of the dialog. ViewSslCertificateDialog viewSslCertificateDialog = new ViewSslCertificateDialog(); @@ -75,11 +88,23 @@ public class ViewSslCertificateDialog extends DialogFragment { // Get the activity's layout inflater. LayoutInflater layoutInflater = getActivity().getLayoutInflater(); + // Get the arguments. + Bundle arguments = getArguments(); + // Remove the incorrect lint warning below that `getArguments().getLong()` might be null. - assert getArguments() != null; + assert arguments != null; + + // Get the favorite icon byte array. + byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array"); + + // Remove the incorrect lint warning below 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); // Get the current position of this WebView fragment. - int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(getArguments().getLong("webview_fragment_id")); + int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(arguments.getLong("webview_fragment_id")); // Get the WebView tab fragment. WebViewTabFragment webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition); @@ -104,7 +129,7 @@ public class ViewSslCertificateDialog extends DialogFragment { } // Create a drawable version of the favorite icon. - Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIconBitmap); + Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), favoriteIconBitmap); // Set the icon. dialogBuilder.setIcon(favoriteIconDrawable); diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/CheckPinnedMismatchHelper.java b/app/src/main/java/com/stoutner/privacybrowser/helpers/CheckPinnedMismatchHelper.java index 25d84144..48bf73bd 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/CheckPinnedMismatchHelper.java +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/CheckPinnedMismatchHelper.java @@ -121,7 +121,7 @@ public class CheckPinnedMismatchHelper { !currentWebsiteSslEndDateString.equals(pinnedSslEndDateString)))) { // Get a handle for the pinned mismatch alert dialog. - DialogFragment pinnedMismatchDialogFragment = PinnedMismatchDialog.displayDialog(nestedScrollWebView.getWebViewFragmentId()); + DialogFragment pinnedMismatchDialogFragment = PinnedMismatchDialog.displayDialog(nestedScrollWebView.getWebViewFragmentId(), nestedScrollWebView.getFavoriteOrDefaultIcon()); // Show the pinned mismatch alert dialog. pinnedMismatchDialogFragment.show(fragmentManager, "Pinned Mismatch"); diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java index f7d57b68..ca93d6fb 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java +++ b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.java @@ -20,11 +20,17 @@ package com.stoutner.privacybrowser.views; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.webkit.WebView; +import com.stoutner.privacybrowser.R; + import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.core.view.NestedScrollingChild2; import androidx.core.view.NestedScrollingChildHelper; import androidx.core.view.ViewCompat; @@ -91,6 +97,9 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild // The ignore pinned domain information tracker. This is set when a user proceeds past a pinned mismatch dialog to prevent the dialog from showing again until after the domain changes. private boolean ignorePinnedDomainInformation; + // The default or favorite icon. + Bitmap favoriteOrDefaultIcon; + // The nested scrolling child helper is used throughout the class. private NestedScrollingChildHelper nestedScrollingChildHelper; @@ -479,6 +488,37 @@ public class NestedScrollWebView extends WebView implements NestedScrollingChild } + // Favorite or default icon. + public void initializeFavoriteIcon() { + // Get the default favorite icon drawable. `ContextCompat` must be used until API >= 21. + Drawable favoriteIconDrawable = ContextCompat.getDrawable(getContext(), R.drawable.world); + + // Cast the favorite icon drawable to a bitmap drawable. + BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable; + + // Remove the incorrect warning below that the favorite icon bitmap drawable might be null. + assert favoriteIconBitmapDrawable != null; + + // Store the default icon bitmap. + favoriteOrDefaultIcon = favoriteIconBitmapDrawable.getBitmap(); + } + + public void setFavoriteOrDefaultIcon(Bitmap icon) { + // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation. + if ((icon.getHeight() > 256) || (icon.getWidth() > 256)) { + favoriteOrDefaultIcon = Bitmap.createScaledBitmap(icon, 256, 256, true); + } else { + // Store the icon as presented. + favoriteOrDefaultIcon = icon; + } + } + + public Bitmap getFavoriteOrDefaultIcon() { + // Return the favorite or default icon. + return favoriteOrDefaultIcon; + } + + @Override public boolean onTouchEvent(MotionEvent motionEvent) {