]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt
Don't replace a high resolution favorite icon with a lower resolution one. https...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / views / NestedScrollWebView.kt
1 /*
2  * Copyright 2019-2022 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.views
21
22 import android.animation.ObjectAnimator
23 import android.annotation.SuppressLint
24 import android.content.Context
25 import android.graphics.Bitmap
26 import android.graphics.drawable.BitmapDrawable
27 import android.os.Bundle
28 import android.util.AttributeSet
29 import android.view.MotionEvent
30 import android.webkit.HttpAuthHandler
31 import android.webkit.SslErrorHandler
32 import android.webkit.WebView
33
34 import androidx.appcompat.content.res.AppCompatResources.getDrawable
35 import androidx.core.view.NestedScrollingChild2
36 import androidx.core.view.NestedScrollingChildHelper
37 import androidx.core.view.ViewCompat
38
39 import com.stoutner.privacybrowser.R
40 import com.stoutner.privacybrowser.activities.MainWebViewActivity
41
42 import java.util.Collections
43 import java.util.Date
44
45 import kotlin.collections.ArrayList
46
47 import kotlin.jvm.JvmOverloads
48
49 // Define the saved state constants.
50 private const val DOMAIN_SETTINGS_APPLIED = "domain_settings_applied"
51 private const val DOMAIN_SETTINGS_DATABASE_ID = "domain_settings_database_id"
52 private const val CURRENT_DOMAIN_NAME = "current_domain_name"
53 private const val CURRENT_URl = "current_url"
54 private const val ACCEPT_COOKIES = "accept_cookies"
55 private const val EASYLIST_ENABLED = "easylist_enabled"
56 private const val EASYPRIVACY_ENABLED = "easyprivacy_enabled"
57 private const val FANBOYS_ANNOYANCE_LIST_ENABLED = "fanboys_annoyance_list_enabled"
58 private const val FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED = "fanboys_social_blocking_list_enabled"
59 private const val ULTRALIST_ENABLED = "ultralist_enabled"
60 private const val ULTRAPRIVACY_ENABLED = "ultraprivacy_enabled"
61 private const val BLOCK_ALL_THIRD_PARTY_REQUESTS = "block_all_third_party_requests"
62 private const val HAS_PINNED_SSL_CERTIFICATE = "has_pinned_ssl_certificate"
63 private const val PINNED_SSL_ISSUED_TO_CNAME = "pinned_ssl_issued_to_cname"
64 private const val PINNED_SSL_ISSUED_TO_ONAME = "pinned_ssl_issued_to_oname"
65 private const val PINNED_SSL_ISSUED_TO_UNAME = "pinned_ssl_issued_to_uname"
66 private const val PINNED_SSL_ISSUED_BY_CNAME = "pinned_ssl_issued_by_cname"
67 private const val PINNED_SSL_ISSUED_BY_ONAME = "pinned_ssl_issued_by_oname"
68 private const val PINNED_SSL_ISSUED_BY_UNAME = "pinned_ssl_issued_by_uname"
69 private const val PINNED_SSL_START_DATE = "pinned_ssl_start_date"
70 private const val PINNED_SSL_END_DATE = "pinned_ssl_end_date"
71 private const val PINNED_IP_ADDRESSES = "pinned_ip_addresses"
72 private const val IGNORE_PINNED_DOMAIN_INFORMATION = "ignore_pinned_domain_information"
73 private const val SWIPE_TO_REFRESH = "swipe_to_refresh"
74 private const val JAVASCRIPT_ENABLED = "javascript_enabled"
75 private const val DOM_STORAGE_ENABLED = "dom_storage_enabled"
76 private const val USER_AGENT = "user_agent"
77 private const val WIDE_VIEWPORT = "wide_viewport"
78 private const val FONT_SIZE = "font_size"
79
80 // NestedScrollWebView extends WebView to handle nested scrolls (scrolling the app bar off the screen).  It also stores extra information about the state of the WebView used by Privacy Browser.
81 class NestedScrollWebView @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null, defaultStyle: Int = android.R.attr.webViewStyle) : WebView(context, attributeSet, defaultStyle),
82     NestedScrollingChild2 {
83     companion object {
84         // Define the public companion object constants.  These can be moved to public class constants once the entire project has migrated to Kotlin.
85         const val BLOCKED_REQUESTS = 0
86         const val EASYLIST = 1
87         const val EASYPRIVACY = 2
88         const val FANBOYS_ANNOYANCE_LIST = 3
89         const val FANBOYS_SOCIAL_BLOCKING_LIST = 4
90         const val ULTRALIST = 5
91         const val ULTRAPRIVACY = 6
92         const val THIRD_PARTY_REQUESTS = 7
93     }
94
95     // Define the public variables.
96     var acceptCookies = false
97     var blockAllThirdPartyRequests = false
98     var currentDomainName = ""
99     var currentIpAddresses = ""
100     var currentUrl = ""
101     var domainSettingsApplied = false
102     var domainSettingsDatabaseId = 0
103     var easyListEnabled = true
104     var easyPrivacyEnabled = true
105     var fanboysAnnoyanceListEnabled = true
106     var fanboysSocialBlockingListEnabled = true
107     var httpAuthHandler: HttpAuthHandler? = null
108     var ignorePinnedDomainInformation = false
109     var pinnedIpAddresses = ""
110     var sslErrorHandler: SslErrorHandler? = null
111     var swipeToRefresh = false
112     var ultraListEnabled = true
113     var ultraPrivacyEnabled = true
114     var waitingForProxyUrlString = ""
115     var webViewFragmentId: Long = 0
116
117
118     // Define the private variables.
119     private val nestedScrollingChildHelper: NestedScrollingChildHelper = NestedScrollingChildHelper(this)
120     private lateinit var favoriteIcon: Bitmap
121     private var favoriteIconHeight = 0
122     private var previousYPosition = 0  // The previous Y position needs to be tracked between motion events.
123     private var hasPinnedSslCertificate = false
124     private var pinnedSslIssuedToCName = ""
125     private var pinnedSslIssuedToOName = ""
126     private var pinnedSslIssuedToUName = ""
127     private var pinnedSslIssuedByCName = ""
128     private var pinnedSslIssuedByOName = ""
129     private var pinnedSslIssuedByUName = ""
130     private var pinnedSslStartDate = Date(0)
131     private var pinnedSslEndDate = Date(0)
132     private val resourceRequests = Collections.synchronizedList(ArrayList<Array<String>>())  // Using a synchronized list makes adding resource requests thread safe.
133     private var blockedRequests = 0
134     private var easyListBlockedRequests = 0
135     private var easyPrivacyBlockedRequests = 0
136     private var fanboysAnnoyanceListBlockedRequests = 0
137     private var fanboysSocialBlockingListBlockedRequests = 0
138     private var ultraListBlockedRequests = 0
139     private var ultraPrivacyBlockedRequests = 0
140     private var thirdPartyBlockedRequests = 0
141
142     init {
143         // Enable nested scrolling by default.
144         nestedScrollingChildHelper.isNestedScrollingEnabled = true
145
146         // Initialize the favorite icon.
147         initializeFavoriteIcon()
148     }
149
150
151     // Favorite or default icon.
152     fun initializeFavoriteIcon() {
153         // Get the default favorite icon drawable.
154         val favoriteIconDrawable = getDrawable(context, R.drawable.world)
155
156         // Cast the favorite icon drawable to a bitmap drawable.
157         val favoriteIconBitmapDrawable = (favoriteIconDrawable as BitmapDrawable?)!!
158
159         // Store the default icon bitmap.
160         favoriteIcon = favoriteIconBitmapDrawable.bitmap
161
162         // Set the favorite icon height to be 0.  This way any favorite icons presented by the website will overwrite it.
163         favoriteIconHeight = 0
164     }
165
166     fun setFavoriteIcon(icon: Bitmap) {
167         // Store the current favorite icon height.
168         favoriteIconHeight = icon.height
169
170         // Scale the favorite icon bitmap down if it is larger than 256 x 256.  Filtering uses bilinear interpolation.
171         favoriteIcon = if (icon.height > 256 || icon.width > 256) {
172             Bitmap.createScaledBitmap(icon, 256, 256, true)
173         } else {
174             // Store the icon as presented.
175             icon
176         }
177     }
178
179     fun getFavoriteIcon(): Bitmap {
180         // Return the favorite icon.  This is the only way to return a non-nullable variable while retaining the custom initialization and setter functions above.
181         return favoriteIcon
182     }
183
184     fun getFavoriteIconHeight(): Int {
185         // Return the favorite icon height.
186         return favoriteIconHeight
187     }
188
189     // Reset the handlers.
190     fun resetSslErrorHandler() {
191         // Reset the current SSL error handler.
192         sslErrorHandler = null
193     }
194
195     fun resetHttpAuthHandler() {
196         // Reset the current HTTP authentication handler.
197         httpAuthHandler = null
198     }
199
200
201     // Pinned SSL certificates.
202     fun hasPinnedSslCertificate(): Boolean {
203         // Return the status of the pinned SSL certificate.
204         return hasPinnedSslCertificate
205     }
206
207     fun setPinnedSslCertificate(issuedToCName: String, issuedToOName: String, issuedToUName: String, issuedByCName: String, issuedByOName: String, issuedByUName: String, startDate: Date, endDate: Date) {
208         // Store the pinned SSL certificate information.
209         pinnedSslIssuedToCName = issuedToCName
210         pinnedSslIssuedToOName = issuedToOName
211         pinnedSslIssuedToUName = issuedToUName
212         pinnedSslIssuedByCName = issuedByCName
213         pinnedSslIssuedByOName = issuedByOName
214         pinnedSslIssuedByUName = issuedByUName
215         pinnedSslStartDate = startDate
216         pinnedSslEndDate = endDate
217
218         // Set the pinned SSL certificate tracker.
219         hasPinnedSslCertificate = true
220     }
221
222     fun getPinnedSslCertificate(): Pair<Array<String>, Array<Date>> {
223         // Create the SSL certificate string array.
224         val sslCertificateStringArray = arrayOf(pinnedSslIssuedToCName, pinnedSslIssuedToOName, pinnedSslIssuedToUName, pinnedSslIssuedByCName, pinnedSslIssuedByOName, pinnedSslIssuedByUName)
225
226         // Create the SSL certificate date array.
227         val sslCertificateDateArray = arrayOf(pinnedSslStartDate, pinnedSslEndDate)
228
229         // Return the pinned SSL certificate pair.
230         return Pair(sslCertificateStringArray, sslCertificateDateArray)
231     }
232
233     fun clearPinnedSslCertificate() {
234         // Clear the pinned SSL certificate.
235         pinnedSslIssuedToCName = ""
236         pinnedSslIssuedToOName = ""
237         pinnedSslIssuedToUName = ""
238         pinnedSslIssuedByCName = ""
239         pinnedSslIssuedByOName = ""
240         pinnedSslIssuedByUName = ""
241         pinnedSslStartDate = Date(0)
242         pinnedSslEndDate = Date(0)
243
244         // Clear the pinned SSL certificate tracker.
245         hasPinnedSslCertificate = false
246     }
247
248
249     // Resource requests.
250     fun addResourceRequest(resourceRequest: Array<String>) {
251         // Add the resource request to the list.
252         resourceRequests.add(resourceRequest)
253     }
254
255     fun getResourceRequests(): List<Array<String>> {
256         // Return the list of resource requests as an array list.
257         return resourceRequests
258     }
259
260     fun clearResourceRequests() {
261         // Clear the resource requests.
262         resourceRequests.clear()
263     }
264
265
266     // Resource request counters.
267     fun incrementRequestsCount(blocklist: Int) {
268         // Increment the count of the indicated blocklist.
269         when (blocklist) {
270             BLOCKED_REQUESTS -> blockedRequests++
271             EASYLIST -> easyListBlockedRequests++
272             EASYPRIVACY -> easyPrivacyBlockedRequests++
273             FANBOYS_ANNOYANCE_LIST -> fanboysAnnoyanceListBlockedRequests++
274             FANBOYS_SOCIAL_BLOCKING_LIST -> fanboysSocialBlockingListBlockedRequests++
275             ULTRALIST -> ultraListBlockedRequests++
276             ULTRAPRIVACY -> ultraPrivacyBlockedRequests++
277             THIRD_PARTY_REQUESTS -> thirdPartyBlockedRequests++
278         }
279     }
280
281     fun getRequestsCount(blocklist: Int): Int {
282         // Return the count of the indicated blocklist.
283         return when (blocklist) {
284             BLOCKED_REQUESTS -> blockedRequests
285             EASYLIST -> easyListBlockedRequests
286             EASYPRIVACY -> easyPrivacyBlockedRequests
287             FANBOYS_ANNOYANCE_LIST -> fanboysAnnoyanceListBlockedRequests
288             FANBOYS_SOCIAL_BLOCKING_LIST -> fanboysSocialBlockingListBlockedRequests
289             ULTRALIST -> ultraListBlockedRequests
290             ULTRAPRIVACY -> ultraPrivacyBlockedRequests
291             THIRD_PARTY_REQUESTS -> thirdPartyBlockedRequests
292             else -> 0 // Return 0.  This should never be called, but it is required by the return when statement.
293         }
294     }
295
296     fun resetRequestsCounters() {
297         // Reset all the resource request counters.
298         blockedRequests = 0
299         easyListBlockedRequests = 0
300         easyPrivacyBlockedRequests = 0
301         fanboysAnnoyanceListBlockedRequests = 0
302         fanboysSocialBlockingListBlockedRequests = 0
303         ultraListBlockedRequests = 0
304         ultraPrivacyBlockedRequests = 0
305         thirdPartyBlockedRequests = 0
306     }
307
308
309     // Publicly expose the scroll ranges.
310     fun getHorizontalScrollRange(): Int {
311         // Return the horizontal scroll range.
312         return computeHorizontalScrollRange()
313     }
314
315     fun getVerticalScrollRange(): Int {
316         // Return the vertical scroll range.
317         return computeVerticalScrollRange()
318     }
319
320     override fun onOverScrolled(scrollX: Int, scrollY: Int, clampedX: Boolean, clampedY: Boolean) {
321         // Run the default commands.
322         super.onOverScrolled(scrollX, scrollY, clampedX, clampedY)
323
324         // Display the bottom app bar if it has been hidden and the WebView was over-scrolled at the top of the screen.
325         if ((MainWebViewActivity.appBarLayout.translationY != 0f) && (scrollY == 0) && clampedY) {
326             // Animate the bottom app bar onto the screen.
327             val objectAnimator = ObjectAnimator.ofFloat(MainWebViewActivity.appBarLayout, "translationY", 0f)
328
329             // Make it so.
330             objectAnimator.start()
331         }
332     }
333
334     // Handle touches.
335     @SuppressLint("ClickableViewAccessibility")
336     override fun onTouchEvent(motionEvent: MotionEvent): Boolean {
337         // Run the commands for the given motion event action.
338         when (motionEvent.action) {
339             MotionEvent.ACTION_DOWN -> {
340                 // Start nested scrolling along the vertical axis.  `ViewCompat` must be used until the minimum API >= 21.
341                 startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
342
343                 // Save the current Y position.  Action down will not be called again until a new motion starts.
344                 previousYPosition = motionEvent.y.toInt()
345             }
346             MotionEvent.ACTION_MOVE -> {
347                 // Get the current Y position.
348                 val currentYMotionPosition = motionEvent.y.toInt()
349
350                 // Calculate the pre-scroll delta Y.
351                 val preScrollDeltaY = previousYPosition - currentYMotionPosition
352
353                 // Initialize a variable to track how much of the scroll is consumed.
354                 val consumedScroll = IntArray(2)
355
356                 // Initialize a variable to track the offset in the window.
357                 val offsetInWindow = IntArray(2)
358
359                 // Get the WebView Y position.
360                 val webViewYPosition = scrollY
361
362                 // Set the scroll delta Y to initially be the same as the pre-scroll delta Y.
363                 var scrollDeltaY = preScrollDeltaY
364
365                 // Dispatch the nested pre-school.  This scrolls the app bar if it needs it.  `offsetInWindow` will be returned with an updated value.
366                 if (dispatchNestedPreScroll(0, preScrollDeltaY, consumedScroll, offsetInWindow)) {
367                     // Update the scroll delta Y if some of it was consumed.
368                     scrollDeltaY = preScrollDeltaY - consumedScroll[1]
369                 }
370
371                 // Check to see if the WebView is at the top and and the scroll action is downward.
372                 if (webViewYPosition == 0 && scrollDeltaY < 0) {  // Swipe to refresh is being engaged.
373                     // Stop the nested scroll so that swipe to refresh has complete control.  This way releasing the scroll to refresh circle doesn't scroll the WebView at the same time.
374                     stopNestedScroll()
375                 } else {  // Swipe to refresh is not being engaged.
376                     // Start the nested scroll so that the app bar can scroll off the screen.
377                     startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
378
379                     // Dispatch the nested scroll.  This scrolls the WebView.  The delta Y unconsumed normally controls the swipe refresh layout, but that is handled with the `if` statement above.
380                     dispatchNestedScroll(0, scrollDeltaY, 0, 0, offsetInWindow)
381
382                     // Store the current Y position for use in the next action move.
383                     previousYPosition -= scrollDeltaY
384                 }
385             }
386             else -> stopNestedScroll()  // Stop nested scrolling.
387         }
388
389         // Perform a click.  This is required by the Android accessibility guidelines.
390         performClick()
391
392         // Run the default commands and return the result.
393         return super.onTouchEvent(motionEvent)
394     }
395
396
397     // Save and restore state.
398     fun saveNestedScrollWebViewState(): Bundle {
399         // Create a saved state bundle.
400         val savedState = Bundle()
401
402         // Populate the saved state bundle.
403         savedState.putBoolean(DOMAIN_SETTINGS_APPLIED, domainSettingsApplied)
404         savedState.putInt(DOMAIN_SETTINGS_DATABASE_ID, domainSettingsDatabaseId)
405         savedState.putString(CURRENT_DOMAIN_NAME, currentDomainName)
406         savedState.putString(CURRENT_URl, currentUrl)
407         savedState.putBoolean(ACCEPT_COOKIES, acceptCookies)
408         savedState.putBoolean(EASYLIST_ENABLED, easyListEnabled)
409         savedState.putBoolean(EASYPRIVACY_ENABLED, easyPrivacyEnabled)
410         savedState.putBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED, fanboysAnnoyanceListEnabled)
411         savedState.putBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED, fanboysSocialBlockingListEnabled)
412         savedState.putBoolean(ULTRALIST_ENABLED, ultraListEnabled)
413         savedState.putBoolean(ULTRAPRIVACY_ENABLED, ultraPrivacyEnabled)
414         savedState.putBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests)
415         savedState.putBoolean(HAS_PINNED_SSL_CERTIFICATE, hasPinnedSslCertificate)
416         savedState.putString(PINNED_SSL_ISSUED_TO_CNAME, pinnedSslIssuedToCName)
417         savedState.putString(PINNED_SSL_ISSUED_TO_ONAME, pinnedSslIssuedToOName)
418         savedState.putString(PINNED_SSL_ISSUED_TO_UNAME, pinnedSslIssuedToUName)
419         savedState.putString(PINNED_SSL_ISSUED_BY_CNAME, pinnedSslIssuedByCName)
420         savedState.putString(PINNED_SSL_ISSUED_BY_ONAME, pinnedSslIssuedByOName)
421         savedState.putString(PINNED_SSL_ISSUED_BY_UNAME, pinnedSslIssuedByUName)
422         savedState.putLong(PINNED_SSL_START_DATE, pinnedSslStartDate.time)
423         savedState.putLong(PINNED_SSL_END_DATE, pinnedSslEndDate.time)
424         savedState.putString(PINNED_IP_ADDRESSES, pinnedIpAddresses)
425         savedState.putBoolean(IGNORE_PINNED_DOMAIN_INFORMATION, ignorePinnedDomainInformation)
426         savedState.putBoolean(SWIPE_TO_REFRESH, swipeToRefresh)
427         savedState.putBoolean(JAVASCRIPT_ENABLED, this.settings.javaScriptEnabled)
428         savedState.putBoolean(DOM_STORAGE_ENABLED, this.settings.domStorageEnabled)
429         savedState.putString(USER_AGENT, this.settings.userAgentString)
430         savedState.putBoolean(WIDE_VIEWPORT, this.settings.useWideViewPort)
431         savedState.putInt(FONT_SIZE, this.settings.textZoom)
432
433         // Return the saved state bundle.
434         return savedState
435     }
436
437     fun restoreNestedScrollWebViewState(savedState: Bundle) {
438         // Restore the class variables.
439         domainSettingsApplied = savedState.getBoolean(DOMAIN_SETTINGS_APPLIED)
440         domainSettingsDatabaseId = savedState.getInt(DOMAIN_SETTINGS_DATABASE_ID)
441         currentDomainName = savedState.getString(CURRENT_DOMAIN_NAME)!!
442         currentUrl = savedState.getString(CURRENT_URl)!!
443         acceptCookies = savedState.getBoolean(ACCEPT_COOKIES)
444         easyListEnabled = savedState.getBoolean(EASYLIST_ENABLED)
445         easyPrivacyEnabled = savedState.getBoolean(EASYPRIVACY_ENABLED)
446         fanboysAnnoyanceListEnabled = savedState.getBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED)
447         fanboysSocialBlockingListEnabled = savedState.getBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED)
448         ultraListEnabled = savedState.getBoolean(ULTRALIST_ENABLED)
449         ultraPrivacyEnabled = savedState.getBoolean(ULTRAPRIVACY_ENABLED)
450         blockAllThirdPartyRequests = savedState.getBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS)
451         hasPinnedSslCertificate = savedState.getBoolean(HAS_PINNED_SSL_CERTIFICATE)
452         pinnedSslIssuedToCName = savedState.getString(PINNED_SSL_ISSUED_TO_CNAME)!!
453         pinnedSslIssuedToOName = savedState.getString(PINNED_SSL_ISSUED_TO_ONAME)!!
454         pinnedSslIssuedToUName = savedState.getString(PINNED_SSL_ISSUED_TO_UNAME)!!
455         pinnedSslIssuedByCName = savedState.getString(PINNED_SSL_ISSUED_BY_CNAME)!!
456         pinnedSslIssuedByOName = savedState.getString(PINNED_SSL_ISSUED_BY_ONAME)!!
457         pinnedSslIssuedByUName = savedState.getString(PINNED_SSL_ISSUED_BY_UNAME)!!
458         pinnedSslStartDate = Date(savedState.getLong(PINNED_SSL_START_DATE))
459         pinnedSslEndDate = Date(savedState.getLong(PINNED_SSL_END_DATE))
460         pinnedIpAddresses = savedState.getString(PINNED_IP_ADDRESSES)!!
461         ignorePinnedDomainInformation = savedState.getBoolean(IGNORE_PINNED_DOMAIN_INFORMATION)
462         swipeToRefresh = savedState.getBoolean(SWIPE_TO_REFRESH)
463         this.settings.javaScriptEnabled = savedState.getBoolean(JAVASCRIPT_ENABLED)
464         this.settings.domStorageEnabled = savedState.getBoolean(DOM_STORAGE_ENABLED)
465         this.settings.userAgentString = savedState.getString(USER_AGENT)
466         this.settings.useWideViewPort = savedState.getBoolean(WIDE_VIEWPORT)
467         this.settings.textZoom = savedState.getInt(FONT_SIZE)
468     }
469
470
471     // Method from NestedScrollingChild.
472     override fun setNestedScrollingEnabled(status: Boolean) {
473         // Set the status of the nested scrolling.
474         nestedScrollingChildHelper.isNestedScrollingEnabled = status
475     }
476
477     // Method from NestedScrollingChild.
478     override fun isNestedScrollingEnabled(): Boolean {
479         // Return the status of nested scrolling.
480         return nestedScrollingChildHelper.isNestedScrollingEnabled
481     }
482
483     // Method from NestedScrollingChild.
484     override fun startNestedScroll(axes: Int): Boolean {
485         // Start a nested scroll along the indicated axes.
486         return nestedScrollingChildHelper.startNestedScroll(axes)
487     }
488
489     // Method from NestedScrollingChild2.
490     override fun startNestedScroll(axes: Int, type: Int): Boolean {
491         // Start a nested scroll along the indicated axes for the given type of input which caused the scroll event.
492         return nestedScrollingChildHelper.startNestedScroll(axes, type)
493     }
494
495     // Method from NestedScrollingChild.
496     override fun stopNestedScroll() {
497         // Stop the nested scroll.
498         nestedScrollingChildHelper.stopNestedScroll()
499     }
500
501     // Method from NestedScrollingChild2.
502     override fun stopNestedScroll(type: Int) {
503         // Stop the nested scroll of the given type of input which caused the scroll event.
504         nestedScrollingChildHelper.stopNestedScroll(type)
505     }
506
507     // Method from NestedScrollingChild.
508     override fun hasNestedScrollingParent(): Boolean {
509         // Return the status of the nested scrolling parent.
510         return nestedScrollingChildHelper.hasNestedScrollingParent()
511     }
512
513     // Method from NestedScrollingChild2.
514     override fun hasNestedScrollingParent(type: Int): Boolean {
515         // return the status of the nested scrolling parent for the given type of input which caused the scroll event.
516         return nestedScrollingChildHelper.hasNestedScrollingParent(type)
517     }
518
519     // Method from NestedScrollingChild.
520     override fun dispatchNestedPreScroll(deltaX: Int, deltaY: Int, consumed: IntArray?, offsetInWindow: IntArray?): Boolean {
521         // Dispatch a nested pre-scroll with the specified deltas, which lets a parent to consume some of the scroll if desired.
522         return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow)
523     }
524
525     // Method from NestedScrollingChild2.
526     override fun dispatchNestedPreScroll(deltaX: Int, deltaY: Int, consumed: IntArray?, offsetInWindow: IntArray?, type: Int): Boolean {
527         // Dispatch a nested pre-scroll with the specified deltas for the given type of input which caused the scroll event, which lets a parent to consume some of the scroll if desired.
528         return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow, type)
529     }
530
531     // Method from NestedScrollingChild.
532     override fun dispatchNestedScroll(deltaXConsumed: Int, deltaYConsumed: Int, deltaXUnconsumed: Int, deltaYUnconsumed: Int, offsetInWindow: IntArray?): Boolean {
533         // Dispatch a nested scroll with the specified deltas.
534         return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow)
535     }
536
537     // Method from NestedScrollingChild2.
538     override fun dispatchNestedScroll(deltaXConsumed: Int, deltaYConsumed: Int, deltaXUnconsumed: Int, deltaYUnconsumed: Int, offsetInWindow: IntArray?, type: Int): Boolean {
539         // Dispatch a nested scroll with the specified deltas for the given type of input which caused the scroll event.
540         return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow, type)
541     }
542
543     // Method from NestedScrollingChild.
544     override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float): Boolean {
545         // Dispatch a nested pre-fling with the specified velocity, which lets a parent consume the fling if desired.
546         return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY)
547     }
548
549     // Method from NestedScrollingChild.
550     override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {
551         // Dispatch a nested fling with the specified velocity.
552         return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed)
553     }
554 }