AccessibilityService
DroidKaigi 2018 (2/8~2/9)
by Tamaki Hidetsugu (Ralph) @r_ralph_h
Tamaki Hidetsugu (Ralph)
• 4
• Twitter: @r_ralph_h
• 2015/2 ~ Holiday
• 2018/4 ~ LINE
•
•
•
AccessibilityService ?
AccessibilityService
•
•
• FB
•
https://developer.android.com/training/accessibility/service.html
AccessibilityService
• DroidKaigi 2017
• AccessibilityService
https://speakerdeck.com/litmon/accessibilityservicewoshi-
tuteapurifalseke-neng-xing-woguang-geyou
• Google TalkBack
AccessibilityService
AS
•
•
AS
•
• AS
• View
• View
AccessibilityService
• AccessibilityService
• AccessibilityService
AccessibilityService
•
onAccessibilityEvent()
•
• onAccessibilityEvent()
AccessibilityNodeInfo
• View
• ViewGroup child
NodeInfo
• View
getRootInActiveWindow()
• AccessibilityNodeInfo
• Activity
NodeInfo
• View
View Read
•
• contentDescription
nodeInfo.text
nodeInfo.contentDescription
View Write
• EditText
• View
val text = "Hello World"
val args = Bundle().also {
it.putString(
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
text)
}
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args)
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK)
AccessibilityService
Android
https://www.symantec.com/connect/nl/blogs/android-33
1.
• ChatKit
stfalcon-studio/ChatKit
View
fun logViewHierarchy(nodeInfo: AccessibilityNodeInfo?,
depth: Int) {
when (nodeInfo?.childCount) {
null -> return
0 -> Log.d(TAG, "${" ".repeat(depth)} " +
"View: ${nodeInfo.className} " +
"(id=${nodeInfo.viewIdResourceName})")
else -> (0 until nodeInfo.childCount)
.map { nodeInfo.getChild(it) }
.forEach { logViewHierarchy(it, depth + 1) }
}
}
getRootInActiveWindow() NodeInfo
View
View: android.widget.TextView (id=null)
View: android.widget.TextView (id=ms.ralph.dk2018_sample1:id/messageText)
View: android.widget.TextView (id=ms.ralph.dk2018_sample1:id/messageText)
View: android.widget.TextView (id=ms.ralph.dk2018_sample1:id/messageTime)
View: android.widget.TextView (id=ms.ralph.dk2018_sample1:id/messageText)
View: android.widget.TextView (id=ms.ralph.dk2018_sample1:id/messageTime)
View: android.widget.TextView (id=ms.ralph.dk2018_sample1:id/messageTime)
View: android.widget.TextView (id=ms.ralph.dk2018_sample1:id/messageText)
View: android.widget.TextView (id=ms.ralph.dk2018_sample1:id/messageText)
View: android.widget.TextView (id=ms.ralph.dk2018_sample1:id/messageTime)
View: android.widget.EditText (id=ms.ralph.dk2018_sample1:id/messageInput)
View: android.widget.ImageButton (id=ms.ralph.dk2018_sample1:id/
messageSendButton)
id AccessibilityNodeInfo
rootInActiveWindow.findAccessibilityNodeInfosByViewId(
"ms.ralph.android.dk2018_sample1:id/messageText") // <=id
.forEach { Log.d(TAG, it.text.toString()) }
val editNode = rootInActiveWindow
.findAccessibilityNodeInfosByViewId(
"ms.ralph.dk2018_sample1:id/messageInput")[0]
pasteText(editNode, System.currentTimeMillis().toString())
pasteText() EditText
val time = System.currentTimeMillis()
pasteText(editNode, time.toString())
if (time % 10 == 0L) {
val btnNode = rootInActiveWindow
.findAccessibilityNodeInfosByViewId(
"ms.ralph.dk2018_sample1:id/messageSendButton")[0]
tapButton(btnNode)
}
UNIX 1 0
tapButton() View
2. Runtime Permission
Runtime Permission?
Android 6.0
Runtime Permission
( )
•
•
•
• PlayStore
2017/11
http://www.androidpolice.com/2017/11/12/google-will-remove-play-store-apps-use-
accessibility-services-anything-except-helping-disabled-users/
•
•
•
•
•
Thank you !

AccessibilityService でできてしまうこと