Avoid Screen Overlay Detected for service that uses SYSTEM_ALERT_WINDOW - android

My app main usage is overlay, the overlay is running from a service.
Android Security add the nice "Screen Overlay Detected"
I want to avoid "Screen Overlay Detected" when user tries to change permissions. so... I've add an AccessiblityService that detects:
if ( event.getPackageName().equals("com.google.android.packageinstaller") ){
stopService(myServiceIntent);
}
However, even now I see this message popping. (when my service is stopped...).
I saw Twilight does it without problem.
What am I missing?
p.s. - I've also tried building a signed apk but saw exact same behavior.

It seems I've been able to resolve this.
a) stopService isn't assured your service will be stopped.
as described here :
It will not be destroyed until all of these bindings are removed. See > the Service documentation for more details on a service's lifecycle.
b) I was able to kill my service by sending intent that called stopSelf().
However process killing/starting can be slow.
c) Best resolution: so it seems Android checks for view visibility. no need to kill services or do anything more complicated.
Current way I'm doing it:
- AccessibilityService (already used by my app) monitor "com.google.android.packageinstaller" though it can be refined to class: "com.android.packageinstaller.permission.ui.ManagePermissionsActivity"
Once detected in this class, we send Intent to "duck", and when we're out, we send another intent that we're back on.
The service handles those calls by:
[ourView].setVisibility(View.INVISIBLE); // when permission settings shown
[ourView].setVisibility(View.VISIBLE); // when normal flow

As long as Android 6.x is buggy on some devices where this "overlay alert" is displayed without any reason (on 2 to 5% of the devices according to my analytics data), the best solution is to avoid the whole permission process by defining the targetSdk to 22. Take care that you can't downgrade the target sdk for a new version or this will induce a INSTALL_FAILED_PERMISSION_DOWNGRADE error when the user updates requiring an unisntall/install of the app.

Related

Android 8.1.0 API 27: how to register to receive broadcasts about your app's Notification Settings Changes?

Can anyone suggest an Action (intent) which an Android 8.1.0 system should broadcast to registered receivers when changing Notification Channel setting values? Some years back, we did the work to update our notifications system into the required channels and groups and specified a broadcast receiver for the settings changes in the manifest (later on we had to fix that when they took away implicit intents, so now it registers in code too - but that's fixed already). Our receiver sets internal "display" settings which correspond to the notification-channel setting chosen by the user into our sharedpreferences file. That's what controls the display of the content when a user actually opens the app.
I have notes that say we tested this on Android 8, but the actions/intents we registered for don't exist until API28. I'm unclear on how this ever passed on the 8.1 devices, but maybe we were focused on the notifications only and didn't notice the display. So right now, we're stuck with notification settings changes working, but if a user happens to go to the app for something else, they still see messages they expected to be hidden.
Android 9+ notification settings changes work fine all the way through because the broadcast receiver registers for the new-in-API-28 NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED, ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED and ACTION_APP_BLOCK_STATE_CHANGED and these get delivered fine when a user changes settings, since I can see the receiver runs and sets the preferences as we want.
Just to debug this, I registered our BroadcastListener for a few extra intents (basically everything that looked like it might have something to do with notifications!) - like this:
// Register to receive a broadcast whenever notification settings are changed (before API 26 this was done by specifying in AndroidManifest only,):
notificationSettingsReceiver = new NotificationSettingsBroadcastReceiver();
IntentFilter filter = new IntentFilter(NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED);
filter.addAction(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
filter.addAction(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED);
filter.addAction(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED);
filter.addAction(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED);
this.registerReceiver(notificationSettingsReceiver,filter);
This proved that the code in my BroadcastReceiver is working fine in 8.1.0 if it would only get called; I can force it to run by changing a few Notification settings (disabling them, or changing the sounds, etc) and then switching the phone into do-not-disturb mode. The actual notification-settings-changes don't ever cause any intent to arrive at my receiver, but the DND change does, so this triggers the notification settings to get written into sharedpreferences (which is where our display code is expecting to find them).
Pre-android 8 notification settings still seem to work fine too and we write these changes into our sharedpreferences file directly. Something about compatibility must just handle this for us because it all still "just works" on API 23 devices.
If anyone could suggest a way for an API 27 device to listen for notification-channel settings changes, I would be most grateful! There has to be a way to to this in API 27, isn't there?
After a few days of looking around and trying things, I was unable to have the NotificationManager in API 27 send anything at all to our BroadcastReceiver.
I was able to come up with a solution, although at first it seemed a bit heavy-handed.
For Android O+ devices, I simply added the same "syncPreferences" block of code to our app's onCreate, onResume and onDestroy methods which calls the same function as our BroadcastReceiver (which works fine in API 28+) to write the values into our shared_prefs file at that time. I say "heavy-handed" since it does it every time, regardless of whether anything has changed, but it actually works very well. It's actually simpler than all the overhead of building a receiver and listening for notification changes... I could probably eliminate that whole process now!
As an amusing aside, as a trekker, I have to admit that I got quite a chuckle from whoever adds the android VERSION_CODES constants though! Check the comment I found while looking up API numbers-to-buildcode declarations:
/**
* Q.
* <p>
* <em>Why? Why, to give you a taste of your future, a preview of things
* to come. Con permiso, Capitan. The hall is rented, the orchestra
* engaged. It's now time to see if you can dance.</em>
*/
public static final int Q = 29;

Android O limits for lower target SDK

I started to test my app on Nexus 5x with Android O.
My targetSdkVersion is 22.
In the developer site I read about Background execution limits:
Where:
By default, these restrictions only apply to apps that target O. However, users can enable these restrictions for any app from the Settings screen, even if the app has not targetted O.
Where is these settings (to enforce Android O limitations)?
Whats is the best practice for these limitation while I still want
to keep lower targetSdkVersion?
I found the setting under App info > Battery usage although not all apps have this setting.
When this setting is OFF I see following logs:
W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.$ACTION dat=package:$APP_PACKAGE flg=0x4000010 (has extras) } to $APP_PACKAGE/$APP_RECEIVER
[UPDATE Sep 27, 2017]
As described here:
However, developers cannot use the Settings app to apply this limitation, unless their app happens to be in the battery blame list, which ideally doesn’t happen.
This article offers undocumented way to test background limitations via following command (ignore and allow values are possible)
adb shell appops set your.application.id.here RUN_IN_BACKGROUND ignore
Best practices are
If you plan on sticking with a lower targetSdkVersion for a while, and you are really really sure that your app will not show up on the battery blame list, and you want to ignore the background limitations for now, that’s your decision to make.
If, however, you plan on sticking with a lower targetSdkVersion and your app does tend to consume a fair bit of battery life, you should test your app with the adb shell appops command cited above. If nothing else, you can identify the likely symptoms that users will experience if they limit your background work through the Battery screen in Settings. That way, if you get customer service calls/emails/texts/Play Store comments/candygrams about those symptoms, you can better advise users about what to do.
See also Android Oreo Background Execution Limits
I cannot find it either.
Best practise would be to develop this for API 26, although you are not targeting it. So starting your service(s) as foreground service. After that, your service should start a foreground Notification in the onCreate.
From the docs:
The new Context.startForegroundService() method starts a foreground service. The system allows apps to call Context.startForegroundService() even while the app is in the background. However, the app must call that service's startForeground() method within five seconds after the service is created. (startForeground pushes the notification)
App info > Battery usage
IMO best practice is unfortunately to target API 26... This default behaviour is there only for legacy apps (sitting in play store but not being updated anymore).

Options for dealing with Android 6.0's new permissions requirements from a service or model component?

I'm looking into porting some existing code to take Android M's new way of dealing with permissions into consideration. However the permission API needs to have an activity associated with it (for example the requestPermissions() method's first parameter is an activity).
So how should a service that needs to check if a permissions has been granted and request for permissions use this new API if the service doesn't have an activity?
Is it possible for the service to create a dummy invisible activity just for use with the permissions API? (if its possible I don't like the thought of doing that anyway though).
Or suppose its not a service but a model class that needs to perform a permissions check, in MVC a model shouldn't have any knowledge of the Vs and Cs and yet now either it has to in order to know which Activity to use with the permission API. Or potentially lots of code might have to migrate from model code into Activity code.
Any thoughts on how to migrate non activity based code that needs to check/prompt for permissions over to Android 6.0?
Update: I left out an important piece of information - this is code that is pre-installed (our company provides code that device manufacture's place in rom) and often may be run at device boot time and run in the background. Therefore the usual situation of a user being prompted for permission when they launch the app or later (and there therefore being an activity at that point) does not necessarily apply.
So how should a service that needs to check if a permissions has been granted and request for permissions use this new API if the service doesn't have an activity?
There is almost always an activity, except for pre-installed apps and plugins for other apps. Otherwise, your service is unlikely to ever run, as nothing will have used an explicit Intent to start up one of your app's components, so it will remain in the stopped state.
For the ~99.9% of Android apps that have an activity already, if the permissions are needed for the whole operation of the app, request them on first run. As Snild Dolkow notes, if the user later revokes the permission through Settings, you can detect that without an activity, then use other UI options (e.g., Notification, app widget) to let the user know that operation is suspended until they grant you the permissions again, which they would then do through your activity.
Is it possible for the service to create a dummy invisible activity just for use with the permissions API?
Presumably you can have a Theme.NoDisplay activity use requestPermissions(). However, from the user's standpoint, it will not make much sense, unless there's some alternative UI (app widget?) that they are interacting with. Popping up a permission dialog out of nowhere is unlikely to make you popular.
UPDATE 2019-06-15: Note that Android Q bans services popping up activities frmo the background. Please use a notification instead.
in MVC a model shouldn't have any knowledge of the Vs and Cs and yet now either it has to in order to know which Activity to use with the permission API
Do not touch the models until you have requested the permission, and gracefully fail if the permission is revoked. You already have to gracefully fail in other circumstances (out of disk space, no Internet connection, etc.), so a revoked permission should be handled in much the same way.
using this new 6.0 API seems like an recipe for bad design and tight coupling
You are welcome to your opinion. Based on what I have read, the Android engineers believe that asking the user for permissions is part of the user experience and is best handled at the UI layer as a result.
Again: the vast majority of Android apps will not have a problem with this, as they have a user interface. Apps that do not have a user interface and need dangerous permissions are in for some amount of rework.
this is code that is pre-installed (our company provides code that device manufacture's place in rom) and often may be run at device boot time
First, please understand that this is so far from normal that you can't even see normal from where you are due to the curvature of the Earth. :-) You can't really complain that Google did not optimize this particular scenario.
As I understand it, even system apps should be asking for runtime permissions. The Camera app did, for example, on the 6.0 preview. That being said, there's gotta be some database on the device somewhere that is tracking what has been granted, and presumably there is some way to pre-populate it. However, the user could still revoke it from Settings, presumably. But, the manufacturer could pull some stunts (e.g., messing with the Settings app) to possibly even preclude that scenario. I'd be looking in the same area as "how do I get it so my app cannot be force-stopped?" that device manufacturers can do.
Your alternatives would be to get rid of the dangerous permissions or to migrate your app off the SDK and into a standard Linux binary that would be run as part of the boot process and be put into a Linux user group that has access to the stuff that you need.
Ask for it when the user enables whatever feature your service provides. They'll be in one of your activities at the time. Yes, it means that your activities need knowledge of what permissions your services will require.
The service can always check for the permission by itself, though, since checkSelfPermission() is available in all Context instances. So you don't need an activity for that.
I guess an alternative would be to have your service post a notification saying "feature X requires you to approve more permissions". Actually, that may be a good idea regardless, in case the user goes into settings and revokes any permissions after the fact. That notification would then take the user to some activity with an "enable feature X" button/checkbox -- ask for the permission when that is selected.
You can send a notification. Look this library to manage the permissions: permission library

Calling a method in the system process without a qualified user error

I'm using the notification listener service in android 4.4 and I'm coming across an error that causes my app to stop getting notifications posted.
It's fairly random, but when it happens I'm seeing:
12-31 01:40:44.080 21680-21680/? W/ContextImpl﹕ Calling a method in the system process without a qualified user:
android.app.ContextImpl.sendOrderedBroadcast:1192
android.app.ContextImpl.sendOrderedBroadcast:1183
android.content.ContextWrapper.sendOrderedBroadcast:390
com.android.settings.applications.ProcessStatsDetail.checkForceStop:314
com.android.settings.applications.ProcessStatsDetail.onResume:108
in the logs.
I can even recreate this by just entering the "process stats" section of the developer tools on the phone. As soon as I select an app that uses the notification listener the puts up this warning and unbinds and destroys the service and when it recreates is it doesn't always pick up on events again.
I'm not sure why this would happen, can anyone shed any light?
1) the NotificationListenerService is started by the system and the code for sendOrderedBroadcast throws a warning if it was called by the system process (here)
2) That is just a warning though. There is probably a crash somewhere else in your code. When a NotificationListenerService crashes, Android doesn't restart it unless you toggle the permission or restart your phone. Look for another crash and try either of those methods to restart it if it has. Starting it yourself will not work.
Check your AIDL Package name, for me the Package name in client and server were mismatched. Hope it help somebody

Listen to ActivityManager events?

is it possible somehow to listen to the events of the ActivityManager, e.g. when activities are started? Does the ActivityManager send broadcasts? I havn't found anything indicating that it does.
What I basically need to do: I want my app to launch one of my activities whenever a certain (thirdparty) app is launched/takes focus. Problem is this needs to happen before the thirdparty app is actually displayed.
What I have tried so far as workarounds:
Logcat output: I query logcat every 0.8s (filtered to show ActivityManager events only) but this eats up to many ressources
getRunningTasks: Slows down the phone a lot too and is not very safe, as an activity might be running but not currently in focus
Any ideas?
I suppose there is no actually other legacy way to handle glabal system state, only
(ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.getRecentTasks() - Return a list of the tasks that are currently running, with the most recent being first and older ones after in order.
For details check docs
Perhaps though Android is a Linux you can run system tools like
Runtime.getRuntime().exec("ps -aux | grep smth")
But I think it would be hard to detect particular java application.
I think you can use the launch mode to determine which activity to launch to top level. Please check the question: Android singleTask or singleInstance launch mode?. Maybe it will help you.
I had a look in the android source, but there doesn't seem to be any events broadcasted.
https://android.googlesource.com/platform/packages/providers/ApplicationsProvider

Categories

Resources