]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/adapters/WebViewPagerAdapter.kt
Release 3.14.
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / adapters / WebViewPagerAdapter.kt
1 /*
2  * Copyright © 2019-2023 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
5  *
6  * Privacy Browser Android is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser Android is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser Android.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.adapters
21
22 import android.os.Bundle
23 import android.os.Handler
24 import android.os.Looper
25 import android.widget.FrameLayout
26
27 import androidx.fragment.app.Fragment
28 import androidx.fragment.app.FragmentManager
29 import androidx.fragment.app.FragmentPagerAdapter
30 import androidx.viewpager.widget.ViewPager
31
32 import com.stoutner.privacybrowser.R
33 import com.stoutner.privacybrowser.fragments.WebViewTabFragment
34 import com.stoutner.privacybrowser.fragments.WebViewTabFragment.Companion.createPage
35 import com.stoutner.privacybrowser.views.NestedScrollWebView
36
37 import java.util.LinkedList
38
39 class WebViewPagerAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
40     // Define the class values.
41     private val webViewFragmentsList = LinkedList<WebViewTabFragment>()
42
43     override fun getCount(): Int {
44         // Return the number of pages.
45         return webViewFragmentsList.size
46     }
47
48     override fun getItem(pageNumber: Int): Fragment {
49         // Get the fragment for a particular page.  Page numbers are 0 indexed.
50         return webViewFragmentsList[pageNumber]
51     }
52
53     override fun getItemId(position: Int): Long {
54         // Return the unique ID for this page.
55         return webViewFragmentsList[position].fragmentId
56     }
57
58     override fun getItemPosition(`object`: Any): Int {
59         return if (webViewFragmentsList.contains(`object`)) {
60             // Return the current page position.
61             webViewFragmentsList.indexOf(`object`)
62         } else {
63             // The tab has been deleted.
64             POSITION_NONE
65         }
66     }
67
68     fun addPage(pageNumber: Int, webViewPager: ViewPager, url: String, moveToNewPage: Boolean) {
69         // Add a new page.
70         webViewFragmentsList.add(createPage(pageNumber, url))
71
72         // Update the view pager.
73         notifyDataSetChanged()
74
75         // Move to the new page if indicated.
76         if (moveToNewPage) {
77             moveToNewPage(pageNumber, webViewPager)
78         }
79     }
80
81     fun deletePage(pageNumber: Int, webViewPager: ViewPager): Boolean {
82         // Get the WebView tab fragment.
83         val webViewTabFragment = webViewFragmentsList[pageNumber]
84
85         // Get the WebView frame layout.
86         val webViewFrameLayout = (webViewTabFragment.view as FrameLayout?)!!
87
88         // Get a handle for the nested scroll WebView.
89         val nestedScrollWebView = webViewFrameLayout.findViewById<NestedScrollWebView>(R.id.nestedscroll_webview)
90
91         // Pause the current WebView.
92         nestedScrollWebView.onPause()
93
94         // Remove all the views from the frame layout.
95         webViewFrameLayout.removeAllViews()
96
97         // Destroy the current WebView.
98         nestedScrollWebView.destroy()
99
100         // Delete the page.
101         webViewFragmentsList.removeAt(pageNumber)
102
103         // Update the view pager.
104         notifyDataSetChanged()
105
106         // Return true if the selected page number did not change after the delete (because the newly selected tab has has same number as the previously deleted tab).
107         // This will cause the calling method to reset the current WebView to the new contents of this page number.
108         return webViewPager.currentItem == pageNumber
109     }
110
111     fun getPageFragment(pageNumber: Int): WebViewTabFragment {
112         // Return the page fragment.
113         return webViewFragmentsList[pageNumber]
114     }
115
116     fun getPositionForId(fragmentId: Long): Int {
117         // Initialize the position variable.
118         var position = -1
119
120         // Initialize the while counter.
121         var i = 0
122
123         // Find the current position of the WebView fragment with the given ID.
124         while (position < 0 && i < webViewFragmentsList.size) {
125             // Check to see if the tab ID of this WebView matches the page ID.
126             if (webViewFragmentsList[i].fragmentId == fragmentId) {
127                 // Store the position if they are a match.
128                 position = i
129             }
130
131             // Increment the counter.
132             i++
133         }
134
135         // Set the position to be the last tab if it is not found.
136         // Sometimes there is a race condition in populating the webView fragments list when resuming Privacy Browser and displaying an SSL certificate error while loading a new intent.
137         // In that case, the last tab should be the one it is looking for.
138         if (position == -1) {
139             position = webViewFragmentsList.size - 1
140         }
141
142         // Return the position.
143         return position
144     }
145
146     fun restorePage(savedState: Bundle, savedNestedScrollWebViewState: Bundle) {
147         // Restore the page.
148         webViewFragmentsList.add(WebViewTabFragment.restorePage(savedState, savedNestedScrollWebViewState))
149
150         // Update the view pager.
151         notifyDataSetChanged()
152     }
153
154     private fun moveToNewPage(pageNumber: Int, webViewPager: ViewPager) {
155         // Check to see if the new page has been populated.
156         if (webViewPager.childCount >= pageNumber) {  // The new page is ready.
157             // Move to the new page.
158             webViewPager.currentItem = pageNumber
159         } else {  // The new page is not yet ready.
160             // Create a handler.
161             val moveToNewPageHandler = Handler(Looper.getMainLooper())
162
163             // Create a runnable.
164             val moveToNewPageRunnable = Runnable {
165                 // Move to the new page.
166                 webViewPager.currentItem = pageNumber
167             }
168
169             // Try again to move to the new page after 50 milliseconds.
170             moveToNewPageHandler.postDelayed(moveToNewPageRunnable, 50)
171         }
172     }
173 }