forked from mozilla-mobile/android-components
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix mozilla-mobile#9614 - Add a new InputResultDetail
This will serve the following purposes: - wrapper for all the new data from GeckoView's onTouchEventForDetailResult - filters out values not in range (eg: GV's INPUT_RESULT_IGNORED) - controls how the data can be updated and offers clear APIs for querying this data without needing to know about the implementation specifics.
- Loading branch information
Showing
2 changed files
with
533 additions
and
0 deletions.
There are no files selected for viewing
267 changes: 267 additions & 0 deletions
267
...nents/concept/engine/src/main/java/mozilla/components/concept/engine/InputResultDetail.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
package mozilla.components.concept.engine | ||
|
||
import android.view.MotionEvent | ||
import androidx.annotation.VisibleForTesting | ||
|
||
// The below top-level values are following the same from [org.mozilla.geckoview.PanZoomController] | ||
|
||
/** | ||
* The the content has no scrollable element. | ||
* | ||
* @see [InputResultDetail.isTouchUnhandled] | ||
*/ | ||
@VisibleForTesting | ||
internal const val INPUT_UNHANDLED = 0 | ||
|
||
/** | ||
* The touch event is consumed by the [EngineView] | ||
* | ||
* @see [InputResultDetail.isTouchHandledByBrowser] | ||
*/ | ||
@VisibleForTesting | ||
internal const val INPUT_HANDLED = 1 | ||
|
||
/** | ||
* The touch event is consumed by the website through it's own touch listeners. | ||
* | ||
* @see [InputResultDetail.isTouchHandledByWebsite] | ||
*/ | ||
@VisibleForTesting | ||
internal const val INPUT_HANDLED_CONTENT = 2 | ||
|
||
/** | ||
* The website content is not scrollable. | ||
*/ | ||
@VisibleForTesting | ||
internal const val SCROLL_DIRECTIONS_NONE = 0 | ||
|
||
/** | ||
* The website content can be scrolled to the top. | ||
* | ||
* @see [InputResultDetail.canScrollToTop] | ||
*/ | ||
@VisibleForTesting | ||
internal const val SCROLL_DIRECTIONS_TOP = 1 shl 0 | ||
|
||
/** | ||
* The website content can be scrolled to the right. | ||
* | ||
* @see [InputResultDetail.canScrollToRight] | ||
*/ | ||
@VisibleForTesting | ||
internal const val SCROLL_DIRECTIONS_RIGHT = 1 shl 1 | ||
|
||
/** | ||
* The website content can be scrolled to the bottom. | ||
* | ||
* @see [InputResultDetail.canScrollToBottom] | ||
*/ | ||
@VisibleForTesting | ||
internal const val SCROLL_DIRECTIONS_BOTTOM = 1 shl 2 | ||
|
||
/** | ||
* The website content can be scrolled to the left. | ||
* | ||
* @see [InputResultDetail.canScrollToLeft] | ||
*/ | ||
@VisibleForTesting | ||
internal const val SCROLL_DIRECTIONS_LEFT = 1 shl 3 | ||
|
||
/** | ||
* The website content cannot be overscrolled. | ||
*/ | ||
@VisibleForTesting | ||
internal const val OVERSCROLL_DIRECTIONS_NONE = 0 | ||
|
||
/** | ||
* The website content can be overscrolled horizontally. | ||
* | ||
* @see [InputResultDetail.canOverscrollRight] | ||
* @see [InputResultDetail.canOverscrollLeft] | ||
*/ | ||
@VisibleForTesting | ||
internal const val OVERSCROLL_DIRECTIONS_HORIZONTAL = 1 shl 0 | ||
|
||
/** | ||
* The website content can be overscrolled vertically. | ||
* | ||
* @see [InputResultDetail.canOverscrollTop] | ||
* @see [InputResultDetail.canOverscrollBottom] | ||
*/ | ||
@VisibleForTesting | ||
internal const val OVERSCROLL_DIRECTIONS_VERTICAL = 1 shl 1 | ||
|
||
/** | ||
* All data about how a touch will be handled by the browser. | ||
* - whether the event is used for panning/zooming by the browser / by the website or will be ignored. | ||
* - whether the event can scroll the page and in what direction. | ||
* - whether the event can overscroll the page and in what direction. | ||
* | ||
* Data wrapped by this class is safe to use after first calling [update] to update the default values. | ||
* | ||
* This class can be reused by calling [reset] to return all data values to it's default value. | ||
*/ | ||
@Suppress("TooManyFunctions") | ||
class InputResultDetail { | ||
/** | ||
* Indicates who will use the current [MotionEvent]. | ||
* | ||
* @see INPUT_UNHANDLED | ||
* @see INPUT_HANDLED | ||
* @see INPUT_HANDLED_CONTENT | ||
*/ | ||
@VisibleForTesting | ||
internal var inputResult: Int = INPUT_UNHANDLED | ||
|
||
/** | ||
* Bitwise ORed value of the directions the page can be scrolled to. | ||
* | ||
* This is the same as GeckoView's [org.mozilla.geckoview.PanZoomController.ScrollableDirections]. | ||
*/ | ||
@VisibleForTesting | ||
internal var scrollDirections: Int = SCROLL_DIRECTIONS_NONE | ||
|
||
/** | ||
* Bitwise ORed value of the directions the page can be overscrolled to. | ||
* | ||
* This is the same as GeckoView's [org.mozilla.geckoview.PanZoomController.OverscrollDirections]. | ||
* | ||
* The default value is [OVERSCROLL_DIRECTIONS_VERTICAL] and not [OVERSCROLL_DIRECTIONS_NONE] since | ||
* there are cases in which this class can be used before valid values being set and it helps more to have | ||
* overscroll vertically allowed and then stop depending on the values with which this class is updated | ||
* rather than start with a disabled overscroll functionality for the current gesture. | ||
*/ | ||
@VisibleForTesting | ||
internal var overscrollDirections: Int = OVERSCROLL_DIRECTIONS_VERTICAL | ||
|
||
/** | ||
* The only way to update the values contained by this class. | ||
* Only after calling this method the various getters are safe to use. | ||
* | ||
* This method will filter out unexpected values to ensure data consistency. | ||
*/ | ||
fun update( | ||
inputResult: Int? = this.inputResult, | ||
scrollDirections: Int? = this.scrollDirections, | ||
overscrollDirections: Int? = this.overscrollDirections | ||
) { | ||
// The range check automatically checks for null but doesn't yet have a contract to say so. | ||
// As such it it safe to use the not-null assertion operator. | ||
|
||
if (inputResult in INPUT_UNHANDLED..INPUT_HANDLED_CONTENT) { | ||
this.inputResult = inputResult!! | ||
} | ||
if (scrollDirections in SCROLL_DIRECTIONS_NONE..(SCROLL_DIRECTIONS_LEFT or (SCROLL_DIRECTIONS_LEFT - 1))) { | ||
this.scrollDirections = scrollDirections!! | ||
} | ||
if (overscrollDirections in | ||
OVERSCROLL_DIRECTIONS_NONE..(OVERSCROLL_DIRECTIONS_VERTICAL or (OVERSCROLL_DIRECTIONS_VERTICAL - 1))) { | ||
|
||
this.overscrollDirections = overscrollDirections!! | ||
} | ||
} | ||
|
||
/** | ||
* Reset all data to default values. | ||
*/ | ||
fun reset() { | ||
inputResult = INPUT_UNHANDLED | ||
scrollDirections = SCROLL_DIRECTIONS_NONE | ||
overscrollDirections = OVERSCROLL_DIRECTIONS_VERTICAL | ||
} | ||
|
||
/** | ||
* The [EngineView] handled the last [MotionEvent] to pan or zoom the content. | ||
*/ | ||
fun isTouchHandledByBrowser() = inputResult == INPUT_HANDLED | ||
|
||
/** | ||
* The website handled the last [MotionEvent] through it's own touch listeners | ||
* and consumed it without the [EngineView] panning or zooming the website | ||
*/ | ||
fun isTouchHandledByWebsite() = inputResult == INPUT_HANDLED_CONTENT | ||
|
||
/** | ||
* Neither the [EngineView], nor the website will handle this [MotionEvent]. | ||
* | ||
* This might happen on a website without touch listeners that is not bigger than the screen | ||
* or when the content has no scrollable element. | ||
*/ | ||
fun isTouchUnhandled() = inputResult == INPUT_UNHANDLED | ||
|
||
/** | ||
* Whether the width of the webpage exceeds the display and the webpage can be scrolled to left. | ||
*/ | ||
fun canScrollToLeft(): Boolean = | ||
inputResult == INPUT_HANDLED && | ||
scrollDirections and SCROLL_DIRECTIONS_LEFT != 0 | ||
|
||
/** | ||
* Whether the height of the webpage exceeds the display and the webpage can be scrolled to top. | ||
*/ | ||
fun canScrollToTop(): Boolean = | ||
inputResult == INPUT_HANDLED && | ||
scrollDirections and SCROLL_DIRECTIONS_TOP != 0 | ||
|
||
/** | ||
* Whether the width of the webpage exceeds the display and the webpage can be scrolled to right. | ||
*/ | ||
fun canScrollToRight(): Boolean = | ||
inputResult == INPUT_HANDLED && | ||
scrollDirections and SCROLL_DIRECTIONS_RIGHT != 0 | ||
|
||
/** | ||
* Whether the height of the webpage exceeds the display and the webpage can be scrolled to bottom. | ||
*/ | ||
fun canScrollToBottom(): Boolean = | ||
inputResult == INPUT_HANDLED && | ||
scrollDirections and SCROLL_DIRECTIONS_BOTTOM != 0 | ||
|
||
/** | ||
* Whether the webpage can be overscrolled to the left. | ||
* | ||
* @return `true` if the page is already scrolled to the left most part | ||
* and the touch event is not handled by the webpage. | ||
*/ | ||
fun canOverscrollLeft(): Boolean = | ||
inputResult != INPUT_HANDLED_CONTENT && | ||
(scrollDirections and SCROLL_DIRECTIONS_LEFT == 0) && | ||
(overscrollDirections and OVERSCROLL_DIRECTIONS_HORIZONTAL != 0) | ||
|
||
/** | ||
* Whether the webpage can be overscrolled to the top. | ||
* | ||
* @return `true` if the page is already scrolled to the top most part | ||
* and the touch event is not handled by the webpage. | ||
*/ | ||
fun canOverscrollTop(): Boolean = | ||
inputResult != INPUT_HANDLED_CONTENT && | ||
(scrollDirections and SCROLL_DIRECTIONS_TOP == 0) && | ||
(overscrollDirections and OVERSCROLL_DIRECTIONS_VERTICAL != 0) | ||
|
||
/** | ||
* Whether the webpage can be overscrolled to the right. | ||
* | ||
* @return `true` if the page is already scrolled to the right most part | ||
* and the touch event is not handled by the webpage. | ||
*/ | ||
fun canOverscrollRight(): Boolean = | ||
inputResult != INPUT_HANDLED_CONTENT && | ||
(scrollDirections and SCROLL_DIRECTIONS_RIGHT == 0) && | ||
(overscrollDirections and OVERSCROLL_DIRECTIONS_HORIZONTAL != 0) | ||
|
||
/** | ||
* Whether the webpage can be overscrolled to the bottom. | ||
* | ||
* @return `true` if the page is already scrolled to the bottom most part | ||
* and the touch event is not handled by the webpage. | ||
*/ | ||
fun canOverscrollBottom(): Boolean = | ||
inputResult != INPUT_HANDLED_CONTENT && | ||
(scrollDirections and SCROLL_DIRECTIONS_BOTTOM == 0) && | ||
(overscrollDirections and OVERSCROLL_DIRECTIONS_VERTICAL != 0) | ||
} |
Oops, something went wrong.