2 * Copyright © 2019-2020 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.Collections;
42 import java.util.Date;
43 import java.util.List;
45 // NestedScrollWebView extends WebView to handle nested scrolls (scrolling the app bar off the screen).
46 public class NestedScrollWebView extends WebView implements NestedScrollingChild2 {
47 // These constants identify the blocklists.
48 public final static int BLOCKED_REQUESTS = 0;
49 public final static int EASYLIST = 1;
50 public final static int EASYPRIVACY = 2;
51 public final static int FANBOYS_ANNOYANCE_LIST = 3;
52 public final static int FANBOYS_SOCIAL_BLOCKING_LIST = 4;
53 public final static int ULTRALIST = 5;
54 public final static int ULTRAPRIVACY = 6;
55 public final static int THIRD_PARTY_REQUESTS = 7;
57 // Keep a copy of the WebView fragment ID.
58 private long webViewFragmentId;
60 // Store the handlers.
61 private SslErrorHandler sslErrorHandler;
62 private HttpAuthHandler httpAuthHandler;
64 // Track if domain settings are applied to this nested scroll WebView and, if so, the database ID.
65 private boolean domainSettingsApplied;
66 private int domainSettingsDatabaseId;
68 // Keep track of the current URL. This is used to not block resource requests to the main URL.
69 private String currentUrl;
71 // Keep track of when the domain name changes so that domain settings can be reapplied. This should never be null.
72 private String currentDomainName = "";
74 // Track the status of first-party cookies.
75 private boolean acceptFirstPartyCookies;
77 // Track the resource requests.
78 private List<String[]> resourceRequests = Collections.synchronizedList(new ArrayList<>()); // Using a synchronized list makes adding resource requests thread safe.
79 private boolean easyListEnabled;
80 private boolean easyPrivacyEnabled;
81 private boolean fanboysAnnoyanceListEnabled;
82 private boolean fanboysSocialBlockingListEnabled;
83 private boolean ultraListEnabled;
84 private boolean ultraPrivacyEnabled;
85 private boolean blockAllThirdPartyRequests;
86 private int blockedRequests;
87 private int easyListBlockedRequests;
88 private int easyPrivacyBlockedRequests;
89 private int fanboysAnnoyanceListBlockedRequests;
90 private int fanboysSocialBlockingListBlockedRequests;
91 private int ultraListBlockedRequests;
92 private int ultraPrivacyBlockedRequests;
93 private int thirdPartyBlockedRequests;
95 // The pinned SSL certificate variables.
96 private boolean hasPinnedSslCertificate;
97 private String pinnedSslIssuedToCName;
98 private String pinnedSslIssuedToOName;
99 private String pinnedSslIssuedToUName;
100 private String pinnedSslIssuedByCName;
101 private String pinnedSslIssuedByOName;
102 private String pinnedSslIssuedByUName;
103 private Date pinnedSslStartDate;
104 private Date pinnedSslEndDate;
106 // The current IP addresses variables.
107 private boolean hasCurrentIpAddresses;
108 private String currentIpAddresses;
110 // The pinned IP addresses variables.
111 private boolean hasPinnedIpAddresses;
112 private String pinnedIpAddresses;
114 // 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.
115 private boolean ignorePinnedDomainInformation;
117 // The default or favorite icon.
118 private Bitmap favoriteOrDefaultIcon;
120 // Track swipe to refresh.
121 private boolean swipeToRefresh;
123 // Track a URL waiting for a proxy.
124 private String waitingForProxyUrlString = "";
126 // The nested scrolling child helper is used throughout the class.
127 private NestedScrollingChildHelper nestedScrollingChildHelper;
129 // The previous Y position needs to be tracked between motion events.
130 private int previousYPosition;
134 // The basic constructor.
135 public NestedScrollWebView(Context context) {
136 // Roll up to the next constructor.
140 // The intermediate constructor.
141 public NestedScrollWebView(Context context, AttributeSet attributeSet) {
142 // Roll up to the next constructor.
143 this(context, attributeSet, android.R.attr.webViewStyle);
146 // The full constructor.
147 public NestedScrollWebView(Context context, AttributeSet attributeSet, int defaultStyle) {
148 // Run the default commands.
149 super(context, attributeSet, defaultStyle);
151 // Initialize the nested scrolling child helper.
152 nestedScrollingChildHelper = new NestedScrollingChildHelper(this);
154 // Enable nested scrolling by default.
155 nestedScrollingChildHelper.setNestedScrollingEnabled(true);
160 // WebView Fragment ID.
161 public void setWebViewFragmentId(long webViewFragmentId) {
162 // Store the WebView fragment ID.
163 this.webViewFragmentId = webViewFragmentId;
166 public long getWebViewFragmentId() {
167 // Return the WebView fragment ID.
168 return webViewFragmentId;
172 // SSL error handler.
173 public void setSslErrorHandler(SslErrorHandler sslErrorHandler) {
174 // Store the current SSL error handler.
175 this.sslErrorHandler = sslErrorHandler;
178 public SslErrorHandler getSslErrorHandler() {
179 // Return the current SSL error handler.
180 return sslErrorHandler;
183 public void resetSslErrorHandler() {
184 // Reset the current SSL error handler.
185 sslErrorHandler = null;
189 // HTTP authentication handler.
190 public void setHttpAuthHandler(HttpAuthHandler httpAuthHandler) {
191 // Store the current HTTP authentication handler.
192 this.httpAuthHandler = httpAuthHandler;
195 public HttpAuthHandler getHttpAuthHandler() {
196 // Return the current HTTP authentication handler.
197 return httpAuthHandler;
200 public void resetHttpAuthHandler() {
201 // Reset the current HTTP authentication handler.
202 httpAuthHandler = null;
207 public void setDomainSettingsApplied(boolean applied) {
208 // Store the domain settings applied status.
209 domainSettingsApplied = applied;
212 public boolean getDomainSettingsApplied() {
213 // Return the domain settings applied status.
214 return domainSettingsApplied;
218 // Domain settings database ID.
219 public void setDomainSettingsDatabaseId(int databaseId) {
220 // Store the domain settings database ID.
221 domainSettingsDatabaseId = databaseId;
224 public int getDomainSettingsDatabaseId() {
225 // Return the domain settings database ID.
226 return domainSettingsDatabaseId;
231 public void setCurrentUrl(String url) {
232 // Store the current URL.
236 public String getCurrentUrl() {
237 // Return the current URL.
242 // Current domain name. To function well when called, the domain name should never be allowed to be null.
243 public void setCurrentDomainName(@NonNull String domainName) {
244 // Store the current domain name.
245 currentDomainName = domainName;
248 public void resetCurrentDomainName() {
249 // Reset the current domain name.
250 currentDomainName = "";
253 public String getCurrentDomainName() {
254 // Return the current domain name.
255 return currentDomainName;
259 // First-party cookies.
260 public void setAcceptFirstPartyCookies(boolean status) {
261 // Store the accept first-party cookies status.
262 acceptFirstPartyCookies = status;
265 public boolean getAcceptFirstPartyCookies() {
266 // Return the accept first-party cookies status.
267 return acceptFirstPartyCookies;
271 // Resource requests.
272 public void addResourceRequest(String[] resourceRequest) {
273 // Add the resource request to the list.
274 resourceRequests.add(resourceRequest);
277 public List<String[]> getResourceRequests() {
278 // Return the list of resource requests as an array list.
279 return resourceRequests;
282 public void clearResourceRequests() {
283 // Clear the resource requests.
284 resourceRequests.clear();
289 public void enableBlocklist(int blocklist, boolean status) {
290 // Update the status of the indicated blocklist.
293 // Update the status of the blocklist.
294 easyListEnabled = status;
298 // Update the status of the blocklist.
299 easyPrivacyEnabled = status;
302 case FANBOYS_ANNOYANCE_LIST:
303 // Update the status of the blocklist.
304 fanboysAnnoyanceListEnabled = status;
307 case FANBOYS_SOCIAL_BLOCKING_LIST:
308 // Update the status of the blocklist.
309 fanboysSocialBlockingListEnabled = status;
313 // Update the status of the blocklist.
314 ultraListEnabled = status;
318 // Update the status of the blocklist.
319 ultraPrivacyEnabled = status;
322 case THIRD_PARTY_REQUESTS:
323 // Update the status of the blocklist.
324 blockAllThirdPartyRequests = status;
329 public boolean isBlocklistEnabled(int blocklist) {
330 // Get the status of the indicated blocklist.
333 // Return the status of the blocklist.
334 return easyListEnabled;
337 // Return the status of the blocklist.
338 return easyPrivacyEnabled;
340 case FANBOYS_ANNOYANCE_LIST:
341 // Return the status of the blocklist.
342 return fanboysAnnoyanceListEnabled;
344 case FANBOYS_SOCIAL_BLOCKING_LIST:
345 // Return the status of the blocklist.
346 return fanboysSocialBlockingListEnabled;
349 // Return the status of the blocklist.
350 return ultraListEnabled;
353 // Return the status of the blocklist.
354 return ultraPrivacyEnabled;
356 case THIRD_PARTY_REQUESTS:
357 // Return the status of the blocklist.
358 return blockAllThirdPartyRequests;
361 // The default value is required but should never be used.
367 // Resource request counters.
368 public void resetRequestsCounters() {
369 // Reset all the resource request counters.
371 easyListBlockedRequests = 0;
372 easyPrivacyBlockedRequests = 0;
373 fanboysAnnoyanceListBlockedRequests = 0;
374 fanboysSocialBlockingListBlockedRequests = 0;
375 ultraListBlockedRequests = 0;
376 ultraPrivacyBlockedRequests = 0;
377 thirdPartyBlockedRequests = 0;
380 public void incrementRequestsCount(int blocklist) {
381 // Increment the count of the indicated blocklist.
383 case BLOCKED_REQUESTS:
384 // Increment the blocked requests count.
389 // Increment the EasyList blocked requests count.
390 easyListBlockedRequests++;
394 // Increment the EasyPrivacy blocked requests count.
395 easyPrivacyBlockedRequests++;
398 case FANBOYS_ANNOYANCE_LIST:
399 // Increment the Fanboy's Annoyance List blocked requests count.
400 fanboysAnnoyanceListBlockedRequests++;
403 case FANBOYS_SOCIAL_BLOCKING_LIST:
404 // Increment the Fanboy's Social Blocking List blocked requests count.
405 fanboysSocialBlockingListBlockedRequests++;
409 // Increment the UltraList blocked requests count.
410 ultraListBlockedRequests++;
414 // Increment the UltraPrivacy blocked requests count.
415 ultraPrivacyBlockedRequests++;
418 case THIRD_PARTY_REQUESTS:
419 // Increment the Third Party blocked requests count.
420 thirdPartyBlockedRequests++;
425 public int getRequestsCount(int blocklist) {
426 // Get the count of the indicated blocklist.
428 case BLOCKED_REQUESTS:
429 // Return the blocked requests count.
430 return blockedRequests;
433 // Return the EasyList blocked requests count.
434 return easyListBlockedRequests;
437 // Return the EasyPrivacy blocked requests count.
438 return easyPrivacyBlockedRequests;
440 case FANBOYS_ANNOYANCE_LIST:
441 // Return the Fanboy's Annoyance List blocked requests count.
442 return fanboysAnnoyanceListBlockedRequests;
444 case FANBOYS_SOCIAL_BLOCKING_LIST:
445 // Return the Fanboy's Social Blocking List blocked requests count.
446 return fanboysSocialBlockingListBlockedRequests;
449 // Return the UltraList blocked requests count.
450 return ultraListBlockedRequests;
453 // Return the UltraPrivacy blocked requests count.
454 return ultraPrivacyBlockedRequests;
456 case THIRD_PARTY_REQUESTS:
457 // Return the Third Party blocked requests count.
458 return thirdPartyBlockedRequests;
461 // Return 0. This should never end up being called.
467 // Pinned SSL certificates.
468 public boolean hasPinnedSslCertificate() {
469 // Return the status of the pinned SSL certificate.
470 return hasPinnedSslCertificate;
473 public void setPinnedSslCertificate(String issuedToCName, String issuedToOName, String issuedToUName, String issuedByCName, String issuedByOName, String issuedByUName, Date startDate, Date endDate) {
474 // Store the pinned SSL certificate information.
475 pinnedSslIssuedToCName = issuedToCName;
476 pinnedSslIssuedToOName = issuedToOName;
477 pinnedSslIssuedToUName = issuedToUName;
478 pinnedSslIssuedByCName = issuedByCName;
479 pinnedSslIssuedByOName = issuedByOName;
480 pinnedSslIssuedByUName = issuedByUName;
481 pinnedSslStartDate = startDate;
482 pinnedSslEndDate = endDate;
484 // Set the pinned SSL certificate tracker.
485 hasPinnedSslCertificate = true;
488 public ArrayList<Object> getPinnedSslCertificate() {
489 // Initialize an array list.
490 ArrayList<Object> arrayList = new ArrayList<>();
492 // Create the SSL certificate string array.
493 String[] sslCertificateStringArray = new String[] {pinnedSslIssuedToCName, pinnedSslIssuedToOName, pinnedSslIssuedToUName, pinnedSslIssuedByCName, pinnedSslIssuedByOName, pinnedSslIssuedByUName};
495 // Create the SSL certificate date array.
496 Date[] sslCertificateDateArray = new Date[] {pinnedSslStartDate, pinnedSslEndDate};
498 // Add the arrays to the array list.
499 arrayList.add(sslCertificateStringArray);
500 arrayList.add(sslCertificateDateArray);
502 // Return the pinned SSL certificate array list.
506 public void clearPinnedSslCertificate() {
507 // Clear the pinned SSL certificate.
508 pinnedSslIssuedToCName = null;
509 pinnedSslIssuedToOName = null;
510 pinnedSslIssuedToUName = null;
511 pinnedSslIssuedByCName = null;
512 pinnedSslIssuedByOName = null;
513 pinnedSslIssuedByUName = null;
514 pinnedSslStartDate = null;
515 pinnedSslEndDate = null;
517 // Clear the pinned SSL certificate tracker.
518 hasPinnedSslCertificate = false;
522 // Current IP addresses.
523 public boolean hasCurrentIpAddresses() {
524 // Return the status of the current IP addresses.
525 return hasCurrentIpAddresses;
528 public void setCurrentIpAddresses(String ipAddresses) {
529 // Store the current IP addresses.
530 currentIpAddresses = ipAddresses;
532 // Set the current IP addresses tracker.
533 hasCurrentIpAddresses = true;
536 public String getCurrentIpAddresses() {
537 // Return the current IP addresses.
538 return currentIpAddresses;
541 public void clearCurrentIpAddresses() {
542 // Clear the current IP addresses.
543 currentIpAddresses = null;
545 // Clear the current IP addresses tracker.
546 hasCurrentIpAddresses = false;
550 // Pinned IP addresses.
551 public boolean hasPinnedIpAddresses() {
552 // Return the status of the pinned IP addresses.
553 return hasPinnedIpAddresses;
556 public void setPinnedIpAddresses(String ipAddresses) {
557 // Store the pinned IP addresses.
558 pinnedIpAddresses = ipAddresses;
560 // Set the pinned IP addresses tracker.
561 hasPinnedIpAddresses = true;
564 public String getPinnedIpAddresses() {
565 // Return the pinned IP addresses.
566 return pinnedIpAddresses;
569 public void clearPinnedIpAddresses() {
570 // Clear the pinned IP addresses.
571 pinnedIpAddresses = null;
573 // Clear the pinned IP addresses tracker.
574 hasPinnedIpAddresses = false;
578 // Ignore pinned information.
579 public void setIgnorePinnedDomainInformation(boolean status) {
580 // Set the status of the ignore pinned domain information tracker.
581 ignorePinnedDomainInformation = status;
584 // The syntax looks better as written, even if it is always inverted.
585 @SuppressWarnings("BooleanMethodIsAlwaysInverted")
586 public boolean ignorePinnedDomainInformation() {
587 // Return the status of the ignore pinned domain information tracker.
588 return ignorePinnedDomainInformation;
592 // Favorite or default icon.
593 public void initializeFavoriteIcon() {
594 // Get the default favorite icon drawable. `ContextCompat` must be used until API >= 21.
595 Drawable favoriteIconDrawable = ContextCompat.getDrawable(getContext(), R.drawable.world);
597 // Cast the favorite icon drawable to a bitmap drawable.
598 BitmapDrawable favoriteIconBitmapDrawable = (BitmapDrawable) favoriteIconDrawable;
600 // Remove the incorrect warning below that the favorite icon bitmap drawable might be null.
601 assert favoriteIconBitmapDrawable != null;
603 // Store the default icon bitmap.
604 favoriteOrDefaultIcon = favoriteIconBitmapDrawable.getBitmap();
607 public void setFavoriteOrDefaultIcon(Bitmap icon) {
608 // Scale the favorite icon bitmap down if it is larger than 256 x 256. Filtering uses bilinear interpolation.
609 if ((icon.getHeight() > 256) || (icon.getWidth() > 256)) {
610 favoriteOrDefaultIcon = Bitmap.createScaledBitmap(icon, 256, 256, true);
612 // Store the icon as presented.
613 favoriteOrDefaultIcon = icon;
617 public Bitmap getFavoriteOrDefaultIcon() {
618 // Return the favorite or default icon.
619 return favoriteOrDefaultIcon;
624 public void setSwipeToRefresh(boolean status) {
625 // Store the swipe to refresh status.
626 swipeToRefresh = status;
629 public boolean getSwipeToRefresh() {
630 // Return the swipe to refresh status.
631 return swipeToRefresh;
635 // Waiting for proxy.
636 public void setWaitingForProxyUrlString(String urlString) {
637 // Store the waiting for proxy URL string.
638 waitingForProxyUrlString = urlString;
641 public String getWaitingForProxyUrlString() {
642 // Return the waiting for proxy URL string.
643 return waitingForProxyUrlString;
646 public void resetWaitingForProxyUrlString() {
647 // Clear the waiting for proxy URL string.
648 waitingForProxyUrlString = "";
652 public int getHorizontalScrollRange() {
653 // Return the horizontal scroll range.
654 return computeHorizontalScrollRange();
657 public int getVerticalScrollRange() {
658 // Return the vertical scroll range.
659 return computeVerticalScrollRange();
665 public boolean onTouchEvent(MotionEvent motionEvent) {
666 // Initialize a tracker to return if this motion event is handled.
667 boolean motionEventHandled;
669 // Run the commands for the given motion event action.
670 switch (motionEvent.getAction()) {
671 case MotionEvent.ACTION_DOWN:
672 // Start nested scrolling along the vertical axis. `ViewCompat` must be used until the minimum API >= 21.
673 startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
675 // Save the current Y position. Action down will not be called again until a new motion starts.
676 previousYPosition = (int) motionEvent.getY();
678 // Run the default commands.
679 motionEventHandled = super.onTouchEvent(motionEvent);
682 case MotionEvent.ACTION_MOVE:
683 // Get the current Y position.
684 int currentYMotionPosition = (int) motionEvent.getY();
686 // Calculate the pre-scroll delta Y.
687 int preScrollDeltaY = previousYPosition - currentYMotionPosition;
689 // Initialize a variable to track how much of the scroll is consumed.
690 int[] consumedScroll = new int[2];
692 // Initialize a variable to track the offset in the window.
693 int[] offsetInWindow = new int[2];
695 // Get the WebView Y position.
696 int webViewYPosition = getScrollY();
698 // Set the scroll delta Y to initially be the same as the pre-scroll delta Y.
699 int scrollDeltaY = preScrollDeltaY;
701 // Dispatch the nested pre-school. This scrolls the app bar if it needs it. `offsetInWindow` will be returned with an updated value.
702 if (dispatchNestedPreScroll(0, preScrollDeltaY, consumedScroll, offsetInWindow)) {
703 // Update the scroll delta Y if some of it was consumed.
704 // 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.
705 scrollDeltaY = preScrollDeltaY - consumedScroll[1];
708 // Check to see if the WebView is at the top and and the scroll action is downward.
709 if ((webViewYPosition == 0) && (scrollDeltaY < 0)) { // Swipe to refresh is being engaged.
710 // 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.
712 } else { // Swipe to refresh is not being engaged.
713 // Start the nested scroll so that the app bar can scroll off the screen.
714 startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
716 // 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.
717 dispatchNestedScroll(0, scrollDeltaY, 0, 0, offsetInWindow);
719 // Store the current Y position for use in the next action move.
720 previousYPosition = previousYPosition - scrollDeltaY;
723 // Run the default commands.
724 motionEventHandled = super.onTouchEvent(motionEvent);
729 // Stop nested scrolling.
732 // Run the default commands.
733 motionEventHandled = super.onTouchEvent(motionEvent);
736 // Perform a click. This is required by the Android accessibility guidelines.
739 // Return the status of the motion event.
740 return motionEventHandled;
743 // The Android accessibility guidelines require overriding `performClick()` and calling it from `onTouchEvent()`.
745 public boolean performClick() {
746 return super.performClick();
750 // Method from NestedScrollingChild.
752 public void setNestedScrollingEnabled(boolean status) {
753 // Set the status of the nested scrolling.
754 nestedScrollingChildHelper.setNestedScrollingEnabled(status);
757 // Method from NestedScrollingChild.
759 public boolean isNestedScrollingEnabled() {
760 // Return the status of nested scrolling.
761 return nestedScrollingChildHelper.isNestedScrollingEnabled();
765 // Method from NestedScrollingChild.
767 public boolean startNestedScroll(int axes) {
768 // Start a nested scroll along the indicated axes.
769 return nestedScrollingChildHelper.startNestedScroll(axes);
772 // Method from NestedScrollingChild2.
774 public boolean startNestedScroll(int axes, int type) {
775 // Start a nested scroll along the indicated axes for the given type of input which caused the scroll event.
776 return nestedScrollingChildHelper.startNestedScroll(axes, type);
780 // Method from NestedScrollingChild.
782 public void stopNestedScroll() {
783 // Stop the nested scroll.
784 nestedScrollingChildHelper.stopNestedScroll();
787 // Method from NestedScrollingChild2.
789 public void stopNestedScroll(int type) {
790 // Stop the nested scroll of the given type of input which caused the scroll event.
791 nestedScrollingChildHelper.stopNestedScroll(type);
795 // Method from NestedScrollingChild.
797 public boolean hasNestedScrollingParent() {
798 // Return the status of the nested scrolling parent.
799 return nestedScrollingChildHelper.hasNestedScrollingParent();
802 // Method from NestedScrollingChild2.
804 public boolean hasNestedScrollingParent(int type) {
805 // return the status of the nested scrolling parent for the given type of input which caused the scroll event.
806 return nestedScrollingChildHelper.hasNestedScrollingParent(type);
810 // Method from NestedScrollingChild.
812 public boolean dispatchNestedPreScroll(int deltaX, int deltaY, int[] consumed, int[] offsetInWindow) {
813 // Dispatch a nested pre-scroll with the specified deltas, which lets a parent to consume some of the scroll if desired.
814 return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow);
817 // Method from NestedScrollingChild2.
819 public boolean dispatchNestedPreScroll(int deltaX, int deltaY, int[] consumed, int[] offsetInWindow, int type) {
820 // 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.
821 return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow, type);
825 // Method from NestedScrollingChild.
827 public boolean dispatchNestedScroll(int deltaXConsumed, int deltaYConsumed, int deltaXUnconsumed, int deltaYUnconsumed, int[] offsetInWindow) {
828 // Dispatch a nested scroll with the specified deltas.
829 return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow);
832 // Method from NestedScrollingChild2.
834 public boolean dispatchNestedScroll(int deltaXConsumed, int deltaYConsumed, int deltaXUnconsumed, int deltaYUnconsumed, int[] offsetInWindow, int type) {
835 // Dispatch a nested scroll with the specified deltas for the given type of input which caused the scroll event.
836 return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow, type);
840 // Method from NestedScrollingChild.
842 public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
843 // Dispatch a nested pre-fling with the specified velocity, which lets a parent consume the fling if desired.
844 return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
847 // Method from NestedScrollingChild.
849 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
850 // Dispatch a nested fling with the specified velocity.
851 return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);