]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/commitdiff
Attempt to handle race conditions with the creation of tabs.
authorSoren Stoutner <soren@stoutner.com>
Thu, 28 Dec 2023 21:30:50 +0000 (14:30 -0700)
committerSoren Stoutner <soren@stoutner.com>
Thu, 28 Dec 2023 21:30:50 +0000 (14:30 -0700)
app/build.gradle
app/src/main/java/com/stoutner/privacybrowser/activities/ImportExportActivity.kt
app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt
app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt
app/src/main/res/values-ru/strings.xml
build.gradle
gradle.properties
gradle/wrapper/gradle-wrapper.properties

index ebf69c8ad30ee56a5def9549221f1e711e0d06e1..8a16a90c8cdc0f0ee50d267f714ca41868937bf7 100644 (file)
@@ -58,6 +58,11 @@ android {
         }
     }
 
+    buildFeatures {
+        // Generate BuildConfig so it can be accessed from withing the app.
+        buildConfig = true
+    }
+
     // Gradle requires a `flavorDimension`, but it isn't used for anything in Privacy Browser.
     flavorDimensions = ['basic']
 
@@ -78,7 +83,7 @@ android {
 
 dependencies {
     // Include the following AndroidX libraries.
-    implementation "androidx.activity:activity-ktx:1.8.1"
+    implementation "androidx.activity:activity-ktx:1.8.2"
     implementation 'androidx.arch.core:core-common:2.2.0'
     implementation 'androidx.arch.core:core-runtime:2.2.0'
     implementation 'androidx.appcompat:appcompat:1.6.1'
@@ -90,11 +95,11 @@ dependencies {
     implementation 'androidx.preference:preference-ktx:1.2.1'
     implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
     implementation 'androidx.viewpager:viewpager:1.0.0'
-    implementation 'androidx.webkit:webkit:1.8.0'
+    implementation 'androidx.webkit:webkit:1.9.0'
 
     // Include the Kotlin standard library.  This should be the same version number listed in project build.gradle.
-    implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.8.22'
+    implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.9.0'
 
     // Include the Google material library.
-    implementation 'com.google.android.material:material:1.10.0'
+    implementation 'com.google.android.material:material:1.11.0'
 }
index 35f4321acf4fc54fd6f59e6d64b86157fed5070a..36d1e725a3b190cecfa5c77c35d59a3bee6b79dd 100644 (file)
@@ -48,8 +48,8 @@ import androidx.preference.PreferenceManager
 import com.google.android.material.snackbar.Snackbar
 import com.google.android.material.textfield.TextInputLayout
 
-import com.stoutner.privacybrowser.R
 import com.stoutner.privacybrowser.BuildConfig
+import com.stoutner.privacybrowser.R
 import com.stoutner.privacybrowser.helpers.EXPORT_SUCCESSFUL
 import com.stoutner.privacybrowser.helpers.IMPORT_EXPORT_SCHEMA_VERSION
 import com.stoutner.privacybrowser.helpers.IMPORT_SUCCESSFUL
index 367511041dbc0376e6246627c1a7ac88b38c8e5f..8294caef64a51db2db5de73c7f3444c68f643b68 100644 (file)
@@ -38,8 +38,8 @@ import androidx.preference.PreferenceManager
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
 
 import com.google.android.material.snackbar.Snackbar
-import com.stoutner.privacybrowser.BuildConfig
 
+import com.stoutner.privacybrowser.BuildConfig
 import com.stoutner.privacybrowser.R
 
 import kotlinx.coroutines.CoroutineScope
index 7dd983a0845f94ad86d79e617f88c3e9163632c9..d1fb09ae8afd1bc2bb36e7586c2c5455b11c1390 100644 (file)
@@ -697,7 +697,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
                         // Get the previous entry data.
                         val previousUrl = webBackForwardList.getItemAtIndex(webBackForwardList.currentIndex - 1).url
-                        val previousFavoriteIcon = webBackForwardList.getItemAtIndex(webBackForwardList.currentIndex - 1).favicon!!
+                        val previousFavoriteIcon = webBackForwardList.getItemAtIndex(webBackForwardList.currentIndex - 1).favicon
 
                         // Apply the domain settings.
                         applyDomainSettings(currentWebView!!, previousUrl, resetTab = false, reloadWebsite = false, loadUrl = false)
@@ -711,8 +711,9 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                         // Get the favorite icon image view from the tab.
                         val tabFavoriteIconImageView = tabView.findViewById<ImageView>(R.id.favorite_icon_imageview)
 
-                        // Set the previous favorite icon.
-                        tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(previousFavoriteIcon, 64, 64, true))
+                        // Set the previous favorite icon if it isn't null.
+                        if (previousFavoriteIcon != null)
+                            tabFavoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(previousFavoriteIcon, 64, 64, true))
 
                         // Go back.
                         currentWebView!!.goBack()
@@ -800,7 +801,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     loadingNewIntent = true
 
                     // Add a new tab.
-                    addNewTab(url!!, adjacent = false, moveToTab = true)
+                    addNewPage(url!!, adjacent = false, moveToTab = true)
                 } else {  // Load the URL in the current tab.
                     // Make it so.
                     loadUrl(currentWebView!!, url!!)
@@ -2028,10 +2029,10 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Open a new tab according to the current URL.
                 if (currentWebView!!.currentUrl.startsWith("view-source:")) {  // The source is currently viewed.
                     // Open the rendered website in a new tab.
-                    addNewTab(currentWebView!!.currentUrl.substring(12, currentWebView!!.currentUrl.length), true, moveToTab = true)
+                    addNewPage(currentWebView!!.currentUrl.substring(12, currentWebView!!.currentUrl.length), true, moveToTab = true)
                 } else {  // The rendered website is currently viewed.
                     // Open the source in a new tab.
-                    addNewTab("view-source:${currentWebView!!.currentUrl}", adjacent = true, moveToTab = true)
+                    addNewPage("view-source:${currentWebView!!.currentUrl}", adjacent = true, moveToTab = true)
                 }
 
                 // Consume the event.
@@ -2627,7 +2628,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in new tab entry.
                 contextMenu.add(R.string.open_in_new_tab).setOnMenuItemClickListener {
                     // Load the link URL in a new tab and move to it.
-                    addNewTab(linkUrl, adjacent = true, moveToTab = true)
+                    addNewPage(linkUrl, adjacent = true, moveToTab = true)
 
                     // Consume the event.
                     true
@@ -2636,7 +2637,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in background entry.
                 contextMenu.add(R.string.open_in_background).setOnMenuItemClickListener {
                     // Load the link URL in a new tab but do not move to it.
-                    addNewTab(linkUrl, adjacent = true, moveToTab = false)
+                    addNewPage(linkUrl, adjacent = true, moveToTab = false)
 
                     // Consume the event.
                     true
@@ -2723,7 +2724,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in new tab entry.
                 contextMenu.add(R.string.open_image_in_new_tab).setOnMenuItemClickListener {
                     // Load the image in a new tab.
-                    addNewTab(imageUrl, adjacent = true, moveToTab = true)
+                    addNewPage(imageUrl, adjacent = true, moveToTab = true)
 
                     // Consume the event.
                     true
@@ -2829,7 +2830,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in new tab entry.
                 contextMenu.add(R.string.open_in_new_tab).setOnMenuItemClickListener {
                     // Load the link URL in a new tab and move to it.
-                    addNewTab(linkUrl, adjacent = true, moveToTab = true)
+                    addNewPage(linkUrl, adjacent = true, moveToTab = true)
 
                     // Consume the event.
                     true
@@ -2838,7 +2839,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open in background entry.
                 contextMenu.add(R.string.open_in_background).setOnMenuItemClickListener {
                     // Lod the link URL in a new tab but do not move to it.
-                    addNewTab(linkUrl, adjacent = true, moveToTab = false)
+                    addNewPage(linkUrl, adjacent = true, moveToTab = false)
 
                     // Consume the event.
                     true
@@ -2847,7 +2848,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Add an open image in new tab entry.
                 contextMenu.add(R.string.open_image_in_new_tab).setOnMenuItemClickListener {
                     // Load the image in a new tab and move to it.
-                    addNewTab(imageUrl, adjacent = true, moveToTab = true)
+                    addNewPage(imageUrl, adjacent = true, moveToTab = true)
 
                     // Consume the event.
                     true
@@ -3013,10 +3014,10 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     // The view parameter cannot be removed because it is called from the layout onClick.
     fun addTab(@Suppress("UNUSED_PARAMETER")view: View?) {
         // Add a new tab with a blank URL.
-        addNewTab(urlString = "", adjacent = true, moveToTab = true)
+        addNewPage(urlString = "", adjacent = true, moveToTab = true)
     }
 
-    private fun addNewTab(urlString: String, adjacent: Boolean, moveToTab: Boolean) {
+    private fun addNewPage(urlString: String, adjacent: Boolean, moveToTab: Boolean) {
         // Clear the focus from the URL edit text, so that it will be populated with the information from the new tab.
         urlEditText.clearFocus()
 
@@ -3029,32 +3030,52 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         // Add the new WebView page.
         webViewStateAdapter!!.addPage(newTabPosition, urlString)
 
-        // Create a new tab.
-        val newTab = tabLayout.newTab()
+        // Add the new tab.
+        addNewTab(newTabPosition, moveToTab)
+    }
 
-        // Set a custom view on the new tab.
-        newTab.setCustomView(R.layout.tab_custom_view)
+    private fun addNewTab(newTabPosition: Int, moveToTab: Boolean) {
+        // Check to see if the new page is ready.
+        if (webViewStateAdapter!!.itemCount >= tabLayout.tabCount) {  // The new page is ready.
+            // Create a new tab.
+            val newTab = tabLayout.newTab()
 
-        // Add the new tab.
-        tabLayout.addTab(newTab, newTabPosition, moveToTab)
+            // Set a custom view on the new tab.
+            newTab.setCustomView(R.layout.tab_custom_view)
+
+            // Add the new tab.
+            tabLayout.addTab(newTab, newTabPosition, moveToTab)
 
-        // Select the new tab if it is the first one.  For some odd reason, Android doesn't select the first tab if it is the only one, which causes problems with the new tab position logic above.
-        if (newTabPosition == 0)
-            tabLayout.selectTab(newTab)
+            // Select the new tab if it is the first one.  For some odd reason, Android doesn't select the first tab if it is the only one, which causes problems with the new tab position logic above.
+            if (newTabPosition == 0)
+                tabLayout.selectTab(newTab)
+
+            // Scroll to the new tab position if moving to the new tab.
+            if (moveToTab)
+                tabLayout.post {
+                    tabLayout.setScrollPosition(newTabPosition, 0F, false, false)
+                }
 
-        // Scroll to the new tab position if moving to the new tab.
-        if (moveToTab)
-            tabLayout.post {
-                tabLayout.setScrollPosition(newTabPosition, 0F, false, false)
+            // Show the app bar if it is at the bottom of the screen and the new tab is taking focus.
+            if (bottomAppBar && moveToTab && appBarLayout.translationY != 0f) {
+                // Animate the bottom app bar onto the screen.
+                objectAnimator = ObjectAnimator.ofFloat(appBarLayout, "translationY", 0f)
+
+                // Make it so.
+                objectAnimator.start()
             }
+        } else {  // The new page is not ready.
+            // Create a new tab handler.
+            val newTabHandler = Handler(Looper.getMainLooper())
 
-        // Show the app bar if it is at the bottom of the screen and the new tab is taking focus.
-        if (bottomAppBar && moveToTab && appBarLayout.translationY != 0f) {
-            // Animate the bottom app bar onto the screen.
-            objectAnimator = ObjectAnimator.ofFloat(appBarLayout, "translationY", 0f)
+            // Create a new tab runnable.
+            val newTabRunnable = Runnable {
+                // Create the new tab.
+                addNewTab(newTabPosition, moveToTab)
+            }
 
-            // Make it so.
-            objectAnimator.start()
+            // Try adding the new tab again after 50 milliseconds.
+            newTabHandler.postDelayed(newTabRunnable, 50)
         }
     }
 
@@ -4251,7 +4272,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         // Check to see if the activity has been restarted with a saved state.
         if ((savedStateArrayList == null) || (savedStateArrayList!!.size == 0)) {  // The activity has not been restarted or it was restarted on start to change the theme.
             // Add the first tab.
-            addNewTab(urlString = "", adjacent = false, moveToTab = false)
+            addNewPage(urlString = "", adjacent = false, moveToTab = false)
         } else {  // The activity has been restarted with a saved state.
             // Restore each tab.
             for (i in savedStateArrayList!!.indices) {
@@ -4310,7 +4331,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     loadingNewIntent = true
 
                     // Add a new tab.
-                    addNewTab(urlString, adjacent = false, moveToTab = true)
+                    addNewPage(urlString, adjacent = false, moveToTab = true)
                 } else {  // Load the URL in the current tab.
                     // Make it so.
                     loadUrl(currentWebView!!, urlString)
@@ -4455,8 +4476,10 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     // Select the same page in the view pager.
                     webViewViewPager2.currentItem = tab.position
 
-                    // Set the current WebView.
-                    setCurrentWebView(tab.position)
+                    // Set the current WebView after the tab layout has quiesced (otherwise, sometimes the wong WebView might be used).  See <https://redmine.stoutner.com/issues/1136>
+                    tabLayout.post {
+                        setCurrentWebView(tab.position)
+                    }
                 }
             }
 
@@ -4631,7 +4654,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Open each bookmark
                 for (i in 0 until bookmarksCursor.count) {
                     // Load the bookmark in a new tab, moving to the tab for the first bookmark if the drawer is not pinned.
-                    addNewTab(bookmarksCursor.getString(bookmarksCursor.getColumnIndexOrThrow(BOOKMARK_URL)), adjacent = false, moveToTab = !bookmarksDrawerPinned && (i == 0))
+                    addNewPage(bookmarksCursor.getString(bookmarksCursor.getColumnIndexOrThrow(BOOKMARK_URL)), adjacent = false, moveToTab = !bookmarksDrawerPinned && (i == 0))
 
                     // Move to the next bookmark.
                     bookmarksCursor.moveToNext()
@@ -4647,7 +4670,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 bookmarkCursor.moveToFirst()
 
                 // Load the bookmark in a new tab and move to the tab if the drawer is not pinned.
-                addNewTab(bookmarkCursor.getString(bookmarkCursor.getColumnIndexOrThrow(BOOKMARK_URL)), adjacent = true, moveToTab = !bookmarksDrawerPinned)
+                addNewPage(bookmarkCursor.getString(bookmarkCursor.getColumnIndexOrThrow(BOOKMARK_URL)), adjacent = true, moveToTab = !bookmarksDrawerPinned)
 
                 // Close the cursor.
                 bookmarkCursor.close()
@@ -6311,8 +6334,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 // Remove any background on the URL relative layout.
                 urlRelativeLayout.background = AppCompatResources.getDrawable(this, R.color.transparent)
             }
-        }  catch (exception: Exception) {
-            //  Try again in 50 milliseconds if the WebView has not yet been populated.
+        }  catch (exception: Exception) {  //  Try again in 10 milliseconds if the WebView has not yet been populated.
             // Create a handler to set the current WebView.
             val setCurrentWebViewHandler = Handler(Looper.getMainLooper())
 
@@ -6322,8 +6344,8 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                 setCurrentWebView(pageNumber)
             }
 
-            // Try setting the current WebView again after 50 milliseconds.
-            setCurrentWebViewHandler.postDelayed(setCurrentWebWebRunnable, 50)
+            // Try setting the current WebView again after 10 milliseconds.
+            setCurrentWebViewHandler.postDelayed(setCurrentWebWebRunnable, 10)
         }
     }
 
index 3014d7635b261487a64230c5c9087acde3ba44eb..c736a79d73df3790cf3e3b8f3b0b386eed541239 100644 (file)
         <string name="full_screen_browsing_mode_summary">Двойное касание переключает режим просмотра.</string>
         <string name="hide_app_bar">Скрыть панель приложения</string>
         <string name="hide_app_bar_summary">Скрывает панель приложения, которая содержит URL.</string>
+        <string name="display_under_cutouts">Отображение под вырезом</string>
+        <string name="display_under_cutouts_summary">Отрисовывать сайт под вырезами, например, под камерой. Изменение этой настройки приведет к перезапуску Privacy Browser.</string>
     <string name="clear_everything">Очистить все</string>
         <!-- The form data part of this string can be removed once the minimum API >= 26. -->
         <string name="clear_everything_summary">Очищает cookie, DOM-хранилище, данные форм, logcat и кэш WebView. После этого вручную удаляет каталоги "app_webview" и "cache".</string>
index 708dc886ecda51429ebcd64e6ef618067a8c048c..64eb513d1192e219cfa2bca4307ab8ada637e43a 100644 (file)
@@ -26,8 +26,8 @@ buildscript {
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:8.1.4'
-        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.22"
+        classpath 'com.android.tools.build:gradle:8.2.0'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0"
 
         // NOTE: Do not place your application dependencies here; they belong
         // in the individual module build.gradle files
index b8a7a3558285616cd39742bf2e10042329603a14..4c64ae1e6e520687ac7c5db7d87d96937d912cca 100644 (file)
@@ -35,7 +35,7 @@ org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
 # Use AndroidX.
 android.useAndroidX=true
 
-# Use the experimental configuration cache, which can speed up the build process in nothing in the configuration has changed.
+# Use the experimental configuration cache, which can speed up the build process if nothing in the configuration has changed.
 org.gradle.unsafe.configuration-cache=true
 
 # Use non-transitive R classes, which speed up the build process when the configuration has not changed.
@@ -43,5 +43,3 @@ android.nonTransitiveRClass=true
 
 # Use non-final resource IDs for faster incremental compilation.
 android.nonFinalResIds=true
-
-android.defaults.buildfeatures.buildconfig=true
index 6423b377599d131053eb53b4b94eaa0bea7d011f..fe335734fd4f837704fa89a7fd1d62c2f390d76c 100644 (file)
@@ -20,4 +20,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip