Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sxychenjing
engine
提交
380d5353
E
engine
项目概览
sxychenjing
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
engine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
380d5353
编写于
2月 05, 2016
作者:
I
Ian Hickson
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #2353 from Hixie/actions
Make AccessibilityNodeInfos interactive.
上级
36c536f4
707ff9b4
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
224 addition
and
34 deletion
+224
-34
sky/shell/platform/android/org/domokit/sky/shell/FlutterSemanticsToAndroidAccessibilityBridge.java
...y/shell/FlutterSemanticsToAndroidAccessibilityBridge.java
+167
-10
sky/shell/platform/android/org/domokit/sky/shell/PlatformViewAndroid.java
...rm/android/org/domokit/sky/shell/PlatformViewAndroid.java
+57
-24
未找到文件。
sky/shell/platform/android/org/domokit/sky/shell/FlutterSemanticsToAndroidAccessibilityBridge.java
浏览文件 @
380d5353
...
...
@@ -6,7 +6,9 @@ package org.domokit.sky.shell;
import
android.graphics.Rect
;
import
android.opengl.Matrix
;
import
android.os.Bundle
;
import
android.view.View
;
import
android.view.accessibility.AccessibilityEvent
;
import
android.view.accessibility.AccessibilityManager
;
import
android.view.accessibility.AccessibilityNodeInfo
;
import
android.view.accessibility.AccessibilityNodeProvider
;
...
...
@@ -26,10 +28,17 @@ public class FlutterSemanticsToAndroidAccessibilityBridge extends AccessibilityN
implements
SemanticsListener
{
private
Map
<
Integer
,
PersistentAccessibilityNode
>
mTreeNodes
;
private
PlatformViewAndroid
mOwner
;
FlutterSemanticsToAndroidAccessibilityBridge
(
PlatformViewAndroid
view
)
{
mOwner
=
view
;
private
SemanticsServer
.
Proxy
mSemanticsServer
;
private
PersistentAccessibilityNode
mFocusedNode
;
private
PersistentAccessibilityNode
mHoveredNode
;
FlutterSemanticsToAndroidAccessibilityBridge
(
PlatformViewAndroid
owner
,
SemanticsServer
.
Proxy
semanticsServer
)
{
assert
owner
!=
null
;
assert
semanticsServer
!=
null
;
mOwner
=
owner
;
mTreeNodes
=
new
HashMap
<
Integer
,
PersistentAccessibilityNode
>();
mSemanticsServer
=
semanticsServer
;
mSemanticsServer
.
addSemanticsListener
(
this
);
}
@Override
...
...
@@ -71,17 +80,46 @@ public class FlutterSemanticsToAndroidAccessibilityBridge extends AccessibilityN
}
result
.
setBoundsInScreen
(
bounds
);
result
.
setVisibleToUser
(
true
);
result
.
setEnabled
(
true
);
// TODO(ianh): Expose disabled subtrees
// TODO(ianh): Add support for interactivity:
// private boolean canBeTapped;
// private boolean canBeLongPressed;
// private boolean canBeScrolledHorizontally;
// private boolean canBeScrolledVertically;
if
(
node
.
canBeTapped
)
{
result
.
addAction
(
AccessibilityNodeInfo
.
ACTION_CLICK
);
result
.
setClickable
(
true
);
}
if
(
node
.
canBeLongPressed
)
{
result
.
addAction
(
AccessibilityNodeInfo
.
ACTION_LONG_CLICK
);
result
.
setLongClickable
(
true
);
}
if
((
node
.
canBeScrolledHorizontally
&&
!
node
.
canBeScrolledVertically
)
||
(!
node
.
canBeScrolledHorizontally
&&
node
.
canBeScrolledVertically
))
{
result
.
addAction
(
AccessibilityNodeInfo
.
ACTION_SCROLL_FORWARD
);
result
.
addAction
(
AccessibilityNodeInfo
.
ACTION_SCROLL_BACKWARD
);
}
if
(
node
.
canBeScrolledHorizontally
||
node
.
canBeScrolledVertically
)
{
// TODO(ianh): Figure out how to enable panning. SDK v23
// has AccessibilityAction.ACTION_SCROLL_LEFT and company,
// but earlier versions do not. Right now we only forward
// scroll actions if it's unidirectional.
result
.
setScrollable
(
true
);
}
result
.
setCheckable
(
node
.
hasCheckedState
);
result
.
setChecked
(
node
.
isChecked
);
result
.
setText
(
node
.
label
);
// TODO(ianh): use setTraversalBefore/setTraversalAfter to set
// the relative order of the views. For each set of siblings,
// the views should be ordered top-to-bottom, tie-breaking
// left-to-right (right-to-left in rtl environments), height,
// width, and finally by list order.
// Accessibility Focus
if
(
mFocusedNode
!=
null
&&
mFocusedNode
.
id
==
virtualViewId
)
{
result
.
addAction
(
AccessibilityNodeInfo
.
ACTION_CLEAR_ACCESSIBILITY_FOCUS
);
}
else
{
result
.
addAction
(
AccessibilityNodeInfo
.
ACTION_ACCESSIBILITY_FOCUS
);
}
for
(
PersistentAccessibilityNode
child
:
node
.
children
)
{
result
.
addChild
(
mOwner
,
child
.
id
);
}
...
...
@@ -89,10 +127,99 @@ public class FlutterSemanticsToAndroidAccessibilityBridge extends AccessibilityN
return
result
;
}
@Override
public
boolean
performAction
(
int
virtualViewId
,
int
action
,
Bundle
arguments
)
{
PersistentAccessibilityNode
node
=
mTreeNodes
.
get
(
virtualViewId
);
if
(
node
==
null
)
return
false
;
switch
(
action
)
{
case
AccessibilityNodeInfo
.
ACTION_CLICK
:
{
mSemanticsServer
.
tap
(
virtualViewId
);
return
true
;
}
case
AccessibilityNodeInfo
.
ACTION_LONG_CLICK
:
{
mSemanticsServer
.
longPress
(
virtualViewId
);
return
true
;
}
case
AccessibilityNodeInfo
.
ACTION_SCROLL_BACKWARD
:
{
if
(
node
.
canBeScrolledHorizontally
&&
!
node
.
canBeScrolledVertically
)
{
// TODO(ianh): bidi support
mSemanticsServer
.
scrollLeft
(
virtualViewId
);
}
else
if
(
node
.
canBeScrolledHorizontally
&&
!
node
.
canBeScrolledVertically
)
{
mSemanticsServer
.
scrollUp
(
virtualViewId
);
}
else
{
return
false
;
}
return
true
;
}
case
AccessibilityNodeInfo
.
ACTION_SCROLL_FORWARD
:
{
if
(
node
.
canBeScrolledHorizontally
&&
!
node
.
canBeScrolledVertically
)
{
// TODO(ianh): bidi support
mSemanticsServer
.
scrollRight
(
virtualViewId
);
}
else
if
(
node
.
canBeScrolledHorizontally
&&
!
node
.
canBeScrolledVertically
)
{
mSemanticsServer
.
scrollDown
(
virtualViewId
);
}
else
{
return
false
;
}
return
true
;
}
case
AccessibilityNodeInfo
.
ACTION_CLEAR_ACCESSIBILITY_FOCUS
:
{
sendAccessibilityEvent
(
virtualViewId
,
AccessibilityEvent
.
TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
);
mFocusedNode
=
null
;
return
true
;
}
case
AccessibilityNodeInfo
.
ACTION_ACCESSIBILITY_FOCUS
:
{
sendAccessibilityEvent
(
virtualViewId
,
AccessibilityEvent
.
TYPE_VIEW_ACCESSIBILITY_FOCUSED
);
mFocusedNode
=
node
;
return
true
;
}
}
// TODO(ianh): Implement left/right/up/down scrolling
return
false
;
}
// TODO(ianh): implement findAccessibilityNodeInfosByText()
// TODO(ianh): implement findFocus()
public
void
handleTouchExplorationExit
()
{
if
(
mHoveredNode
!=
null
)
{
sendAccessibilityEvent
(
mHoveredNode
.
id
,
AccessibilityEvent
.
TYPE_VIEW_HOVER_EXIT
);
mHoveredNode
=
null
;
}
}
public
void
handleTouchExploration
(
float
x
,
float
y
)
{
if
(
mTreeNodes
.
isEmpty
())
return
;
assert
mTreeNodes
.
containsKey
(
0
);
PersistentAccessibilityNode
newNode
=
mTreeNodes
.
get
(
0
).
hitTest
(
Math
.
round
(
x
),
Math
.
round
(
y
));
if
(
newNode
!=
mHoveredNode
)
{
if
(
newNode
!=
null
)
{
sendAccessibilityEvent
(
newNode
.
id
,
AccessibilityEvent
.
TYPE_VIEW_HOVER_ENTER
);
}
if
(
mHoveredNode
!=
null
)
{
sendAccessibilityEvent
(
mHoveredNode
.
id
,
AccessibilityEvent
.
TYPE_VIEW_HOVER_EXIT
);
}
mHoveredNode
=
newNode
;
}
}
@Override
public
void
updateSemanticsTree
(
SemanticsNode
[]
nodes
)
{
for
(
SemanticsNode
node
:
nodes
)
{
updateSemanticsNode
(
node
);
sendAccessibilityEvent
(
node
.
id
,
AccessibilityEvent
.
TYPE_WINDOW_CONTENT_CHANGED
);
}
}
private
void
sendAccessibilityEvent
(
int
virtualViewId
,
int
eventType
)
{
if
(
virtualViewId
==
0
)
{
mOwner
.
sendAccessibilityEvent
(
eventType
);
}
else
{
AccessibilityEvent
event
=
AccessibilityEvent
.
obtain
(
eventType
);
event
.
setPackageName
(
mOwner
.
getContext
().
getPackageName
());
event
.
setSource
(
mOwner
,
virtualViewId
);
mOwner
.
getParent
().
requestSendAccessibilityEvent
(
mOwner
,
event
);
}
}
...
...
@@ -112,10 +239,25 @@ public class FlutterSemanticsToAndroidAccessibilityBridge extends AccessibilityN
assert
mTreeNodes
.
containsKey
(
node
.
id
);
assert
mTreeNodes
.
get
(
node
.
id
).
parent
==
null
;
mTreeNodes
.
remove
(
node
.
id
);
if
(
mFocusedNode
==
node
)
{
mFocusedNode
=
null
;
}
if
(
mHoveredNode
==
node
)
{
mHoveredNode
=
null
;
}
for
(
PersistentAccessibilityNode
child
:
node
.
children
)
{
removePersistentNode
(
child
);
}
}
public
void
reset
()
{
public
void
reset
(
SemanticsServer
.
Proxy
newSemanticsServer
)
{
mTreeNodes
.
clear
();
mFocusedNode
=
null
;
mHoveredNode
=
null
;
mSemanticsServer
.
close
();
sendAccessibilityEvent
(
0
,
AccessibilityEvent
.
TYPE_WINDOW_CONTENT_CHANGED
);
mSemanticsServer
=
newSemanticsServer
;
mSemanticsServer
.
addSemanticsListener
(
this
);
}
private
class
PersistentAccessibilityNode
{
...
...
@@ -177,7 +319,6 @@ public class FlutterSemanticsToAndroidAccessibilityBridge extends AccessibilityN
// since they also get marked dirty
invalidateGlobalGeometry
();
}
// TODO(ianh): Notify Android that our tree is dirty
}
// fields that we pass straight to the Android accessibility API
...
...
@@ -205,6 +346,8 @@ public class FlutterSemanticsToAndroidAccessibilityBridge extends AccessibilityN
return
;
}
geometryDirty
=
true
;
// TODO(ianh): if we are the FlutterSemanticsToAndroidAccessibilityBridge.this.mFocusedNode
// then we may have to unfocus and refocus ourselves to get Android to update the focus rect
for
(
PersistentAccessibilityNode
child
:
children
)
{
child
.
invalidateGlobalGeometry
();
}
...
...
@@ -268,6 +411,20 @@ public class FlutterSemanticsToAndroidAccessibilityBridge extends AccessibilityN
}
return
globalRect
;
}
public
PersistentAccessibilityNode
hitTest
(
int
x
,
int
y
)
{
Rect
rect
=
getGlobalRect
();
if
(!
rect
.
contains
(
x
,
y
))
return
null
;
for
(
int
index
=
children
.
size
()-
1
;
index
>=
0
;
index
-=
1
)
{
PersistentAccessibilityNode
child
=
children
.
get
(
index
);
PersistentAccessibilityNode
result
=
child
.
hitTest
(
x
,
y
);
if
(
result
!=
null
)
{
return
result
;
}
}
return
this
;
}
}
@Override
...
...
sky/shell/platform/android/org/domokit/sky/shell/PlatformViewAndroid.java
浏览文件 @
380d5353
...
...
@@ -37,8 +37,6 @@ import org.chromium.mojom.pointer.PointerKind;
import
org.chromium.mojom.pointer.PointerPacket
;
import
org.chromium.mojom.pointer.PointerType
;
import
org.chromium.mojom.raw_keyboard.RawKeyboardService
;
import
org.chromium.mojom.semantics.SemanticsListener
;
import
org.chromium.mojom.semantics.SemanticsNode
;
import
org.chromium.mojom.semantics.SemanticsServer
;
import
org.chromium.mojom.sky.ServicesData
;
import
org.chromium.mojom.sky.SkyEngine
;
...
...
@@ -250,6 +248,16 @@ public class PlatformViewAndroid extends SurfaceView
return
true
;
}
@Override
public
boolean
onHoverEvent
(
MotionEvent
event
)
{
boolean
handled
=
handleAccessibilityHoverEvent
(
event
);
if
(!
handled
)
{
// TODO(ianh): Expose hover events to the platform,
// implementing ADD, REMOVE, etc.
}
return
handled
;
}
@Override
protected
void
onSizeChanged
(
int
width
,
int
height
,
int
oldWidth
,
int
oldHeight
)
{
mMetrics
.
physicalWidth
=
width
;
...
...
@@ -298,6 +306,14 @@ public class PlatformViewAndroid extends SurfaceView
}
void
runFromBundle
(
String
path
)
{
if
(
mServiceProvider
!=
null
)
{
mServiceProvider
.
close
();
}
if
(
mDartServiceProvider
!=
null
)
{
mDartServiceProvider
.
close
();
}
Core
core
=
CoreImpl
.
getInstance
();
Pair
<
ServiceProvider
.
Proxy
,
InterfaceRequest
<
ServiceProvider
>>
serviceProvider
=
ServiceProvider
.
MANAGER
.
getInterfaceRequest
(
core
);
...
...
@@ -326,10 +342,13 @@ public class PlatformViewAndroid extends SurfaceView
// ACCESSIBILITY
private
boolean
mTouchExplorationEnabled
=
false
;
@Override
protected
void
onAttachedToWindow
()
{
super
.
onAttachedToWindow
();
if
(
mAccessibilityManager
.
isEnabled
()
||
mAccessibilityManager
.
isTouchExplorationEnabled
())
mTouchExplorationEnabled
=
mAccessibilityManager
.
isTouchExplorationEnabled
();
if
(
mAccessibilityManager
.
isEnabled
()
||
mTouchExplorationEnabled
)
ensureAccessibilityEnabled
();
mAccessibilityManager
.
addAccessibilityStateChangeListener
(
this
);
mAccessibilityManager
.
addTouchExplorationStateChangeListener
(
this
);
...
...
@@ -343,25 +362,15 @@ public class PlatformViewAndroid extends SurfaceView
@Override
public
void
onTouchExplorationStateChanged
(
boolean
enabled
)
{
if
(
enabled
)
if
(
enabled
)
{
mTouchExplorationEnabled
=
true
;
ensureAccessibilityEnabled
();
// TODO(ianh): else, actually discard the state for exploration
}
private
FlutterSemanticsToAndroidAccessibilityBridge
mAccessibilityNodeProvider
;
private
SemanticsServer
.
Proxy
mSemanticsServer
;
void
ensureAccessibilityEnabled
()
{
if
(
mAccessibilityNodeProvider
==
null
)
{
mAccessibilityNodeProvider
=
new
FlutterSemanticsToAndroidAccessibilityBridge
(
this
);
Core
core
=
CoreImpl
.
getInstance
();
Pair
<
SemanticsServer
.
Proxy
,
InterfaceRequest
<
SemanticsServer
>>
server
=
SemanticsServer
.
MANAGER
.
getInterfaceRequest
(
core
);
mSemanticsServer
=
server
.
first
;
mDartServiceProvider
.
connectToService
(
SemanticsServer
.
MANAGER
.
getName
(),
server
.
second
.
passHandle
());
mSemanticsServer
.
addSemanticsListener
(
mAccessibilityNodeProvider
);
}
else
{
mTouchExplorationEnabled
=
false
;
if
(
mAccessibilityNodeProvider
!=
null
)
{
mAccessibilityNodeProvider
.
handleTouchExplorationExit
();
}
}
assert
mSemanticsServer
!=
null
;
}
@Override
...
...
@@ -370,13 +379,37 @@ public class PlatformViewAndroid extends SurfaceView
return
mAccessibilityNodeProvider
;
}
// TODO(ianh): implement touch exploration
private
FlutterSemanticsToAndroidAccessibilityBridge
mAccessibilityNodeProvider
;
void
ensureAccessibilityEnabled
()
{
if
(
mAccessibilityNodeProvider
==
null
)
{
mAccessibilityNodeProvider
=
new
FlutterSemanticsToAndroidAccessibilityBridge
(
this
,
createSemanticsServer
());
}
}
// TODO(ianh): implement accessibility focus
private
SemanticsServer
.
Proxy
createSemanticsServer
()
{
Core
core
=
CoreImpl
.
getInstance
();
Pair
<
SemanticsServer
.
Proxy
,
InterfaceRequest
<
SemanticsServer
>>
server
=
SemanticsServer
.
MANAGER
.
getInterfaceRequest
(
core
);
mDartServiceProvider
.
connectToService
(
SemanticsServer
.
MANAGER
.
getName
(),
server
.
second
.
passHandle
());
return
server
.
first
;
}
void
resetAccessibilityTree
()
{
if
(
mAccessibilityNodeProvider
!=
null
)
mAccessibilityNodeProvider
.
reset
();
if
(
mAccessibilityNodeProvider
!=
null
)
{
mAccessibilityNodeProvider
.
reset
(
createSemanticsServer
());
}
}
private
boolean
handleAccessibilityHoverEvent
(
MotionEvent
event
)
{
if
(!
mTouchExplorationEnabled
)
return
false
;
if
(
event
.
getAction
()
==
MotionEvent
.
ACTION_HOVER_EXIT
)
{
mAccessibilityNodeProvider
.
handleTouchExplorationExit
();
}
else
{
mAccessibilityNodeProvider
.
handleTouchExploration
(
event
.
getX
(),
event
.
getY
());
}
return
true
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录