2 * Copyright 2019-2020,2022-2023 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.fragments
22 import android.annotation.SuppressLint
23 import android.content.Context
24 import android.os.Bundle
25 import android.view.LayoutInflater
26 import android.view.View
27 import android.view.ViewGroup
28 import android.widget.ProgressBar
30 import androidx.fragment.app.Fragment
32 import com.stoutner.privacybrowser.R
33 import com.stoutner.privacybrowser.views.NestedScrollWebView
35 import java.util.Calendar
37 // Define the class constants.
38 private const val CREATE_NEW_PAGE = "A"
39 private const val BOTTOM_APP_BAR = "B"
40 private const val PAGE_POSITION = "C"
41 private const val SAVED_NESTED_SCROLL_WEBVIEW_STATE = "D"
42 private const val SAVED_STATE = "E"
43 private const val URL = "F"
45 class WebViewTabFragment : Fragment() {
46 // Define the public variables.
47 var fragmentId = Calendar.getInstance().timeInMillis
49 // The public interface is used to send information back to the parent activity.
50 interface NewTabListener {
51 @SuppressLint("ClickableViewAccessibility")
52 fun initializeWebView(nestedScrollWebView: NestedScrollWebView, pagePosition: Int, progressBar: ProgressBar, urlString: String, restoringState: Boolean)
55 // Declare the class variables.
56 private lateinit var newTabListener: NewTabListener
58 // Declare the class views.
59 private lateinit var nestedScrollWebView: NestedScrollWebView
62 fun createPage(pageNumber: Int, url: String?, bottomAppBar: Boolean): WebViewTabFragment {
63 // Create an arguments bundle.
64 val argumentsBundle = Bundle()
66 // Store the argument in the bundle.
67 argumentsBundle.putBoolean(CREATE_NEW_PAGE, true)
68 argumentsBundle.putInt(PAGE_POSITION, pageNumber)
69 argumentsBundle.putString(URL, url)
70 argumentsBundle.putBoolean(BOTTOM_APP_BAR, bottomAppBar)
72 // Create a new instance of the WebView tab fragment.
73 val webViewTabFragment = WebViewTabFragment()
75 // Add the arguments bundle to the fragment.
76 webViewTabFragment.arguments = argumentsBundle
78 // Return the new fragment.
79 return webViewTabFragment
82 fun restorePage(savedState: Bundle, savedNestedScrollWebViewState: Bundle, bottomAppBar: Boolean): WebViewTabFragment {
83 // Create an arguments bundle
84 val argumentsBundle = Bundle()
86 // Store the saved states in the arguments bundle.
87 argumentsBundle.putBundle(SAVED_STATE, savedState)
88 argumentsBundle.putBundle(SAVED_NESTED_SCROLL_WEBVIEW_STATE, savedNestedScrollWebViewState)
89 argumentsBundle.putBoolean(BOTTOM_APP_BAR, bottomAppBar)
91 // Create a new instance of the WebView tab fragment.
92 val webViewTabFragment = WebViewTabFragment()
94 // Add the arguments bundle to the fragment.
95 webViewTabFragment.arguments = argumentsBundle
97 // Return the new fragment.
98 return webViewTabFragment
102 override fun onAttach(context: Context) {
103 // Run the default commands.
104 super.onAttach(context)
106 // Get a handle for the new tab listener from the launching context.
107 newTabListener = context as NewTabListener
110 override fun onCreateView(layoutInflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
111 // Get the bottom app bar status from the arguments.
112 val bottomAppBar = requireArguments().getBoolean(BOTTOM_APP_BAR)
114 // Inflate the tab's WebView according to the app bar position. Setting false at the end of inflater.inflate does not attach the inflated layout as a child of container.
115 // The fragment will take care of attaching the root automatically.
116 val newPageView = if (bottomAppBar)
117 layoutInflater.inflate(R.layout.webview_framelayout_bottom_appbar, container, false)
119 layoutInflater.inflate(R.layout.webview_framelayout_top_appbar, container, false)
121 // Get handles for the views.
122 nestedScrollWebView = newPageView.findViewById(R.id.nestedscroll_webview)
123 val progressBar = newPageView.findViewById<ProgressBar>(R.id.progress_bar)
125 // Store the WebView fragment ID in the nested scroll WebView.
126 nestedScrollWebView.webViewFragmentId = fragmentId
128 // Check to see if the fragment is being restarted without the app being killed.
129 return if (savedInstanceState == null) { // The fragment is not being restarted. It is either new or is being restored after the app was killed.
130 // Check to see if a new page is being created.
131 if (requireArguments().getBoolean(CREATE_NEW_PAGE)) { // A new page is being created.
132 // Get the variables from the arguments
133 val pagePosition = requireArguments().getInt(PAGE_POSITION)
134 val url = requireArguments().getString(URL)!!
136 // Request the main activity initialize the WebView.
137 newTabListener.initializeWebView(nestedScrollWebView, pagePosition, progressBar, url, false)
139 // Return the new page view.
141 } else { // A page is being restored after the app was killed.
142 // Get the saved states from the arguments.
143 val savedState = requireArguments().getBundle(SAVED_STATE)!!
144 val savedNestedScrollWebViewState = requireArguments().getBundle(SAVED_NESTED_SCROLL_WEBVIEW_STATE)!!
146 // Restore the nested scroll WebView state.
147 nestedScrollWebView.restoreNestedScrollWebViewState(savedNestedScrollWebViewState)
149 // Restore the WebView state.
150 nestedScrollWebView.restoreState(savedState)
152 // Initialize the WebView.
153 newTabListener.initializeWebView(nestedScrollWebView, 0, progressBar, "", true)
155 // Return the new page view.
158 } else { // The fragment is being restarted.
159 // 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.