Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
qq_34031325
engine
提交
4c6abc1e
E
engine
项目概览
qq_34031325
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
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,发现更多精彩内容 >>
未验证
提交
4c6abc1e
编写于
3月 29, 2021
作者:
C
chunhtai
提交者:
GitHub
3月 29, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Revert "Fixes android voice access delete text, redo, and undo actions. (#25050)" (#25286)
This reverts commit
8d73893b
.
上级
a99a0382
变更
2
显示空白变更内容
内联
并排
Showing
2 changed file
with
4 addition
and
452 deletion
+4
-452
shell/platform/android/io/flutter/view/AccessibilityBridge.java
...platform/android/io/flutter/view/AccessibilityBridge.java
+4
-96
shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java
...android/test/io/flutter/view/AccessibilityBridgeTest.java
+0
-356
未找到文件。
shell/platform/android/io/flutter/view/AccessibilityBridge.java
浏览文件 @
4c6abc1e
...
...
@@ -34,8 +34,6 @@ import io.flutter.util.Predicate;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
import
java.util.*
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
/**
* Bridge between Android's OS accessibility system and Flutter's accessibility system.
...
...
@@ -635,7 +633,8 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
}
// These are non-ops on older devices. Attempting to interact with the text will cause Talkback
// to read the contents of the text box instead.
// to read the
// contents of the text box instead.
if
(
Build
.
VERSION
.
SDK_INT
>
Build
.
VERSION_CODES
.
JELLY_BEAN_MR2
)
{
if
(
semanticsNode
.
hasAction
(
Action
.
SET_SELECTION
))
{
result
.
addAction
(
AccessibilityNodeInfo
.
ACTION_SET_SELECTION
);
...
...
@@ -651,13 +650,6 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
}
}
// Set text API isn't available until API 21.
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
LOLLIPOP
)
{
if
(
semanticsNode
.
hasAction
(
Action
.
SET_TEXT
))
{
result
.
addAction
(
AccessibilityNodeInfo
.
ACTION_SET_TEXT
);
}
}
if
(
semanticsNode
.
hasFlag
(
Flag
.
IS_BUTTON
)
||
semanticsNode
.
hasFlag
(
Flag
.
IS_LINK
))
{
result
.
setClassName
(
"android.widget.Button"
);
}
...
...
@@ -1042,12 +1034,6 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
}
accessibilityChannel
.
dispatchSemanticsAction
(
virtualViewId
,
Action
.
SET_SELECTION
,
selection
);
// The voice access expects the semantics node to update immediately. We update the
// semantics node based on prediction. If the result is incorrect, it will be updated in
// the next frame.
SemanticsNode
node
=
flutterSemanticsTree
.
get
(
virtualViewId
);
node
.
textSelectionBase
=
selection
.
get
(
"base"
);
node
.
textSelectionExtent
=
selection
.
get
(
"extent"
);
return
true
;
}
case
AccessibilityNodeInfo
.
ACTION_COPY
:
...
...
@@ -1078,7 +1064,7 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
if
(
Build
.
VERSION
.
SDK_INT
<
Build
.
VERSION_CODES
.
LOLLIPOP
)
{
return
false
;
}
return
performSetText
(
semanticsNode
,
virtualViewId
,
arguments
);
return
performSetText
(
virtualViewId
,
arguments
);
}
default
:
// might be a custom accessibility accessibilityAction.
...
...
@@ -1108,9 +1094,6 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
arguments
.
getInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
);
final
boolean
extendSelection
=
arguments
.
getBoolean
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
);
// The voice access expects the semantics node to update immediately. We update the semantics
// node based on prediction. If the result is incorrect, it will be updated in the next frame.
predictCursorMovement
(
semanticsNode
,
granularity
,
forward
,
extendSelection
);
switch
(
granularity
)
{
case
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_CHARACTER
:
{
...
...
@@ -1138,98 +1121,23 @@ public class AccessibilityBridge extends AccessibilityNodeProvider {
return
true
;
}
break
;
case
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_LINE
:
case
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_PARAGRAPH
:
case
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_PAGE
:
return
true
;
}
return
false
;
}
private
void
predictCursorMovement
(
@NonNull
SemanticsNode
node
,
int
granularity
,
boolean
forward
,
boolean
extendSelection
)
{
if
(
node
.
textSelectionExtent
<
0
||
node
.
textSelectionBase
<
0
)
{
return
;
}
switch
(
granularity
)
{
case
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_CHARACTER
:
if
(
forward
&&
node
.
textSelectionExtent
<
node
.
value
.
length
())
{
node
.
textSelectionExtent
+=
1
;
}
else
if
(!
forward
&&
node
.
textSelectionExtent
>
0
)
{
node
.
textSelectionExtent
-=
1
;
}
break
;
case
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_WORD
:
if
(
forward
&&
node
.
textSelectionExtent
<
node
.
value
.
length
())
{
Pattern
pattern
=
Pattern
.
compile
(
"\\p{L}(\\b)"
);
Matcher
result
=
pattern
.
matcher
(
node
.
value
.
substring
(
node
.
textSelectionExtent
));
// we discard the first result because we want to find the "next" word
if
(
result
.
find
()
&&
result
.
find
())
{
node
.
textSelectionExtent
+=
result
.
start
(
1
);
}
else
{
node
.
textSelectionExtent
=
node
.
value
.
length
();
}
}
else
if
(!
forward
&&
node
.
textSelectionExtent
>
0
)
{
// Finds last beginning of the word boundary.
Pattern
pattern
=
Pattern
.
compile
(
"(?s:.*)(\\b)\\p{L}"
);
Matcher
result
=
pattern
.
matcher
(
node
.
value
.
substring
(
0
,
node
.
textSelectionExtent
));
if
(
result
.
find
())
{
node
.
textSelectionExtent
=
result
.
start
(
1
);
}
}
break
;
case
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_LINE
:
if
(
forward
&&
node
.
textSelectionExtent
<
node
.
value
.
length
())
{
// Finds the next new line.
Pattern
pattern
=
Pattern
.
compile
(
"(?!^)(\\n)"
);
Matcher
result
=
pattern
.
matcher
(
node
.
value
.
substring
(
node
.
textSelectionExtent
));
if
(
result
.
find
())
{
node
.
textSelectionExtent
+=
result
.
start
(
1
);
}
else
{
node
.
textSelectionExtent
=
node
.
value
.
length
();
}
}
else
if
(!
forward
&&
node
.
textSelectionExtent
>
0
)
{
// Finds the last new line.
Pattern
pattern
=
Pattern
.
compile
(
"(?s:.*)(\\n)"
);
Matcher
result
=
pattern
.
matcher
(
node
.
value
.
substring
(
0
,
node
.
textSelectionExtent
));
if
(
result
.
find
())
{
node
.
textSelectionExtent
=
result
.
start
(
1
);
}
else
{
node
.
textSelectionExtent
=
0
;
}
}
break
;
case
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_PARAGRAPH
:
case
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_PAGE
:
if
(
forward
)
{
node
.
textSelectionExtent
=
node
.
value
.
length
();
}
else
{
node
.
textSelectionExtent
=
0
;
}
break
;
}
if
(!
extendSelection
)
{
node
.
textSelectionBase
=
node
.
textSelectionExtent
;
}
}
/**
* Handles the responsibilities of {@link #performAction(int, int, Bundle)} for the specific
* scenario of cursor movement.
*/
@TargetApi
(
21
)
@RequiresApi
(
21
)
private
boolean
performSetText
(
SemanticsNode
node
,
int
virtualViewId
,
@NonNull
Bundle
arguments
)
{
private
boolean
performSetText
(
int
virtualViewId
,
@NonNull
Bundle
arguments
)
{
String
newText
=
""
;
if
(
arguments
!=
null
&&
arguments
.
containsKey
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
))
{
newText
=
arguments
.
getString
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
);
}
accessibilityChannel
.
dispatchSemanticsAction
(
virtualViewId
,
Action
.
SET_TEXT
,
newText
);
// The voice access expects the semantics node to update immediately. We update the semantics
// node based on prediction. If the result is incorrect, it will be updated in the next frame.
node
.
value
=
newText
;
return
true
;
}
...
...
shell/platform/android/test/io/flutter/view/AccessibilityBridgeTest.java
浏览文件 @
4c6abc1e
...
...
@@ -6,7 +6,6 @@ package io.flutter.view;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertNotNull
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
import
static
org
.
mockito
.
Matchers
.
eq
;
import
static
org
.
mockito
.
Mockito
.
any
;
import
static
org
.
mockito
.
Mockito
.
anyInt
;
...
...
@@ -373,357 +372,6 @@ public class AccessibilityBridgeTest {
.
dispatchSemanticsAction
(
1
,
AccessibilityBridge
.
Action
.
SET_TEXT
,
expectedText
);
}
@TargetApi
(
21
)
@Test
public
void
itCanPredictSetText
()
{
AccessibilityChannel
mockChannel
=
mock
(
AccessibilityChannel
.
class
);
AccessibilityViewEmbedder
mockViewEmbedder
=
mock
(
AccessibilityViewEmbedder
.
class
);
AccessibilityManager
mockManager
=
mock
(
AccessibilityManager
.
class
);
View
mockRootView
=
mock
(
View
.
class
);
Context
context
=
mock
(
Context
.
class
);
when
(
mockRootView
.
getContext
()).
thenReturn
(
context
);
when
(
context
.
getPackageName
()).
thenReturn
(
"test"
);
AccessibilityBridge
accessibilityBridge
=
setUpBridge
(
/*rootAccessibilityView=*/
mockRootView
,
/*accessibilityChannel=*/
mockChannel
,
/*accessibilityManager=*/
mockManager
,
/*contentResolver=*/
null
,
/*accessibilityViewEmbedder=*/
mockViewEmbedder
,
/*platformViewsAccessibilityDelegate=*/
null
);
ViewParent
mockParent
=
mock
(
ViewParent
.
class
);
when
(
mockRootView
.
getParent
()).
thenReturn
(
mockParent
);
when
(
mockManager
.
isEnabled
()).
thenReturn
(
true
);
TestSemanticsNode
root
=
new
TestSemanticsNode
();
root
.
id
=
0
;
TestSemanticsNode
node1
=
new
TestSemanticsNode
();
node1
.
id
=
1
;
node1
.
addFlag
(
AccessibilityBridge
.
Flag
.
IS_TEXT_FIELD
);
root
.
children
.
add
(
node1
);
TestSemanticsUpdate
testSemanticsUpdate
=
root
.
toUpdate
();
accessibilityBridge
.
updateSemantics
(
testSemanticsUpdate
.
buffer
,
testSemanticsUpdate
.
strings
);
Bundle
bundle
=
new
Bundle
();
String
expectedText
=
"some string"
;
bundle
.
putString
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE
,
expectedText
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_SET_TEXT
,
bundle
);
AccessibilityNodeInfo
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
assertEquals
(
nodeInfo
.
getText
(),
expectedText
);
}
@TargetApi
(
21
)
@Test
public
void
itCanCreateAccessibilityNodeInfoWithSetText
()
{
AccessibilityChannel
mockChannel
=
mock
(
AccessibilityChannel
.
class
);
AccessibilityViewEmbedder
mockViewEmbedder
=
mock
(
AccessibilityViewEmbedder
.
class
);
AccessibilityManager
mockManager
=
mock
(
AccessibilityManager
.
class
);
View
mockRootView
=
mock
(
View
.
class
);
Context
context
=
mock
(
Context
.
class
);
when
(
mockRootView
.
getContext
()).
thenReturn
(
context
);
when
(
context
.
getPackageName
()).
thenReturn
(
"test"
);
AccessibilityBridge
accessibilityBridge
=
setUpBridge
(
/*rootAccessibilityView=*/
mockRootView
,
/*accessibilityChannel=*/
mockChannel
,
/*accessibilityManager=*/
mockManager
,
/*contentResolver=*/
null
,
/*accessibilityViewEmbedder=*/
mockViewEmbedder
,
/*platformViewsAccessibilityDelegate=*/
null
);
ViewParent
mockParent
=
mock
(
ViewParent
.
class
);
when
(
mockRootView
.
getParent
()).
thenReturn
(
mockParent
);
when
(
mockManager
.
isEnabled
()).
thenReturn
(
true
);
TestSemanticsNode
root
=
new
TestSemanticsNode
();
root
.
id
=
0
;
TestSemanticsNode
node1
=
new
TestSemanticsNode
();
node1
.
id
=
1
;
node1
.
addFlag
(
AccessibilityBridge
.
Flag
.
IS_TEXT_FIELD
);
node1
.
addAction
(
AccessibilityBridge
.
Action
.
SET_TEXT
);
root
.
children
.
add
(
node1
);
TestSemanticsUpdate
testSemanticsUpdate
=
root
.
toUpdate
();
accessibilityBridge
.
updateSemantics
(
testSemanticsUpdate
.
buffer
,
testSemanticsUpdate
.
strings
);
AccessibilityNodeInfo
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
List
<
AccessibilityNodeInfo
.
AccessibilityAction
>
actions
=
nodeInfo
.
getActionList
();
assertTrue
(
actions
.
contains
(
AccessibilityNodeInfo
.
AccessibilityAction
.
ACTION_SET_TEXT
));
}
@Test
public
void
itCanPredictSetSelection
()
{
AccessibilityChannel
mockChannel
=
mock
(
AccessibilityChannel
.
class
);
AccessibilityViewEmbedder
mockViewEmbedder
=
mock
(
AccessibilityViewEmbedder
.
class
);
AccessibilityManager
mockManager
=
mock
(
AccessibilityManager
.
class
);
View
mockRootView
=
mock
(
View
.
class
);
Context
context
=
mock
(
Context
.
class
);
when
(
mockRootView
.
getContext
()).
thenReturn
(
context
);
when
(
context
.
getPackageName
()).
thenReturn
(
"test"
);
AccessibilityBridge
accessibilityBridge
=
setUpBridge
(
/*rootAccessibilityView=*/
mockRootView
,
/*accessibilityChannel=*/
mockChannel
,
/*accessibilityManager=*/
mockManager
,
/*contentResolver=*/
null
,
/*accessibilityViewEmbedder=*/
mockViewEmbedder
,
/*platformViewsAccessibilityDelegate=*/
null
);
ViewParent
mockParent
=
mock
(
ViewParent
.
class
);
when
(
mockRootView
.
getParent
()).
thenReturn
(
mockParent
);
when
(
mockManager
.
isEnabled
()).
thenReturn
(
true
);
TestSemanticsNode
root
=
new
TestSemanticsNode
();
root
.
id
=
0
;
TestSemanticsNode
node1
=
new
TestSemanticsNode
();
node1
.
id
=
1
;
node1
.
value
=
"some text"
;
node1
.
textSelectionBase
=
-
1
;
node1
.
textSelectionExtent
=
-
1
;
node1
.
addFlag
(
AccessibilityBridge
.
Flag
.
IS_TEXT_FIELD
);
root
.
children
.
add
(
node1
);
TestSemanticsUpdate
testSemanticsUpdate
=
root
.
toUpdate
();
accessibilityBridge
.
updateSemantics
(
testSemanticsUpdate
.
buffer
,
testSemanticsUpdate
.
strings
);
Bundle
bundle
=
new
Bundle
();
int
expectedStart
=
1
;
int
expectedEnd
=
3
;
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_SELECTION_START_INT
,
expectedStart
);
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_SELECTION_END_INT
,
expectedEnd
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_SET_SELECTION
,
bundle
);
AccessibilityNodeInfo
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
assertEquals
(
nodeInfo
.
getTextSelectionStart
(),
expectedStart
);
assertEquals
(
nodeInfo
.
getTextSelectionEnd
(),
expectedEnd
);
}
@Test
public
void
itCanPredictCursorMovementsWithGranularityWord
()
{
AccessibilityChannel
mockChannel
=
mock
(
AccessibilityChannel
.
class
);
AccessibilityViewEmbedder
mockViewEmbedder
=
mock
(
AccessibilityViewEmbedder
.
class
);
AccessibilityManager
mockManager
=
mock
(
AccessibilityManager
.
class
);
View
mockRootView
=
mock
(
View
.
class
);
Context
context
=
mock
(
Context
.
class
);
when
(
mockRootView
.
getContext
()).
thenReturn
(
context
);
when
(
context
.
getPackageName
()).
thenReturn
(
"test"
);
AccessibilityBridge
accessibilityBridge
=
setUpBridge
(
/*rootAccessibilityView=*/
mockRootView
,
/*accessibilityChannel=*/
mockChannel
,
/*accessibilityManager=*/
mockManager
,
/*contentResolver=*/
null
,
/*accessibilityViewEmbedder=*/
mockViewEmbedder
,
/*platformViewsAccessibilityDelegate=*/
null
);
ViewParent
mockParent
=
mock
(
ViewParent
.
class
);
when
(
mockRootView
.
getParent
()).
thenReturn
(
mockParent
);
when
(
mockManager
.
isEnabled
()).
thenReturn
(
true
);
TestSemanticsNode
root
=
new
TestSemanticsNode
();
root
.
id
=
0
;
TestSemanticsNode
node1
=
new
TestSemanticsNode
();
node1
.
id
=
1
;
node1
.
value
=
"some text"
;
node1
.
textSelectionBase
=
0
;
node1
.
textSelectionExtent
=
0
;
node1
.
addFlag
(
AccessibilityBridge
.
Flag
.
IS_TEXT_FIELD
);
root
.
children
.
add
(
node1
);
TestSemanticsUpdate
testSemanticsUpdate
=
root
.
toUpdate
();
accessibilityBridge
.
updateSemantics
(
testSemanticsUpdate
.
buffer
,
testSemanticsUpdate
.
strings
);
Bundle
bundle
=
new
Bundle
();
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
,
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_WORD
);
bundle
.
putBoolean
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
,
false
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_NEXT_AT_MOVEMENT_GRANULARITY
,
bundle
);
AccessibilityNodeInfo
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
// The seletction should be at the end of 'text'
assertEquals
(
nodeInfo
.
getTextSelectionStart
(),
9
);
assertEquals
(
nodeInfo
.
getTextSelectionEnd
(),
9
);
bundle
=
new
Bundle
();
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
,
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_WORD
);
bundle
.
putBoolean
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
,
false
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
,
bundle
);
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
// The seletction should be go to beginning of 'text'.
assertEquals
(
nodeInfo
.
getTextSelectionStart
(),
5
);
assertEquals
(
nodeInfo
.
getTextSelectionEnd
(),
5
);
}
@Test
public
void
itCanPredictCursorMovementsWithGranularityWordUnicode
()
{
AccessibilityChannel
mockChannel
=
mock
(
AccessibilityChannel
.
class
);
AccessibilityViewEmbedder
mockViewEmbedder
=
mock
(
AccessibilityViewEmbedder
.
class
);
AccessibilityManager
mockManager
=
mock
(
AccessibilityManager
.
class
);
View
mockRootView
=
mock
(
View
.
class
);
Context
context
=
mock
(
Context
.
class
);
when
(
mockRootView
.
getContext
()).
thenReturn
(
context
);
when
(
context
.
getPackageName
()).
thenReturn
(
"test"
);
AccessibilityBridge
accessibilityBridge
=
setUpBridge
(
/*rootAccessibilityView=*/
mockRootView
,
/*accessibilityChannel=*/
mockChannel
,
/*accessibilityManager=*/
mockManager
,
/*contentResolver=*/
null
,
/*accessibilityViewEmbedder=*/
mockViewEmbedder
,
/*platformViewsAccessibilityDelegate=*/
null
);
ViewParent
mockParent
=
mock
(
ViewParent
.
class
);
when
(
mockRootView
.
getParent
()).
thenReturn
(
mockParent
);
when
(
mockManager
.
isEnabled
()).
thenReturn
(
true
);
TestSemanticsNode
root
=
new
TestSemanticsNode
();
root
.
id
=
0
;
TestSemanticsNode
node1
=
new
TestSemanticsNode
();
node1
.
id
=
1
;
node1
.
value
=
"你 好 嗎"
;
node1
.
textSelectionBase
=
0
;
node1
.
textSelectionExtent
=
0
;
node1
.
addFlag
(
AccessibilityBridge
.
Flag
.
IS_TEXT_FIELD
);
root
.
children
.
add
(
node1
);
TestSemanticsUpdate
testSemanticsUpdate
=
root
.
toUpdate
();
accessibilityBridge
.
updateSemantics
(
testSemanticsUpdate
.
buffer
,
testSemanticsUpdate
.
strings
);
Bundle
bundle
=
new
Bundle
();
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
,
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_WORD
);
bundle
.
putBoolean
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
,
false
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_NEXT_AT_MOVEMENT_GRANULARITY
,
bundle
);
AccessibilityNodeInfo
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
// The seletction should be at the end of '好'
assertEquals
(
nodeInfo
.
getTextSelectionStart
(),
3
);
assertEquals
(
nodeInfo
.
getTextSelectionEnd
(),
3
);
bundle
=
new
Bundle
();
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
,
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_WORD
);
bundle
.
putBoolean
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
,
false
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
,
bundle
);
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
// The seletction should be go to beginning of '好'.
assertEquals
(
nodeInfo
.
getTextSelectionStart
(),
2
);
assertEquals
(
nodeInfo
.
getTextSelectionEnd
(),
2
);
}
@Test
public
void
itCanPredictCursorMovementsWithGranularityLine
()
{
AccessibilityChannel
mockChannel
=
mock
(
AccessibilityChannel
.
class
);
AccessibilityViewEmbedder
mockViewEmbedder
=
mock
(
AccessibilityViewEmbedder
.
class
);
AccessibilityManager
mockManager
=
mock
(
AccessibilityManager
.
class
);
View
mockRootView
=
mock
(
View
.
class
);
Context
context
=
mock
(
Context
.
class
);
when
(
mockRootView
.
getContext
()).
thenReturn
(
context
);
when
(
context
.
getPackageName
()).
thenReturn
(
"test"
);
AccessibilityBridge
accessibilityBridge
=
setUpBridge
(
/*rootAccessibilityView=*/
mockRootView
,
/*accessibilityChannel=*/
mockChannel
,
/*accessibilityManager=*/
mockManager
,
/*contentResolver=*/
null
,
/*accessibilityViewEmbedder=*/
mockViewEmbedder
,
/*platformViewsAccessibilityDelegate=*/
null
);
ViewParent
mockParent
=
mock
(
ViewParent
.
class
);
when
(
mockRootView
.
getParent
()).
thenReturn
(
mockParent
);
when
(
mockManager
.
isEnabled
()).
thenReturn
(
true
);
TestSemanticsNode
root
=
new
TestSemanticsNode
();
root
.
id
=
0
;
TestSemanticsNode
node1
=
new
TestSemanticsNode
();
node1
.
id
=
1
;
node1
.
value
=
"How are you\nI am fine\nThank you"
;
// Selection is at the second line.
node1
.
textSelectionBase
=
14
;
node1
.
textSelectionExtent
=
14
;
node1
.
addFlag
(
AccessibilityBridge
.
Flag
.
IS_TEXT_FIELD
);
root
.
children
.
add
(
node1
);
TestSemanticsUpdate
testSemanticsUpdate
=
root
.
toUpdate
();
accessibilityBridge
.
updateSemantics
(
testSemanticsUpdate
.
buffer
,
testSemanticsUpdate
.
strings
);
Bundle
bundle
=
new
Bundle
();
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
,
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_LINE
);
bundle
.
putBoolean
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
,
false
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_NEXT_AT_MOVEMENT_GRANULARITY
,
bundle
);
AccessibilityNodeInfo
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
// The seletction should be at the beginning of the third line.
assertEquals
(
nodeInfo
.
getTextSelectionStart
(),
21
);
assertEquals
(
nodeInfo
.
getTextSelectionEnd
(),
21
);
bundle
=
new
Bundle
();
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
,
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_LINE
);
bundle
.
putBoolean
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
,
false
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
,
bundle
);
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
// The seletction should be at the beginning of the second line.
assertEquals
(
nodeInfo
.
getTextSelectionStart
(),
11
);
assertEquals
(
nodeInfo
.
getTextSelectionEnd
(),
11
);
}
@Test
public
void
itCanPredictCursorMovementsWithGranularityCharacter
()
{
AccessibilityChannel
mockChannel
=
mock
(
AccessibilityChannel
.
class
);
AccessibilityViewEmbedder
mockViewEmbedder
=
mock
(
AccessibilityViewEmbedder
.
class
);
AccessibilityManager
mockManager
=
mock
(
AccessibilityManager
.
class
);
View
mockRootView
=
mock
(
View
.
class
);
Context
context
=
mock
(
Context
.
class
);
when
(
mockRootView
.
getContext
()).
thenReturn
(
context
);
when
(
context
.
getPackageName
()).
thenReturn
(
"test"
);
AccessibilityBridge
accessibilityBridge
=
setUpBridge
(
/*rootAccessibilityView=*/
mockRootView
,
/*accessibilityChannel=*/
mockChannel
,
/*accessibilityManager=*/
mockManager
,
/*contentResolver=*/
null
,
/*accessibilityViewEmbedder=*/
mockViewEmbedder
,
/*platformViewsAccessibilityDelegate=*/
null
);
ViewParent
mockParent
=
mock
(
ViewParent
.
class
);
when
(
mockRootView
.
getParent
()).
thenReturn
(
mockParent
);
when
(
mockManager
.
isEnabled
()).
thenReturn
(
true
);
TestSemanticsNode
root
=
new
TestSemanticsNode
();
root
.
id
=
0
;
TestSemanticsNode
node1
=
new
TestSemanticsNode
();
node1
.
id
=
1
;
node1
.
value
=
"some text"
;
node1
.
textSelectionBase
=
0
;
node1
.
textSelectionExtent
=
0
;
node1
.
addFlag
(
AccessibilityBridge
.
Flag
.
IS_TEXT_FIELD
);
root
.
children
.
add
(
node1
);
TestSemanticsUpdate
testSemanticsUpdate
=
root
.
toUpdate
();
accessibilityBridge
.
updateSemantics
(
testSemanticsUpdate
.
buffer
,
testSemanticsUpdate
.
strings
);
Bundle
bundle
=
new
Bundle
();
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
,
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_CHARACTER
);
bundle
.
putBoolean
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
,
false
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_NEXT_AT_MOVEMENT_GRANULARITY
,
bundle
);
AccessibilityNodeInfo
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
assertEquals
(
nodeInfo
.
getTextSelectionStart
(),
1
);
assertEquals
(
nodeInfo
.
getTextSelectionEnd
(),
1
);
bundle
=
new
Bundle
();
bundle
.
putInt
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT
,
AccessibilityNodeInfo
.
MOVEMENT_GRANULARITY_CHARACTER
);
bundle
.
putBoolean
(
AccessibilityNodeInfo
.
ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN
,
false
);
accessibilityBridge
.
performAction
(
1
,
AccessibilityNodeInfo
.
ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
,
bundle
);
nodeInfo
=
accessibilityBridge
.
createAccessibilityNodeInfo
(
1
);
assertEquals
(
nodeInfo
.
getTextSelectionStart
(),
0
);
assertEquals
(
nodeInfo
.
getTextSelectionEnd
(),
0
);
}
@Test
public
void
itAnnouncesWhiteSpaceWhenNoNamesRoute
()
{
AccessibilityViewEmbedder
mockViewEmbedder
=
mock
(
AccessibilityViewEmbedder
.
class
);
...
...
@@ -952,10 +600,6 @@ public class AccessibilityBridgeTest {
flags
|=
flag
.
value
;
}
void
addAction
(
AccessibilityBridge
.
Action
action
)
{
actions
|=
action
.
value
;
}
// These fields are declared in the order they should be
// encoded.
int
id
=
0
;
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录