зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 5 changesets (bug 1633322, bug 1634504) for touchEventForResult gv-junit failures CLOSED TREE
Backed out changeset 3f866663b0aa (bug 1634504) Backed out changeset 953d128f4c51 (bug 1633322) Backed out changeset 84454fa520be (bug 1633322) Backed out changeset 1aa6be497177 (bug 1633322) Backed out changeset 9be548b05e86 (bug 1633322)
This commit is contained in:
Родитель
a904137456
Коммит
6d322bffe4
|
@ -53,25 +53,30 @@ struct APZEventResult {
|
|||
*/
|
||||
nsEventStatus mStatus;
|
||||
/**
|
||||
* The guid of the APZC initially targeted by this event.
|
||||
* This will usually be the APZC that handles the event, but in cases
|
||||
* where the event is dispatched to content, it may end up being
|
||||
* handled by a different APZC.
|
||||
* The guid of the APZC this event was delivered to.
|
||||
*/
|
||||
ScrollableLayerGuid mTargetGuid;
|
||||
/**
|
||||
* This is:
|
||||
* - set to true if we know for sure that the event will be handled
|
||||
* by the root content APZC;
|
||||
* - set to false if we know for sure it will not be;
|
||||
* - left empty if we are unsure.
|
||||
* Whether or not mTargetGuid refers to the root content APZC. This gets set
|
||||
* to false in cases where APZ is unsure due to imprecision in hit-testing.
|
||||
*/
|
||||
Maybe<bool> mHandledByRootApzc;
|
||||
bool mTargetIsRoot;
|
||||
/**
|
||||
* If this event started or was added to an input block, the id of that
|
||||
* input block, otherwise InputBlockState::NO_BLOCK_ID.
|
||||
*/
|
||||
uint64_t mInputBlockId;
|
||||
/**
|
||||
* True if the event is targeting a region with non-passive APZ-aware
|
||||
* listeners, that is, a region where we need to dispatch the event to Gecko
|
||||
* to see if a listener will prevent-default it.
|
||||
* Notes:
|
||||
* 1) This is currently only set for touch events.
|
||||
* 2) For non-WebRender, this will have some false positives; it will
|
||||
* be set in some cases where we need to dispatch the event to Gecko
|
||||
* before handling for other reasons than APZ-aware listeners.
|
||||
*/
|
||||
bool mHitRegionWithApzAwareListeners;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -131,27 +131,6 @@ class IAPZCTreeManager {
|
|||
*/
|
||||
virtual APZInputBridge* InputBridge() = 0;
|
||||
|
||||
/**
|
||||
* Add a callback to be invoked when |aInputBlockId| is ready for handling,
|
||||
* with a boolean indicating whether the APZC handling the input block is
|
||||
* the root content APZC.
|
||||
*
|
||||
* Should only be used for input blocks that are not yet ready for handling
|
||||
* at the time this is called. If the input block was already handled,
|
||||
* the callback will never be called.
|
||||
*
|
||||
* Only one callback can be registered for an input block at a time.
|
||||
* Subsequent attempts to register a callback for an input block will be
|
||||
* ignored until the existing callback is triggered.
|
||||
*
|
||||
* This is only implemented when the caller is in the same process as
|
||||
* the APZCTreeManager.
|
||||
*/
|
||||
using InputBlockCallback =
|
||||
std::function<void(uint64_t aInputBlockId, bool aHandledByRootApzc)>;
|
||||
virtual void AddInputBlockCallback(uint64_t aInputBlockId,
|
||||
InputBlockCallback&& aCallback) = 0;
|
||||
|
||||
protected:
|
||||
// Discourage destruction outside of decref
|
||||
|
||||
|
|
|
@ -1543,7 +1543,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
|
|||
|
||||
// Update the out-parameters so they are what the caller expects.
|
||||
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
|
||||
result.mHandledByRootApzc = hit.HandledByRoot();
|
||||
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
|
||||
|
||||
if (!hitScrollbar) {
|
||||
// The input was not targeted at a scrollbar, so we untransform it
|
||||
|
@ -1628,7 +1628,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
|
|||
|
||||
// Update the out-parameters so they are what the caller expects.
|
||||
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
|
||||
result.mHandledByRootApzc = hit.HandledByRoot();
|
||||
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
|
||||
wheelInput.mOrigin = *untransformedOrigin;
|
||||
}
|
||||
break;
|
||||
|
@ -1687,7 +1687,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
|
|||
|
||||
// Update the out-parameters so they are what the caller expects.
|
||||
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
|
||||
result.mHandledByRootApzc = hit.HandledByRoot();
|
||||
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
|
||||
panInput.mPanStartPoint = *untransformedStartPoint;
|
||||
panInput.mPanDisplacement = *untransformedDisplacement;
|
||||
|
||||
|
@ -1736,7 +1736,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
|
|||
|
||||
// Update the out-parameters so they are what the caller expects.
|
||||
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
|
||||
result.mHandledByRootApzc = hit.HandledByRoot();
|
||||
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
|
||||
pinchInput.mFocusPoint = *untransformedFocusPoint;
|
||||
}
|
||||
break;
|
||||
|
@ -1766,7 +1766,7 @@ APZEventResult APZCTreeManager::ReceiveInputEvent(InputData& aEvent) {
|
|||
|
||||
// Update the out-parameters so they are what the caller expects.
|
||||
hit.mTargetApzc->GetGuid(&result.mTargetGuid);
|
||||
result.mHandledByRootApzc = hit.HandledByRoot();
|
||||
result.mTargetIsRoot = hit.TargetIsConfirmedRoot();
|
||||
tapInput.mPoint = *untransformedPoint;
|
||||
}
|
||||
break;
|
||||
|
@ -1938,6 +1938,21 @@ APZCTreeManager::HitTestResult APZCTreeManager::GetTouchInputBlockAPZC(
|
|||
return hit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether |aHitResult| *may* indicate that we hit a region with
|
||||
* APZ-aware listeners.
|
||||
*/
|
||||
bool MayHaveApzAwareListeners(CompositorHitTestInfo aHitResult) {
|
||||
// With WebRender, we can answer this accurately.
|
||||
if (gfx::gfxVars::UseWebRender()) {
|
||||
return aHitResult.contains(CompositorHitTestFlags::eApzAwareListeners);
|
||||
}
|
||||
// With non-WebRender, several hit results including eApzAwareListeners
|
||||
// get lumped together into the dispatch-to-content region. We err on
|
||||
// the side of false positives.
|
||||
return !((aHitResult & CompositorHitTestDispatchToContent).isEmpty());
|
||||
}
|
||||
|
||||
APZEventResult APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput) {
|
||||
APZEventResult result; // mStatus == eIgnore
|
||||
aInput.mHandledByAPZ = true;
|
||||
|
@ -2037,13 +2052,15 @@ APZEventResult APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput) {
|
|||
CompositorHitTestInvisibleToHit);
|
||||
|
||||
mTouchBlockHitResult.mTargetApzc->GetGuid(&result.mTargetGuid);
|
||||
result.mHandledByRootApzc = mTouchBlockHitResult.HandledByRoot();
|
||||
result.mTargetIsRoot = mTouchBlockHitResult.TargetIsConfirmedRoot();
|
||||
result.mStatus = mInputQueue->ReceiveInputEvent(
|
||||
mTouchBlockHitResult.mTargetApzc,
|
||||
TargetConfirmationFlags{mTouchBlockHitResult.mHitResult}, aInput,
|
||||
&result.mInputBlockId,
|
||||
touchBehaviors.IsEmpty() ? Nothing()
|
||||
: Some(std::move(touchBehaviors)));
|
||||
result.mHitRegionWithApzAwareListeners =
|
||||
MayHaveApzAwareListeners(mTouchBlockHitResult.mHitResult);
|
||||
|
||||
// For computing the event to pass back to Gecko, use up-to-date
|
||||
// transforms (i.e. not anything cached in an input block). This ensures
|
||||
|
@ -2138,7 +2155,7 @@ APZEventResult APZCTreeManager::ProcessTouchInputForScrollbarDrag(
|
|||
}
|
||||
|
||||
mTouchBlockHitResult.mTargetApzc->GetGuid(&result.mTargetGuid);
|
||||
result.mHandledByRootApzc = mTouchBlockHitResult.HandledByRoot();
|
||||
result.mTargetIsRoot = mTouchBlockHitResult.TargetIsConfirmedRoot();
|
||||
|
||||
// Since the input was targeted at a scrollbar:
|
||||
// - The original touch event (which will be sent on to content) will
|
||||
|
@ -2950,11 +2967,6 @@ void APZCTreeManager::SetLongTapEnabled(bool aLongTapEnabled) {
|
|||
GestureEventListener::SetLongTapEnabled(aLongTapEnabled);
|
||||
}
|
||||
|
||||
void APZCTreeManager::AddInputBlockCallback(uint64_t aInputBlockId,
|
||||
InputBlockCallback&& aCallback) {
|
||||
mInputQueue->AddInputBlockCallback(aInputBlockId, std::move(aCallback));
|
||||
}
|
||||
|
||||
void APZCTreeManager::FindScrollThumbNode(
|
||||
const AsyncDragMetrics& aDragMetrics,
|
||||
HitTestingTreeNodeAutoLock& aOutThumbNode) {
|
||||
|
@ -3944,19 +3956,12 @@ APZCTreeManager::StickyPositionInfo::StickyPositionInfo(
|
|||
mStickyScrollRangeOuter = aNode->GetStickyScrollRangeOuter();
|
||||
}
|
||||
|
||||
Maybe<bool> APZCTreeManager::HitTestResult::HandledByRoot() const {
|
||||
if (!mTargetApzc->IsRootContent()) {
|
||||
// If the initial target is not the root, this will definitely not be
|
||||
// handled by the root. (The confirmed target is either the initial
|
||||
// target, or a descendant.)
|
||||
return Some(false);
|
||||
} else if ((mHitResult & CompositorHitTestDispatchToContent).isEmpty()) {
|
||||
// If the initial target is the root and we don't need to dispatch to
|
||||
// content, the event will definitely be handled by the root.
|
||||
return Some(true);
|
||||
}
|
||||
// Otherwise, we're not sure.
|
||||
return Nothing();
|
||||
bool APZCTreeManager::HitTestResult::TargetIsConfirmedRoot() const {
|
||||
CompositorHitTestInfo impreciseHitAreaFlags(
|
||||
CompositorHitTestFlags::eIrregularArea,
|
||||
CompositorHitTestFlags::eInactiveScrollframe);
|
||||
return (mHitResult & impreciseHitAreaFlags).isEmpty() &&
|
||||
mTargetApzc->IsRootContent();
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -424,9 +424,6 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
|
|||
|
||||
APZInputBridge* InputBridge() override { return this; }
|
||||
|
||||
void AddInputBlockCallback(uint64_t aInputBlockId,
|
||||
InputBlockCallback&& aCallback) override;
|
||||
|
||||
// Methods to help process WidgetInputEvents (or manage conversion to/from
|
||||
// InputData)
|
||||
|
||||
|
@ -560,7 +557,7 @@ class APZCTreeManager : public IAPZCTreeManager, public APZInputBridge {
|
|||
// Make it move-only.
|
||||
HitTestResult(HitTestResult&&) = default;
|
||||
HitTestResult& operator=(HitTestResult&&) = default;
|
||||
Maybe<bool> HandledByRoot() const;
|
||||
bool TargetIsConfirmedRoot() const;
|
||||
};
|
||||
|
||||
/* Some helper functions to find an APZC given some identifying input. These
|
||||
|
|
|
@ -25,7 +25,9 @@ namespace layers {
|
|||
|
||||
APZEventResult::APZEventResult()
|
||||
: mStatus(nsEventStatus_eIgnore),
|
||||
mInputBlockId(InputBlockState::NO_BLOCK_ID) {}
|
||||
mTargetIsRoot(false),
|
||||
mInputBlockId(InputBlockState::NO_BLOCK_ID),
|
||||
mHitRegionWithApzAwareListeners(false) {}
|
||||
|
||||
static bool WillHandleMouseEvent(const WidgetMouseEventBase& aEvent) {
|
||||
return aEvent.mMessage == eMouseMove || aEvent.mMessage == eMouseDown ||
|
||||
|
|
|
@ -640,12 +640,6 @@ InputBlockState* InputQueue::GetBlockForId(uint64_t aInputBlockId) {
|
|||
return FindBlockForId(aInputBlockId, nullptr);
|
||||
}
|
||||
|
||||
void InputQueue::AddInputBlockCallback(uint64_t aInputBlockId,
|
||||
InputBlockCallback&& aCallback) {
|
||||
mInputBlockCallbacks.insert(
|
||||
InputBlockCallbackMap::value_type(aInputBlockId, std::move(aCallback)));
|
||||
}
|
||||
|
||||
InputBlockState* InputQueue::FindBlockForId(uint64_t aInputBlockId,
|
||||
InputData** aOutFirstInput) {
|
||||
for (const auto& queuedInput : mQueuedInputs) {
|
||||
|
@ -827,18 +821,6 @@ void InputQueue::ProcessQueue() {
|
|||
curBlock, cancelable && cancelable->IsDefaultPrevented(),
|
||||
curBlock->ShouldDropEvents(), curBlock->GetTargetApzc().get());
|
||||
RefPtr<AsyncPanZoomController> target = curBlock->GetTargetApzc();
|
||||
|
||||
// If there is an input block callback registered for this
|
||||
// input block, invoke it.
|
||||
auto it = mInputBlockCallbacks.find(curBlock->GetBlockId());
|
||||
if (it != mInputBlockCallbacks.end()) {
|
||||
bool handledByRootApzc =
|
||||
!curBlock->ShouldDropEvents() && target && target->IsRootContent();
|
||||
it->second(curBlock->GetBlockId(), handledByRootApzc);
|
||||
// The callback is one-shot; discard it after calling it.
|
||||
mInputBlockCallbacks.erase(it);
|
||||
}
|
||||
|
||||
// target may be null here if the initial target was unconfirmed and then
|
||||
// we later got a confirmed null target. in that case drop the events.
|
||||
if (target) {
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class InputData;
|
||||
|
@ -146,11 +144,6 @@ class InputQueue {
|
|||
|
||||
InputBlockState* GetBlockForId(uint64_t aInputBlockId);
|
||||
|
||||
using InputBlockCallback =
|
||||
std::function<void(uint64_t aInputBlockId, bool aHandledByRootApzc)>;
|
||||
void AddInputBlockCallback(uint64_t aInputBlockId,
|
||||
InputBlockCallback&& aCallback);
|
||||
|
||||
private:
|
||||
~InputQueue();
|
||||
|
||||
|
@ -255,12 +248,6 @@ class InputQueue {
|
|||
// Temporarily stores a timeout task that needs to be run as soon as
|
||||
// as the event that triggered it has been queued.
|
||||
RefPtr<Runnable> mImmediateTimeout;
|
||||
|
||||
// Maps input block ids to callbacks that will be invoked when the input block
|
||||
// is ready for handling.
|
||||
using InputBlockCallbackMap =
|
||||
std::unordered_map<uint64_t, InputBlockCallback>;
|
||||
InputBlockCallbackMap mInputBlockCallbacks;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "APZCTreeManagerTester.h"
|
||||
#include "APZTestCommon.h"
|
||||
#include "InputUtils.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
|
||||
class APZEventRegionsTester : public APZCTreeManagerTester {
|
||||
protected:
|
||||
|
@ -311,9 +310,9 @@ TEST_F(APZEventRegionsTester, Bug1117712) {
|
|||
manager->SetTargetAPZC(inputBlockId, targets);
|
||||
}
|
||||
|
||||
// Test that APZEventResult::mHandledByRootApzc is correctly
|
||||
// Test that APZEventResult::mHitRegionWithApzAwareListeners is correctly
|
||||
// populated.
|
||||
TEST_F(APZEventRegionsTester, HandledByRootApzcFlag) {
|
||||
TEST_F(APZEventRegionsTester, ApzAwareListenersFlag) {
|
||||
// Create simple layer tree containing a dispatch-to-content region
|
||||
// that covers part but not all of its area.
|
||||
const char* layerTreeSyntax = "c";
|
||||
|
@ -323,8 +322,6 @@ TEST_F(APZEventRegionsTester, HandledByRootApzcFlag) {
|
|||
root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm,
|
||||
layers);
|
||||
SetScrollableFrameMetrics(root, ScrollableLayerGuid::START_SCROLL_ID);
|
||||
ModifyFrameMetrics(
|
||||
root, [](FrameMetrics& metrics) { metrics.SetIsRootContent(true); });
|
||||
// away from the scrolling container layer.
|
||||
EventRegions regions(nsIntRegion(IntRect(0, 0, 100, 100)));
|
||||
// bottom half is dispatch-to-content
|
||||
|
@ -334,53 +331,16 @@ TEST_F(APZEventRegionsTester, HandledByRootApzcFlag) {
|
|||
MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
|
||||
UpdateHitTestingTree();
|
||||
|
||||
// Tap the top half and check that we report that the event was
|
||||
// handled by the root APZC.
|
||||
// Tap the top half and check that we don't report hitting a region
|
||||
// with APZ-aware listeners.
|
||||
APZEventResult result =
|
||||
TouchDown(manager, ScreenIntPoint(50, 25), mcc->Time());
|
||||
TouchUp(manager, ScreenIntPoint(50, 25), mcc->Time());
|
||||
EXPECT_EQ(result.mHandledByRootApzc, Some(true));
|
||||
EXPECT_FALSE(result.mHitRegionWithApzAwareListeners);
|
||||
|
||||
// Tap the bottom half and check that we report that we're not
|
||||
// sure whether the event was handled by the root APZC.
|
||||
// Tap the bottom half and check we do report hitting a region with
|
||||
// APZ-aware listeners.
|
||||
result = TouchDown(manager, ScreenIntPoint(50, 75), mcc->Time());
|
||||
TouchUp(manager, ScreenIntPoint(50, 75), mcc->Time());
|
||||
EXPECT_EQ(result.mHandledByRootApzc, Nothing());
|
||||
|
||||
// Register an input block callback that will tell us the
|
||||
// delayed answer.
|
||||
Maybe<bool> delayedAnswer;
|
||||
manager->AddInputBlockCallback(result.mInputBlockId,
|
||||
[&](uint64_t id, bool answer) {
|
||||
EXPECT_EQ(id, result.mInputBlockId);
|
||||
delayedAnswer = Some(answer);
|
||||
});
|
||||
|
||||
// Send APZ the relevant notifications to allow it to process the
|
||||
// input block.
|
||||
manager->SetAllowedTouchBehavior(result.mInputBlockId,
|
||||
{AllowedTouchBehavior::VERTICAL_PAN});
|
||||
manager->SetTargetAPZC(result.mInputBlockId, {result.mTargetGuid});
|
||||
manager->ContentReceivedInputBlock(result.mInputBlockId,
|
||||
/*preventDefault=*/false);
|
||||
|
||||
// Check that we received the delayed answer and it is what we expect.
|
||||
EXPECT_EQ(delayedAnswer, Some(true));
|
||||
|
||||
// Now repeat the tap on the bottom half, but simulate a prevent-default.
|
||||
// This time, we expect a delayed answer of false.
|
||||
result = TouchDown(manager, ScreenIntPoint(50, 75), mcc->Time());
|
||||
TouchUp(manager, ScreenIntPoint(50, 75), mcc->Time());
|
||||
EXPECT_EQ(result.mHandledByRootApzc, Nothing());
|
||||
manager->AddInputBlockCallback(result.mInputBlockId,
|
||||
[&](uint64_t id, bool answer) {
|
||||
EXPECT_EQ(id, result.mInputBlockId);
|
||||
delayedAnswer = Some(answer);
|
||||
});
|
||||
manager->SetAllowedTouchBehavior(result.mInputBlockId,
|
||||
{AllowedTouchBehavior::VERTICAL_PAN});
|
||||
manager->SetTargetAPZC(result.mInputBlockId, {result.mTargetGuid});
|
||||
manager->ContentReceivedInputBlock(result.mInputBlockId,
|
||||
/*preventDefault=*/true);
|
||||
EXPECT_EQ(delayedAnswer, Some(false));
|
||||
EXPECT_TRUE(result.mHitRegionWithApzAwareListeners);
|
||||
}
|
||||
|
|
|
@ -105,12 +105,6 @@ APZInputBridge* APZCTreeManagerChild::InputBridge() {
|
|||
return mInputBridge.get();
|
||||
}
|
||||
|
||||
void APZCTreeManagerChild::AddInputBlockCallback(
|
||||
uint64_t aInputBlockId, InputBlockCallback&& aCallback) {
|
||||
MOZ_RELEASE_ASSERT(false,
|
||||
"Remoting of input block callbacks is not implemented");
|
||||
}
|
||||
|
||||
void APZCTreeManagerChild::AddIPDLReference() {
|
||||
MOZ_ASSERT(mIPCOpen == false);
|
||||
mIPCOpen = true;
|
||||
|
|
|
@ -62,9 +62,6 @@ class APZCTreeManagerChild : public IAPZCTreeManager,
|
|||
|
||||
APZInputBridge* InputBridge() override;
|
||||
|
||||
void AddInputBlockCallback(uint64_t aInputBlockId,
|
||||
InputBlockCallback&& aCallback) override;
|
||||
|
||||
void AddIPDLReference();
|
||||
void ReleaseIPDLReference();
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
|
|
@ -551,7 +551,8 @@ struct ParamTraits<mozilla::layers::APZEventResult> {
|
|||
WriteParam(aMsg, aParam.mStatus);
|
||||
WriteParam(aMsg, aParam.mTargetGuid);
|
||||
WriteParam(aMsg, aParam.mInputBlockId);
|
||||
WriteParam(aMsg, aParam.mHandledByRootApzc);
|
||||
WriteParam(aMsg, aParam.mHitRegionWithApzAwareListeners);
|
||||
WriteParam(aMsg, aParam.mTargetIsRoot);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter,
|
||||
|
@ -559,7 +560,8 @@ struct ParamTraits<mozilla::layers::APZEventResult> {
|
|||
return (ReadParam(aMsg, aIter, &aResult->mStatus) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mTargetGuid) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mInputBlockId) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mHandledByRootApzc));
|
||||
ReadParam(aMsg, aIter, &aResult->mHitRegionWithApzAwareListeners) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mTargetIsRoot));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -531,11 +531,13 @@ package org.mozilla.geckoview {
|
|||
method @UiThread public void orientationChanged();
|
||||
method @UiThread public void orientationChanged(int);
|
||||
method @AnyThread public void readFromParcel(@NonNull Parcel);
|
||||
method @Deprecated @UiThread @NonNull public GeckoResult<Void> registerWebExtension(@NonNull WebExtension);
|
||||
method @UiThread public void setDelegate(@Nullable GeckoRuntime.Delegate);
|
||||
method @UiThread public void setLoginStorageDelegate(@Nullable Autocomplete.LoginStorageDelegate);
|
||||
method @UiThread public void setServiceWorkerDelegate(@Nullable GeckoRuntime.ServiceWorkerDelegate);
|
||||
method @UiThread public void setWebNotificationDelegate(@Nullable WebNotificationDelegate);
|
||||
method @AnyThread public void shutdown();
|
||||
method @Deprecated @UiThread @NonNull public GeckoResult<Void> unregisterWebExtension(@NonNull WebExtension);
|
||||
field public static final String ACTION_CRASHED = "org.mozilla.gecko.ACTION_CRASHED";
|
||||
field public static final Parcelable.Creator<GeckoRuntime> CREATOR;
|
||||
field public static final String EXTRA_CRASH_FATAL = "fatal";
|
||||
|
@ -1243,7 +1245,8 @@ package org.mozilla.geckoview {
|
|||
method public boolean getAutofillEnabled();
|
||||
method @NonNull public PanZoomController getPanZoomController();
|
||||
method @AnyThread @Nullable public GeckoSession getSession();
|
||||
method @NonNull public GeckoResult<Integer> onTouchEventForResult(@NonNull MotionEvent);
|
||||
method public int onGenericMotionEventForResult(@NonNull MotionEvent);
|
||||
method public int onTouchEventForResult(@NonNull MotionEvent);
|
||||
method @UiThread @Nullable public GeckoSession releaseSession();
|
||||
method public void setAutofillEnabled(boolean);
|
||||
method public void setDynamicToolbarMaxHeight(int);
|
||||
|
@ -1417,10 +1420,9 @@ package org.mozilla.geckoview {
|
|||
@UiThread public class PanZoomController {
|
||||
ctor protected PanZoomController(GeckoSession);
|
||||
method public float getScrollFactor();
|
||||
method public void onMotionEvent(@NonNull MotionEvent);
|
||||
method public void onMouseEvent(@NonNull MotionEvent);
|
||||
method public void onTouchEvent(@NonNull MotionEvent);
|
||||
method @NonNull public GeckoResult<Integer> onTouchEventForResult(@NonNull MotionEvent);
|
||||
method public int onMotionEvent(@NonNull MotionEvent);
|
||||
method public int onMouseEvent(@NonNull MotionEvent);
|
||||
method public int onTouchEvent(@NonNull MotionEvent);
|
||||
method @UiThread public void scrollBy(@NonNull ScreenLength, @NonNull ScreenLength);
|
||||
method @UiThread public void scrollBy(@NonNull ScreenLength, @NonNull ScreenLength, int);
|
||||
method @UiThread public void scrollTo(@NonNull ScreenLength, @NonNull ScreenLength);
|
||||
|
@ -1555,6 +1557,8 @@ package org.mozilla.geckoview {
|
|||
}
|
||||
|
||||
public class WebExtension {
|
||||
ctor @Deprecated public WebExtension(@NonNull String, @NonNull String, long, @NonNull WebExtensionController);
|
||||
ctor @Deprecated public WebExtension(@NonNull String, @NonNull WebExtensionController);
|
||||
method @UiThread @Nullable public WebExtension.TabDelegate getTabDelegate();
|
||||
method @AnyThread public void setActionDelegate(@Nullable WebExtension.ActionDelegate);
|
||||
method @UiThread public void setMessageDelegate(@Nullable WebExtension.MessageDelegate, @NonNull String);
|
||||
|
@ -1563,7 +1567,7 @@ package org.mozilla.geckoview {
|
|||
field @NonNull public final String id;
|
||||
field public final boolean isBuiltIn;
|
||||
field @NonNull public final String location;
|
||||
field @NonNull public final WebExtension.MetaData metaData;
|
||||
field @Nullable public final WebExtension.MetaData metaData;
|
||||
}
|
||||
|
||||
@AnyThread public static class WebExtension.Action {
|
||||
|
@ -1764,6 +1768,11 @@ package org.mozilla.geckoview {
|
|||
method @Nullable default public GeckoResult<AllowOrDeny> onUpdatePrompt(@NonNull WebExtension, @NonNull WebExtension, @NonNull String[], @NonNull String[]);
|
||||
}
|
||||
|
||||
@Deprecated public static interface WebExtensionController.TabDelegate {
|
||||
method @UiThread @NonNull default public GeckoResult<AllowOrDeny> onCloseTab(@Nullable WebExtension, @NonNull GeckoSession);
|
||||
method @UiThread @Nullable default public GeckoResult<GeckoSession> onNewTab(@Nullable WebExtension, @Nullable String);
|
||||
}
|
||||
|
||||
@AnyThread public abstract class WebMessage {
|
||||
ctor protected WebMessage(@NonNull WebMessage.Builder);
|
||||
field @NonNull public final Map<String,String> headers;
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="height=device-height,width=device-width,initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0px;
|
||||
background: linear-gradient(135deg, red, white);
|
||||
}
|
||||
|
||||
#one {
|
||||
background-color: red;
|
||||
width: 100%;
|
||||
height: 33vh;
|
||||
}
|
||||
|
||||
#two {
|
||||
background-color: green;
|
||||
width: 100%;
|
||||
height: 33vh;
|
||||
}
|
||||
|
||||
#three {
|
||||
background-color: blue;
|
||||
width: 100%;
|
||||
height: 33vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="one"></div>
|
||||
<div id="two"></div>
|
||||
<div id="three"></div>
|
||||
<script>
|
||||
document.getElementById('two').addEventListener('touchstart', e => {
|
||||
console.log('preventing default');
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.getElementById('three').addEventListener('touchstart', e => {
|
||||
console.log('not preventing default');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -74,8 +74,6 @@ open class BaseSessionTest(noErrorCollector: Boolean = false) {
|
|||
const val IFRAME_UNKNOWN_PROTOCOL = "/assets/www/iframe_unknown_protocol.html"
|
||||
const val MEDIA_SESSION_DOM1_PATH = "/assets/www/media_session_dom1.html"
|
||||
const val MEDIA_SESSION_DEFAULT1_PATH = "/assets/www/media_session_default1.html"
|
||||
const val TOUCH_HTML_PATH = "/assets/www/touch.html"
|
||||
|
||||
const val TEST_ENDPOINT = GeckoSessionTestRule.TEST_ENDPOINT
|
||||
}
|
||||
|
||||
|
|
|
@ -1458,9 +1458,9 @@ class NavigationDelegateTest : BaseSessionTest() {
|
|||
controller.install("https://example.org/tests/junit/page-history.xpi"))
|
||||
|
||||
assertThat("baseUrl should be a valid extension URL",
|
||||
extension.metaData.baseUrl, startsWith("moz-extension://"))
|
||||
extension.metaData!!.baseUrl, startsWith("moz-extension://"))
|
||||
|
||||
val url = extension.metaData.baseUrl + "page.html"
|
||||
val url = extension.metaData!!.baseUrl + "page.html"
|
||||
val isRemote = sessionRule.getPrefs("extensions.webextensions.remote")[0] as Boolean
|
||||
processSwitchingTest(url, isRemote)
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package org.mozilla.geckoview.test
|
||||
|
||||
import android.os.SystemClock
|
||||
import android.view.MotionEvent
|
||||
import org.mozilla.geckoview.ScreenLength
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
|
||||
|
||||
|
@ -10,11 +8,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
|
|||
import org.hamcrest.Matchers.*
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.geckoview.GeckoResult
|
||||
import org.mozilla.geckoview.GeckoSession
|
||||
import org.mozilla.geckoview.PanZoomController
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule
|
||||
import org.mozilla.geckoview.test.util.Callbacks
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
|
@ -22,7 +16,7 @@ class PanZoomControllerTest : BaseSessionTest() {
|
|||
private val errorEpsilon = 3.0
|
||||
private val scrollWaitTimeout = 10000.0 // 10 seconds
|
||||
|
||||
private fun setupScroll() {
|
||||
private fun setup() {
|
||||
sessionRule.setPrefsUntilTestEnd(mapOf("dom.visualviewport.enabled" to true))
|
||||
sessionRule.session.loadTestPath(SCROLL_TEST_PATH)
|
||||
sessionRule.waitForPageStop()
|
||||
|
@ -56,7 +50,7 @@ class PanZoomControllerTest : BaseSessionTest() {
|
|||
|
||||
|
||||
private fun scrollByVertical(mode: Int) {
|
||||
setupScroll()
|
||||
setup()
|
||||
val vh = mainSession.evaluateJS("window.visualViewport.height") as Double
|
||||
assertThat("Visual viewport height is not zero", vh, greaterThan(0.0))
|
||||
sessionRule.session.panZoomController.scrollBy(ScreenLength.zero(), ScreenLength.fromVisualViewportHeight(1.0), mode)
|
||||
|
@ -67,7 +61,7 @@ class PanZoomControllerTest : BaseSessionTest() {
|
|||
|
||||
|
||||
private fun scrollByHorizontal(mode: Int) {
|
||||
setupScroll()
|
||||
setup()
|
||||
val vw = mainSession.evaluateJS("window.visualViewport.width") as Double
|
||||
assertThat("Visual viewport width is not zero", vw, greaterThan(0.0))
|
||||
sessionRule.session.panZoomController.scrollBy(ScreenLength.fromVisualViewportWidth(1.0), ScreenLength.zero(), mode)
|
||||
|
@ -101,7 +95,7 @@ class PanZoomControllerTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
private fun scrollByVerticalTwice(mode: Int) {
|
||||
setupScroll()
|
||||
setup()
|
||||
val vh = mainSession.evaluateJS("window.visualViewport.height") as Double
|
||||
assertThat("Visual viewport height is not zero", vh, greaterThan(0.0))
|
||||
sessionRule.session.panZoomController.scrollBy(ScreenLength.zero(), ScreenLength.fromVisualViewportHeight(1.0), mode)
|
||||
|
@ -125,7 +119,7 @@ class PanZoomControllerTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
private fun scrollToVertical(mode: Int) {
|
||||
setupScroll()
|
||||
setup()
|
||||
val vh = mainSession.evaluateJS("window.visualViewport.height") as Double
|
||||
assertThat("Visual viewport height is not zero", vh, greaterThan(0.0))
|
||||
sessionRule.session.panZoomController.scrollTo(ScreenLength.zero(), ScreenLength.fromVisualViewportHeight(1.0), mode)
|
||||
|
@ -136,7 +130,7 @@ class PanZoomControllerTest : BaseSessionTest() {
|
|||
|
||||
|
||||
private fun scrollToHorizontal(mode: Int) {
|
||||
setupScroll()
|
||||
setup()
|
||||
val vw = mainSession.evaluateJS("window.visualViewport.width") as Double
|
||||
assertThat("Visual viewport width is not zero", vw, greaterThan(0.0))
|
||||
sessionRule.session.panZoomController.scrollTo(ScreenLength.fromVisualViewportWidth(1.0), ScreenLength.zero(), mode)
|
||||
|
@ -170,7 +164,7 @@ class PanZoomControllerTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
private fun scrollToVerticalOnZoomedContent(mode: Int) {
|
||||
setupScroll()
|
||||
setup()
|
||||
|
||||
val originalVH = mainSession.evaluateJS("window.visualViewport.height") as Double
|
||||
assertThat("Visual viewport height is not zero", originalVH, greaterThan(0.0))
|
||||
|
@ -210,7 +204,7 @@ class PanZoomControllerTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
private fun scrollToVerticalTwice(mode: Int) {
|
||||
setupScroll()
|
||||
setup()
|
||||
val vh = mainSession.evaluateJS("window.visualViewport.height") as Double
|
||||
assertThat("Visual viewport height is not zero", vh, greaterThan(0.0))
|
||||
sessionRule.session.panZoomController.scrollTo(ScreenLength.zero(), ScreenLength.fromVisualViewportHeight(1.0), mode)
|
||||
|
@ -232,51 +226,4 @@ class PanZoomControllerTest : BaseSessionTest() {
|
|||
fun scrollToVerticalTwiceAuto() {
|
||||
scrollToVerticalTwice(PanZoomController.SCROLL_BEHAVIOR_AUTO)
|
||||
}
|
||||
|
||||
private fun setupTouch() {
|
||||
mainSession.loadTestPath(TOUCH_HTML_PATH)
|
||||
sessionRule.waitUntilCalled(object : Callbacks.ContentDelegate {
|
||||
@GeckoSessionTestRule.AssertCalled(count = 1)
|
||||
override fun onFirstContentfulPaint(session: GeckoSession) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun sendDownEvent(x: Float, y: Float): GeckoResult<Int> {
|
||||
val downTime = SystemClock.uptimeMillis();
|
||||
val down = MotionEvent.obtain(
|
||||
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, x, y, 0);
|
||||
|
||||
val result = mainSession.panZoomController.onTouchEventForResult(down)
|
||||
|
||||
val up = MotionEvent.obtain(
|
||||
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0);
|
||||
|
||||
mainSession.panZoomController.onTouchEvent(up)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@WithDisplay(width = 100, height = 100)
|
||||
@Test
|
||||
fun touchEventForResult() {
|
||||
setupTouch()
|
||||
|
||||
// No touch handlers, without scrolling
|
||||
var value = sessionRule.waitForResult(sendDownEvent(50f, 15f))
|
||||
assertThat("Value should match", value, equalTo(PanZoomController.INPUT_RESULT_UNHANDLED))
|
||||
|
||||
// Touch handler with preventDefault
|
||||
value = sessionRule.waitForResult(sendDownEvent(50f, 45f))
|
||||
assertThat("Value should match", value, equalTo(PanZoomController.INPUT_RESULT_HANDLED_CONTENT))
|
||||
|
||||
// Touch handler without preventDefault
|
||||
value = sessionRule.waitForResult(sendDownEvent(50f, 75f))
|
||||
assertThat("Value should match", value, equalTo(PanZoomController.INPUT_RESULT_HANDLED))
|
||||
|
||||
// No touch handlers, with scrolling
|
||||
setupScroll()
|
||||
value = sessionRule.waitForResult(sendDownEvent(50f, 50f))
|
||||
assertThat("Value should match", value, equalTo(PanZoomController.INPUT_RESULT_HANDLED))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,13 +87,13 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
// Check that the WebExtension was applied by checking the border color
|
||||
assertBodyBorderEqualTo("red")
|
||||
|
||||
// Uninstall WebExtension and check again
|
||||
// Unregister WebExtension and check again
|
||||
sessionRule.waitForResult(controller.uninstall(borderify))
|
||||
|
||||
mainSession.reload()
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
// Check that the WebExtension was not applied after being uninstalled
|
||||
// Check that the WebExtension was not applied after being unregistered
|
||||
assertBodyBorderEqualTo("")
|
||||
}
|
||||
|
||||
|
@ -120,15 +120,15 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
assertThat("enabled should match",
|
||||
extension.metaData.enabled, equalTo(enabled))
|
||||
extension.metaData!!.enabled, equalTo(enabled))
|
||||
assertThat("userDisabled should match",
|
||||
extension.metaData.disabledFlags and DisabledFlags.USER > 0,
|
||||
extension.metaData!!.disabledFlags and DisabledFlags.USER > 0,
|
||||
equalTo(userDisabled))
|
||||
assertThat("appDisabled should match",
|
||||
extension.metaData.disabledFlags and DisabledFlags.APP > 0,
|
||||
extension.metaData!!.disabledFlags and DisabledFlags.APP > 0,
|
||||
equalTo(appDisabled))
|
||||
assertThat("blocklistDisabled should match",
|
||||
extension.metaData.disabledFlags and DisabledFlags.BLOCKLIST > 0,
|
||||
extension.metaData!!.disabledFlags and DisabledFlags.BLOCKLIST > 0,
|
||||
equalTo(blocklistDisabled))
|
||||
}
|
||||
|
||||
|
@ -190,15 +190,15 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
sessionRule.delegateDuringNextWait(object : WebExtensionController.PromptDelegate {
|
||||
@AssertCalled
|
||||
override fun onInstallPrompt(extension: WebExtension): GeckoResult<AllowOrDeny> {
|
||||
assertEquals(extension.metaData.description,
|
||||
assertEquals(extension.metaData!!.description,
|
||||
"Adds a red border to all webpages matching example.com.")
|
||||
assertEquals(extension.metaData.name, "Borderify")
|
||||
assertEquals(extension.metaData.version, "1.0")
|
||||
assertEquals(extension.metaData!!.name, "Borderify")
|
||||
assertEquals(extension.metaData!!.version, "1.0")
|
||||
assertEquals(extension.isBuiltIn, false)
|
||||
assertEquals(extension.metaData.enabled, false)
|
||||
assertEquals(extension.metaData.signedState,
|
||||
assertEquals(extension.metaData!!.enabled, false)
|
||||
assertEquals(extension.metaData!!.signedState,
|
||||
WebExtension.SignedStateFlags.SIGNED)
|
||||
assertEquals(extension.metaData.blocklistState,
|
||||
assertEquals(extension.metaData!!.blocklistState,
|
||||
WebExtension.BlocklistStateFlags.NOT_BLOCKED)
|
||||
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW)
|
||||
|
@ -219,7 +219,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
assertTrue(list.containsKey(borderify.id))
|
||||
assertTrue(list.containsKey(RuntimeCreator.TEST_SUPPORT_EXTENSION_ID))
|
||||
|
||||
// Uninstall WebExtension and check again
|
||||
// Unregister WebExtension and check again
|
||||
sessionRule.waitForResult(controller.uninstall(borderify))
|
||||
|
||||
list = extensionsMap(sessionRule.waitForResult(controller.list()))
|
||||
|
@ -229,7 +229,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
mainSession.reload()
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
// Check that the WebExtension was not applied after being uninstalled
|
||||
// Check that the WebExtension was not applied after being unregistered
|
||||
assertBodyBorderEqualTo("")
|
||||
}
|
||||
|
||||
|
@ -254,14 +254,14 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
|
||||
// Make sure private mode is enabled
|
||||
assertTrue(mainSession.settings.usePrivateMode)
|
||||
assertFalse(borderify.metaData.allowedInPrivateBrowsing)
|
||||
assertFalse(borderify.metaData!!.allowedInPrivateBrowsing)
|
||||
// Check that the WebExtension was not applied to a private mode page
|
||||
assertBodyBorderEqualTo("")
|
||||
|
||||
borderify = sessionRule.waitForResult(
|
||||
controller.setAllowedInPrivateBrowsing(borderify, true))
|
||||
|
||||
assertTrue(borderify.metaData.allowedInPrivateBrowsing)
|
||||
assertTrue(borderify.metaData!!.allowedInPrivateBrowsing)
|
||||
// Check that the WebExtension was applied to a private mode page now that the extension
|
||||
// is enabled in private mode
|
||||
mainSession.reload();
|
||||
|
@ -271,14 +271,14 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
borderify = sessionRule.waitForResult(
|
||||
controller.setAllowedInPrivateBrowsing(borderify, false))
|
||||
|
||||
assertFalse(borderify.metaData.allowedInPrivateBrowsing)
|
||||
assertFalse(borderify.metaData!!.allowedInPrivateBrowsing)
|
||||
// Check that the WebExtension was not applied to a private mode page after being
|
||||
// not allowed to run in private mode
|
||||
mainSession.reload();
|
||||
sessionRule.waitForPageStop()
|
||||
assertBodyBorderEqualTo("")
|
||||
|
||||
// Uninstall WebExtension and check again
|
||||
// Unregister WebExtension and check again
|
||||
sessionRule.waitForResult(controller.uninstall(borderify))
|
||||
mainSession.reload();
|
||||
sessionRule.waitForPageStop()
|
||||
|
@ -302,7 +302,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
val dummy = sessionRule.waitForResult(
|
||||
controller.install("resource://android/assets/web_extensions/dummy.xpi"))
|
||||
|
||||
val metadata = dummy.metaData
|
||||
val metadata = dummy.metaData!!
|
||||
assertTrue((metadata.optionsPageUrl ?: "").matches("^moz-extension://[0-9a-f\\-]*/options.html$".toRegex()));
|
||||
assertEquals(metadata.openOptionsPageInTab, true);
|
||||
assertTrue(metadata.baseUrl.matches("^moz-extension://[0-9a-f\\-]*/$".toRegex()))
|
||||
|
@ -404,11 +404,11 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
val borderify = sessionRule.waitForResult(controller.install(
|
||||
"resource://android/assets/web_extensions/borderify-unsigned.xpi")
|
||||
.then { extension ->
|
||||
assertEquals(extension!!.metaData.signedState,
|
||||
assertEquals(extension!!.metaData!!.signedState,
|
||||
WebExtension.SignedStateFlags.MISSING)
|
||||
assertEquals(extension.metaData.blocklistState,
|
||||
assertEquals(extension.metaData!!.blocklistState,
|
||||
WebExtension.BlocklistStateFlags.NOT_BLOCKED)
|
||||
assertEquals(extension.metaData.name, "Borderify")
|
||||
assertEquals(extension.metaData!!.name, "Borderify")
|
||||
GeckoResult.fromValue(extension)
|
||||
})
|
||||
|
||||
|
@ -806,7 +806,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
}
|
||||
|
||||
// This test
|
||||
// - installs a web extension
|
||||
// - registers a web extension
|
||||
// - waits for the web extension to connect to the browser
|
||||
// - on connect it will start listening on the port for a message
|
||||
// - When the message is received it sends a message in response and waits for another message
|
||||
|
@ -1202,7 +1202,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
"extension-page-update@tests.mozilla.org"))
|
||||
|
||||
assertThat("ID match", ensure.id, equalTo(extension.id))
|
||||
assertThat("version match", ensure.metaData.version, equalTo(extension.metaData.version))
|
||||
assertThat("version match", ensure.metaData!!.version, equalTo(extension.metaData!!.version))
|
||||
|
||||
// Make sure the page loaded successfully
|
||||
sessionRule.waitForResult(pageStop)
|
||||
|
@ -1212,14 +1212,14 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
assertThat("WebExtension page should have access to privileged APIs",
|
||||
sessionRule.waitForResult(result), equalTo("HELLO_FROM_PAGE"))
|
||||
|
||||
// Test that after uninstalling an extension, all its pages get closed
|
||||
// Test that after unregistering an extension, all its pages get closed
|
||||
sessionRule.addExternalDelegateUntilTestEnd(
|
||||
WebExtension.SessionTabDelegate::class,
|
||||
{ delegate -> mainSession.webExtensionController.setTabDelegate(extension, delegate) },
|
||||
{ mainSession.webExtensionController.setTabDelegate(extension, null) },
|
||||
object : WebExtension.SessionTabDelegate {})
|
||||
|
||||
val uninstall = controller.uninstall(extension)
|
||||
val unregister = controller.uninstall(extension)
|
||||
|
||||
sessionRule.waitUntilCalled(object : WebExtension.SessionTabDelegate {
|
||||
@AssertCalled
|
||||
|
@ -1231,7 +1231,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
}
|
||||
})
|
||||
|
||||
sessionRule.waitForResult(uninstall)
|
||||
sessionRule.waitForResult(unregister)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1298,7 +1298,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
sessionRule.delegateDuringNextWait(object : WebExtensionController.PromptDelegate {
|
||||
@AssertCalled
|
||||
override fun onInstallPrompt(extension: WebExtension): GeckoResult<AllowOrDeny> {
|
||||
assertEquals(extension.metaData.version, "1.0")
|
||||
assertEquals(extension.metaData!!.version, "1.0")
|
||||
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW)
|
||||
}
|
||||
|
@ -1314,7 +1314,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
assertBodyBorderEqualTo("red")
|
||||
|
||||
val update2 = sessionRule.waitForResult(controller.update(update1));
|
||||
assertEquals(update2.metaData.version, "2.0")
|
||||
assertEquals(update2.metaData!!.version, "2.0")
|
||||
|
||||
mainSession.reload()
|
||||
sessionRule.waitForPageStop()
|
||||
|
@ -1322,13 +1322,13 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
// Check that updated extension changed the border color.
|
||||
assertBodyBorderEqualTo("blue")
|
||||
|
||||
// Uninstall WebExtension and check again
|
||||
// Unregister WebExtension and check again
|
||||
sessionRule.waitForResult(controller.uninstall(update2))
|
||||
|
||||
mainSession.reload()
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
// Check that the WebExtension was not applied after being uninstalled
|
||||
// Check that the WebExtension was not applied after being unregistered
|
||||
assertBodyBorderEqualTo("")
|
||||
}
|
||||
|
||||
|
@ -1350,7 +1350,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
sessionRule.delegateDuringNextWait(object : WebExtensionController.PromptDelegate {
|
||||
@AssertCalled
|
||||
override fun onInstallPrompt(extension: WebExtension): GeckoResult<AllowOrDeny> {
|
||||
assertEquals(extension.metaData.version, "1.0")
|
||||
assertEquals(extension.metaData!!.version, "1.0")
|
||||
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW)
|
||||
}
|
||||
|
@ -1371,8 +1371,8 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
updatedExtension: WebExtension,
|
||||
newPermissions: Array<String>,
|
||||
newOrigins: Array<String>): GeckoResult<AllowOrDeny> {
|
||||
assertEquals(currentlyInstalled.metaData.version, "1.0")
|
||||
assertEquals(updatedExtension.metaData.version, "2.0")
|
||||
assertEquals(currentlyInstalled.metaData!!.version, "1.0")
|
||||
assertEquals(updatedExtension.metaData!!.version, "2.0")
|
||||
assertEquals(newPermissions.size, 1)
|
||||
assertEquals(newPermissions[0], "tabs")
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW);
|
||||
|
@ -1380,7 +1380,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
})
|
||||
|
||||
val update2 = sessionRule.waitForResult(controller.update(update1));
|
||||
assertEquals(update2.metaData.version, "2.0")
|
||||
assertEquals(update2.metaData!!.version, "2.0")
|
||||
|
||||
mainSession.reload()
|
||||
sessionRule.waitForPageStop()
|
||||
|
@ -1388,13 +1388,13 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
// Check that updated extension changed the border color.
|
||||
assertBodyBorderEqualTo("blue")
|
||||
|
||||
// Uninstall WebExtension and check again
|
||||
// Unregister WebExtension and check again
|
||||
sessionRule.waitForResult(controller.uninstall(update2))
|
||||
|
||||
mainSession.reload()
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
// Check that the WebExtension was not applied after being uninstalled
|
||||
// Check that the WebExtension was not applied after being unregistered
|
||||
assertBodyBorderEqualTo("")
|
||||
}
|
||||
|
||||
|
@ -1416,7 +1416,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
sessionRule.delegateDuringNextWait(object : WebExtensionController.PromptDelegate {
|
||||
@AssertCalled
|
||||
override fun onInstallPrompt(extension: WebExtension): GeckoResult<AllowOrDeny> {
|
||||
assertEquals(extension.metaData.version, "2.0")
|
||||
assertEquals(extension.metaData!!.version, "2.0")
|
||||
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW)
|
||||
}
|
||||
|
@ -1434,13 +1434,13 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
val update2 = sessionRule.waitForResult(controller.update(update1))
|
||||
assertNull(update2);
|
||||
|
||||
// Uninstall WebExtension and check again
|
||||
// Unregister WebExtension and check again
|
||||
sessionRule.waitForResult(controller.uninstall(update1))
|
||||
|
||||
mainSession.reload()
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
// Check that the WebExtension was not applied after being uninstalled
|
||||
// Check that the WebExtension was not applied after being unregistered
|
||||
assertBodyBorderEqualTo("")
|
||||
}
|
||||
|
||||
|
@ -1462,7 +1462,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
sessionRule.delegateDuringNextWait(object : WebExtensionController.PromptDelegate {
|
||||
@AssertCalled
|
||||
override fun onInstallPrompt(extension: WebExtension): GeckoResult<AllowOrDeny> {
|
||||
assertEquals(extension.metaData.version, "1.0")
|
||||
assertEquals(extension.metaData!!.version, "1.0")
|
||||
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW)
|
||||
}
|
||||
|
@ -1483,8 +1483,8 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
updatedExtension: WebExtension,
|
||||
newPermissions: Array<String>,
|
||||
newOrigins: Array<String>): GeckoResult<AllowOrDeny> {
|
||||
assertEquals(currentlyInstalled.metaData.version, "1.0")
|
||||
assertEquals(updatedExtension.metaData.version, "2.0")
|
||||
assertEquals(currentlyInstalled.metaData!!.version, "1.0")
|
||||
assertEquals(updatedExtension.metaData!!.version, "2.0")
|
||||
return GeckoResult.fromValue(AllowOrDeny.DENY);
|
||||
}
|
||||
})
|
||||
|
@ -1505,13 +1505,13 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
// Check that updated extension changed the border color.
|
||||
assertBodyBorderEqualTo("red")
|
||||
|
||||
// Uninstall WebExtension and check again
|
||||
// Unregister WebExtension and check again
|
||||
sessionRule.waitForResult(controller.uninstall(update1))
|
||||
|
||||
mainSession.reload()
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
// Check that the WebExtension was not applied after being uninstalled
|
||||
// Check that the WebExtension was not applied after being unregistered
|
||||
assertBodyBorderEqualTo("")
|
||||
}
|
||||
|
||||
|
@ -1560,7 +1560,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
sessionRule.delegateDuringNextWait(object : WebExtensionController.PromptDelegate {
|
||||
@AssertCalled
|
||||
override fun onInstallPrompt(extension: WebExtension): GeckoResult<AllowOrDeny> {
|
||||
assertEquals(extension.metaData.version, "1.0")
|
||||
assertEquals(extension.metaData!!.version, "1.0")
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW)
|
||||
}
|
||||
})
|
||||
|
@ -1688,7 +1688,7 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
@AssertCalled(count = 1)
|
||||
override fun onOpenOptionsPage(source: WebExtension) {
|
||||
assertThat(
|
||||
source.metaData.optionsPageUrl,
|
||||
source.metaData!!.optionsPageUrl,
|
||||
endsWith("options.html"))
|
||||
assertEquals(optionsExtension!!.id, source.id)
|
||||
openOptionsPageResult.complete(null)
|
||||
|
|
|
@ -463,6 +463,99 @@ public final class GeckoRuntime implements Parcelable {
|
|||
return mProfilerController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link WebExtension} that will be run with this GeckoRuntime.
|
||||
*
|
||||
* <p>At this time, WebExtensions don't have access to any UI element and
|
||||
* cannot communicate with the application. Any UI element will be
|
||||
* ignored.</p>
|
||||
*
|
||||
* Example:
|
||||
* <pre><code>
|
||||
* runtime.registerWebExtension(new WebExtension(
|
||||
* "resource://android/assets/web_extensions/my_webextension/"))
|
||||
* .exceptionally(ex -> {
|
||||
* Log.e("MyActivity", "Could not register WebExtension", ex);
|
||||
* return null;
|
||||
* });
|
||||
*
|
||||
* runtime.registerWebExtension(new WebExtension(
|
||||
* "file:///path/to/web_extension/my_webextension2.xpi",
|
||||
* "mywebextension2@example.com"));
|
||||
* </code></pre>
|
||||
*
|
||||
* To learn more about WebExtensions refer to
|
||||
* <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions">
|
||||
* Mozilla/Add-ons/WebExtensions
|
||||
* </a>.
|
||||
*
|
||||
* @param webExtension {@link WebExtension} to register
|
||||
*
|
||||
* @return A {@link GeckoResult} that will complete when the WebExtension
|
||||
* has been installed.
|
||||
*
|
||||
* @deprecated Use {@link WebExtensionController#installBuiltIn} instead. This method will
|
||||
* be removed in GeckoView 81.
|
||||
*/
|
||||
@Deprecated // Bug 1634504
|
||||
@UiThread
|
||||
public @NonNull GeckoResult<Void> registerWebExtension(
|
||||
final @NonNull WebExtension webExtension) {
|
||||
final CallbackResult<Void> result = new CallbackResult<Void>() {
|
||||
@Override
|
||||
public void sendSuccess(final Object response) {
|
||||
complete(null);
|
||||
}
|
||||
};
|
||||
|
||||
final GeckoBundle bundle = new GeckoBundle(3);
|
||||
bundle.putString("locationUri", webExtension.location);
|
||||
bundle.putString("id", webExtension.id);
|
||||
bundle.putBoolean("allowContentMessaging",
|
||||
(webExtension.flags & WebExtension.Flags.ALLOW_CONTENT_MESSAGING) > 0);
|
||||
|
||||
mWebExtensionController.registerWebExtension(webExtension);
|
||||
|
||||
EventDispatcher.getInstance().dispatch("GeckoView:RegisterWebExtension",
|
||||
bundle, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters this WebExtension. After a WebExtension is unregistered all
|
||||
* scripts associated with it stop running.
|
||||
*
|
||||
* @param webExtension {@link WebExtension} to unregister
|
||||
*
|
||||
* @return A {@link GeckoResult} that will complete when the WebExtension
|
||||
* has been unregistered.
|
||||
*
|
||||
* @deprecated Use {@link WebExtensionController#uninstall} instead. This method will
|
||||
* be removed in GeckoView 81.
|
||||
*/
|
||||
@Deprecated // Bug 1634504
|
||||
@UiThread
|
||||
public @NonNull GeckoResult<Void> unregisterWebExtension(
|
||||
final @NonNull WebExtension webExtension) {
|
||||
final CallbackResult<Void> result = new CallbackResult<Void>() {
|
||||
@Override
|
||||
public void sendSuccess(final Object response) {
|
||||
complete(null);
|
||||
}
|
||||
};
|
||||
|
||||
final GeckoBundle bundle = new GeckoBundle(1);
|
||||
bundle.putString("id", webExtension.id);
|
||||
|
||||
EventDispatcher.getInstance().dispatch("GeckoView:UnregisterWebExtension", bundle, result);
|
||||
|
||||
return result.then(success -> {
|
||||
mWebExtensionController.unregisterWebExtension(webExtension);
|
||||
return GeckoResult.fromValue(success);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new runtime with the given settings and attach it to the given
|
||||
* context.
|
||||
|
|
|
@ -739,7 +739,7 @@ public class GeckoView extends FrameLayout {
|
|||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouchEvent(final MotionEvent event) {
|
||||
mSession.getPanZoomController().onTouchEventForResult(event);
|
||||
onTouchEventForResult(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -748,43 +748,51 @@ public class GeckoView extends FrameLayout {
|
|||
* {@link #onTouchEvent(MotionEvent)}, but instead returns a {@link PanZoomController.InputResult}
|
||||
* indicating how the event was handled.
|
||||
*
|
||||
* NOTE: It is highly recommended to only call this with ACTION_DOWN or in otherwise
|
||||
* limited capacity. Returning a GeckoResult for every touch event will generate
|
||||
* a lot of allocations and unnecessary GC pressure.
|
||||
*
|
||||
* @param event A {@link MotionEvent}
|
||||
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) indicating how the event was handled.
|
||||
*/
|
||||
public @NonNull GeckoResult<Integer> onTouchEventForResult(final @NonNull MotionEvent event) {
|
||||
public @PanZoomController.InputResult int onTouchEventForResult(final @NonNull MotionEvent event) {
|
||||
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||
requestFocus();
|
||||
}
|
||||
|
||||
if (mSession == null) {
|
||||
return GeckoResult.fromValue(PanZoomController.INPUT_RESULT_UNHANDLED);
|
||||
return PanZoomController.INPUT_RESULT_UNHANDLED;
|
||||
}
|
||||
|
||||
// NOTE: Treat mouse events as "touch" rather than as "mouse", so mouse can be
|
||||
// used to pan/zoom. Call onMouseEvent() instead for behavior similar to desktop.
|
||||
return mSession.getPanZoomController().onTouchEventForResult(event);
|
||||
return mSession.getPanZoomController().onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(final MotionEvent event) {
|
||||
onGenericMotionEventForResult(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a {@link MotionEvent} to the {@link PanZoomController}. This is the same as
|
||||
* {@link #onGenericMotionEvent(MotionEvent)} (MotionEvent)}, but instead returns
|
||||
* a {@link PanZoomController.InputResult} indicating how the event was handled.
|
||||
*
|
||||
* @param event A {@link MotionEvent}
|
||||
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) indicating how the event was handled.
|
||||
*/
|
||||
public @PanZoomController.InputResult int onGenericMotionEventForResult(final @NonNull MotionEvent event) {
|
||||
if (AndroidGamepadManager.handleMotionEvent(event)) {
|
||||
return true;
|
||||
return PanZoomController.INPUT_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
if (mSession == null) {
|
||||
return true;
|
||||
return PanZoomController.INPUT_RESULT_UNHANDLED;
|
||||
}
|
||||
|
||||
if (mSession.getAccessibility().onMotionEvent(event)) {
|
||||
return true;
|
||||
return PanZoomController.INPUT_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
mSession.getPanZoomController().onMotionEvent(event);
|
||||
return true;
|
||||
return mSession.getPanZoomController().onMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -98,10 +98,10 @@ public class PanZoomController {
|
|||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "ui")
|
||||
private native void handleMotionEvent(
|
||||
private native @InputResult int handleMotionEvent(
|
||||
int action, int actionIndex, long time, int metaState, float screenX, float screenY,
|
||||
int pointerId[], float x[], float y[], float orientation[], float pressure[],
|
||||
float toolMajor[], float toolMinor[], GeckoResult<Integer> result);
|
||||
float toolMajor[], float toolMinor[]);
|
||||
|
||||
@WrapForJNI(calledFrom = "ui")
|
||||
private native @InputResult int handleScrollEvent(
|
||||
|
@ -150,17 +150,10 @@ public class PanZoomController {
|
|||
|
||||
/* package */ final NativeProvider mNative = new NativeProvider();
|
||||
|
||||
private void handleMotionEvent(final MotionEvent event) {
|
||||
handleMotionEvent(event, null);
|
||||
}
|
||||
|
||||
private void handleMotionEvent(final MotionEvent event, final GeckoResult<Integer> result) {
|
||||
private @InputResult int handleMotionEvent(final MotionEvent event) {
|
||||
if (!mAttached) {
|
||||
mQueuedEvents.add(new Pair<>(EVENT_SOURCE_MOTION, event));
|
||||
if (result != null) {
|
||||
result.complete(INPUT_RESULT_HANDLED);
|
||||
}
|
||||
return;
|
||||
return INPUT_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
final int action = event.getActionMasked();
|
||||
|
@ -169,10 +162,7 @@ public class PanZoomController {
|
|||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
mLastDownTime = event.getDownTime();
|
||||
} else if (mLastDownTime != event.getDownTime()) {
|
||||
if (result != null) {
|
||||
result.complete(INPUT_RESULT_UNHANDLED);
|
||||
}
|
||||
return;
|
||||
return INPUT_RESULT_UNHANDLED;
|
||||
}
|
||||
|
||||
final int[] pointerId = new int[count];
|
||||
|
@ -210,9 +200,9 @@ public class PanZoomController {
|
|||
mSession.onScreenOriginChanged((int)screenX, (int)screenY);
|
||||
}
|
||||
|
||||
mNative.handleMotionEvent(action, event.getActionIndex(), event.getEventTime(),
|
||||
event.getMetaState(), screenX, screenY, pointerId, x, y,
|
||||
orientation, pressure, toolMajor, toolMinor, result);
|
||||
return mNative.handleMotionEvent(action, event.getActionIndex(), event.getEventTime(),
|
||||
event.getMetaState(), screenX, screenY, pointerId, x, y,
|
||||
orientation, pressure, toolMajor, toolMinor);
|
||||
}
|
||||
|
||||
private @InputResult int handleScrollEvent(final MotionEvent event) {
|
||||
|
@ -324,42 +314,15 @@ public class PanZoomController {
|
|||
* display surface.
|
||||
*
|
||||
* @param event MotionEvent to process.
|
||||
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) constants indicating how the event was handled.
|
||||
*/
|
||||
public void onTouchEvent(final @NonNull MotionEvent event) {
|
||||
public @InputResult int onTouchEvent(final @NonNull MotionEvent event) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
if (!sTreatMouseAsTouch && event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
|
||||
handleMouseEvent(event);
|
||||
return;
|
||||
return handleMouseEvent(event);
|
||||
}
|
||||
handleMotionEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a touch event through the pan-zoom controller. Treat any mouse events as
|
||||
* "touch" rather than as "mouse". Pointer coordinates should be relative to the
|
||||
* display surface.
|
||||
*
|
||||
* NOTE: It is highly recommended to only call this with ACTION_DOWN or in otherwise
|
||||
* limited capacity. Returning a GeckoResult for every touch event will generate
|
||||
* a lot of allocations and unnecessary GC pressure. Instead, prefer to call
|
||||
* {@link #onTouchEvent(MotionEvent)}.
|
||||
*
|
||||
* @param event MotionEvent to process.
|
||||
* @return A GeckoResult resolving to one of the
|
||||
* {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) constants indicating
|
||||
* how the event was handled.
|
||||
*/
|
||||
public @NonNull GeckoResult<Integer> onTouchEventForResult(final @NonNull MotionEvent event) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
if (!sTreatMouseAsTouch && event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
|
||||
return GeckoResult.fromValue(handleMouseEvent(event));
|
||||
}
|
||||
|
||||
final GeckoResult<Integer> result = new GeckoResult<>();
|
||||
handleMotionEvent(event, result);
|
||||
return result;
|
||||
return handleMotionEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -368,14 +331,15 @@ public class PanZoomController {
|
|||
* display surface.
|
||||
*
|
||||
* @param event MotionEvent to process.
|
||||
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) constants indicating how the event was handled.
|
||||
*/
|
||||
public void onMouseEvent(final @NonNull MotionEvent event) {
|
||||
public @InputResult int onMouseEvent(final @NonNull MotionEvent event) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
|
||||
return;
|
||||
return handleMouseEvent(event);
|
||||
}
|
||||
handleMotionEvent(event);
|
||||
return handleMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -389,8 +353,9 @@ public class PanZoomController {
|
|||
* display surface.
|
||||
*
|
||||
* @param event MotionEvent to process.
|
||||
* @return One of the {@link PanZoomController#INPUT_RESULT_UNHANDLED INPUT_RESULT_*}) indicating how the event was handled.
|
||||
*/
|
||||
public void onMotionEvent(final @NonNull MotionEvent event) {
|
||||
public @InputResult int onMotionEvent(final @NonNull MotionEvent event) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
final int action = event.getActionMasked();
|
||||
|
@ -400,13 +365,15 @@ public class PanZoomController {
|
|||
} else if ((InputDevice.getDevice(event.getDeviceId()) != null) &&
|
||||
(InputDevice.getDevice(event.getDeviceId()).getSources() &
|
||||
InputDevice.SOURCE_TOUCHPAD) == InputDevice.SOURCE_TOUCHPAD) {
|
||||
return;
|
||||
return INPUT_RESULT_UNHANDLED;
|
||||
}
|
||||
handleScrollEvent(event);
|
||||
return handleScrollEvent(event);
|
||||
} else if ((action == MotionEvent.ACTION_HOVER_MOVE) ||
|
||||
(action == MotionEvent.ACTION_HOVER_ENTER) ||
|
||||
(action == MotionEvent.ACTION_HOVER_EXIT)) {
|
||||
handleMouseEvent(event);
|
||||
return handleMouseEvent(event);
|
||||
} else {
|
||||
return INPUT_RESULT_UNHANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Date;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Represents a WebExtension that may be used by GeckoView.
|
||||
|
@ -54,7 +55,8 @@ public class WebExtension {
|
|||
public final @WebExtensionFlags long flags;
|
||||
|
||||
/** Provides information about this {@link WebExtension}. */
|
||||
public final @NonNull MetaData metaData;
|
||||
// TODO: move to @NonNull when we remove registerWebExtension
|
||||
public final @Nullable MetaData metaData;
|
||||
|
||||
/**
|
||||
* Whether this extension is built-in. Built-in extension can be installed
|
||||
|
@ -121,6 +123,70 @@ public class WebExtension {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a WebExtension instance that can be loaded in GeckoView using
|
||||
* {@link GeckoRuntime#registerWebExtension}
|
||||
*
|
||||
* @param location The WebExtension install location. It must be either a
|
||||
* <code>resource:</code> URI to a folder inside the APK or
|
||||
* a <code>file:</code> URL to a <code>.xpi</code> file.
|
||||
* @param id Unique identifier for this WebExtension. This identifier must
|
||||
* either be a GUID or a string formatted like an email address.
|
||||
* E.g. <pre><code>
|
||||
* "extensionname@example.org"
|
||||
* "{daf44bf7-a45e-4450-979c-91cf07434c3d}"
|
||||
* </code></pre>
|
||||
*
|
||||
* See also: <ul>
|
||||
* <li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings">
|
||||
* WebExtensions/manifest.json/browser_specific_settings
|
||||
* </a>
|
||||
* <li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/WebExtensions_and_the_Add-on_ID#When_do_you_need_an_add-on_ID">
|
||||
* WebExtensions/WebExtensions_and_the_Add-on_ID
|
||||
* </a>
|
||||
* </ul>
|
||||
* @param flags {@link Flags} for this WebExtension.
|
||||
* @param controller the current {@link WebExtensionController} instance
|
||||
*
|
||||
* @deprecated Use the return value of {@link WebExtensionController#installBuiltIn} instead.
|
||||
* This method will be removed in GeckoView 81.
|
||||
*/
|
||||
@Deprecated
|
||||
public WebExtension(final @NonNull String location, final @NonNull String id,
|
||||
final @WebExtensionFlags long flags,
|
||||
final @NonNull WebExtensionController controller) {
|
||||
setDelegateController(controller.delegateFor(this));
|
||||
this.location = location;
|
||||
this.id = id;
|
||||
this.flags = flags;
|
||||
|
||||
// TODO:
|
||||
this.isBuiltIn = false;
|
||||
this.metaData = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a WebExtension instance that can be loaded in GeckoView using
|
||||
* {@link GeckoRuntime#registerWebExtension}
|
||||
* The <code>id</code> for this web extension will be automatically
|
||||
* generated.
|
||||
*
|
||||
* All messaging from the web extension will be ignored.
|
||||
*
|
||||
* @param location The WebExtension install location. It must be either a
|
||||
* <code>resource:</code> URI to a folder inside the APK or
|
||||
* a <code>file:</code> URL to a <code>.xpi</code> file.
|
||||
* @param controller the current {@link WebExtensionController} instance
|
||||
*
|
||||
* @deprecated Use the return value of {@link WebExtensionController#installBuiltIn} instead.
|
||||
* This method will be removed in GeckoView 81.
|
||||
*/
|
||||
@Deprecated
|
||||
public WebExtension(final @NonNull String location,
|
||||
final @NonNull WebExtensionController controller) {
|
||||
this(location, "{" + UUID.randomUUID().toString() + "}", Flags.NONE, controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the message delegate for a Native App.
|
||||
*
|
||||
|
@ -405,7 +471,8 @@ public class WebExtension {
|
|||
* See also: <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/remove">
|
||||
* WebExtensions/API/tabs/remove</a>
|
||||
*
|
||||
* @param source An instance of {@link WebExtension}
|
||||
* @param source An instance of {@link WebExtension} or null if extension was not registered
|
||||
* with GeckoRuntime.registerWebextension
|
||||
* @param session An instance of {@link GeckoSession} to be closed.
|
||||
* @return GeckoResult.ALLOW if the tab will be closed, GeckoResult.DENY otherwise
|
||||
*/
|
||||
|
|
|
@ -176,6 +176,52 @@ public class WebExtensionController {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: remove once we remove GeckoRuntime#registerWebExtension
|
||||
/* package */ DelegateController delegateFor(final WebExtension extension) {
|
||||
return new DelegateController(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link WebExtension.TabDelegate} and {@link WebExtension.SessionTabDelegate}.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface TabDelegate {
|
||||
/**
|
||||
* Called when tabs.create is invoked, this method returns a *newly-created* session
|
||||
* that GeckoView will use to load the requested page on. If the returned value
|
||||
* is null the page will not be opened.
|
||||
*
|
||||
* @param source An instance of {@link WebExtension} or null if extension was not registered
|
||||
* with GeckoRuntime.registerWebextension
|
||||
* @param uri The URI to be loaded. This is provided for informational purposes only,
|
||||
* do not call {@link GeckoSession#loadUri} on it.
|
||||
* @return A {@link GeckoResult} which holds the returned GeckoSession. May be null, in
|
||||
* which case the request for a new tab by the extension will fail.
|
||||
* The implementation of onNewTab is responsible for maintaining a reference
|
||||
* to the returned object, to prevent it from being garbage collected.
|
||||
*/
|
||||
@UiThread
|
||||
@Nullable
|
||||
default GeckoResult<GeckoSession> onNewTab(@Nullable WebExtension source, @Nullable String uri) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Called when tabs.remove is invoked, this method decides if WebExtension can close the
|
||||
* tab. In case WebExtension can close the tab, it should close passed GeckoSession and
|
||||
* return GeckoResult.ALLOW or GeckoResult.DENY in case tab cannot be closed.
|
||||
*
|
||||
* @param source An instance of {@link WebExtension} or null if extension was not registered
|
||||
* with GeckoRuntime.registerWebextension
|
||||
* @param session An instance of {@link GeckoSession} to be closed.
|
||||
* @return GeckoResult.ALLOW if the tab will be closed, GeckoResult.DENY otherwise
|
||||
*/
|
||||
@UiThread
|
||||
@NonNull
|
||||
default GeckoResult<AllowOrDeny> onCloseTab(@Nullable WebExtension source, @NonNull GeckoSession session) {
|
||||
return GeckoResult.DENY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This delegate will be called whenever an extension is about to be installed or it needs
|
||||
* new permissions, e.g during an update or because it called <code>permissions.request</code>
|
||||
|
|
|
@ -18,16 +18,11 @@ exclude: true
|
|||
to [`ContentBlocking.Settings`][81.2].
|
||||
- Added [`GeckoSession.ContentDelegate.onPaintStatusReset()`][81.3] callback which notifies when valid content is no longer being rendered.
|
||||
- Made [`GeckoSession.ContentDelegate.onFirstContentfulPaint()`][81.4] additionally be called for the first contentful paint following a `onPaintStatusReset()` event, rather than just the first contentful paint of the session.
|
||||
- ⚠️ Changed [`GeckoView.onTouchEventForResult`][81.5] to return a `GeckoResult`, as it now
|
||||
makes a round-trip to Gecko. The result will be more accurate now, since how content treats
|
||||
the event is now considered.
|
||||
- Removed deprecated `GeckoRuntime.registerWebExtension`. Use [`WebExtensionController.install`][73.1] instead.
|
||||
|
||||
[81.1]: {{javadoc_uri}}/ContentBlocking.Settings.Builder.html
|
||||
[81.2]: {{javadoc_uri}}/ContentBlocking.Settings.html
|
||||
[81.3]: {{javadoc_uri}}/GeckoSession.ContentDelegate.html#onPaintStatusReset-org.mozilla.geckoview.GeckoSession-
|
||||
[81.4]: {{javadoc_uri}}/GeckoSession.ContentDelegate.html#onFirstContentfulPaint-org.mozilla.geckoview.GeckoSession-
|
||||
[81.5]: {{javadoc_uri}}/GeckoView.html#onTouchEventForResult-android.view.MotionEvent-
|
||||
|
||||
## v80
|
||||
- Removed `GeckoSession.hashCode` and `GeckoSession.equals` overrides in favor
|
||||
|
@ -770,4 +765,4 @@ to allow adding gecko profiler markers.
|
|||
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
|
||||
[65.25]: {{javadoc_uri}}/GeckoResult.html
|
||||
|
||||
[api-version]: ca995cc1f0626ab33312d27e35100485d35333a7
|
||||
[api-version]: 9f4bf24e0795c8da7caf58487e659918ea1a56cc
|
||||
|
|
|
@ -164,7 +164,18 @@ class GeckoViewConnection {
|
|||
constructor(sender, nativeApp, allowContentMessaging) {
|
||||
this.sender = sender;
|
||||
this.nativeApp = nativeApp;
|
||||
this.allowContentMessaging = allowContentMessaging;
|
||||
if (allowContentMessaging) {
|
||||
this.allowContentMessaging = allowContentMessaging;
|
||||
} else {
|
||||
const scope = GeckoViewWebExtension.extensionScopes.get(
|
||||
sender.extensionId
|
||||
);
|
||||
if (scope) {
|
||||
this.allowContentMessaging = scope.allowContentMessaging;
|
||||
} else {
|
||||
this.allowContentMessaging = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.allowContentMessaging && !sender.verified) {
|
||||
throw new Error(`Unexpected messaging sender: ${JSON.stringify(sender)}`);
|
||||
|
@ -584,13 +595,56 @@ var GeckoViewWebExtension = {
|
|||
}
|
||||
},
|
||||
|
||||
async extensionById(aId) {
|
||||
const addon = await AddonManager.getAddonByID(aId);
|
||||
if (!addon) {
|
||||
debug`Could not find extension with id=${aId}`;
|
||||
return null;
|
||||
async registerWebExtension(aId, aUri, allowContentMessaging, aCallback) {
|
||||
const params = {
|
||||
id: aId,
|
||||
resourceURI: aUri,
|
||||
temporarilyInstalled: true,
|
||||
builtIn: true,
|
||||
};
|
||||
|
||||
let file;
|
||||
if (aUri instanceof Ci.nsIFileURL) {
|
||||
file = aUri.file;
|
||||
}
|
||||
return addon;
|
||||
|
||||
const scope = Extension.getBootstrapScope(aId, file);
|
||||
scope.allowContentMessaging = allowContentMessaging;
|
||||
// Always allow built-in extensions to run in private browsing
|
||||
ExtensionPermissions.add(aId, PRIVATE_BROWSING_PERMISSION);
|
||||
this.extensionScopes.set(aId, scope);
|
||||
|
||||
await scope.startup(params, undefined);
|
||||
|
||||
scope.extension.callOnClose({
|
||||
close: () => this.extensionScopes.delete(aId),
|
||||
});
|
||||
},
|
||||
|
||||
async unregisterWebExtension(aId, aCallback) {
|
||||
try {
|
||||
const scope = this.extensionScopes.get(aId);
|
||||
await scope.shutdown();
|
||||
this.extensionScopes.delete(aId);
|
||||
aCallback.onSuccess();
|
||||
} catch (ex) {
|
||||
aCallback.onError(`Error unregistering WebExtension ${aId}. ${ex}`);
|
||||
}
|
||||
},
|
||||
|
||||
async extensionById(aId) {
|
||||
const scope = this.extensionScopes.get(aId);
|
||||
if (!scope) {
|
||||
// Check if this is an installed extension
|
||||
const addon = await AddonManager.getAddonByID(aId);
|
||||
if (!addon) {
|
||||
debug`Could not find extension with id=${aId}`;
|
||||
return null;
|
||||
}
|
||||
return addon;
|
||||
}
|
||||
|
||||
return scope.extension;
|
||||
},
|
||||
|
||||
async ensureBuiltIn(aUri, aId) {
|
||||
|
@ -828,11 +882,69 @@ var GeckoViewWebExtension = {
|
|||
break;
|
||||
}
|
||||
|
||||
// TODO: Remove deprecated Bug 1634504
|
||||
case "GeckoView:RegisterWebExtension": {
|
||||
let uri;
|
||||
try {
|
||||
uri = Services.io.newURI(aData.locationUri);
|
||||
} catch (ex) {
|
||||
aCallback.onError(`Could not parse URI: ${aData.locationUri}`);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!uri ||
|
||||
(!(uri instanceof Ci.nsIFileURL) && !(uri instanceof Ci.nsIJARURI))
|
||||
) {
|
||||
aCallback.onError(
|
||||
`Extension does not point to a resource URI or a file URL. extension=${aData.locationUri}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uri.fileName != "" && uri.fileExtension != "xpi") {
|
||||
aCallback.onError(
|
||||
`Extension does not point to a folder or an .xpi file. Hint: the path needs to end with a "/" to be considered a folder. extension=${aData.locationUri}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.extensionScopes.has(aData.id)) {
|
||||
aCallback.onError(
|
||||
`An extension with id='${aData.id}' has already been registered.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.registerWebExtension(
|
||||
aData.id,
|
||||
uri,
|
||||
aData.allowContentMessaging
|
||||
).then(aCallback.onSuccess, error =>
|
||||
aCallback.onError(
|
||||
`An error occurred while registering the WebExtension ${aData.locationUri}: ${error}.`
|
||||
)
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
case "GeckoView:ActionDelegate:Attached": {
|
||||
this.actionDelegateAttached(aData.extensionId);
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Remove deprecated Bug 1634504
|
||||
case "GeckoView:UnregisterWebExtension": {
|
||||
if (!this.extensionScopes.has(aData.id)) {
|
||||
aCallback.onError(
|
||||
`Could not find an extension with id='${aData.id}'.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.unregisterWebExtension(aData.id, aCallback);
|
||||
break;
|
||||
}
|
||||
|
||||
case "GeckoView:WebExtension:Get": {
|
||||
const extension = await this.extensionById(aData.extensionId);
|
||||
if (!extension) {
|
||||
|
@ -1019,6 +1131,8 @@ var GeckoViewWebExtension = {
|
|||
},
|
||||
};
|
||||
|
||||
// TODO: Remove deprecated Bug 1634504
|
||||
GeckoViewWebExtension.extensionScopes = new Map();
|
||||
// WeakMap[Extension -> BrowserAction]
|
||||
GeckoViewWebExtension.browserActions = new WeakMap();
|
||||
// WeakMap[Extension -> PageAction]
|
||||
|
|
|
@ -34,17 +34,12 @@
|
|||
#include "mozilla/dom/MouseEventBinding.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/layers/RenderTrace.h"
|
||||
#include <algorithm>
|
||||
|
||||
using mozilla::Unused;
|
||||
using mozilla::dom::ContentChild;
|
||||
using mozilla::dom::ContentParent;
|
||||
using mozilla::gfx::DataSourceSurface;
|
||||
using mozilla::gfx::IntSize;
|
||||
using mozilla::gfx::Matrix;
|
||||
using mozilla::gfx::SurfaceFormat;
|
||||
|
||||
#include "nsWindow.h"
|
||||
|
||||
|
@ -883,9 +878,10 @@ class nsWindow::NPZCSupport final
|
|||
WheelDeltaAdjustmentStrategy::eNone);
|
||||
|
||||
APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input);
|
||||
int32_t ret = (result.mHandledByRootApzc == Some(true))
|
||||
? INPUT_RESULT_HANDLED
|
||||
: INPUT_RESULT_HANDLED_CONTENT;
|
||||
int32_t ret =
|
||||
!result.mTargetIsRoot || result.mHitRegionWithApzAwareListeners
|
||||
? INPUT_RESULT_HANDLED_CONTENT
|
||||
: INPUT_RESULT_HANDLED;
|
||||
|
||||
if (result.mStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
return ret;
|
||||
|
@ -1006,9 +1002,10 @@ class nsWindow::NPZCSupport final
|
|||
GetEventTimeStamp(aTime), GetModifiers(aMetaState));
|
||||
|
||||
APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input);
|
||||
int32_t ret = (result.mHandledByRootApzc == Some(true))
|
||||
? INPUT_RESULT_HANDLED
|
||||
: INPUT_RESULT_HANDLED_CONTENT;
|
||||
int32_t ret =
|
||||
!result.mTargetIsRoot || result.mHitRegionWithApzAwareListeners
|
||||
? INPUT_RESULT_HANDLED_CONTENT
|
||||
: INPUT_RESULT_HANDLED;
|
||||
|
||||
if (result.mStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
return ret;
|
||||
|
@ -1030,17 +1027,15 @@ class nsWindow::NPZCSupport final
|
|||
}
|
||||
}
|
||||
|
||||
void HandleMotionEvent(
|
||||
int32_t HandleMotionEvent(
|
||||
const java::PanZoomController::NativeProvider::LocalRef& aInstance,
|
||||
int32_t aAction, int32_t aActionIndex, int64_t aTime, int32_t aMetaState,
|
||||
float aScreenX, float aScreenY, jni::IntArray::Param aPointerId,
|
||||
jni::FloatArray::Param aX, jni::FloatArray::Param aY,
|
||||
jni::FloatArray::Param aOrientation, jni::FloatArray::Param aPressure,
|
||||
jni::FloatArray::Param aToolMajor, jni::FloatArray::Param aToolMinor,
|
||||
jni::Object::Param aResult) {
|
||||
jni::FloatArray::Param aToolMajor, jni::FloatArray::Param aToolMinor) {
|
||||
MOZ_ASSERT(AndroidBridge::IsJavaUiThread());
|
||||
|
||||
auto returnResult = java::GeckoResult::Ref::From(aResult);
|
||||
RefPtr<IAPZCTreeManager> controller;
|
||||
|
||||
if (LockedWindowPtr window{mWindow}) {
|
||||
|
@ -1048,11 +1043,7 @@ class nsWindow::NPZCSupport final
|
|||
}
|
||||
|
||||
if (!controller) {
|
||||
if (returnResult) {
|
||||
returnResult->Complete(
|
||||
java::sdk::Integer::ValueOf(INPUT_RESULT_UNHANDLED));
|
||||
}
|
||||
return;
|
||||
return INPUT_RESULT_UNHANDLED;
|
||||
}
|
||||
|
||||
nsTArray<int32_t> pointerId(aPointerId->GetElements());
|
||||
|
@ -1081,11 +1072,7 @@ class nsWindow::NPZCSupport final
|
|||
type = MultiTouchInput::MULTITOUCH_CANCEL;
|
||||
break;
|
||||
default:
|
||||
if (returnResult) {
|
||||
returnResult->Complete(
|
||||
java::sdk::Integer::ValueOf(INPUT_RESULT_UNHANDLED));
|
||||
}
|
||||
return;
|
||||
return INPUT_RESULT_UNHANDLED;
|
||||
}
|
||||
|
||||
MultiTouchInput input(type, aTime, GetEventTimeStamp(aTime), 0);
|
||||
|
@ -1142,15 +1129,13 @@ class nsWindow::NPZCSupport final
|
|||
}
|
||||
|
||||
APZEventResult result = controller->InputBridge()->ReceiveInputEvent(input);
|
||||
int32_t handled = (result.mHandledByRootApzc == Some(true))
|
||||
? INPUT_RESULT_HANDLED
|
||||
: INPUT_RESULT_HANDLED_CONTENT;
|
||||
int32_t ret =
|
||||
!result.mTargetIsRoot || result.mHitRegionWithApzAwareListeners
|
||||
? INPUT_RESULT_HANDLED_CONTENT
|
||||
: INPUT_RESULT_HANDLED;
|
||||
|
||||
if (result.mStatus == nsEventStatus_eConsumeNoDefault) {
|
||||
if (returnResult) {
|
||||
returnResult->Complete(java::sdk::Integer::ValueOf(handled));
|
||||
}
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Dispatch APZ input event on Gecko thread.
|
||||
|
@ -1160,40 +1145,15 @@ class nsWindow::NPZCSupport final
|
|||
window->DispatchHitTest(touchEvent);
|
||||
});
|
||||
|
||||
if (!returnResult) {
|
||||
// We don't care how APZ handled the event so we're done here.
|
||||
return;
|
||||
switch (result.mStatus) {
|
||||
case nsEventStatus_eIgnore:
|
||||
return INPUT_RESULT_UNHANDLED;
|
||||
case nsEventStatus_eConsumeDoDefault:
|
||||
return ret;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected nsEventStatus");
|
||||
return INPUT_RESULT_UNHANDLED;
|
||||
}
|
||||
|
||||
if (result.mHandledByRootApzc != Nothing()) {
|
||||
// We know conclusively that the root APZ handled this or not and
|
||||
// don't need to do any more work.
|
||||
switch (result.mStatus) {
|
||||
case nsEventStatus_eIgnore:
|
||||
returnResult->Complete(
|
||||
java::sdk::Integer::ValueOf(INPUT_RESULT_UNHANDLED));
|
||||
break;
|
||||
case nsEventStatus_eConsumeDoDefault:
|
||||
returnResult->Complete(java::sdk::Integer::ValueOf(handled));
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected nsEventStatus");
|
||||
returnResult->Complete(
|
||||
java::sdk::Integer::ValueOf(INPUT_RESULT_UNHANDLED));
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait to see if APZ handled the event or not...
|
||||
controller->AddInputBlockCallback(
|
||||
result.mInputBlockId,
|
||||
[returnResult = java::GeckoResult::GlobalRef(returnResult)](
|
||||
uint64_t aInputBlockId, bool aHandledByRootApzc) {
|
||||
returnResult->Complete(java::sdk::Integer::ValueOf(
|
||||
aHandledByRootApzc ? INPUT_RESULT_HANDLED
|
||||
: INPUT_RESULT_HANDLED_CONTENT));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче