From: Soren Stoutner Date: Wed, 26 Oct 2022 23:43:12 +0000 (-0700) Subject: Convert all the fragments to Kotlin. https://redmine.stoutner.com/issues/882 X-Git-Tag: v3.12~16 X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=commitdiff_plain;h=f3a2827543d388de53b27a124663c5f84af764c9 Convert all the fragments to Kotlin. https://redmine.stoutner.com/issues/882 --- 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 905a98d0..d7137e20 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2022 Soren Stoutner . + * Copyright 2016-2022 Soren Stoutner . * * This file is part of Privacy Browser Android . * @@ -48,6 +48,7 @@ import android.widget.ListView; import android.widget.RadioButton; import android.widget.TextView; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; @@ -83,9 +84,10 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma private MenuItem moveBookmarkUpMenuItem; private MenuItem moveBookmarkDownMenuItem; - // `bookmarksDatabaseHelper` is used in `onCreate()`, `onOptionsItemSelected()`, `onBackPressed()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveBookmark()`, `onSaveBookmarkFolder()`, - // `onMoveToFolder()`, `deleteBookmarkFolderContents()`, `loadFolder()`, and `onDestroy()`. + // Declare the class variables. private BookmarksDatabaseHelper bookmarksDatabaseHelper; + private Snackbar bookmarksDeletedSnackbar; + private boolean closeActivityAfterDismissingSnackbar; // `bookmarksListView` is used in `onCreate()`, `onOptionsItemSelected()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveBookmark()`, `onSaveBookmarkFolder()`, `onMoveToFolder()`, // `updateMoveIcons()`, `scrollBookmarks()`, and `loadFolder()`. @@ -107,12 +109,6 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // `oldFolderName` is used in `onCreate()` and `onSaveBookmarkFolder()`. private String oldFolderNameString; - // `bookmarksDeletedSnackbar` is used in `onCreate()`, `onOptionsItemSelected()`, and `onBackPressed()`. - private Snackbar bookmarksDeletedSnackbar; - - // `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; @@ -184,6 +180,18 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Display the home arrow on the app bar. appBar.setDisplayHomeAsUpEnabled(true); + // Control what the system back command does. + OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + // Prepare to finish the activity. + prepareFinish(); + } + }; + + // Register the on back pressed callback. + getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback); + // Initialize the database helper. bookmarksDatabaseHelper = new BookmarksDatabaseHelper(this); @@ -554,7 +562,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Close the activity if back has been pressed. if (closeActivityAfterDismissingSnackbar) { - onBackPressed(); + finish(); } } }); @@ -687,8 +695,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Run the command according to the selected option. if (menuItemId == android.R.id.home) { // Home. The home arrow is identified as `android.R.id.home`, not just `R.id.home`. if (currentFolder.isEmpty()) { // Currently in the home folder. - // Run the back commands. - onBackPressed(); + // Prepare to finish the activity. + prepareFinish(); } else { // Currently in a subfolder. // Place the former parent folder in `currentFolder`. currentFolder = bookmarksDatabaseHelper.getParentFolderName(currentFolder); @@ -722,27 +730,6 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma return true; } - @Override - public void onBackPressed() { - // Check to see if a snackbar is currently displayed. If so, it must be closed before exiting so that a pending delete is completed before reloading the list view in the bookmarks drawer. - if ((bookmarksDeletedSnackbar != null) && bookmarksDeletedSnackbar.isShown()) { // Close the bookmarks deleted snackbar before going home. - // Set the close flag. - closeActivityAfterDismissingSnackbar = true; - - // Dismiss the snackbar. - bookmarksDeletedSnackbar.dismiss(); - } else { // Go home immediately. - // Update the bookmarks folder for the bookmarks drawer in the main WebView activity. - MainWebViewActivity.currentBookmarksFolder = currentFolder; - - // Close the bookmarks drawer and reload the bookmarks ListView when returning to the main WebView activity. - MainWebViewActivity.restartFromBookmarksActivity = true; - - // Exit the bookmarks activity. - super.onBackPressed(); - } - } - @Override public void onCreateBookmark(DialogFragment dialogFragment, Bitmap favoriteIconBitmap) { // Get the alert dialog from the fragment. @@ -1094,6 +1081,26 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma } } + private void prepareFinish() { + // Check to see if a snackbar is currently displayed. If so, it must be closed before exiting so that a pending delete is completed before reloading the list view in the bookmarks drawer. + if ((bookmarksDeletedSnackbar != null) && bookmarksDeletedSnackbar.isShown()) { // Close the bookmarks deleted snackbar before going home. + // Set the close flag. + closeActivityAfterDismissingSnackbar = true; + + // Dismiss the snackbar. + bookmarksDeletedSnackbar.dismiss(); + } else { // Go home immediately. + // Update the bookmarks folder for the bookmarks drawer in the main WebView activity. + MainWebViewActivity.currentBookmarksFolder = currentFolder; + + // Close the bookmarks drawer and reload the bookmarks ListView when returning to the main WebView activity. + MainWebViewActivity.restartFromBookmarksActivity = true; + + // Exit the bookmarks activity. + finish(); + } + } + private void updateMoveIcons() { // Get a long array of the selected bookmarks. long[] selectedBookmarksLongArray = bookmarksListView.getCheckedItemIds(); @@ -1214,4 +1221,4 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Run the default commands. super.onDestroy(); } -} \ No newline at end of file +} 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 7452b0bc..da2ceda3 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2022 Soren Stoutner . + * Copyright 2016-2022 Soren Stoutner . * * This file is part of Privacy Browser Android . * @@ -53,6 +53,7 @@ import android.widget.ResourceCursorAdapter; import android.widget.Spinner; import android.widget.TextView; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; @@ -150,6 +151,18 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements actionBar.setCustomView(R.layout.spinner); actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_HOME_AS_UP); + // Control what the system back command does. + OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + // Prepare to finish the activity. + prepareFinish(); + } + }; + + // Register the on back pressed callback. + getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback); + // Initialize the database handler. bookmarksDatabaseHelper = new BookmarksDatabaseHelper(this); @@ -585,7 +598,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements // Close the activity if back has been pressed. if (closeActivityAfterDismissingSnackbar) { - onBackPressed(); + finish(); } } }); @@ -629,8 +642,8 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements // Run the command that corresponds to the selected menu item. if (menuItemId == android.R.id.home) { // Go Home. The home arrow is identified as `android.R.id.home`, not just `R.id.home`. - // Exit the activity. - onBackPressed(); + // Prepare to finish the activity. + prepareFinish(); } else if (menuItemId == R.id.sort) { // Toggle the sort mode. // Update the sort by display order tracker. sortByDisplayOrder = !sortByDisplayOrder; @@ -672,8 +685,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements savedInstanceState.putBoolean(SORT_BY_DISPLAY_ORDER, sortByDisplayOrder); } - @Override - public void onBackPressed() { + private void prepareFinish() { // Check to see if a snackbar is currently displayed. If so, it must be closed before existing so that a pending delete is completed before reloading the list view in the bookmarks activity. if ((bookmarksDeletedSnackbar != null) && bookmarksDeletedSnackbar.isShown()) { // Close the bookmarks deleted snackbar before going home. // Set the close flag. @@ -695,7 +707,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements BookmarksActivity.restartFromBookmarksDatabaseViewActivity = true; // Exit the bookmarks database view activity. - super.onBackPressed(); + finish(); } } @@ -915,4 +927,4 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements // Run the default commands. super.onDestroy(); } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.kt index 2edab552..d15f9aee 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.kt @@ -205,7 +205,7 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DismissSnackbarI addDomainDialog.show(supportFragmentManager, resources.getString(R.string.add_domain)) } - // Control what the navigation bar back button does. + // Control what the system back command does. val onBackPressedCallback: OnBackPressedCallback = object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { if (twoPanedMode) { // The device is in two-paned mode. diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt index 9d9d5d53..75efc825 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright © 2019-2022 Soren Stoutner . + * Copyright 2019-2022 Soren Stoutner . * * This file is part of Privacy Browser Android . * @@ -275,4 +275,4 @@ class LogcatActivity : AppCompatActivity() { // Stop the swipe to refresh animation if it is displayed. swipeRefreshLayout.isRefreshing = false } -} \ No newline at end of file +} 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 db953814..a7cbffb5 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -99,6 +99,7 @@ import android.widget.RadioButton; import android.widget.RelativeLayout; import android.widget.TextView; +import androidx.activity.OnBackPressedCallback; import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; @@ -609,6 +610,48 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Apply the app settings from the shared preferences. applyAppSettings(); + // Control what the system back command does. + OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + // Process the different back options. + if (drawerLayout.isDrawerVisible(GravityCompat.START)) { // The navigation drawer is open. + // Close the navigation drawer. + drawerLayout.closeDrawer(GravityCompat.START); + } else if (drawerLayout.isDrawerVisible(GravityCompat.END)){ // The bookmarks drawer is open. + // close the bookmarks drawer. + drawerLayout.closeDrawer(GravityCompat.END); + } else if (displayingFullScreenVideo) { // A full screen video is shown. + // Exit the full screen video. + exitFullScreenVideo(); + } else if (currentWebView.canGoBack()) { // There is at least one item in the current WebView history. + // Get the current web back forward list. + WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList(); + + // Get the previous entry URL. + String previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() - 1).getUrl(); + + // Apply the domain settings. + applyDomainSettings(currentWebView, previousUrl, false, false, false); + + // Go back. + currentWebView.goBack(); + } else if (tabLayout.getTabCount() > 1) { // There are at least two tabs. + // Close the current tab. + closeCurrentTab(); + } else { // There isn't anything to do in Privacy Browser. + // Close Privacy Browser. `finishAndRemoveTask()` also removes Privacy Browser from the recent app list. + finishAndRemoveTask(); + + // Manually kill Privacy Browser. Otherwise, it is glitchy when restarted. + System.exit(0); + } + } + }; + + // Register the on back pressed callback. + getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback); + // Populate the blocklists. populateBlocklists = new PopulateBlocklists(this, this).execute(); } @@ -2767,43 +2810,6 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook bookmarksCursorAdapter.changeCursor(bookmarksCursor); } - // Override `onBackPressed()` to handle the navigation drawer and and the WebViews. - @Override - public void onBackPressed() { - // Check the different options for processing `back`. - if (drawerLayout.isDrawerVisible(GravityCompat.START)) { // The navigation drawer is open. - // Close the navigation drawer. - drawerLayout.closeDrawer(GravityCompat.START); - } else if (drawerLayout.isDrawerVisible(GravityCompat.END)){ // The bookmarks drawer is open. - // close the bookmarks drawer. - drawerLayout.closeDrawer(GravityCompat.END); - } else if (displayingFullScreenVideo) { // A full screen video is shown. - // Exit the full screen video. - exitFullScreenVideo(); - } else if (currentWebView.canGoBack()) { // There is at least one item in the current WebView history. - // Get the current web back forward list. - WebBackForwardList webBackForwardList = currentWebView.copyBackForwardList(); - - // Get the previous entry URL. - String previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.getCurrentIndex() - 1).getUrl(); - - // Apply the domain settings. - applyDomainSettings(currentWebView, previousUrl, false, false, false); - - // Go back. - currentWebView.goBack(); - } else if (tabLayout.getTabCount() > 1) { // There are at least two tabs. - // Close the current tab. - closeCurrentTab(); - } else { // There isn't anything to do in Privacy Browser. - // Close Privacy Browser. `finishAndRemoveTask()` also removes Privacy Browser from the recent app list. - finishAndRemoveTask(); - - // Manually kill Privacy Browser. Otherwise, it is glitchy when restarted. - System.exit(0); - } - } - // Process the results of a file browse. @Override public void onActivityResult(int requestCode, int resultCode, Intent returnedIntent) { @@ -5090,7 +5096,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook @SuppressLint("ClickableViewAccessibility") @Override - public void initializeWebView(NestedScrollWebView nestedScrollWebView, int pageNumber, ProgressBar progressBar, String url, Boolean restoringState) { + public void initializeWebView(@NonNull NestedScrollWebView nestedScrollWebView, int pageNumber, @NonNull ProgressBar progressBar, @NonNull String url, boolean restoringState) { // Get a handle for the shared preferences. SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); diff --git a/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveAboutVersionImage.java b/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveAboutVersionImage.java index 2fa4f99a..72be3512 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveAboutVersionImage.java +++ b/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveAboutVersionImage.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020-2022 Soren Stoutner . + * Copyright 2020-2022 Soren Stoutner . * * This file is part of Privacy Browser Android . * @@ -168,4 +168,4 @@ public class SaveAboutVersionImage extends AsyncTask { Snackbar.make(aboutVersionLinearLayout, activity.getString(R.string.error_saving_file) + " " + fileCreationDisposition, Snackbar.LENGTH_INDEFINITE).show(); } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveUrl.java b/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveUrl.java index 9d751c41..34fefc47 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveUrl.java +++ b/app/src/main/java/com/stoutner/privacybrowser/asynctasks/SaveUrl.java @@ -1,5 +1,5 @@ /* - * Copyright © 2020-2022 Soren Stoutner . + * Copyright 2020-2022 Soren Stoutner . * * This file is part of Privacy Browser Android . * @@ -285,4 +285,4 @@ public class SaveUrl extends AsyncTask { Snackbar.make(noSwipeViewPager, activity.getString(R.string.error_saving_file) + " " + saveDisposition, Snackbar.LENGTH_INDEFINITE).show(); } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/WebViewTabFragment.java b/app/src/main/java/com/stoutner/privacybrowser/fragments/WebViewTabFragment.java deleted file mode 100644 index bc92bf93..00000000 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/WebViewTabFragment.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright © 2019-2020,2022 Soren Stoutner . - * - * This file is part of Privacy Browser Android . - * - * Privacy Browser Android is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Privacy Browser Android is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Privacy Browser Android. If not, see . - */ - -package com.stoutner.privacybrowser.fragments; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ProgressBar; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; - -import com.stoutner.privacybrowser.R; -import com.stoutner.privacybrowser.views.NestedScrollWebView; - -import java.util.Calendar; - -public class WebViewTabFragment extends Fragment { - // Set a unique ID for this tab based on the time it was created. - public long fragmentId = Calendar.getInstance().getTimeInMillis(); - - // The public interface is used to send information back to the parent activity. - public interface NewTabListener { - void initializeWebView(NestedScrollWebView nestedScrollWebView, int pageNumber, ProgressBar progressBar, String url, Boolean restoringState); - } - - // The new tab listener is used in `onAttach()` and `onCreateView()`. - private NewTabListener newTabListener; - - // Define the bundle constants. - private final static String CREATE_NEW_PAGE = "create_new_page"; - private final static String PAGE_NUMBER = "page_number"; - private final static String URL = "url"; - private final static String SAVED_STATE = "saved_state"; - private final static String SAVED_NESTED_SCROLL_WEBVIEW_STATE = "saved_nested_scroll_webview_state"; - - // Define the class views. - NestedScrollWebView nestedScrollWebView; - - @Override - public void onAttach(@NonNull Context context) { - // Run the default commands. - super.onAttach(context); - - // Get a handle for the new tab listener from the launching context. - newTabListener = (NewTabListener) context; - } - - public static WebViewTabFragment createPage(int pageNumber, String url) { - // Create an arguments bundle. - Bundle argumentsBundle = new Bundle(); - - // Store the argument in the bundle. - argumentsBundle.putBoolean(CREATE_NEW_PAGE, true); - argumentsBundle.putInt(PAGE_NUMBER, pageNumber); - argumentsBundle.putString(URL, url); - - // Create a new instance of the WebView tab fragment. - WebViewTabFragment webViewTabFragment = new WebViewTabFragment(); - - // Add the arguments bundle to the fragment. - webViewTabFragment.setArguments(argumentsBundle); - - // Return the new fragment. - return webViewTabFragment; - } - - public static WebViewTabFragment restorePage(Bundle savedState, Bundle savedNestedScrollWebViewState) { - // Create an arguments bundle - Bundle argumentsBundle = new Bundle(); - - // Store the saved states in the arguments bundle. - argumentsBundle.putBundle(SAVED_STATE, savedState); - argumentsBundle.putBundle(SAVED_NESTED_SCROLL_WEBVIEW_STATE, savedNestedScrollWebViewState); - - // Create a new instance of the WebView tab fragment. - WebViewTabFragment webViewTabFragment = new WebViewTabFragment(); - - // Add the arguments bundle to the fragment. - webViewTabFragment.setArguments(argumentsBundle); - - // Return the new fragment. - return webViewTabFragment; - } - - @Override - public View onCreateView(@NonNull LayoutInflater layoutInflater, ViewGroup container, Bundle savedInstanceState) { - // Check to see if the fragment is being restarted. - if (savedInstanceState == null) { // The fragment is not being restarted. Load and configure a new fragment. - // Get the arguments. - Bundle arguments = getArguments(); - - // Remove the incorrect lint warning that the arguments might be null. - assert arguments != null; - - // Check to see if a new page is being created. - if (arguments.getBoolean(CREATE_NEW_PAGE)) { // A new page is being created. - // Get the variables from the arguments - int pageNumber = arguments.getInt(PAGE_NUMBER); - String url = arguments.getString(URL); - - // Inflate the tab's WebView. Setting false at the end of inflater.inflate does not attach the inflated layout as a child of container. - // The fragment will take care of attaching the root automatically. - View newPageView = layoutInflater.inflate(R.layout.webview_framelayout, container, false); - - // Get handles for the views. - nestedScrollWebView = newPageView.findViewById(R.id.nestedscroll_webview); - ProgressBar progressBar = newPageView.findViewById(R.id.progress_bar); - - // Store the WebView fragment ID in the nested scroll WebView. - nestedScrollWebView.setWebViewFragmentId(fragmentId); - - // Request the main activity initialize the WebView. - newTabListener.initializeWebView(nestedScrollWebView, pageNumber, progressBar, url, false); - - // Return the new page view. - return newPageView; - } else { // A page is being restored. - // Get the saved states from the arguments. - Bundle savedState = arguments.getBundle(SAVED_STATE); - Bundle savedNestedScrollWebViewState = arguments.getBundle(SAVED_NESTED_SCROLL_WEBVIEW_STATE); - - // Remove the incorrect lint warning below that the saved nested scroll WebView state might be null. - assert savedNestedScrollWebViewState != null; - - // Inflate the tab's WebView. Setting false at the end of inflater.inflate does not attach the inflated layout as a child of container. - // The fragment will take care of attaching the root automatically. - View newPageView = layoutInflater.inflate(R.layout.webview_framelayout, container, false); - - // Get handles for the views. - nestedScrollWebView = newPageView.findViewById(R.id.nestedscroll_webview); - ProgressBar progressBar = newPageView.findViewById(R.id.progress_bar); - - // Store the WebView fragment ID in the nested scroll WebView. - nestedScrollWebView.setWebViewFragmentId(fragmentId); - - // Restore the nested scroll WebView state. - nestedScrollWebView.restoreNestedScrollWebViewState(savedNestedScrollWebViewState); - - // Restore the WebView state. - nestedScrollWebView.restoreState(savedState); - - // Initialize the WebView. - newTabListener.initializeWebView(nestedScrollWebView, 0, progressBar, null, true); - - // Return the new page view. - return newPageView; - } - } else { // The fragment is being restarted. - // Return null. Otherwise, the fragment will be inflated and initialized by the OS on a restart, discarded, and then recreated with saved settings by Privacy Browser. - return null; - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/WebViewTabFragment.kt b/app/src/main/java/com/stoutner/privacybrowser/fragments/WebViewTabFragment.kt new file mode 100644 index 00000000..5d37613c --- /dev/null +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/WebViewTabFragment.kt @@ -0,0 +1,168 @@ +/* + * Copyright © 2019-2020,2022 Soren Stoutner . + * + * This file is part of Privacy Browser Android . + * + * Privacy Browser Android is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Browser Android is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser Android. If not, see . + */ + +package com.stoutner.privacybrowser.fragments + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ProgressBar + +import androidx.fragment.app.Fragment + +import com.stoutner.privacybrowser.R +import com.stoutner.privacybrowser.views.NestedScrollWebView + +import java.util.Calendar + +// Define the class constants. +private const val CREATE_NEW_PAGE = "create_new_page" +private const val PAGE_NUMBER = "page_number" +private const val URL = "url" +private const val SAVED_STATE = "saved_state" +private const val SAVED_NESTED_SCROLL_WEBVIEW_STATE = "saved_nested_scroll_webview_state" + +class WebViewTabFragment : Fragment() { + // Define the public variables. + @JvmField // TODO. `@JvmField` can be removed once the entire project has been converted to Kotlin. + var fragmentId = Calendar.getInstance().timeInMillis + + // The public interface is used to send information back to the parent activity. + interface NewTabListener { + @SuppressLint("ClickableViewAccessibility") + fun initializeWebView(nestedScrollWebView: NestedScrollWebView, pageNumber: Int, progressBar: ProgressBar, url: String, restoringState: Boolean) + } + + // Declare the class variables. + private lateinit var newTabListener: NewTabListener + + // Declare the class views. + private lateinit var nestedScrollWebView: NestedScrollWebView + + companion object { + @JvmStatic // TODO. `@JvmStatic` can be removed once the entire project has been converted to Kotlin. + fun createPage(pageNumber: Int, url: String?): WebViewTabFragment { + // Create an arguments bundle. + val argumentsBundle = Bundle() + + // Store the argument in the bundle. + argumentsBundle.putBoolean(CREATE_NEW_PAGE, true) + argumentsBundle.putInt(PAGE_NUMBER, pageNumber) + argumentsBundle.putString(URL, url) + + // Create a new instance of the WebView tab fragment. + val webViewTabFragment = WebViewTabFragment() + + // Add the arguments bundle to the fragment. + webViewTabFragment.arguments = argumentsBundle + + // Return the new fragment. + return webViewTabFragment + } + + @JvmStatic // TODO. `@JvmStatic` can be removed once the entire project has been converted to Kotlin. + fun restorePage(savedState: Bundle?, savedNestedScrollWebViewState: Bundle?): WebViewTabFragment { + // Create an arguments bundle + val argumentsBundle = Bundle() + + // Store the saved states in the arguments bundle. + argumentsBundle.putBundle(SAVED_STATE, savedState) + argumentsBundle.putBundle(SAVED_NESTED_SCROLL_WEBVIEW_STATE, savedNestedScrollWebViewState) + + // Create a new instance of the WebView tab fragment. + val webViewTabFragment = WebViewTabFragment() + + // Add the arguments bundle to the fragment. + webViewTabFragment.arguments = argumentsBundle + + // Return the new fragment. + return webViewTabFragment + } + } + + override fun onAttach(context: Context) { + // Run the default commands. + super.onAttach(context) + + // Get a handle for the new tab listener from the launching context. + newTabListener = context as NewTabListener + } + + override fun onCreateView(layoutInflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + // Check to see if the fragment is being restarted. + return if (savedInstanceState == null) { // The fragment is not being restarted. Load and configure a new fragment. + // Check to see if a new page is being created. + if (requireArguments().getBoolean(CREATE_NEW_PAGE)) { // A new page is being created. + // Get the variables from the arguments + val pageNumber = requireArguments().getInt(PAGE_NUMBER) + val url = requireArguments().getString(URL)!! + + // Inflate the tab's WebView. Setting false at the end of inflater.inflate does not attach the inflated layout as a child of container. + // The fragment will take care of attaching the root automatically. + val newPageView = layoutInflater.inflate(R.layout.webview_framelayout, container, false) + + // Get handles for the views. + nestedScrollWebView = newPageView.findViewById(R.id.nestedscroll_webview) + val progressBar = newPageView.findViewById(R.id.progress_bar) + + // Store the WebView fragment ID in the nested scroll WebView. + nestedScrollWebView.webViewFragmentId = fragmentId + + // Request the main activity initialize the WebView. + newTabListener.initializeWebView(nestedScrollWebView, pageNumber, progressBar, url, false) + + // Return the new page view. + newPageView + } else { // A page is being restored. + // Get the saved states from the arguments. + val savedState = requireArguments().getBundle(SAVED_STATE) + val savedNestedScrollWebViewState = requireArguments().getBundle(SAVED_NESTED_SCROLL_WEBVIEW_STATE)!! + + // Inflate the tab's WebView. Setting false at the end of inflater.inflate does not attach the inflated layout as a child of container. + // The fragment will take care of attaching the root automatically. + val newPageView = layoutInflater.inflate(R.layout.webview_framelayout, container, false) + + // Get handles for the views. + nestedScrollWebView = newPageView.findViewById(R.id.nestedscroll_webview) + val progressBar = newPageView.findViewById(R.id.progress_bar) + + // Store the WebView fragment ID in the nested scroll WebView. + nestedScrollWebView.webViewFragmentId = fragmentId + + // Restore the nested scroll WebView state. + nestedScrollWebView.restoreNestedScrollWebViewState(savedNestedScrollWebViewState) + + // Restore the WebView state. + nestedScrollWebView.restoreState(savedState!!) + + // Initialize the WebView. + newTabListener.initializeWebView(nestedScrollWebView, 0, progressBar, "", true) + + // Return the new page view. + newPageView + } + } else { // The fragment is being restarted. + // Return null. Otherwise, the fragment will be inflated and initialized by the OS on a restart, discarded, and then recreated with saved settings by Privacy Browser. + null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.kt b/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.kt index fac7001a..8804e997 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.kt @@ -26,7 +26,7 @@ import android.database.DatabaseUtils import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper -// Define the private class constants. +// Define the class constants. private const val SCHEMA_VERSION = 1 class BookmarksDatabaseHelper(context: Context) : SQLiteOpenHelper(context, BOOKMARKS_DATABASE, null, SCHEMA_VERSION) { diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.kt b/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.kt index 98969343..2c941634 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.kt @@ -30,24 +30,24 @@ import androidx.preference.PreferenceManager import com.stoutner.privacybrowser.R -// The private constants. +// Define the class constants. private const val SCHEMA_VERSION = 14 class DomainsDatabaseHelper(private val appContext: Context) : SQLiteOpenHelper(appContext, DOMAINS_DATABASE, null, SCHEMA_VERSION) { // Define the public companion object constants. These can be moved to public class constants once the entire project has migrated to Kotlin. companion object { - // The database constants. + // Define the public database constants. const val DOMAINS_DATABASE = "domains.db" const val DOMAINS_TABLE = "domains" - // The spinner constants. + // Define the public spinner constants. const val SYSTEM_DEFAULT = 0 const val ENABLED = 1 const val DISABLED = 2 const val LIGHT_THEME = 1 const val DARK_THEME = 2 - // The schema constants. + // Define the public schema constants. const val ID = "_id" const val DOMAIN_NAME = "domainname" const val ENABLE_JAVASCRIPT = "enablejavascript" @@ -80,7 +80,7 @@ class DomainsDatabaseHelper(private val appContext: Context) : SQLiteOpenHelper( const val PINNED_IP_ADDRESSES = "pinned_ip_addresses" const val IP_ADDRESSES = "ip_addresses" - // The table creation constant. + // Define the public table creation constant. const val CREATE_DOMAINS_TABLE = "CREATE TABLE $DOMAINS_TABLE (" + "$ID INTEGER PRIMARY KEY, " + "$DOMAIN_NAME TEXT, " +