Commit c4bd5cac authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

weblayer: update top-control scrolling

Top-controls scrolling was missing a couple of key things:
. when the top-controls are completely visible (and no gesture/scroll is
  underway), the height of the Webcontents should shrink.
. DoBrowserControlsShrinkRendererSize() should not change value while
  a gesture/scroll is underway (otherwise the scrollbar bounces around).

The logic added should match that of Chrome.

BUG=1017204
TEST=none

Change-Id: I2185409244e278dfd230499b65ed2d953eda6d70
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1880589
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709559}
parent 802ccbc0
...@@ -58,6 +58,15 @@ void HandleJavaScriptResult( ...@@ -58,6 +58,15 @@ void HandleJavaScriptResult(
} // namespace } // namespace
#if defined(OS_ANDROID)
BrowserControllerImpl::BrowserControllerImpl(
ProfileImpl* profile,
const base::android::JavaParamRef<jobject>& java_impl)
: BrowserControllerImpl(profile) {
java_impl_ = java_impl;
}
#endif
BrowserControllerImpl::BrowserControllerImpl(ProfileImpl* profile) BrowserControllerImpl::BrowserControllerImpl(ProfileImpl* profile)
: profile_(profile) { : profile_(profile) {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -142,10 +151,12 @@ void BrowserControllerImpl::AttachToView(views::WebView* web_view) { ...@@ -142,10 +151,12 @@ void BrowserControllerImpl::AttachToView(views::WebView* web_view) {
#endif #endif
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
static jlong JNI_BrowserControllerImpl_CreateBrowserController(JNIEnv* env, static jlong JNI_BrowserControllerImpl_CreateBrowserController(
jlong profile) { JNIEnv* env,
return reinterpret_cast<intptr_t>( jlong profile,
new BrowserControllerImpl(reinterpret_cast<ProfileImpl*>(profile))); const base::android::JavaParamRef<jobject>& java_impl) {
return reinterpret_cast<intptr_t>(new BrowserControllerImpl(
reinterpret_cast<ProfileImpl*>(profile), java_impl));
} }
static void JNI_BrowserControllerImpl_DeleteBrowserController( static void JNI_BrowserControllerImpl_DeleteBrowserController(
...@@ -216,7 +227,12 @@ int BrowserControllerImpl::GetTopControlsHeight() { ...@@ -216,7 +227,12 @@ int BrowserControllerImpl::GetTopControlsHeight() {
bool BrowserControllerImpl::DoBrowserControlsShrinkRendererSize( bool BrowserControllerImpl::DoBrowserControlsShrinkRendererSize(
const content::WebContents* web_contents) { const content::WebContents* web_contents) {
return true; #if defined(OS_ANDROID)
return Java_BrowserControllerImpl_doBrowserControlsShrinkRendererSize(
base::android::AttachCurrentThread(), java_impl_);
#else
return false;
#endif
} }
bool BrowserControllerImpl::EmbedsFullscreenWidget() { bool BrowserControllerImpl::EmbedsFullscreenWidget() {
......
...@@ -36,6 +36,11 @@ class BrowserControllerImpl : public BrowserController, ...@@ -36,6 +36,11 @@ class BrowserControllerImpl : public BrowserController,
public content::WebContentsDelegate, public content::WebContentsDelegate,
public content::WebContentsObserver { public content::WebContentsObserver {
public: public:
// TODO(sky): investigate a better way to not have so many ifdefs.
#if defined(OS_ANDROID)
BrowserControllerImpl(ProfileImpl* profile,
const base::android::JavaParamRef<jobject>& java_impl);
#endif
explicit BrowserControllerImpl(ProfileImpl* profile); explicit BrowserControllerImpl(ProfileImpl* profile);
~BrowserControllerImpl() override; ~BrowserControllerImpl() override;
...@@ -115,6 +120,7 @@ class BrowserControllerImpl : public BrowserController, ...@@ -115,6 +120,7 @@ class BrowserControllerImpl : public BrowserController,
base::ObserverList<BrowserObserver>::Unchecked observers_; base::ObserverList<BrowserObserver>::Unchecked observers_;
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
TopControlsContainerView* top_controls_container_view_ = nullptr; TopControlsContainerView* top_controls_container_view_ = nullptr;
base::android::ScopedJavaGlobalRef<jobject> java_impl_;
#endif #endif
bool is_fullscreen_ = false; bool is_fullscreen_ = false;
......
...@@ -21,6 +21,7 @@ android_library("java") { ...@@ -21,6 +21,7 @@ android_library("java") {
"org/chromium/weblayer_private/BrowserFragmentControllerImpl.java", "org/chromium/weblayer_private/BrowserFragmentControllerImpl.java",
"org/chromium/weblayer_private/BrowserFragmentImpl.java", "org/chromium/weblayer_private/BrowserFragmentImpl.java",
"org/chromium/weblayer_private/BrowserObserverProxy.java", "org/chromium/weblayer_private/BrowserObserverProxy.java",
"org/chromium/weblayer_private/ChildProcessServiceImpl.java",
"org/chromium/weblayer_private/ContentView.java", "org/chromium/weblayer_private/ContentView.java",
"org/chromium/weblayer_private/ContentViewRenderView.java", "org/chromium/weblayer_private/ContentViewRenderView.java",
"org/chromium/weblayer_private/DownloadDelegateProxy.java", "org/chromium/weblayer_private/DownloadDelegateProxy.java",
...@@ -30,10 +31,10 @@ android_library("java") { ...@@ -30,10 +31,10 @@ android_library("java") {
"org/chromium/weblayer_private/ProfileImpl.java", "org/chromium/weblayer_private/ProfileImpl.java",
"org/chromium/weblayer_private/FragmentWindowAndroid.java", "org/chromium/weblayer_private/FragmentWindowAndroid.java",
"org/chromium/weblayer_private/ProfileManager.java", "org/chromium/weblayer_private/ProfileManager.java",
"org/chromium/weblayer_private/RemoteFragmentImpl.java",
"org/chromium/weblayer_private/WebContentsGestureStateTracker.java",
"org/chromium/weblayer_private/TopControlsContainerView.java", "org/chromium/weblayer_private/TopControlsContainerView.java",
"org/chromium/weblayer_private/WebLayerImpl.java", "org/chromium/weblayer_private/WebLayerImpl.java",
"org/chromium/weblayer_private/ChildProcessServiceImpl.java",
"org/chromium/weblayer_private/RemoteFragmentImpl.java",
] ]
deps = [ deps = [
......
...@@ -14,6 +14,7 @@ import android.webkit.ValueCallback; ...@@ -14,6 +14,7 @@ import android.webkit.ValueCallback;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods; import org.chromium.base.annotations.NativeMethods;
import org.chromium.content_public.browser.ViewEventSink; import org.chromium.content_public.browser.ViewEventSink;
...@@ -28,8 +29,13 @@ import org.chromium.weblayer_private.aidl.INavigationControllerClient; ...@@ -28,8 +29,13 @@ import org.chromium.weblayer_private.aidl.INavigationControllerClient;
import org.chromium.weblayer_private.aidl.IObjectWrapper; import org.chromium.weblayer_private.aidl.IObjectWrapper;
import org.chromium.weblayer_private.aidl.ObjectWrapper; import org.chromium.weblayer_private.aidl.ObjectWrapper;
/**
* Implementation of IBrowserController.
*/
@JNINamespace("weblayer") @JNINamespace("weblayer")
public final class BrowserControllerImpl extends IBrowserController.Stub { public final class BrowserControllerImpl extends IBrowserController.Stub
implements TopControlsContainerView.Listener,
WebContentsGestureStateTracker.OnGestureStateChangedListener {
private long mNativeBrowserController; private long mNativeBrowserController;
// TODO: move mContentViewRenderView, mContentView, mTopControlsContainerView to // TODO: move mContentViewRenderView, mContentView, mTopControlsContainerView to
...@@ -46,6 +52,13 @@ public final class BrowserControllerImpl extends IBrowserController.Stub { ...@@ -46,6 +52,13 @@ public final class BrowserControllerImpl extends IBrowserController.Stub {
private NavigationControllerImpl mNavigationController; private NavigationControllerImpl mNavigationController;
private DownloadDelegateProxy mDownloadDelegateProxy; private DownloadDelegateProxy mDownloadDelegateProxy;
private FullscreenDelegateProxy mFullscreenDelegateProxy; private FullscreenDelegateProxy mFullscreenDelegateProxy;
private WebContentsGestureStateTracker mGestureStateTracker;
/**
* The value of mCachedDoBrowserControlsShrinkRendererSize is set when
* WebContentsGestureStateTracker begins a gesture. This is necessary as the values should only
* change once a gesture is no longer under way.
*/
private boolean mCachedDoBrowserControlsShrinkRendererSize;
private static class InternalAccessDelegateImpl private static class InternalAccessDelegateImpl
implements ViewEventSink.InternalAccessDelegate { implements ViewEventSink.InternalAccessDelegate {
...@@ -77,12 +90,12 @@ public final class BrowserControllerImpl extends IBrowserController.Stub { ...@@ -77,12 +90,12 @@ public final class BrowserControllerImpl extends IBrowserController.Stub {
mContentViewRenderView.onNativeLibraryLoaded( mContentViewRenderView.onNativeLibraryLoaded(
windowAndroid, ContentViewRenderView.MODE_SURFACE_VIEW); windowAndroid, ContentViewRenderView.MODE_SURFACE_VIEW);
mNativeBrowserController = mNativeBrowserController = BrowserControllerImplJni.get().createBrowserController(
BrowserControllerImplJni.get().createBrowserController(profile.getNativeProfile()); profile.getNativeProfile(), this);
mWebContents = BrowserControllerImplJni.get().getWebContents( mWebContents = BrowserControllerImplJni.get().getWebContents(
mNativeBrowserController, BrowserControllerImpl.this); mNativeBrowserController, BrowserControllerImpl.this);
mTopControlsContainerView = mTopControlsContainerView =
new TopControlsContainerView(context, mWebContents, mContentViewRenderView); new TopControlsContainerView(context, mWebContents, mContentViewRenderView, this);
mContentView = ContentView.createContentView( mContentView = ContentView.createContentView(
context, mWebContents, mTopControlsContainerView.getEventOffsetHandler()); context, mWebContents, mTopControlsContainerView.getEventOffsetHandler());
ViewAndroidDelegate viewAndroidDelegate = new ViewAndroidDelegate(mContentView) { ViewAndroidDelegate viewAndroidDelegate = new ViewAndroidDelegate(mContentView) {
...@@ -109,6 +122,8 @@ public final class BrowserControllerImpl extends IBrowserController.Stub { ...@@ -109,6 +122,8 @@ public final class BrowserControllerImpl extends IBrowserController.Stub {
mWebContents.onShow(); mWebContents.onShow();
mContentView.requestFocus(); mContentView.requestFocus();
mGestureStateTracker = new WebContentsGestureStateTracker(mContentView, mWebContents, this);
} }
long getNativeBrowserController() { long getNativeBrowserController() {
...@@ -123,6 +138,29 @@ public final class BrowserControllerImpl extends IBrowserController.Stub { ...@@ -123,6 +138,29 @@ public final class BrowserControllerImpl extends IBrowserController.Stub {
return mNavigationController; return mNavigationController;
} }
@Override
public void onTopControlsCompletelyShownOrHidden() {
adjustWebContentsHeightIfNecessary();
}
@Override
public void onGestureStateChanged() {
if (mGestureStateTracker.isInGestureOrScroll()) {
mCachedDoBrowserControlsShrinkRendererSize =
mTopControlsContainerView.isTopControlVisible();
}
adjustWebContentsHeightIfNecessary();
}
private void adjustWebContentsHeightIfNecessary() {
if (mGestureStateTracker.isInGestureOrScroll()
|| !mTopControlsContainerView.isTopControlsCompletelyShownOrHidden()) {
return;
}
mContentViewRenderView.setWebContentsHeightDelta(
mTopControlsContainerView.getTopContentOffset());
}
@Override @Override
public void setClient(IBrowserControllerClient client) { public void setClient(IBrowserControllerClient client) {
mBrowserObserverProxy = new BrowserObserverProxy(mNativeBrowserController, client); mBrowserObserverProxy = new BrowserObserverProxy(mNativeBrowserController, client);
...@@ -191,6 +229,7 @@ public final class BrowserControllerImpl extends IBrowserController.Stub { ...@@ -191,6 +229,7 @@ public final class BrowserControllerImpl extends IBrowserController.Stub {
mFullscreenDelegateProxy.destroy(); mFullscreenDelegateProxy.destroy();
mFullscreenDelegateProxy = null; mFullscreenDelegateProxy = null;
} }
mGestureStateTracker.destroy();
mNavigationController = null; mNavigationController = null;
BrowserControllerImplJni.get().deleteBrowserController(mNativeBrowserController); BrowserControllerImplJni.get().deleteBrowserController(mNativeBrowserController);
mNativeBrowserController = 0; mNativeBrowserController = 0;
...@@ -212,9 +251,16 @@ public final class BrowserControllerImpl extends IBrowserController.Stub { ...@@ -212,9 +251,16 @@ public final class BrowserControllerImpl extends IBrowserController.Stub {
(ValueCallback<Boolean>) ObjectWrapper.unwrap(callback, ValueCallback.class)); (ValueCallback<Boolean>) ObjectWrapper.unwrap(callback, ValueCallback.class));
} }
@CalledByNative
private boolean doBrowserControlsShrinkRendererSize() {
return (mGestureStateTracker.isInGestureOrScroll())
? mCachedDoBrowserControlsShrinkRendererSize
: mTopControlsContainerView.isTopControlVisible();
}
@NativeMethods @NativeMethods
interface Natives { interface Natives {
long createBrowserController(long profile); long createBrowserController(long profile, BrowserControllerImpl caller);
void setTopControlsContainerView(long nativeBrowserControllerImpl, void setTopControlsContainerView(long nativeBrowserControllerImpl,
BrowserControllerImpl caller, long nativeTopControlsContainerView); BrowserControllerImpl caller, long nativeTopControlsContainerView);
void deleteBrowserController(long browserController); void deleteBrowserController(long browserController);
......
...@@ -62,6 +62,8 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -62,6 +62,8 @@ public class ContentViewRenderView extends FrameLayout {
private int mWidth; private int mWidth;
private int mHeight; private int mHeight;
private int mWebContentsHeightDelta;
// Common interface to listen to surface related events. // Common interface to listen to surface related events.
private interface SurfaceEventListener { private interface SurfaceEventListener {
void surfaceCreated(); void surfaceCreated();
...@@ -514,11 +516,25 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -514,11 +516,25 @@ public class ContentViewRenderView extends FrameLayout {
mRequested.addCallback(callback); mRequested.addCallback(callback);
} }
/**
* Sets how much to decrease the height of the WebContents by.
*/
public void setWebContentsHeightDelta(int delta) {
if (delta == mWebContentsHeightDelta) return;
mWebContentsHeightDelta = delta;
updateWebContentsSize();
}
private void updateWebContentsSize() {
if (mWebContents == null) return;
mWebContents.setSize(mWidth, mHeight - mWebContentsHeightDelta);
}
@Override @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) { protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mWidth = w; mWidth = w;
mHeight = h; mHeight = h;
if (mWebContents != null) mWebContents.setSize(w, h); updateWebContentsSize();
} }
/** /**
...@@ -581,7 +597,7 @@ public class ContentViewRenderView extends FrameLayout { ...@@ -581,7 +597,7 @@ public class ContentViewRenderView extends FrameLayout {
mWebContents = webContents; mWebContents = webContents;
if (webContents != null) { if (webContents != null) {
webContents.setSize(mWidth, mHeight); updateWebContentsSize();
ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged( ContentViewRenderViewJni.get().onPhysicalBackingSizeChanged(
mNativeContentViewRenderView, webContents, mWidth, mHeight); mNativeContentViewRenderView, webContents, mWidth, mHeight);
} }
......
...@@ -26,6 +26,30 @@ import org.chromium.ui.resources.dynamics.ViewResourceAdapter; ...@@ -26,6 +26,30 @@ import org.chromium.ui.resources.dynamics.ViewResourceAdapter;
* bitmap is placed in a cc::Layer and the layer is shown while scrolling the top-view. * bitmap is placed in a cc::Layer and the layer is shown while scrolling the top-view.
* ViewResourceAdapter is always kept in sync, as to do otherwise results in a noticeable delay * ViewResourceAdapter is always kept in sync, as to do otherwise results in a noticeable delay
* between when the scroll starts the content is available. * between when the scroll starts the content is available.
*
* There are many parts involved in orchestrating top-controls scrolling. The key things to know
* are:
* . TopControlsContainerView (in native code) keeps a cc::Layer that shows a bitmap rendered by
* the top-view. The bitmap is updated anytime the top-view changes. This is done as otherwise
* there is a noticable delay between when the scroll starts and the bitmap is available.
* . When scrolling, the cc::Layer for the WebContents and TopControlsContainerView is moved.
* . The size of the WebContents is only changed after the user releases a touch point. Otherwise
* the scrollbar bounces around.
* . WebContentsDelegate::DoBrowserControlsShrinkRendererSize() only changes when the WebContents
* size change.
* . WebContentsGestureStateTracker is responsible for determining when a scroll/touch is underway.
* . ContentViewRenderView.Delegate is used to adjust the size of the webcontents when the
* top-controls are fully visible (and a scroll is not underway).
*
* The flow of this code is roughly:
* . WebContentsGestureStateTracker generally detects a touch first
* . BrowserControllerImpl is notified and caches state.
* . onTopControlsChanged() is called. This triggers hiding the real view and calling to native code
* to move the cc::Layers.
* . the move continues.
* . when the move completes and both WebContentsGestureStateTracker and TopControlsContainerView
* no longer believe a move/gesture/scroll is underway the size of the WebContents is adjusted
* (if necessary).
*/ */
@JNINamespace("weblayer") @JNINamespace("weblayer")
class TopControlsContainerView extends FrameLayout { class TopControlsContainerView extends FrameLayout {
...@@ -50,7 +74,9 @@ class TopControlsContainerView extends FrameLayout { ...@@ -50,7 +74,9 @@ class TopControlsContainerView extends FrameLayout {
private EventOffsetHandler mEventOffsetHandler; private EventOffsetHandler mEventOffsetHandler;
private int mTopContentOffset; private int mTopContentOffset;
// True if scrolling. // Set to true if |mView| is hidden because the user has scrolled or triggered some action such
// that mView is not visible. While |mView| is not visible if this is true, the bitmap from
// |mView| may be partially visible.
private boolean mInTopControlsScroll; private boolean mInTopControlsScroll;
private boolean mIsFullscreen; private boolean mIsFullscreen;
...@@ -58,6 +84,15 @@ class TopControlsContainerView extends FrameLayout { ...@@ -58,6 +84,15 @@ class TopControlsContainerView extends FrameLayout {
// Used to delay processing fullscreen requests. // Used to delay processing fullscreen requests.
private Runnable mSystemUiFullscreenResizeRunnable; private Runnable mSystemUiFullscreenResizeRunnable;
private final Listener mListener;
public interface Listener {
/**
* Called when the top-controls are either completely showing, or completely hiding.
*/
public void onTopControlsCompletelyShownOrHidden();
}
// Used to delay updating the image for the layer. // Used to delay updating the image for the layer.
private final Runnable mRefreshResourceIdRunnable = () -> { private final Runnable mRefreshResourceIdRunnable = () -> {
if (mView == null) return; if (mView == null) return;
...@@ -65,8 +100,8 @@ class TopControlsContainerView extends FrameLayout { ...@@ -65,8 +100,8 @@ class TopControlsContainerView extends FrameLayout {
mNativeTopControlsContainerView, TopControlsContainerView.this); mNativeTopControlsContainerView, TopControlsContainerView.this);
}; };
TopControlsContainerView( TopControlsContainerView(Context context, WebContents webContents,
Context context, WebContents webContents, ContentViewRenderView contentViewRenderView) { ContentViewRenderView contentViewRenderView, Listener listener) {
super(context); super(context);
mContentViewRenderView = contentViewRenderView; mContentViewRenderView = contentViewRenderView;
mWebContents = webContents; mWebContents = webContents;
...@@ -85,6 +120,7 @@ class TopControlsContainerView extends FrameLayout { ...@@ -85,6 +120,7 @@ class TopControlsContainerView extends FrameLayout {
mNativeTopControlsContainerView = mNativeTopControlsContainerView =
TopControlsContainerViewJni.get().createTopControlsContainerView( TopControlsContainerViewJni.get().createTopControlsContainerView(
this, webContents, contentViewRenderView.getNativeHandle()); this, webContents, contentViewRenderView.getNativeHandle());
mListener = listener;
} }
public void destroy() { public void destroy() {
...@@ -101,6 +137,21 @@ class TopControlsContainerView extends FrameLayout { ...@@ -101,6 +137,21 @@ class TopControlsContainerView extends FrameLayout {
return mEventOffsetHandler; return mEventOffsetHandler;
} }
/**
* Returns the vertical offset for the WebContents.
*/
public int getTopContentOffset() {
return mView == null ? 0 : mTopContentOffset;
}
/**
* Returns true if the top control is visible to the user.
*/
public boolean isTopControlVisible() {
// Don't check the visibility of the View itself as it's hidden while scrolling.
return mView != null && mTopContentOffset != 0;
}
/** /**
* Sets the view from the client. * Sets the view from the client.
*/ */
...@@ -216,8 +267,19 @@ class TopControlsContainerView extends FrameLayout { ...@@ -216,8 +267,19 @@ class TopControlsContainerView extends FrameLayout {
mContentViewRenderView.postOnAnimation(() -> showTopControls()); mContentViewRenderView.postOnAnimation(() -> showTopControls());
} }
/**
* Returns true if the top-controls are completely shown or completely hidden. A return value
* of false indicates the top-controls are being moved.
*/
public boolean isTopControlsCompletelyShownOrHidden() {
return mTopContentOffset == 0 || mTopContentOffset == getHeight();
}
private void setTopControlsOffset(int topControlsOffsetY, int topContentOffsetY) { private void setTopControlsOffset(int topControlsOffsetY, int topContentOffsetY) {
mTopContentOffset = topContentOffsetY; mTopContentOffset = topContentOffsetY;
if (isTopControlsCompletelyShownOrHidden()) {
mListener.onTopControlsCompletelyShownOrHidden();
}
TopControlsContainerViewJni.get().setTopControlsOffset(mNativeTopControlsContainerView, TopControlsContainerViewJni.get().setTopControlsOffset(mNativeTopControlsContainerView,
TopControlsContainerView.this, topControlsOffsetY, topContentOffsetY); TopControlsContainerView.this, topControlsOffsetY, topContentOffsetY);
} }
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.weblayer_private;
import android.view.MotionEvent;
import android.view.View;
import org.chromium.content_public.browser.GestureListenerManager;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.content_public.browser.WebContents;
/**
* WebContentsGestureStateTracker is responsible for tracking when a scroll/gesture is in progress
* and notifying when the state changes.
*/
// TODO(sky): refactor TabGestureStateListener and this to a common place.
public final class WebContentsGestureStateTracker {
private GestureListenerManager mGestureListenerManager;
private GestureStateListener mGestureListener;
private final OnGestureStateChangedListener mListener;
private boolean mScrolling;
private boolean mIsInGesture;
/**
* The View events are tracked on.
*/
private View mContentView;
/**
* Notified when the gesture state changes.
*/
public interface OnGestureStateChangedListener {
/**
* Called when the value of isInGestureOrScroll() changes.
*/
public void onGestureStateChanged();
}
public WebContentsGestureStateTracker(
View contentView, WebContents webContents, OnGestureStateChangedListener listener) {
mListener = listener;
mGestureListenerManager = GestureListenerManager.fromWebContents(webContents);
mContentView = contentView;
mContentView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
final int eventAction = event.getActionMasked();
final boolean oldState = isInGestureOrScroll();
if (eventAction == MotionEvent.ACTION_DOWN
|| eventAction == MotionEvent.ACTION_POINTER_DOWN) {
mIsInGesture = true;
} else if (eventAction == MotionEvent.ACTION_CANCEL
|| eventAction == MotionEvent.ACTION_UP) {
mIsInGesture = false;
}
if (isInGestureOrScroll() != oldState) {
mListener.onGestureStateChanged();
}
return false;
}
});
mGestureListener = new GestureStateListener() {
@Override
public void onFlingStartGesture(int scrollOffsetY, int scrollExtentY) {
onScrollingStateChanged();
}
@Override
public void onFlingEndGesture(int scrollOffsetY, int scrollExtentY) {
onScrollingStateChanged();
}
@Override
public void onScrollStarted(int scrollOffsetY, int scrollExtentY) {
onScrollingStateChanged();
}
@Override
public void onScrollEnded(int scrollOffsetY, int scrollExtentY) {
onScrollingStateChanged();
}
private void onScrollingStateChanged() {
final boolean oldState = isInGestureOrScroll();
mScrolling = mGestureListenerManager.isScrollInProgress();
if (oldState != isInGestureOrScroll()) {
mListener.onGestureStateChanged();
}
}
};
mGestureListenerManager.addListener(mGestureListener);
}
public void destroy() {
mGestureListenerManager.removeListener(mGestureListener);
mGestureListener = null;
mGestureListenerManager = null;
mContentView.setOnTouchListener(null);
}
/**
* Returns true if the user has touched the target view, or is scrolling.
*/
public boolean isInGestureOrScroll() {
return mIsInGesture || mScrolling;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment