Bug 1479034 - Make GeckoView's SessionAccessibility a JNIObject associated with a nsWindow. r=jchen

This commit is contained in:
Eitan Isaacson 2018-09-19 16:01:40 -07:00
parent 537fb3b46c
commit 0206ea9620
7 changed files with 188 additions and 7 deletions

View File

@ -0,0 +1,36 @@
/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SessionAccessibility.h"
#include "AndroidUiThread.h"
#include "nsThreadUtils.h"
#ifdef DEBUG
#include <android/log.h>
#define AALOG(args...) \
__android_log_print(ANDROID_LOG_INFO, "GeckoAccessibilityNative", ##args)
#else
#define AALOG(args...) \
do { \
} while (0)
#endif
template<>
const char nsWindow::NativePtr<mozilla::a11y::SessionAccessibility>::sName[] =
"SessionAccessibility";
using namespace mozilla::a11y;
void
SessionAccessibility::SetAttached(bool aAttached)
{
if (RefPtr<nsThread> uiThread = GetAndroidUiThread()) {
uiThread->Dispatch(NS_NewRunnableFunction(
"SessionAccessibility::Attach",
[aAttached,
sa = java::SessionAccessibility::NativeProvider::GlobalRef(
mSessionAccessibility)] { sa->SetAttached(aAttached); }));
}
}

View File

@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_SessionAccessibility_h_
#define mozilla_a11y_SessionAccessibility_h_
#include "GeneratedJNINatives.h"
#include "nsWindow.h"
namespace mozilla {
namespace a11y {
class SessionAccessibility final
: public java::SessionAccessibility::NativeProvider::Natives<SessionAccessibility>
{
public:
typedef java::SessionAccessibility::NativeProvider::Natives<SessionAccessibility> Base;
SessionAccessibility(
nsWindow::NativePtr<SessionAccessibility>* aPtr,
nsWindow* aWindow,
java::SessionAccessibility::NativeProvider::Param aSessionAccessibility)
: mWindow(aPtr, aWindow)
, mSessionAccessibility(aSessionAccessibility)
{
SetAttached(true);
}
void OnDetach() { SetAttached(false); }
// Native implementations
using Base::AttachNative;
using Base::DisposeNative;
NS_INLINE_DECL_REFCOUNTING(SessionAccessibility)
private:
~SessionAccessibility() {}
void SetAttached(bool aAttached);
nsWindow::WindowPtr<SessionAccessibility> mWindow; // Parent only
java::SessionAccessibility::NativeProvider::GlobalRef mSessionAccessibility;
};
} // namespace a11y
} // namespace mozilla
#endif

View File

@ -6,11 +6,13 @@
EXPORTS.mozilla.a11y += ['AccessibleWrap.h',
'HyperTextAccessibleWrap.h',
'SessionAccessibility.h',
]
SOURCES += [
'AccessibleWrap.cpp',
'Platform.cpp',
'SessionAccessibility.cpp',
]
LOCAL_INCLUDES += [

View File

@ -708,6 +708,7 @@ public final class GeckoSession extends LayerSession
@WrapForJNI(dispatchTo = "proxy")
public static native void open(Window instance, NativeQueue queue,
Compositor compositor, EventDispatcher dispatcher,
SessionAccessibility.NativeProvider sessionAccessibility,
GeckoBundle initData, String id, String chromeUri,
int screenId, boolean privateMode);
@ -756,6 +757,7 @@ public final class GeckoSession extends LayerSession
public synchronized void transfer(final NativeQueue queue,
final Compositor compositor,
final EventDispatcher dispatcher,
final SessionAccessibility.NativeProvider sessionAccessibility,
final GeckoBundle initData) {
if (mNativeQueue == null) {
// Already closed.
@ -763,13 +765,14 @@ public final class GeckoSession extends LayerSession
}
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
nativeTransfer(queue, compositor, dispatcher, initData);
nativeTransfer(queue, compositor, dispatcher, sessionAccessibility, initData);
} else {
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
this, "nativeTransfer",
NativeQueue.class, queue,
Compositor.class, compositor,
EventDispatcher.class, dispatcher,
SessionAccessibility.NativeProvider.class, sessionAccessibility,
GeckoBundle.class, initData);
}
@ -783,12 +786,17 @@ public final class GeckoSession extends LayerSession
@WrapForJNI(dispatchTo = "proxy", stubName = "Transfer")
private native void nativeTransfer(NativeQueue queue, Compositor compositor,
EventDispatcher dispatcher, GeckoBundle initData);
EventDispatcher dispatcher,
SessionAccessibility.NativeProvider sessionAccessibility,
GeckoBundle initData);
@WrapForJNI(dispatchTo = "proxy")
public native void attachEditable(IGeckoEditableParent parent,
GeckoEditableChild child);
@WrapForJNI(dispatchTo = "proxy")
public native void attachAccessibility(SessionAccessibility.NativeProvider sessionAccessibility);
@WrapForJNI(calledFrom = "gecko")
private synchronized void onReady(final @Nullable NativeQueue queue) {
// onReady is called the first time the Gecko window is ready, with a null queue
@ -876,7 +884,8 @@ public final class GeckoSession extends LayerSession
if (mWindow != null) {
mWindow.transfer(mNativeQueue, mCompositor,
mEventDispatcher, createInitData());
mEventDispatcher, mAccessibility != null ? mAccessibility.nativeProvider : null,
createInitData());
onWindowChanged(WINDOW_TRANSFER_IN, /* inProgress */ false);
}
@ -1003,6 +1012,7 @@ public final class GeckoSession extends LayerSession
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
Window.open(mWindow, mNativeQueue, mCompositor, mEventDispatcher,
mAccessibility != null ? mAccessibility.nativeProvider : null,
createInitData(), mId, chromeUri, screenId, isPrivate);
} else {
GeckoThread.queueNativeCallUntil(
@ -1012,6 +1022,8 @@ public final class GeckoSession extends LayerSession
NativeQueue.class, mNativeQueue,
Compositor.class, mCompositor,
EventDispatcher.class, mEventDispatcher,
SessionAccessibility.NativeProvider.class,
mAccessibility != null ? mAccessibility.nativeProvider : null,
GeckoBundle.class, createInitData(),
String.class, mId,
String.class, chromeUri,
@ -1076,8 +1088,18 @@ public final class GeckoSession extends LayerSession
* @return SessionAccessibility instance.
*/
public @NonNull SessionAccessibility getAccessibility() {
if (mAccessibility == null) {
mAccessibility = new SessionAccessibility(this);
ThreadUtils.assertOnUiThread();
if (mAccessibility != null) { return mAccessibility; }
mAccessibility = new SessionAccessibility(this);
if (mWindow != null) {
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
mWindow.attachAccessibility(mAccessibility.nativeProvider);
} else {
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
mWindow, "attachAccessibility",
SessionAccessibility.NativeProvider.class, mAccessibility.nativeProvider);
}
}
return mAccessibility;
}

View File

@ -5,12 +5,14 @@
package org.mozilla.geckoview;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.PrefsHelper;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.mozglue.JNIObject;
import android.content.Context;
import android.graphics.Matrix;
@ -232,6 +234,8 @@ public class SessionAccessibility {
/* package */ final GeckoSession mSession;
// This is the view that delegates accessibility to us. We also sends event through it.
private View mView;
// The native portion of the node provider.
/* package */ final NativeProvider nativeProvider = new NativeProvider();
// Have we reached the last item in content?
private boolean mLastItem;
// Used to store the JSON message and populate the event later in the code path.
@ -241,6 +245,8 @@ public class SessionAccessibility {
private SparseArray<EventCallback> mAutoFillRoots;
private int mAutoFillFocusedId = View.NO_ID;
private boolean mAttached = false;
/* package */ SessionAccessibility(final GeckoSession session) {
mSession = session;
@ -803,4 +809,20 @@ public class SessionAccessibility {
((ViewParent) mView).requestSendAccessibilityEvent(mView, event);
}
}
/* package */ final class NativeProvider extends JNIObject {
@WrapForJNI(calledFrom = "ui")
private void setAttached(final boolean attached) {
if (attached) {
mAttached = true;
} else if (mAttached) {
mAttached = false;
disposeNative();
}
}
@WrapForJNI(calledFrom = "ui", dispatchTo = "gecko")
@Override
protected native void disposeNative();
}
}

View File

@ -17,6 +17,7 @@
#include "mozilla/WeakPtr.h"
#include "mozilla/WheelHandlingHelper.h" // for WheelDeltaAdjustmentStrategy
#include "mozilla/a11y/SessionAccessibility.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/MouseEventBinding.h"
@ -285,6 +286,7 @@ public:
jni::Object::Param aQueue,
jni::Object::Param aCompositor,
jni::Object::Param aDispatcher,
jni::Object::Param aSessionAccessibility,
jni::Object::Param aInitData,
jni::String::Param aId,
jni::String::Param aChromeURI,
@ -299,12 +301,16 @@ public:
jni::Object::Param aQueue,
jni::Object::Param aCompositor,
jni::Object::Param aDispatcher,
jni::Object::Param aSessionAccessibility,
jni::Object::Param aInitData);
void AttachEditable(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aEditableParent,
jni::Object::Param aEditableChild);
void AttachAccessibility(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aSessionAccessibility);
void OnReady(jni::Object::Param aQueue = nullptr);
};
@ -1135,6 +1141,10 @@ nsWindow::GeckoViewSupport::~GeckoViewSupport()
if (window.mLayerViewSupport) {
window.mLayerViewSupport.Detach();
}
if (window.mSessionAccessibility) {
window.mSessionAccessibility.Detach();
}
}
/* static */ void
@ -1143,6 +1153,7 @@ nsWindow::GeckoViewSupport::Open(const jni::Class::LocalRef& aCls,
jni::Object::Param aQueue,
jni::Object::Param aCompositor,
jni::Object::Param aDispatcher,
jni::Object::Param aSessionAccessibility,
jni::Object::Param aInitData,
jni::String::Param aId,
jni::String::Param aChromeURI,
@ -1198,7 +1209,7 @@ nsWindow::GeckoViewSupport::Open(const jni::Class::LocalRef& aCls,
// Attach other session support objects.
window->mGeckoViewSupport->Transfer(
sessionWindow, aQueue, aCompositor, aDispatcher, aInitData);
sessionWindow, aQueue, aCompositor, aDispatcher, aSessionAccessibility, aInitData);
if (window->mWidgetListener) {
nsCOMPtr<nsIXULWindow> xulWindow(
@ -1232,6 +1243,7 @@ nsWindow::GeckoViewSupport::Transfer(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aQueue,
jni::Object::Param aCompositor,
jni::Object::Param aDispatcher,
jni::Object::Param aSessionAccessibility,
jni::Object::Param aInitData)
{
if (window.mNPZCSupport) {
@ -1253,6 +1265,13 @@ nsWindow::GeckoViewSupport::Transfer(const GeckoSession::Window::LocalRef& inst,
window.mAndroidView->mEventDispatcher->Attach(
java::EventDispatcher::Ref::From(aDispatcher), mDOMWindow);
if (window.mSessionAccessibility) {
window.mSessionAccessibility.Detach();
}
if (aSessionAccessibility) {
AttachAccessibility(inst, aSessionAccessibility);
}
if (mIsReady) {
// We're in a transfer; update init-data and notify JS code.
window.mAndroidView->mInitData =
@ -1285,6 +1304,24 @@ nsWindow::GeckoViewSupport::AttachEditable(const GeckoSession::Window::LocalRef&
window.mEditableParent = aEditableParent;
}
void
nsWindow::GeckoViewSupport::AttachAccessibility(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aSessionAccessibility)
{
MOZ_ASSERT(!window.mSessionAccessibility);
java::SessionAccessibility::NativeProvider::LocalRef sessionAccessibility(
inst.Env());
sessionAccessibility = java::SessionAccessibility::NativeProvider::Ref::From(
aSessionAccessibility);
if (window.mSessionAccessibility) {
window.mSessionAccessibility.Detach();
}
window.mSessionAccessibility.Attach(
sessionAccessibility, &window, sessionAccessibility);
}
void
nsWindow::InitNatives()
{
@ -1293,6 +1330,7 @@ nsWindow::InitNatives()
nsWindow::NPZCSupport::Init();
GeckoEditableSupport::Init();
a11y::SessionAccessibility::Init();
}
nsWindow*
@ -2342,4 +2380,3 @@ nsIWidget::CreateChildWindow()
nsCOMPtr<nsIWidget> window = new nsWindow();
return window.forget();
}

View File

@ -38,6 +38,10 @@ namespace mozilla {
namespace ipc {
class Shmem;
} // namespace ipc
namespace a11y {
class SessionAccessibility;
}
}
class nsWindow final : public nsBaseWidget
@ -186,6 +190,10 @@ private:
NativePtr<mozilla::widget::GeckoEditableSupport> mEditableSupport;
mozilla::jni::Object::GlobalRef mEditableParent;
// Object that implements native SessionAccessibility calls.
// Strong referenced by the Java instance.
NativePtr<mozilla::a11y::SessionAccessibility> mSessionAccessibility;
class GeckoViewSupport;
// Object that implements native GeckoView calls and associated states.
// nullptr for nsWindows that were not opened from GeckoView.
@ -306,6 +314,8 @@ public:
mozilla::jni::Object::Ref& GetEditableParent() { return mEditableParent; }
mozilla::a11y::SessionAccessibility* GetSessionAccessibility() { return mSessionAccessibility; }
void RecvToolbarAnimatorMessageFromCompositor(int32_t aMessage) override;
void UpdateRootFrameMetrics(const ScreenPoint& aScrollOffset, const CSSToScreenScale& aZoom) override;
void RecvScreenPixels(mozilla::ipc::Shmem&& aMem, const ScreenIntSize& aSize) override;
@ -353,6 +363,7 @@ private:
// Explicit template declarations to make clang be quiet.
template<> const char nsWindow::NativePtr<nsWindow::LayerViewSupport>::sName[];
template<> const char nsWindow::NativePtr<mozilla::widget::GeckoEditableSupport>::sName[];
template<> const char nsWindow::NativePtr<mozilla::a11y::SessionAccessibility>::sName[];
template<> const char nsWindow::NativePtr<nsWindow::NPZCSupport>::sName[];
template<class Impl>