2 * Copyright © 2019-2022 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
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.
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.
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/>.
20 package com.stoutner.privacybrowser.adapters;
22 import android.os.Bundle;
23 import android.os.Handler;
24 import android.widget.FrameLayout;
26 import androidx.annotation.NonNull;
27 import androidx.fragment.app.Fragment;
28 import androidx.fragment.app.FragmentManager;
29 import androidx.fragment.app.FragmentPagerAdapter;
30 import androidx.viewpager.widget.ViewPager;
32 import com.stoutner.privacybrowser.R;
33 import com.stoutner.privacybrowser.fragments.WebViewTabFragment;
34 import com.stoutner.privacybrowser.views.NestedScrollWebView;
36 import java.util.LinkedList;
38 public class WebViewPagerAdapter extends FragmentPagerAdapter {
39 // The WebView fragments list contains all the WebViews.
40 private final LinkedList<WebViewTabFragment> webViewFragmentsList = new LinkedList<>();
42 // Define the constructor.
43 public WebViewPagerAdapter(FragmentManager fragmentManager) {
44 // Run the default commands.
45 super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
49 public int getCount() {
50 // Return the number of pages.
51 return webViewFragmentsList.size();
55 public int getItemPosition(@NonNull Object object) {
56 //noinspection SuspiciousMethodCalls
57 if (webViewFragmentsList.contains(object)) {
58 // Return the current page position.
59 //noinspection SuspiciousMethodCalls
60 return webViewFragmentsList.indexOf(object);
62 // The tab has been deleted.
69 public Fragment getItem(int pageNumber) {
70 // Get the fragment for a particular page. Page numbers are 0 indexed.
71 return webViewFragmentsList.get(pageNumber);
75 public long getItemId(int position) {
76 // Return the unique ID for this page.
77 return webViewFragmentsList.get(position).fragmentId;
80 public int getPositionForId(long fragmentId) {
81 // Initialize the position variable.
84 // Initialize the while counter.
87 // Find the current position of the WebView fragment with the given ID.
88 while (position < 0 && i < webViewFragmentsList.size()) {
89 // Check to see if the tab ID of this WebView matches the page ID.
90 if (webViewFragmentsList.get(i).fragmentId == fragmentId) {
91 // Store the position if they are a match.
95 // Increment the counter.
99 // Set the position to be the last tab if it is not found.
100 // 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.
101 // In that case, the last tab should be the one it is looking for.
102 if (position == -1) {
103 position = webViewFragmentsList.size() - 1;
106 // Return the position.
110 public void addPage(int pageNumber, ViewPager webViewPager, String url, boolean moveToNewPage) {
112 webViewFragmentsList.add(WebViewTabFragment.createPage(pageNumber, url));
114 // Update the view pager.
115 notifyDataSetChanged();
117 // Move to the new page if indicated.
119 moveToNewPage(pageNumber, webViewPager);
123 public void restorePage(Bundle savedState, Bundle savedNestedScrollWebViewState) {
125 webViewFragmentsList.add(WebViewTabFragment.restorePage(savedState, savedNestedScrollWebViewState));
127 // Update the view pager.
128 notifyDataSetChanged();
131 public boolean deletePage(int pageNumber, ViewPager webViewPager) {
132 // Get the WebView tab fragment.
133 WebViewTabFragment webViewTabFragment = webViewFragmentsList.get(pageNumber);
135 // Get the WebView frame layout.
136 FrameLayout webViewFrameLayout = (FrameLayout) webViewTabFragment.getView();
138 // Remove the warning below that the WebView frame layout might be null.
139 assert webViewFrameLayout != null;
141 // Get a handle for the nested scroll WebView.
142 NestedScrollWebView nestedScrollWebView = webViewFrameLayout.findViewById(R.id.nestedscroll_webview);
144 // Pause the current WebView.
145 nestedScrollWebView.onPause();
147 // Remove all the views from the frame layout.
148 webViewFrameLayout.removeAllViews();
150 // Destroy the current WebView.
151 nestedScrollWebView.destroy();
154 webViewFragmentsList.remove(pageNumber);
156 // Update the view pager.
157 notifyDataSetChanged();
159 // 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).
160 // This will cause the calling method to reset the current WebView to the new contents of this page number.
161 return (webViewPager.getCurrentItem() == pageNumber);
164 public WebViewTabFragment getPageFragment(int pageNumber) {
165 // Return the page fragment.
166 return webViewFragmentsList.get(pageNumber);
169 private void moveToNewPage(int pageNumber, ViewPager webViewPager) {
170 // Check to see if the new page has been populated.
171 if (webViewPager.getChildCount() >= pageNumber) { // The new page is ready.
172 // Move to the new page.
173 webViewPager.setCurrentItem(pageNumber);
174 } else { // The new page is not yet ready.
176 Handler moveToNewPageHandler = new Handler();
178 // Create a runnable.
179 Runnable moveToNewPageRunnable = () -> {
180 // Move to the new page.
181 webViewPager.setCurrentItem(pageNumber);
184 // Try again to move to the new page after 50 milliseconds.
185 moveToNewPageHandler.postDelayed(moveToNewPageRunnable, 50);