I want to show a floating view when the user gets a phone call or a text message. But overlay permission check in broadcastReceiver returns false with built apk on Android 13.
I use BroadcastReceiver with RxWorker (more than 12) and Service (less than 12) to get a caller information. In Worker or Service, when you success to get a information, you call WindowManager.addview(mView). When the app is first launched, the user has already granted the permission to draw overlays.
<receiver
android:name=".receiver.PhoneCallReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
In this receiver, I check SYSTEM_ALERT_WINDOW
permission by using Settings.canDrawOverlays(context)
.
When I run this in Android Studio, it works well. However, permission is not checked when built with apk only on Android 13. Returns false even though you have permission. Sometimes, an error occurs when calling addView within Worker even if the permission is correctly confirmed on the broadcast!
"android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@7c33a48 -- permission denied for window type 2038"
<receiver
android:name=".receiver.MessageReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
When receiving a phone call or text message, WindowManager.addView
is called within the same worker, but the view is normally displayed when receiving a text message, and there is no permission when receiving a phone call. For your information, I'm testing with Samsung Galaxy S21.
Is there any solution?
CodePudding user response:
It appears that you are facing an issue with the SYSTEM_ALERT_WINDOW permission not being checked correctly when using a BroadcastReceiver on Android 13.
The issue you're facing may be related to changes in the Android 13 security model. In Android 13, the SYSTEM_ALERT_WINDOW permission is now requested at runtime, rather than at install time. This means that even if the user has already granted the permission, you will need to check for it again at runtime.
One possible solution to this issue would be to use the new requestOverlayPermission() method to request the SYSTEM_ALERT_WINDOW permission at runtime. You can use this method in your BroadcastReceiver to request the permission and check the result before calling addView.
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
intent.data = Uri.parse("package:$packageName")
startActivityForResult(intent, REQUEST_CODE_OVERLAY_PERMISSION)
You can also check for the status of the permission using the checkSelfPermission() method from the ActivityCompat class.
val result = ActivityCompat.checkSelfPermission(context, Manifest.permission.SYSTEM_ALERT_WINDOW)
if (result == PackageManager.PERMISSION_GRANTED) {
//Permission granted
} else {
//Permission denied
}
Another option would be to check for the status of the permission using the canDrawOverlays() method from the Settings class before calling addView.
val canDrawOverlays = Settings.canDrawOverlays(context)
if (canDrawOverlays) {
//Permission granted
} else {
//Permission denied
}
It's also good to check that your AndroidManifest.xml file is configured correctly and that you have the latest version of the Android Studio and all the necessary dependencies installed.
You can also try running the app on different emulators or devices to see if the issue is specific to the device you are currently testing on.
CodePudding user response:
Asking permission when a call is received harms the user experience, but I tested it with reference to Fazle Rabbi's answer. Since the context within the broadcast is not an activity context, a separate activity was created to request permission. (The code has been modified. Check to allow permissions with Settings.canDrawOverlays() instead of comparing with result.resultCode.)
@RequiresApi(Build.VERSION_CODES.R)
class PermissionActivity : AppCompatActivity() {
private val requestOverlayPermission = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
if (Settings.canDrawOverlays(this)) {
//Permission granted
/*
do something
*/
} else {
//Permission denied
}
finish()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pemission)
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
intent.data = Uri.parse("package:$packageName")
requestOverlayPermission.launch(intent)
}
}
In BroadcastReceiver,
if (!Settings.canDrawOverlays(ctx)) {
val i = Intent(ctx,PermissionActivity::class.java)
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
ctx.startActivity(i)
return
}
Settings.canDrawOverlays returns false and goes to the Permission Request page whenever BroadcastReceiver is called, even if the app's settings confirm that it has overlay privileges. In addition, permissions are still disabled on the moved overlay permission request page.
It's really weird. Funny how it's normal when it's running on Android studio. It is well confirmed that there is also permission. This only happens when executed with the built APK On Android 13! The problem seems to occur not only on one particular device, but on most Samsung phones updated with Android 13. Did I miss anything?