Migrate to AndroidX from the Android Support Library. https://redmine.stoutner.com...
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / views / NestedScrollWebView.java
1 /*
2  * Copyright © 2019 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 package com.stoutner.privacybrowser.views;
21
22 import android.content.Context;
23 import android.util.AttributeSet;
24 import android.view.MotionEvent;
25 import android.webkit.WebView;
26
27 import androidx.core.view.NestedScrollingChild2;
28 import androidx.core.view.NestedScrollingChildHelper;
29 import androidx.core.view.ViewCompat;
30
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;
35
36     // The previous Y position needs to be tracked between motion events.
37     private int previousYPosition;
38
39
40     // Basic constructor.
41     public NestedScrollWebView(Context context) {
42         // Roll up to the next constructor.
43         this(context, null);
44     }
45
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);
50     }
51
52     // Full constructor.
53     public NestedScrollWebView(Context context, AttributeSet attributeSet, int defaultStyle) {
54         // Run the default commands.
55         super(context, attributeSet, defaultStyle);
56
57         // Initialize the nested scrolling child helper.
58         nestedScrollingChildHelper = new NestedScrollingChildHelper(this);
59
60         // Enable nested scrolling by default.
61         nestedScrollingChildHelper.setNestedScrollingEnabled(true);
62     }
63
64
65     @Override
66     public boolean onTouchEvent(MotionEvent motionEvent) {
67         // Initialize a tracker to return if this motion event is handled.
68         boolean motionEventHandled;
69
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);
75
76                 // Save the current Y position.  Action down will not be called again until a new motion starts.
77                 previousYPosition = (int) motionEvent.getY();
78
79                 // Run the default commands.
80                 motionEventHandled = super.onTouchEvent(motionEvent);
81                 break;
82
83             case MotionEvent.ACTION_MOVE:
84                 // Get the current Y position.
85                 int currentYPosition = (int) motionEvent.getY();
86
87                 // Calculate the delta Y.
88                 int deltaY = previousYPosition - currentYPosition;
89
90                 // Store the current Y position for use in the next action move.
91                 previousYPosition = currentYPosition;
92
93                 // Dispatch the nested pre-school.
94                 dispatchNestedPreScroll(0, deltaY, null, null);
95
96                 // Dispatch the nested scroll.
97                 dispatchNestedScroll(0, deltaY, 0, 0, null);
98
99                 // Run the default commands.
100                 motionEventHandled = super.onTouchEvent(motionEvent);
101                 break;
102
103
104             default:
105                 // Stop nested scrolling.
106                 stopNestedScroll();
107
108                 // Run the default commands.
109                 motionEventHandled = super.onTouchEvent(motionEvent);
110         }
111
112         // Return the status of the motion event.
113         return motionEventHandled;
114     }
115
116
117     // Method from NestedScrollingChild.
118     @Override
119     public void setNestedScrollingEnabled(boolean status) {
120         // Set the status of the nested scrolling.
121         nestedScrollingChildHelper.setNestedScrollingEnabled(status);
122     }
123
124     // Method from NestedScrollingChild.
125     @Override
126     public boolean isNestedScrollingEnabled() {
127         // Return the status of nested scrolling.
128         return nestedScrollingChildHelper.isNestedScrollingEnabled();
129     }
130
131
132     // Method from NestedScrollingChild.
133     @Override
134     public boolean startNestedScroll(int axes) {
135         // Start a nested scroll along the indicated axes.
136         return nestedScrollingChildHelper.startNestedScroll(axes);
137     }
138
139     // Method from NestedScrollingChild2.
140     @Override
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);
144     }
145
146
147     // Method from NestedScrollingChild.
148     @Override
149     public void stopNestedScroll() {
150         // Stop the nested scroll.
151         nestedScrollingChildHelper.stopNestedScroll();
152     }
153
154     // Method from NestedScrollingChild2.
155     @Override
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);
159     }
160
161
162     // Method from NestedScrollingChild.
163     @Override
164     public boolean hasNestedScrollingParent() {
165         // Return the status of the nested scrolling parent.
166         return nestedScrollingChildHelper.hasNestedScrollingParent();
167     }
168
169     // Method from NestedScrollingChild2.
170     @Override
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);
174     }
175
176
177     // Method from NestedScrollingChild.
178     @Override
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);
182     }
183
184     // Method from NestedScrollingChild2.
185     @Override
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);
189     }
190
191
192     // Method from NestedScrollingChild.
193     @Override
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);
197     }
198
199     // Method from NestedScrollingChild2.
200     @Override
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);
204     }
205
206
207     // Method from NestedScrollingChild.
208     @Override
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);
212     }
213
214     // Method from NestedScrollingChild.
215     @Override
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);
219     }
220 }