2 * Copyright © 2019 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
6 * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.views;
22 import android.content.Context;
23 import android.graphics.Bitmap;
24 import android.graphics.drawable.BitmapDrawable;
25 import android.graphics.drawable.Drawable;
26 import android.util.AttributeSet;
27 import android.view.MotionEvent;
28 import android.webkit.HttpAuthHandler;
29 import android.webkit.SslErrorHandler;
30 import android.webkit.WebView;
32 import androidx.annotation.NonNull;
33 import androidx.core.content.ContextCompat;
34 import androidx.core.view.NestedScrollingChild2;
35 import androidx.core.view.NestedScrollingChildHelper;
36 import androidx.core.view.ViewCompat;
38 import com.stoutner.privacybrowser.R;
40 import java.util.ArrayList;
41 import java.util.Date;
43 // NestedScrollWebView extends WebView to handle nested scrolls (scrolling the app bar off the screen).
44 public class NestedScrollWebView extends WebView implements NestedScrollingChild2 {
45 // These constants identify the blocklists.
46 public final static int BLOCKED_REQUESTS = 0;
47 public final static int EASY_LIST = 1;
48 public final static int EASY_PRIVACY = 2;
49 public final static int FANBOYS_ANNOYANCE_LIST = 3;
50 public final static int FANBOYS_SOCIAL_BLOCKING_LIST = 4;
51 public final static int ULTRA_PRIVACY = 5;
52 public final static int THIRD_PARTY_REQUESTS = 6;
54 // Keep a copy of the WebView fragment ID.
55 private long webViewFragmentId;
57 // Store the handlers.
58 private SslErrorHandler sslErrorHandler;
59 private HttpAuthHandler httpAuthHandler;
61 // Track if domain settings are applied to this nested scroll WebView and, if so, the database ID.
62 private boolean domainSettingsApplied;
63 private int domainSettingsDatabaseId;
65 // Keep track of when the domain name changes so that domain settings can be reapplied. This should never be null.
66 private String currentDomainName = "";
68 // Track the status of first-party cookies.
69 private boolean acceptFirstPartyCookies;
71 // Track the domain settings JavaScript status. This can be removed once night mode does not require JavaScript.
72 private boolean domainSettingsJavaScriptEnabled;
74 // Track the resource requests.
75 private ArrayList<String[]> resourceRequests = new ArrayList<>();
76 private boolean easyListEnabled;
77 private boolean easyPrivacyEnabled;
78 private boolean fanboysAnnoyanceListEnabled;
79 private boolean fanboysSocialBlockingListEnabled;
80 private boolean ultraPrivacyEnabled;
81 private boolean blockAllThirdPartyRequests;
82 private int blockedRequests;
83 private int easyListBlockedRequests;
84 private int easyPrivacyBlockedRequests;
85 private int fanboysAnnoyanceListBlockedRequests;
86 private int fanboysSocialBlockingListBlockedRequests;
87 private int ultraPrivacyBlockedRequests;
88 private int thirdPartyBlockedRequests;
90 // The pinned SSL certificate variables.
91 private boolean hasPinnedSslCertificate;
92 private String pinnedSslIssuedToCName;
93 private String pinnedSslIssuedToOName;
94 private String pinnedSslIssuedToUName;
95 private String pinnedSslIssuedByCName;
96 private String pinnedSslIssuedByOName;
97 private String pinnedSslIssuedByUName;
98 private Date pinnedSslStartDate;
99 private Date pinnedSslEndDate;
101 // The current IP addresses variables.
102 private boolean hasCurrentIpAddresses;
103 private String currentIpAddresses;
105 // The pinned IP addresses variables.
106 private boolean hasPinnedIpAddresses;
107 private String pinnedIpAddresses;
109 // The ignore pinned domain information tracker. This is set when a user proceeds past a pinned mismatch dialog to prevent the dialog from showing again until after the domain changes.
110 private boolean ignorePinnedDomainInformation;
112 // Track navigation of history.
113 private boolean navigatingHistory;
115 // The default or favorite icon.
116 private Bitmap favoriteOrDefaultIcon;
119 private boolean nightMode;
121 // Track swipe to refresh.
122 private boolean swipeToRefresh;
124 // The nested scrolling child helper is used throughout the class.
125 private NestedScrollingChildHelper nestedScrollingChildHelper;
127 // The previous Y position needs to be tracked between motion events.
128 private int previousYPosition;
132 // The basic constructor.
133 public NestedScrollWebView(Context context) {
134 // Roll up to the next constructor.
138 // The intermediate constructor.
139 public NestedScrollWebView(Context context, AttributeSet attributeSet) {
140 // Roll up to the next constructor.
141 this(context, attributeSet, android.R.attr.webViewStyle);
144 // The full constructor.
145 public NestedScrollWebView(Context context, AttributeSet attributeSet, int defaultStyle) {
146 // Run the default commands.
147 super(context, attributeSet, defaultStyle);
149 // Initialize the nested scrolling child helper.
150 nestedScrollingChildHelper = new NestedScrollingChildHelper(this);
152 // Enable nested scrolling by default.
153 nestedScrollingChildHelper.setNestedScrollingEnabled(true);
158 // WebView Fragment ID.
159 public void setWebViewFragmentId(long webViewFragmentId) {
160 // Store the WebView fragment ID.
161 this.webViewFragmentId = webViewFragmentId;
164 public long getWebViewFragmentId() {
165 // Return the WebView fragment ID.
166 return webViewFragmentId;
170 // SSL error handler.
171 public void setSslErrorHandler(SslErrorHandler sslErrorHandler) {
172 // Store the current SSL error handler.
173 this.sslErrorHandler = sslErrorHandler;
176 public SslErrorHandler getSslErrorHandler() {
177 // Return the current SSL error handler.
178 return sslErrorHandler;
181 public void resetSslErrorHandler() {
182 // Reset the current SSL error handler.
183 sslErrorHandler = null;
187 // HTTP authentication handler.
188 public void setHttpAuthHandler(HttpAuthHandler httpAuthHandler) {
189 // Store the current HTTP authentication handler.
190 this.httpAuthHandler = httpAuthHandler;
193 public HttpAuthHandler getHttpAuthHandler() {
194 // Return the current HTTP authentication handler.
195 return httpAuthHandler;
198 public void resetHttpAuthHandler() {
199 // Reset the current HTTP authentication handler.
200 httpAuthHandler = null;
205 public void setDomainSettingsApplied(boolean applied) {
206 // Store the domain settings applied status.
207 domainSettingsApplied = applied;
210 public boolean getDomainSettingsApplied() {
211 // Return the domain settings applied status.
212 return domainSettingsApplied;
216 // Domain settings database ID.
217 public void setDomainSettingsDatabaseId(int databaseId) {
218 // Store the domain settings database ID.
219 domainSettingsDatabaseId = databaseId;
222 public int getDomainSettingsDatabaseId() {
223 // Return the domain settings database ID.
224 return domainSettingsDatabaseId;
228 // Current domain name. To function well when called, the domain name should never be allowed to be null.
229 public void setCurrentDomainName(@NonNull String domainName) {
230 // Store the current domain name.
231 currentDomainName = domainName;
234 public void resetCurrentDomainName() {
235 // Reset the current domain name.
236 currentDomainName = "";
239 public String getCurrentDomainName() {
240 // Return the current domain name.
241 return currentDomainName;
245 // First-party cookies.
246 public void setAcceptFirstPartyCookies(boolean status) {
247 // Store the accept first-party cookies status.
248 acceptFirstPartyCookies = status;
251 public boolean getAcceptFirstPartyCookies() {
252 // Return the accept first-party cookies status.
253 return acceptFirstPartyCookies;
257 // Domain settings JavaScript enabled. This can be removed once night mode does not require JavaScript.
258 public void setDomainSettingsJavaScriptEnabled(boolean status) {
259 // Store the domain settings JavaScript status.
260 domainSettingsJavaScriptEnabled = status;
263 public boolean getDomainSettingsJavaScriptEnabled() {
264 // Return the domain settings JavaScript status.
265 return domainSettingsJavaScriptEnabled;
269 // Resource requests.
270 public void addResourceRequest(String[] resourceRequest) {
271 // Add the resource request to the list.
272 resourceRequests.add(resourceRequest);
275 public ArrayList<String[]> getResourceRequests() {
276 // Return the list of resource requests.
277 return resourceRequests;
280 public void clearResourceRequests() {
281 // Clear the resource requests.
282 resourceRequests.clear();
287 public void enableBlocklist(int blocklist, boolean status) {
288 // Update the status of the indicated blocklist.
291 // Update the status of the blocklist.
292 easyListEnabled = status;
296 // Update the status of the blocklist.
297 easyPrivacyEnabled = status;
300 case FANBOYS_ANNOYANCE_LIST:
301 // Update the status of the blocklist.
302 fanboysAnnoyanceListEnabled = status;
305 case FANBOYS_SOCIAL_BLOCKING_LIST:
306 // Update the status of the blocklist.
307 fanboysSocialBlockingListEnabled = status;
311 // Update the status of the blocklist.
312 ultraPrivacyEnabled = status;
315 case THIRD_PARTY_REQUESTS:
316 // Update the status of the blocklist.
317 blockAllThirdPartyRequests = status;
322 public boolean isBlocklistEnabled(int blocklist) {
323 // Get the status of the indicated blocklist.
326 // Return the status of the blocklist.
327 return easyListEnabled;
330 // Return the status of the blocklist.
331 return easyPrivacyEnabled;
333 case FANBOYS_ANNOYANCE_LIST:
334 // Return the status of the blocklist.
335 return fanboysAnnoyanceListEnabled;
337 case FANBOYS_SOCIAL_BLOCKING_LIST:
338 // Return the status of the blocklist.
339 return fanboysSocialBlockingListEnabled;
342 // Return the status of the blocklist.
343 return ultraPrivacyEnabled;
345 case THIRD_PARTY_REQUESTS:
346 // Return the status of the blocklist.
347 return blockAllThirdPartyRequests;
350 // The default value is required but should never be used.
356 // Resource request counters.
357 public void resetRequestsCounters() {
358 // Reset all the resource request counters.
360 easyListBlockedRequests = 0;
361 easyPrivacyBlockedRequests = 0;
362 fanboysAnnoyanceListBlockedRequests = 0;
363 fanboysSocialBlockingListBlockedRequests = 0;
364 ultraPrivacyBlockedRequests = 0;
365 thirdPartyBlockedRequests = 0;
368 public void incrementRequestsCount(int blocklist) {
369 // Increment the count of the indicated blocklist.
371 case BLOCKED_REQUESTS:
372 // Increment the blocked requests count.
377 // Increment the EasyList blocked requests count.
378 easyListBlockedRequests++;
382 // Increment the EasyPrivacy blocked requests count.
383 easyPrivacyBlockedRequests++;
386 case FANBOYS_ANNOYANCE_LIST:
387 // Increment the Fanboy's Annoyance List blocked requests count.
388 fanboysAnnoyanceListBlockedRequests++;
391 case FANBOYS_SOCIAL_BLOCKING_LIST:
392 // Increment the Fanboy's Social Blocking List blocked requests count.
393 fanboysSocialBlockingListBlockedRequests++;
397 // Increment the UltraPrivacy blocked requests count.
398 ultraPrivacyBlockedRequests++;
401 case THIRD_PARTY_REQUESTS:
402 // Increment the Third Party blocked requests count.
403 thirdPartyBlockedRequests++;
408 public int getRequestsCount(int blocklist) {
409 // Get the count of the indicated blocklist.
411 case BLOCKED_REQUESTS:
412 // Return the blocked requests count.
413 return blockedRequests;
416 // Return the EasyList blocked requests count.
417 return easyListBlockedRequests;
420 // Return the EasyPrivacy blocked requests count.
421 return easyPrivacyBlockedRequests;
423 case FANBOYS_ANNOYANCE_LIST:
424 // Return the Fanboy's Annoyance List blocked requests count.
425 return fanboysAnnoyanceListBlockedRequests;
427 case FANBOYS_SOCIAL_BLOCKING_LIST:
428 // Return the Fanboy's Social Blocking List blocked requests count.
429 return fanboysSocialBlockingListBlockedRequests;
432 // Return the UltraPrivacy blocked requests count.
433 return ultraPrivacyBlockedRequests;
435 case THIRD_PARTY_REQUESTS:
436 // Return the Third Party blocked requests count.
437 return thirdPartyBlockedRequests;
440 // Return 0. This should never end up being called.
446 // Pinned SSL certificates.
447 public boolean hasPinnedSslCertificate() {
448 // Return the status of the pinned SSL certificate.
449 return hasPinnedSslCertificate;
452 public void setPinnedSslCertificate(String issuedToCName, String issuedToOName, String issuedToUName, String issuedByCName, String issuedByOName, String issuedByUName, Date startDate, Date endDate) {
453 // Store the pinned SSL certificate information.
454 pinnedSslIssuedToCName = issuedToCName;
455 pinnedSslIssuedToOName = issuedToOName;
456 pinnedSslIssuedToUName = issuedToUName;
457 pinnedSslIssuedByCName = issuedByCName;
458 pinnedSslIssuedByOName = issuedByOName;
459 pinnedSslIssuedByUName = issuedByUName;
460 pinnedSslStartDate = startDate;
461 pinnedSslEndDate = endDate;
463 // Set the pinned SSL certificate tracker.
464 hasPinnedSslCertificate = true;
467 public ArrayList<Object> getPinnedSslCertificate() {
468 // Initialize an array list.
469 ArrayList<Object> arrayList = new ArrayList<>();
471 // Create the SSL certificate string array.
472 String[] sslCertificateStringArray = new String[] {pinnedSslIssuedToCName, pinnedSslIssuedToOName, pinnedSslIssuedToUName, pinnedSslIssuedByCName, pinnedSslIssuedByOName, pinnedSslIssuedByUName};
474 // Create the SSL certificate date array.
475 Date[] sslCertificateDateArray = new Date[] {pinnedSslStartDate, pinnedSslEndDate};
477 // Add the arrays to the array list.
478 arrayList.add(sslCertificateStringArray);
479 arrayList.add(sslCertificateDateArray);
481 // Return the pinned SSL certificate array list.
485 public void clearPinnedSslCertificate() {
486 // Clear the pinned SSL certificate.
487 pinnedSslIssuedToCName = null;
488 pinnedSslIssuedToOName = null;
489 pinnedSslIssuedToUName = null;
490 pinnedSslIssuedByCName = null;
491 pinnedSslIssuedByOName = null;
492 pinnedSslIssuedByUName = null;
493 pinnedSslStartDate = null;
494 pinnedSslEndDate = null;
496 // Clear the pinned SSL certificate tracker.
497 hasPinnedSslCertificate = false;
501 // Current IP addresses.
502 public boolean hasCurrentIpAddresses() {
503 // Return the status of the current IP addresses.
504 return hasCurrentIpAddresses;
507 public void setCurrentIpAddresses(String ipAddresses) {
508 // Store the current IP addresses.
509 currentIpAddresses = ipAddresses;
511 // Set the current IP addresses tracker.
512 hasCurrentIpAddresses = true;
515 public String getCurrentIpAddresses() {
516 // Return the current IP addresses.
517 return currentIpAddresses;
520 public void clearCurrentIpAddresses() {
521 // Clear the current IP addresses.
522 currentIpAddresses = null;
524 // Clear the current IP addresses tracker.
525 hasCurrentIpAddresses = false;
529 // Pinned IP addresses.
530 public boolean hasPinnedIpAddresses() {
531 // Return the status of the pinned IP addresses.
532 return hasPinnedIpAddresses;
535 public void setPinnedIpAddresses(String ipAddresses) {
536 // Store the pinned IP addresses.
537 pinnedIpAddresses = ipAddresses;
539 // Set the pinned IP addresses tracker.
540 hasPinnedIpAddresses = true;
543 public String getPinnedIpAddresses() {
544 // Return the pinned IP addresses.
545 return pinnedIpAddresses;
548 public void clearPinnedIpAddresses() {
549 // Clear the pinned IP addresses.
550 pinnedIpAddresses = null;
552 // Clear the pinned IP addresses tracker.
553 hasPinnedIpAddresses = false;
557 // Ignore pinned information.
558 public void setIgnorePinnedDomainInformation(boolean status) {
559 // Set the status of the ignore pinned domain information tracker.
560 ignorePinnedDomainInformation = status;
563 // The syntax looks better as written, even if it is always inverted.
564 @SuppressWarnings("BooleanMethodIsAlwaysInverted")
565 public boolean ignorePinnedDomainInformation() {
566 // Return the status of the ignore pinned domain information tracker.
567 return ignorePinnedDomainInformation;
571 // Navigating history.
572 public void setNavigatingHistory(boolean status) {
573 // Set the status of navigating history.
574 navigatingHistory = status;
577 public boolean getNavigatingHistory() {
578 // Return the status of navigating history.
579 return navigatingHistory;
583 // Favorite or default icon.
584 public void initializeFavoriteIcon() {
585 // Get the default favorite icon drawable. `ContextCompat` must be used until API >= 21.
586 Drawable favoriteIconDrawable = ContextCompat.getDrawable(getContext(), R.drawable.world);
588 // Cast the favorite icon drawable to a bitmap drawable.
589 BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable;
591 // Remove the incorrect warning below that the favorite icon bitmap drawable might be null.
592 assert favoriteIconBitmapDrawable != null;
594 // Store the default icon bitmap.
595 favoriteOrDefaultIcon = favoriteIconBitmapDrawable.getBitmap();
598 public void setFavoriteOrDefaultIcon(Bitmap icon) {
599 // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation.
600 if ((icon.getHeight() > 256) || (icon.getWidth() > 256)) {
601 favoriteOrDefaultIcon = Bitmap.createScaledBitmap(icon, 256, 256, true);
603 // Store the icon as presented.
604 favoriteOrDefaultIcon = icon;
608 public Bitmap getFavoriteOrDefaultIcon() {
609 // Return the favorite or default icon.
610 return favoriteOrDefaultIcon;
615 public void setNightMode(boolean status) {
616 // Store the night mode status.
620 public boolean getNightMode() {
621 // Return the night mode status.
627 public void setSwipeToRefresh(boolean status) {
628 // Store the swipe to refresh status.
629 swipeToRefresh = status;
632 public boolean getSwipeToRefresh() {
633 // Return the swipe to refresh status.
634 return swipeToRefresh;
640 public boolean onTouchEvent(MotionEvent motionEvent) {
641 // Initialize a tracker to return if this motion event is handled.
642 boolean motionEventHandled;
644 // Run the commands for the given motion event action.
645 switch (motionEvent.getAction()) {
646 case MotionEvent.ACTION_DOWN:
647 // Start nested scrolling along the vertical axis. `ViewCompat` must be used until the minimum API >= 21.
648 startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
650 // Save the current Y position. Action down will not be called again until a new motion starts.
651 previousYPosition = (int) motionEvent.getY();
653 // Run the default commands.
654 motionEventHandled = super.onTouchEvent(motionEvent);
657 case MotionEvent.ACTION_MOVE:
658 // Get the current Y position.
659 int currentYMotionPosition = (int) motionEvent.getY();
661 // Calculate the pre-scroll delta Y.
662 int preScrollDeltaY = previousYPosition - currentYMotionPosition;
664 // Initialize a variable to track how much of the scroll is consumed.
665 int[] consumedScroll = new int[2];
667 // Initialize a variable to track the offset in the window.
668 int[] offsetInWindow = new int[2];
670 // Get the WebView Y position.
671 int webViewYPosition = getScrollY();
673 // Set the scroll delta Y to initially be the same as the pre-scroll delta Y.
674 int scrollDeltaY = preScrollDeltaY;
676 // Dispatch the nested pre-school. This scrolls the app bar if it needs it. `offsetInWindow` will be returned with an updated value.
677 if (dispatchNestedPreScroll(0, preScrollDeltaY, consumedScroll, offsetInWindow)) {
678 // Update the scroll delta Y if some of it was consumed.
679 // There is currently a bug in Android where if scrolling up at a certain slow speed the input can lock the pre scroll and continue to consume it after the app bar is fully displayed.
680 scrollDeltaY = preScrollDeltaY - consumedScroll[1];
683 // Check to see if the WebView is at the top and and the scroll action is downward.
684 if ((webViewYPosition == 0) && (scrollDeltaY < 0)) { // Swipe to refresh is being engaged.
685 // 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.
687 } else { // Swipe to refresh is not being engaged.
688 // Start the nested scroll so that the app bar can scroll off the screen.
689 startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
691 // 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.
692 dispatchNestedScroll(0, scrollDeltaY, 0, 0, offsetInWindow);
694 // Store the current Y position for use in the next action move.
695 previousYPosition = previousYPosition - scrollDeltaY;
698 // Run the default commands.
699 motionEventHandled = super.onTouchEvent(motionEvent);
704 // Stop nested scrolling.
707 // Run the default commands.
708 motionEventHandled = super.onTouchEvent(motionEvent);
711 // Perform a click. This is required by the Android accessibility guidelines.
714 // Return the status of the motion event.
715 return motionEventHandled;
718 // The Android accessibility guidelines require overriding `performClick()` and calling it from `onTouchEvent()`.
720 public boolean performClick() {
721 return super.performClick();
725 // Method from NestedScrollingChild.
727 public void setNestedScrollingEnabled(boolean status) {
728 // Set the status of the nested scrolling.
729 nestedScrollingChildHelper.setNestedScrollingEnabled(status);
732 // Method from NestedScrollingChild.
734 public boolean isNestedScrollingEnabled() {
735 // Return the status of nested scrolling.
736 return nestedScrollingChildHelper.isNestedScrollingEnabled();
740 // Method from NestedScrollingChild.
742 public boolean startNestedScroll(int axes) {
743 // Start a nested scroll along the indicated axes.
744 return nestedScrollingChildHelper.startNestedScroll(axes);
747 // Method from NestedScrollingChild2.
749 public boolean startNestedScroll(int axes, int type) {
750 // Start a nested scroll along the indicated axes for the given type of input which caused the scroll event.
751 return nestedScrollingChildHelper.startNestedScroll(axes, type);
755 // Method from NestedScrollingChild.
757 public void stopNestedScroll() {
758 // Stop the nested scroll.
759 nestedScrollingChildHelper.stopNestedScroll();
762 // Method from NestedScrollingChild2.
764 public void stopNestedScroll(int type) {
765 // Stop the nested scroll of the given type of input which caused the scroll event.
766 nestedScrollingChildHelper.stopNestedScroll(type);
770 // Method from NestedScrollingChild.
772 public boolean hasNestedScrollingParent() {
773 // Return the status of the nested scrolling parent.
774 return nestedScrollingChildHelper.hasNestedScrollingParent();
777 // Method from NestedScrollingChild2.
779 public boolean hasNestedScrollingParent(int type) {
780 // return the status of the nested scrolling parent for the given type of input which caused the scroll event.
781 return nestedScrollingChildHelper.hasNestedScrollingParent(type);
785 // Method from NestedScrollingChild.
787 public boolean dispatchNestedPreScroll(int deltaX, int deltaY, int[] consumed, int[] offsetInWindow) {
788 // Dispatch a nested pre-scroll with the specified deltas, which lets a parent to consume some of the scroll if desired.
789 return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow);
792 // Method from NestedScrollingChild2.
794 public boolean dispatchNestedPreScroll(int deltaX, int deltaY, int[] consumed, int[] offsetInWindow, int type) {
795 // 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.
796 return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow, type);
800 // Method from NestedScrollingChild.
802 public boolean dispatchNestedScroll(int deltaXConsumed, int deltaYConsumed, int deltaXUnconsumed, int deltaYUnconsumed, int[] offsetInWindow) {
803 // Dispatch a nested scroll with the specified deltas.
804 return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow);
807 // Method from NestedScrollingChild2.
809 public boolean dispatchNestedScroll(int deltaXConsumed, int deltaYConsumed, int deltaXUnconsumed, int deltaYUnconsumed, int[] offsetInWindow, int type) {
810 // Dispatch a nested scroll with the specified deltas for the given type of input which caused the scroll event.
811 return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow, type);
815 // Method from NestedScrollingChild.
817 public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
818 // Dispatch a nested pre-fling with the specified velocity, which lets a parent consume the fling if desired.
819 return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
822 // Method from NestedScrollingChild.
824 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
825 // Dispatch a nested fling with the specified velocity.
826 return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);