SAW (system alert window) permission can be used to draw content on top of other apps.
I was told a very long time ago that accessibility service can do this too, but I never found any tutorial, sample, documentation and even an app that does it... until recently:
https://play.google.com/store/apps/details?id=com.github.ericytsang.screenfilter.app.android
In fact, this app seems to be able to draw everywhere, as opposed to SAW permission. It draws even on top of the settings app and system dialogs, while SAW permission isn't allowed as such.
Sadly, as accessibility is quite a unique and rarely thing to use, just as I wrote, I couldn't find how such a thing works with drawing on top of other apps.
The only thing I know is that this app somehow does it, and this is what it shows when it asks to grant it:
But that's not enough. I know that for some old POC I've made of using accessibility service, it showed the same, and checking it out, I can't see what triggers it. Pretty sure it's the minimal thing the users will see for any kind of accessibility service, so this won't help.
How does AccessibilityService draw on top of other apps?
Does it work the same as SAW permission ? Can you, for example, handle touch events on what it draws?
What are the restrictions of using it, if there are any ?
Check Apps Allowed To Draw Over The Screen So, find out which apps have permission to draw over the screen, as explained follows: Step 1: Go to Settings on your Android smartphone. Step 2: Navigate to Apps and Notification > Special app access. Step 3: Here, look for Display over the apps.
RETRIEVE_WINDOW_CONTENT. retrieve screen content. Allows the app to retrieve the content of the active window. Malicious apps may retrieve the entire window content and examine all its text except passwords.
Using TYPE_ACCESSIBILITY_OVERLAY as type
in the WindowManager.LayoutParams
when adding the view from within the accessibility service seems to do the trick. I did a quick test and the overlay window was shown even in the settings menu. The overlay window also received touch events. This worked also without the SYSTEM_ALERT_WINDOW
permission in the manifest and also without setting the "Display over other apps" permission interactively by the user. I did my testing using target SDK 29.
Sorry, I cannot answer to your third question about what specific restrictions apply.
EDIT: By looking at the old tutorial of Google here, here's a short sample:
GlobalActionBarService.java
public class GlobalActionBarService extends AccessibilityService {
FrameLayout mLayout;
@Override
protected void onServiceConnected() {
// Create an overlay and display the action bar
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.TOP;
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
wm.addView(mLayout, lp);
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
@Override
public void onInterrupt() {
}
}
manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
package="com.lb.myapplication">
<application
android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true"
android:theme="@style/Theme.MyApplication" tools:ignore="AllowBackup">
<activity
android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".GlobalActionBarService" android:exported="false"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data
android:name="android.accessibilityservice" android:resource="@xml/global_action_bar_service" />
</service>
</application>
</manifest>
global_action_bar_service.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault"
android:canPerformGestures="true" android:canRetrieveWindowContent="true" />
action_bar.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content" android:orientation="horizontal">
<Button
android:id="@+id/power" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/power" />
<Button
android:id="@+id/volume_up" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/volume" />
<Button
android:id="@+id/scroll" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/scroll" />
<Button
android:id="@+id/swipe" android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="@string/swipe" />
</LinearLayout>
The answer is: You must use WindowManager which puts views to a window in the service to draw it on top of other apps.
val typeApplication =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
else
WindowManager.LayoutParams.TYPE_PHONE
val layoutParams = WindowManager.LayoutParams(
windowWidth,
ViewGroup.LayoutParams.WRAP_CONTENT,
typeApplication,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
// inflater view with above layoutParams variable
And the application granted the Overlay permission and make sure accessibility is enabled in the device setting (Setting-> Accessibility -> Enable your app). Or use this intent to go to it
Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
. You can check the Overlay permission by the following code
// check
Settings.canDrawOverlays(applicationContext)
// Use this intent to enable permision
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:$packageName"))
Does it work the same as SAW permission? Can you, for example, handle touch events on what it draws? I've never used SAW before so I'm not sure about this question.
Hope can help you!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With