]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt
4011f5a5aba4fe689a628fbd8523afa306e634f6
[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.core.content.ContextCompat
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 favoriteOrDefaultIcon: Bitmap
121     private var previousYPosition = 0  // The previous Y position needs to be tracked between motion events.
122     private var hasPinnedSslCertificate = false
123     private var pinnedSslIssuedToCName = ""
124     private var pinnedSslIssuedToOName = ""
125     private var pinnedSslIssuedToUName = ""
126     private var pinnedSslIssuedByCName = ""
127     private var pinnedSslIssuedByOName = ""
128     private var pinnedSslIssuedByUName = ""
129     private var pinnedSslStartDate = Date(0)
130     private var pinnedSslEndDate = Date(0)
131     private val resourceRequests = Collections.synchronizedList(ArrayList<Array<String>>())  // Using a synchronized list makes adding resource requests thread safe.
132     private var blockedRequests = 0
133     private var easyListBlockedRequests = 0
134     private var easyPrivacyBlockedRequests = 0
135     private var fanboysAnnoyanceListBlockedRequests = 0
136     private var fanboysSocialBlockingListBlockedRequests = 0
137     private var ultraListBlockedRequests = 0
138     private var ultraPrivacyBlockedRequests = 0
139     private var thirdPartyBlockedRequests = 0
140     private var xRequestedWithHeader = mutableMapOf<String, String>()
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.  `ContextCompat` must be used until API >= 21.
154         val favoriteIconDrawable = ContextCompat.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         favoriteOrDefaultIcon = favoriteIconBitmapDrawable.bitmap
161     }
162
163     fun setFavoriteOrDefaultIcon(icon: Bitmap) {
164         // Scale the favorite icon bitmap down if it is larger than 256 x 256.  Filtering uses bilinear interpolation.
165         favoriteOrDefaultIcon = if (icon.height > 256 || icon.width > 256) {
166             Bitmap.createScaledBitmap(icon, 256, 256, true)
167         } else {
168             // Store the icon as presented.
169             icon
170         }
171     }
172
173     fun getFavoriteOrDefaultIcon(): Bitmap {
174         // Return the favorite or default icon.  This is the only way to return a non-nullable variable while retaining the custom initialization and setter functions above.
175         return favoriteOrDefaultIcon
176     }
177
178
179     // Reset the handlers.
180     fun resetSslErrorHandler() {
181         // Reset the current SSL error handler.
182         sslErrorHandler = null
183     }
184
185     fun resetHttpAuthHandler() {
186         // Reset the current HTTP authentication handler.
187         httpAuthHandler = null
188     }
189
190
191     // Pinned SSL certificates.
192     fun hasPinnedSslCertificate(): Boolean {
193         // Return the status of the pinned SSL certificate.
194         return hasPinnedSslCertificate
195     }
196
197     fun setPinnedSslCertificate(issuedToCName: String, issuedToOName: String, issuedToUName: String, issuedByCName: String, issuedByOName: String, issuedByUName: String, startDate: Date, endDate: Date) {
198         // Store the pinned SSL certificate information.
199         pinnedSslIssuedToCName = issuedToCName
200         pinnedSslIssuedToOName = issuedToOName
201         pinnedSslIssuedToUName = issuedToUName
202         pinnedSslIssuedByCName = issuedByCName
203         pinnedSslIssuedByOName = issuedByOName
204         pinnedSslIssuedByUName = issuedByUName
205         pinnedSslStartDate = startDate
206         pinnedSslEndDate = endDate
207
208         // Set the pinned SSL certificate tracker.
209         hasPinnedSslCertificate = true
210     }
211
212     fun getPinnedSslCertificate(): Pair<Array<String>, Array<Date>> {
213         // Create the SSL certificate string array.
214         val sslCertificateStringArray = arrayOf(pinnedSslIssuedToCName, pinnedSslIssuedToOName, pinnedSslIssuedToUName, pinnedSslIssuedByCName, pinnedSslIssuedByOName, pinnedSslIssuedByUName)
215
216         // Create the SSL certificate date array.
217         val sslCertificateDateArray = arrayOf(pinnedSslStartDate, pinnedSslEndDate)
218
219         // Return the pinned SSL certificate pair.
220         return Pair(sslCertificateStringArray, sslCertificateDateArray)
221     }
222
223     fun clearPinnedSslCertificate() {
224         // Clear the pinned SSL certificate.
225         pinnedSslIssuedToCName = ""
226         pinnedSslIssuedToOName = ""
227         pinnedSslIssuedToUName = ""
228         pinnedSslIssuedByCName = ""
229         pinnedSslIssuedByOName = ""
230         pinnedSslIssuedByUName = ""
231         pinnedSslStartDate = Date(0)
232         pinnedSslEndDate = Date(0)
233
234         // Clear the pinned SSL certificate tracker.
235         hasPinnedSslCertificate = false
236     }
237
238
239     // Resource requests.
240     fun addResourceRequest(resourceRequest: Array<String>) {
241         // Add the resource request to the list.
242         resourceRequests.add(resourceRequest)
243     }
244
245     fun getResourceRequests(): List<Array<String>> {
246         // Return the list of resource requests as an array list.
247         return resourceRequests
248     }
249
250     fun clearResourceRequests() {
251         // Clear the resource requests.
252         resourceRequests.clear()
253     }
254
255
256     // Resource request counters.
257     fun incrementRequestsCount(blocklist: Int) {
258         // Increment the count of the indicated blocklist.
259         when (blocklist) {
260             BLOCKED_REQUESTS -> blockedRequests++
261             EASYLIST -> easyListBlockedRequests++
262             EASYPRIVACY -> easyPrivacyBlockedRequests++
263             FANBOYS_ANNOYANCE_LIST -> fanboysAnnoyanceListBlockedRequests++
264             FANBOYS_SOCIAL_BLOCKING_LIST -> fanboysSocialBlockingListBlockedRequests++
265             ULTRALIST -> ultraListBlockedRequests++
266             ULTRAPRIVACY -> ultraPrivacyBlockedRequests++
267             THIRD_PARTY_REQUESTS -> thirdPartyBlockedRequests++
268         }
269     }
270
271     fun getRequestsCount(blocklist: Int): Int {
272         // Return the count of the indicated blocklist.
273         return when (blocklist) {
274             BLOCKED_REQUESTS -> blockedRequests
275             EASYLIST -> easyListBlockedRequests
276             EASYPRIVACY -> easyPrivacyBlockedRequests
277             FANBOYS_ANNOYANCE_LIST -> fanboysAnnoyanceListBlockedRequests
278             FANBOYS_SOCIAL_BLOCKING_LIST -> fanboysSocialBlockingListBlockedRequests
279             ULTRALIST -> ultraListBlockedRequests
280             ULTRAPRIVACY -> ultraPrivacyBlockedRequests
281             THIRD_PARTY_REQUESTS -> thirdPartyBlockedRequests
282             else -> 0 // Return 0.  This should never be called, but it is required by the return when statement.
283         }
284     }
285
286     fun resetRequestsCounters() {
287         // Reset all the resource request counters.
288         blockedRequests = 0
289         easyListBlockedRequests = 0
290         easyPrivacyBlockedRequests = 0
291         fanboysAnnoyanceListBlockedRequests = 0
292         fanboysSocialBlockingListBlockedRequests = 0
293         ultraListBlockedRequests = 0
294         ultraPrivacyBlockedRequests = 0
295         thirdPartyBlockedRequests = 0
296     }
297
298
299     // X-Requested-With header.
300     fun getXRequestedWithHeader() : MutableMap<String, String> {
301         // Return the X-Requested-With header.
302         return xRequestedWithHeader
303     }
304
305     fun setXRequestedWithHeader() {
306         // Set the X-Requested-With header to use a null value.
307         if (xRequestedWithHeader.isEmpty())
308             xRequestedWithHeader["X-Requested-With"] = ""
309     }
310
311     fun resetXRequestedWithHeader() {
312         // Clear the map, which resets the X-Requested-With header to use the default value of the application ID (com.stoutner.privacybrowser.standard).
313         xRequestedWithHeader.clear()
314     }
315
316
317     // Publicly expose the scroll ranges.
318     fun getHorizontalScrollRange(): Int {
319         // Return the horizontal scroll range.
320         return computeHorizontalScrollRange()
321     }
322
323     fun getVerticalScrollRange(): Int {
324         // Return the vertical scroll range.
325         return computeVerticalScrollRange()
326     }
327
328     override fun onOverScrolled(scrollX: Int, scrollY: Int, clampedX: Boolean, clampedY: Boolean) {
329         // Run the default commands.
330         super.onOverScrolled(scrollX, scrollY, clampedX, clampedY)
331
332         // Display the bottom app bar if it has been hidden and the WebView was over-scrolled at the top of the screen.
333         if ((MainWebViewActivity.appBarLayout.translationY != 0f) && (scrollY == 0) && clampedY) {
334             // Animate the bottom app bar onto the screen.
335             val objectAnimator = ObjectAnimator.ofFloat(MainWebViewActivity.appBarLayout, "translationY", 0f)
336
337             // Make it so.
338             objectAnimator.start()
339         }
340     }
341
342     // Handle touches.
343     @SuppressLint("ClickableViewAccessibility")
344     override fun onTouchEvent(motionEvent: MotionEvent): Boolean {
345         // Run the commands for the given motion event action.
346         when (motionEvent.action) {
347             MotionEvent.ACTION_DOWN -> {
348                 // Start nested scrolling along the vertical axis.  `ViewCompat` must be used until the minimum API >= 21.
349                 startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
350
351                 // Save the current Y position.  Action down will not be called again until a new motion starts.
352                 previousYPosition = motionEvent.y.toInt()
353             }
354             MotionEvent.ACTION_MOVE -> {
355                 // Get the current Y position.
356                 val currentYMotionPosition = motionEvent.y.toInt()
357
358                 // Calculate the pre-scroll delta Y.
359                 val preScrollDeltaY = previousYPosition - currentYMotionPosition
360
361                 // Initialize a variable to track how much of the scroll is consumed.
362                 val consumedScroll = IntArray(2)
363
364                 // Initialize a variable to track the offset in the window.
365                 val offsetInWindow = IntArray(2)
366
367                 // Get the WebView Y position.
368                 val webViewYPosition = scrollY
369
370                 // Set the scroll delta Y to initially be the same as the pre-scroll delta Y.
371                 var scrollDeltaY = preScrollDeltaY
372
373                 // Dispatch the nested pre-school.  This scrolls the app bar if it needs it.  `offsetInWindow` will be returned with an updated value.
374                 if (dispatchNestedPreScroll(0, preScrollDeltaY, consumedScroll, offsetInWindow)) {
375                     // Update the scroll delta Y if some of it was consumed.
376                     scrollDeltaY = preScrollDeltaY - consumedScroll[1]
377                 }
378
379                 // Check to see if the WebView is at the top and and the scroll action is downward.
380                 if (webViewYPosition == 0 && scrollDeltaY < 0) {  // Swipe to refresh is being engaged.
381                     // 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.
382                     stopNestedScroll()
383                 } else {  // Swipe to refresh is not being engaged.
384                     // Start the nested scroll so that the app bar can scroll off the screen.
385                     startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
386
387                     // 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.
388                     dispatchNestedScroll(0, scrollDeltaY, 0, 0, offsetInWindow)
389
390                     // Store the current Y position for use in the next action move.
391                     previousYPosition -= scrollDeltaY
392                 }
393             }
394             else -> stopNestedScroll()  // Stop nested scrolling.
395         }
396
397         // Perform a click.  This is required by the Android accessibility guidelines.
398         performClick()
399
400         // Run the default commands and return the result.
401         return super.onTouchEvent(motionEvent)
402     }
403
404
405     // Save and restore state.
406     fun saveNestedScrollWebViewState(): Bundle {
407         // Create a saved state bundle.
408         val savedState = Bundle()
409
410         // Populate the saved state bundle.
411         savedState.putBoolean(DOMAIN_SETTINGS_APPLIED, domainSettingsApplied)
412         savedState.putInt(DOMAIN_SETTINGS_DATABASE_ID, domainSettingsDatabaseId)
413         savedState.putString(CURRENT_DOMAIN_NAME, currentDomainName)
414         savedState.putString(CURRENT_URl, currentUrl)
415         savedState.putBoolean(ACCEPT_COOKIES, acceptCookies)
416         savedState.putBoolean(EASYLIST_ENABLED, easyListEnabled)
417         savedState.putBoolean(EASYPRIVACY_ENABLED, easyPrivacyEnabled)
418         savedState.putBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED, fanboysAnnoyanceListEnabled)
419         savedState.putBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED, fanboysSocialBlockingListEnabled)
420         savedState.putBoolean(ULTRALIST_ENABLED, ultraListEnabled)
421         savedState.putBoolean(ULTRAPRIVACY_ENABLED, ultraPrivacyEnabled)
422         savedState.putBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests)
423         savedState.putBoolean(HAS_PINNED_SSL_CERTIFICATE, hasPinnedSslCertificate)
424         savedState.putString(PINNED_SSL_ISSUED_TO_CNAME, pinnedSslIssuedToCName)
425         savedState.putString(PINNED_SSL_ISSUED_TO_ONAME, pinnedSslIssuedToOName)
426         savedState.putString(PINNED_SSL_ISSUED_TO_UNAME, pinnedSslIssuedToUName)
427         savedState.putString(PINNED_SSL_ISSUED_BY_CNAME, pinnedSslIssuedByCName)
428         savedState.putString(PINNED_SSL_ISSUED_BY_ONAME, pinnedSslIssuedByOName)
429         savedState.putString(PINNED_SSL_ISSUED_BY_UNAME, pinnedSslIssuedByUName)
430         savedState.putLong(PINNED_SSL_START_DATE, pinnedSslStartDate.time)
431         savedState.putLong(PINNED_SSL_END_DATE, pinnedSslEndDate.time)
432         savedState.putString(PINNED_IP_ADDRESSES, pinnedIpAddresses)
433         savedState.putBoolean(IGNORE_PINNED_DOMAIN_INFORMATION, ignorePinnedDomainInformation)
434         savedState.putBoolean(SWIPE_TO_REFRESH, swipeToRefresh)
435         savedState.putBoolean(JAVASCRIPT_ENABLED, this.settings.javaScriptEnabled)
436         savedState.putBoolean(DOM_STORAGE_ENABLED, this.settings.domStorageEnabled)
437         savedState.putString(USER_AGENT, this.settings.userAgentString)
438         savedState.putBoolean(WIDE_VIEWPORT, this.settings.useWideViewPort)
439         savedState.putInt(FONT_SIZE, this.settings.textZoom)
440
441         // Return the saved state bundle.
442         return savedState
443     }
444
445     fun restoreNestedScrollWebViewState(savedState: Bundle) {
446         // Restore the class variables.
447         domainSettingsApplied = savedState.getBoolean(DOMAIN_SETTINGS_APPLIED)
448         domainSettingsDatabaseId = savedState.getInt(DOMAIN_SETTINGS_DATABASE_ID)
449         currentDomainName = savedState.getString(CURRENT_DOMAIN_NAME)!!
450         currentUrl = savedState.getString(CURRENT_URl)!!
451         acceptCookies = savedState.getBoolean(ACCEPT_COOKIES)
452         easyListEnabled = savedState.getBoolean(EASYLIST_ENABLED)
453         easyPrivacyEnabled = savedState.getBoolean(EASYPRIVACY_ENABLED)
454         fanboysAnnoyanceListEnabled = savedState.getBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED)
455         fanboysSocialBlockingListEnabled = savedState.getBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED)
456         ultraListEnabled = savedState.getBoolean(ULTRALIST_ENABLED)
457         ultraPrivacyEnabled = savedState.getBoolean(ULTRAPRIVACY_ENABLED)
458         blockAllThirdPartyRequests = savedState.getBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS)
459         hasPinnedSslCertificate = savedState.getBoolean(HAS_PINNED_SSL_CERTIFICATE)
460         pinnedSslIssuedToCName = savedState.getString(PINNED_SSL_ISSUED_TO_CNAME)!!
461         pinnedSslIssuedToOName = savedState.getString(PINNED_SSL_ISSUED_TO_ONAME)!!
462         pinnedSslIssuedToUName = savedState.getString(PINNED_SSL_ISSUED_TO_UNAME)!!
463         pinnedSslIssuedByCName = savedState.getString(PINNED_SSL_ISSUED_BY_CNAME)!!
464         pinnedSslIssuedByOName = savedState.getString(PINNED_SSL_ISSUED_BY_ONAME)!!
465         pinnedSslIssuedByUName = savedState.getString(PINNED_SSL_ISSUED_BY_UNAME)!!
466         pinnedSslStartDate = Date(savedState.getLong(PINNED_SSL_START_DATE))
467         pinnedSslEndDate = Date(savedState.getLong(PINNED_SSL_END_DATE))
468         pinnedIpAddresses = savedState.getString(PINNED_IP_ADDRESSES)!!
469         ignorePinnedDomainInformation = savedState.getBoolean(IGNORE_PINNED_DOMAIN_INFORMATION)
470         swipeToRefresh = savedState.getBoolean(SWIPE_TO_REFRESH)
471         this.settings.javaScriptEnabled = savedState.getBoolean(JAVASCRIPT_ENABLED)
472         this.settings.domStorageEnabled = savedState.getBoolean(DOM_STORAGE_ENABLED)
473         this.settings.userAgentString = savedState.getString(USER_AGENT)
474         this.settings.useWideViewPort = savedState.getBoolean(WIDE_VIEWPORT)
475         this.settings.textZoom = savedState.getInt(FONT_SIZE)
476     }
477
478
479     // Method from NestedScrollingChild.
480     override fun setNestedScrollingEnabled(status: Boolean) {
481         // Set the status of the nested scrolling.
482         nestedScrollingChildHelper.isNestedScrollingEnabled = status
483     }
484
485     // Method from NestedScrollingChild.
486     override fun isNestedScrollingEnabled(): Boolean {
487         // Return the status of nested scrolling.
488         return nestedScrollingChildHelper.isNestedScrollingEnabled
489     }
490
491     // Method from NestedScrollingChild.
492     override fun startNestedScroll(axes: Int): Boolean {
493         // Start a nested scroll along the indicated axes.
494         return nestedScrollingChildHelper.startNestedScroll(axes)
495     }
496
497     // Method from NestedScrollingChild2.
498     override fun startNestedScroll(axes: Int, type: Int): Boolean {
499         // Start a nested scroll along the indicated axes for the given type of input which caused the scroll event.
500         return nestedScrollingChildHelper.startNestedScroll(axes, type)
501     }
502
503     // Method from NestedScrollingChild.
504     override fun stopNestedScroll() {
505         // Stop the nested scroll.
506         nestedScrollingChildHelper.stopNestedScroll()
507     }
508
509     // Method from NestedScrollingChild2.
510     override fun stopNestedScroll(type: Int) {
511         // Stop the nested scroll of the given type of input which caused the scroll event.
512         nestedScrollingChildHelper.stopNestedScroll(type)
513     }
514
515     // Method from NestedScrollingChild.
516     override fun hasNestedScrollingParent(): Boolean {
517         // Return the status of the nested scrolling parent.
518         return nestedScrollingChildHelper.hasNestedScrollingParent()
519     }
520
521     // Method from NestedScrollingChild2.
522     override fun hasNestedScrollingParent(type: Int): Boolean {
523         // return the status of the nested scrolling parent for the given type of input which caused the scroll event.
524         return nestedScrollingChildHelper.hasNestedScrollingParent(type)
525     }
526
527     // Method from NestedScrollingChild.
528     override fun dispatchNestedPreScroll(deltaX: Int, deltaY: Int, consumed: IntArray?, offsetInWindow: IntArray?): Boolean {
529         // Dispatch a nested pre-scroll with the specified deltas, which lets a parent to consume some of the scroll if desired.
530         return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow)
531     }
532
533     // Method from NestedScrollingChild2.
534     override fun dispatchNestedPreScroll(deltaX: Int, deltaY: Int, consumed: IntArray?, offsetInWindow: IntArray?, type: Int): Boolean {
535         // 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.
536         return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow, type)
537     }
538
539     // Method from NestedScrollingChild.
540     override fun dispatchNestedScroll(deltaXConsumed: Int, deltaYConsumed: Int, deltaXUnconsumed: Int, deltaYUnconsumed: Int, offsetInWindow: IntArray?): Boolean {
541         // Dispatch a nested scroll with the specified deltas.
542         return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow)
543     }
544
545     // Method from NestedScrollingChild2.
546     override fun dispatchNestedScroll(deltaXConsumed: Int, deltaYConsumed: Int, deltaXUnconsumed: Int, deltaYUnconsumed: Int, offsetInWindow: IntArray?, type: Int): Boolean {
547         // Dispatch a nested scroll with the specified deltas for the given type of input which caused the scroll event.
548         return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow, type)
549     }
550
551     // Method from NestedScrollingChild.
552     override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float): Boolean {
553         // Dispatch a nested pre-fling with the specified velocity, which lets a parent consume the fling if desired.
554         return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY)
555     }
556
557     // Method from NestedScrollingChild.
558     override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {
559         // Dispatch a nested fling with the specified velocity.
560         return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed)
561     }
562 }