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.views
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
34 import androidx.core.content.ContextCompat
35 import androidx.core.view.NestedScrollingChild2
36 import androidx.core.view.NestedScrollingChildHelper
37 import androidx.core.view.ViewCompat
39 import com.stoutner.privacybrowser.R
40 import com.stoutner.privacybrowser.activities.MainWebViewActivity
42 import java.util.Collections
45 import kotlin.collections.ArrayList
47 import kotlin.jvm.JvmOverloads
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"
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 {
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
95 // Define the public variables.
96 var acceptCookies = false
97 var blockAllThirdPartyRequests = false
98 var currentDomainName = ""
99 var currentIpAddresses = ""
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
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>()
143 // Enable nested scrolling by default.
144 nestedScrollingChildHelper.isNestedScrollingEnabled = true
146 // Initialize the favorite icon.
147 initializeFavoriteIcon()
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)
156 // Cast the favorite icon drawable to a bitmap drawable.
157 val favoriteIconBitmapDrawable = (favoriteIconDrawable as BitmapDrawable?)!!
159 // Store the default icon bitmap.
160 favoriteOrDefaultIcon = favoriteIconBitmapDrawable.bitmap
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)
168 // Store the icon as presented.
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
179 // Reset the handlers.
180 fun resetSslErrorHandler() {
181 // Reset the current SSL error handler.
182 sslErrorHandler = null
185 fun resetHttpAuthHandler() {
186 // Reset the current HTTP authentication handler.
187 httpAuthHandler = null
191 // Pinned SSL certificates.
192 fun hasPinnedSslCertificate(): Boolean {
193 // Return the status of the pinned SSL certificate.
194 return hasPinnedSslCertificate
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
208 // Set the pinned SSL certificate tracker.
209 hasPinnedSslCertificate = true
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)
216 // Create the SSL certificate date array.
217 val sslCertificateDateArray = arrayOf(pinnedSslStartDate, pinnedSslEndDate)
219 // Return the pinned SSL certificate pair.
220 return Pair(sslCertificateStringArray, sslCertificateDateArray)
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)
234 // Clear the pinned SSL certificate tracker.
235 hasPinnedSslCertificate = false
239 // Resource requests.
240 fun addResourceRequest(resourceRequest: Array<String>) {
241 // Add the resource request to the list.
242 resourceRequests.add(resourceRequest)
245 fun getResourceRequests(): List<Array<String>> {
246 // Return the list of resource requests as an array list.
247 return resourceRequests
250 fun clearResourceRequests() {
251 // Clear the resource requests.
252 resourceRequests.clear()
256 // Resource request counters.
257 fun incrementRequestsCount(blocklist: Int) {
258 // Increment the count of the indicated 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++
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.
286 fun resetRequestsCounters() {
287 // Reset all the resource request counters.
289 easyListBlockedRequests = 0
290 easyPrivacyBlockedRequests = 0
291 fanboysAnnoyanceListBlockedRequests = 0
292 fanboysSocialBlockingListBlockedRequests = 0
293 ultraListBlockedRequests = 0
294 ultraPrivacyBlockedRequests = 0
295 thirdPartyBlockedRequests = 0
299 // X-Requested-With header.
300 fun getXRequestedWithHeader() : MutableMap<String, String> {
301 // Return the X-Requested-With header.
302 return xRequestedWithHeader
305 fun setXRequestedWithHeader() {
306 // Set the X-Requested-With header to use a null value.
307 if (xRequestedWithHeader.isEmpty())
308 xRequestedWithHeader["X-Requested-With"] = ""
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()
317 // Publicly expose the scroll ranges.
318 fun getHorizontalScrollRange(): Int {
319 // Return the horizontal scroll range.
320 return computeHorizontalScrollRange()
323 fun getVerticalScrollRange(): Int {
324 // Return the vertical scroll range.
325 return computeVerticalScrollRange()
328 override fun onOverScrolled(scrollX: Int, scrollY: Int, clampedX: Boolean, clampedY: Boolean) {
329 // Run the default commands.
330 super.onOverScrolled(scrollX, scrollY, clampedX, clampedY)
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)
338 objectAnimator.start()
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)
351 // Save the current Y position. Action down will not be called again until a new motion starts.
352 previousYPosition = motionEvent.y.toInt()
354 MotionEvent.ACTION_MOVE -> {
355 // Get the current Y position.
356 val currentYMotionPosition = motionEvent.y.toInt()
358 // Calculate the pre-scroll delta Y.
359 val preScrollDeltaY = previousYPosition - currentYMotionPosition
361 // Initialize a variable to track how much of the scroll is consumed.
362 val consumedScroll = IntArray(2)
364 // Initialize a variable to track the offset in the window.
365 val offsetInWindow = IntArray(2)
367 // Get the WebView Y position.
368 val webViewYPosition = scrollY
370 // Set the scroll delta Y to initially be the same as the pre-scroll delta Y.
371 var scrollDeltaY = preScrollDeltaY
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]
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.
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)
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)
390 // Store the current Y position for use in the next action move.
391 previousYPosition -= scrollDeltaY
394 else -> stopNestedScroll() // Stop nested scrolling.
397 // Perform a click. This is required by the Android accessibility guidelines.
400 // Run the default commands and return the result.
401 return super.onTouchEvent(motionEvent)
405 // Save and restore state.
406 fun saveNestedScrollWebViewState(): Bundle {
407 // Create a saved state bundle.
408 val savedState = Bundle()
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)
441 // Return the saved state bundle.
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)
479 // Method from NestedScrollingChild.
480 override fun setNestedScrollingEnabled(status: Boolean) {
481 // Set the status of the nested scrolling.
482 nestedScrollingChildHelper.isNestedScrollingEnabled = status
485 // Method from NestedScrollingChild.
486 override fun isNestedScrollingEnabled(): Boolean {
487 // Return the status of nested scrolling.
488 return nestedScrollingChildHelper.isNestedScrollingEnabled
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)
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)
503 // Method from NestedScrollingChild.
504 override fun stopNestedScroll() {
505 // Stop the nested scroll.
506 nestedScrollingChildHelper.stopNestedScroll()
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)
515 // Method from NestedScrollingChild.
516 override fun hasNestedScrollingParent(): Boolean {
517 // Return the status of the nested scrolling parent.
518 return nestedScrollingChildHelper.hasNestedScrollingParent()
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)
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)
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)
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)
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)
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)
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)