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.util.AttributeSet;
24 import android.view.MotionEvent;
25 import android.webkit.WebView;
27 import androidx.core.view.NestedScrollingChild2;
28 import androidx.core.view.NestedScrollingChildHelper;
29 import androidx.core.view.ViewCompat;
31 // NestedScrollWebView extends WebView to handle nested scrolls (scrolling the app bar off the screen).
32 public class NestedScrollWebView extends WebView implements NestedScrollingChild2 {
33 // The nested scrolling child helper is used throughout the class.
34 private NestedScrollingChildHelper nestedScrollingChildHelper;
36 // The previous Y position needs to be tracked between motion events.
37 private int previousYPosition;
41 public NestedScrollWebView(Context context) {
42 // Roll up to the next constructor.
46 // Intermediate constructor.
47 public NestedScrollWebView(Context context, AttributeSet attributeSet) {
48 // Roll up to the next constructor.
49 this(context, attributeSet, android.R.attr.webViewStyle);
53 public NestedScrollWebView(Context context, AttributeSet attributeSet, int defaultStyle) {
54 // Run the default commands.
55 super(context, attributeSet, defaultStyle);
57 // Initialize the nested scrolling child helper.
58 nestedScrollingChildHelper = new NestedScrollingChildHelper(this);
60 // Enable nested scrolling by default.
61 nestedScrollingChildHelper.setNestedScrollingEnabled(true);
66 public boolean onTouchEvent(MotionEvent motionEvent) {
67 // Initialize a tracker to return if this motion event is handled.
68 boolean motionEventHandled;
70 // Run the commands for the given motion event action.
71 switch (motionEvent.getAction()) {
72 case MotionEvent.ACTION_DOWN:
73 // Start nested scrolling along the vertical axis. `ViewCompat` must be used until the minimum API >= 21.
74 startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
76 // Save the current Y position. Action down will not be called again until a new motion starts.
77 previousYPosition = (int) motionEvent.getY();
79 // Run the default commands.
80 motionEventHandled = super.onTouchEvent(motionEvent);
83 case MotionEvent.ACTION_MOVE:
84 // Get the current Y position.
85 int currentYPosition = (int) motionEvent.getY();
87 // Calculate the delta Y.
88 int deltaY = previousYPosition - currentYPosition;
90 // Store the current Y position for use in the next action move.
91 previousYPosition = currentYPosition;
93 // Dispatch the nested pre-school.
94 dispatchNestedPreScroll(0, deltaY, null, null);
96 // Dispatch the nested scroll.
97 dispatchNestedScroll(0, deltaY, 0, 0, null);
99 // Run the default commands.
100 motionEventHandled = super.onTouchEvent(motionEvent);
105 // Stop nested scrolling.
108 // Run the default commands.
109 motionEventHandled = super.onTouchEvent(motionEvent);
112 // Return the status of the motion event.
113 return motionEventHandled;
117 // Method from NestedScrollingChild.
119 public void setNestedScrollingEnabled(boolean status) {
120 // Set the status of the nested scrolling.
121 nestedScrollingChildHelper.setNestedScrollingEnabled(status);
124 // Method from NestedScrollingChild.
126 public boolean isNestedScrollingEnabled() {
127 // Return the status of nested scrolling.
128 return nestedScrollingChildHelper.isNestedScrollingEnabled();
132 // Method from NestedScrollingChild.
134 public boolean startNestedScroll(int axes) {
135 // Start a nested scroll along the indicated axes.
136 return nestedScrollingChildHelper.startNestedScroll(axes);
139 // Method from NestedScrollingChild2.
141 public boolean startNestedScroll(int axes, int type) {
142 // Start a nested scroll along the indicated axes for the given type of input which caused the scroll event.
143 return nestedScrollingChildHelper.startNestedScroll(axes, type);
147 // Method from NestedScrollingChild.
149 public void stopNestedScroll() {
150 // Stop the nested scroll.
151 nestedScrollingChildHelper.stopNestedScroll();
154 // Method from NestedScrollingChild2.
156 public void stopNestedScroll(int type) {
157 // Stop the nested scroll of the given type of input which caused the scroll event.
158 nestedScrollingChildHelper.stopNestedScroll(type);
162 // Method from NestedScrollingChild.
164 public boolean hasNestedScrollingParent() {
165 // Return the status of the nested scrolling parent.
166 return nestedScrollingChildHelper.hasNestedScrollingParent();
169 // Method from NestedScrollingChild2.
171 public boolean hasNestedScrollingParent(int type) {
172 // return the status of the nested scrolling parent for the given type of input which caused the scroll event.
173 return nestedScrollingChildHelper.hasNestedScrollingParent(type);
177 // Method from NestedScrollingChild.
179 public boolean dispatchNestedPreScroll(int deltaX, int deltaY, int[] consumed, int[] offsetInWindow) {
180 // Dispatch a nested pre-scroll with the specified deltas, which lets a parent to consume some of the scroll if desired.
181 return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow);
184 // Method from NestedScrollingChild2.
186 public boolean dispatchNestedPreScroll(int deltaX, int deltaY, int[] consumed, int[] offsetInWindow, int type) {
187 // 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.
188 return nestedScrollingChildHelper.dispatchNestedPreScroll(deltaX, deltaY, consumed, offsetInWindow, type);
192 // Method from NestedScrollingChild.
194 public boolean dispatchNestedScroll(int deltaXConsumed, int deltaYConsumed, int deltaXUnconsumed, int deltaYUnconsumed, int[] offsetInWindow) {
195 // Dispatch a nested scroll with the specified deltas.
196 return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow);
199 // Method from NestedScrollingChild2.
201 public boolean dispatchNestedScroll(int deltaXConsumed, int deltaYConsumed, int deltaXUnconsumed, int deltaYUnconsumed, int[] offsetInWindow, int type) {
202 // Dispatch a nested scroll with the specified deltas for the given type of input which caused the scroll event.
203 return nestedScrollingChildHelper.dispatchNestedScroll(deltaXConsumed, deltaYConsumed, deltaXUnconsumed, deltaYUnconsumed, offsetInWindow, type);
207 // Method from NestedScrollingChild.
209 public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
210 // Dispatch a nested pre-fling with the specified velocity, which lets a parent consume the fling if desired.
211 return nestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
214 // Method from NestedScrollingChild.
216 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
217 // Dispatch a nested fling with the specified velocity.
218 return nestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);