Yash Sampat
Yash Sampat

Reputation: 30611

MODIFY the view hierarchy of another app with an Accessibility Service

It is common knowledge that we can observe or query the view hierarchy of any app with an AccessibilityService:

Create your own accessibility service.

It is also possible to perform actions on behalf of the user:

Developing an Accessibility Service for Android.

My question is, can we modify the view hierarchy of a foreground app with an AccessibilityService?

enter image description here

I have already referred the following questions:

What they're doing is using the WindowManager and the SYSTEM_ALERT_WINDOW permission to overlay a view on top of the app in the foreground. The problem with this approach is that if the user presses BACK or HOME, the app is dismissed, but the view remains visible on the screen, even after the app is gone. The view is on TOP of the view hierarchy, and not a part of it.

My requirement is to display a small view within the app itself. It has to be part of the view hierarchy of the app, so that it stays or goes with the app. For this I need to modify the view hierarchy of the app, namely the AccessibilityNodeInfo objects retrieved from the service.

What I want is something similar to addView(), but add the View to the view hierarchy of the app itself, not on top of it.

How can we do this? Is this possible?

UPDATE:

Apps that support Custom Views for Accessibility

Upvotes: 5

Views: 1598

Answers (3)

SirKnigget
SirKnigget

Reputation: 3644

You can still go with the approach of drawing on top of the app, not as part of its view hierarchy (which is impossible) - using SYSTEM_ALERT_WINDOW permission.

In order to know when the app is dismissed and dismiss your own overlay - listen to the accessibility event TYPE_WINDOW_STATE_CHANGED and check that there's a package change.

You can also go further with listening to TYPE_WINDOW_CONTENT_CHANGED and determining that there was some layout update. More accessibility events might come in handy or fine-tuning your overlay's accuracy.

In short - as long as you have the appropriate information to know about the underlying app's layout and when things happen, you can draw on top as if it's part of the app. Might be tricky and require some calculations since you're not able to just push views into the hierarchy, but totally doable.

Upvotes: 1

Link182
Link182

Reputation: 839

1) You can exploit draw over other apps permission. That solution will allow you only to draw overlays over another apps and not to change another apps behavior.

2) You can exploit instrumentation test mechanism. If you have enough information about the app(app id, activity name) and enough privileges (Run an instrument test from within app and wait for result), or root privileges. Here is an example:

@RunWith(AndroidJUnit4::class)
class InjectView {
    @get:Rule
    val activityRule = ActivityTestRule<MainActivity>(MainActivity::class.java)

    @Test
    fun injectView() {
        val rootLayout = activityRule.activity.findViewById<ViewGroup>(android.R.id.content)
        activityRule.runOnUiThread {
            rootLayout.addView(TextView(activityRule.activity).apply {
                text = "Injected View"
            })
        }

        Thread.sleep(10_000)
    }
}

Upvotes: 1

ataulm
ataulm

Reputation: 15334

No, you can't modify the view hierarchy of another app because it exists in a separate process.

This is similar to not being able to modify accessibility nodes from within an accessibility service.

Upvotes: 1

Related Questions