Ask for ACTION_MANAGE_OVERLAY_PERMISSION using the ActivityResultLauncher - android

Previously I was doing this by the standard 'startActivityForResult()' approach, catching the result in onActivityResult() callback. And it worked. But now the method has a big-strike though since it is deprecated so I am trying to use the new launcher approach. However, I always get the same result regardless of what the user does. result.getResultCode() always returns a failure. Double checking with Settings.canDrawOverlays(context) also returns failure even when the permission has been granted. Though far later in the code when I check using Settings.canDrawOverlays(context) it returns success. Putting in a delay in the launcher callback does not solve the inconsistency.
Here is my Launcher registration and callback:
ActivityResultLauncher<Intent> activityResultOverlayLauncher =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<>()
{
#Override
public void onActivityResult(ActivityResult result)
{
if (result.getResultCode() != Activity.RESULT_OK)
{
HaHStatics.debugLog(TAG, context, "d", "HH2: Permission for device discovery popups not given");
Toast.makeText(context, "Overlay Permission not given.", Toast.LENGTH_LONG).show();
// Double checking with Settings.canDrawOverlays(context) also always returns failure
}
else
{
HaHStatics.debugLog(TAG, context, "d", "HH2: Permission for device discovery popups given.");
}
// Do next thing
}
});
And here is the request code:
#TargetApi(Build.VERSION_CODES.M)
private void getSystemWindowAlertPermission()
{
HaHStatics.debugLog(TAG, context, "d", "HH2: Checking for permission to allow Alert popups");
if (isVersionM_Plus && !Settings.canDrawOverlays(this)) // isVersionM_Plus checks build >= OS 6
{
final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
try
{
activityResultOverlayLauncher.launch(intent);
}
catch (ActivityNotFoundException e)
{
Log.e(TAG, e.getMessage());
}
}
}
The call to initiate the settings activity works fine in all versions of Android though version 11 requires a two-step navigation by the user.
The only thing I can think of is that I am using the wrong contract OR that the system is messing up and not setting what it needs to set until I return from the launcher callback.
I am at a loss. Any ideas of what I am doing wrong?
PS: this approach works great for asking all the Bluetooth and Location and background permissions needed to do discovery, scanning, and auto reconnects from versions OS 6 to 12.

Related

Asking intent to access USB device

I'm trying to read data from a USB device using UsbManager.
The device I am trying to read the data from is a camera (but android recognizes it as a USB device)
The problem that I currently encountered is that it doesn't let me ask for permission to access the USB device.
I have the necessary uses-permissions and enabled host mode in the manifest.
Any suggestions why this happens and how to fix it?
Ive tried 2 methods for asking permissions
private fun requestPermission() {
requestCameraPermissionIfMissing { granted ->
if (granted){
usbComm = Camera(this, intArrayOf(7758))
usbComm.startUsbConnection()//find device from connected devices and establish connection
}
else
Toast.makeText(this, "Please Allow the Permission", Toast.LENGTH_LONG).show()
}
}
// Show popup to request permission to access camera if granted return true otherwise false
private fun requestCameraPermissionIfMissing(onResult: ((Boolean) -> Unit)) {
if (ContextCompat.checkSelfPermission(
this,
ACTION_USB_PERMISSION
) == PackageManager.PERMISSION_GRANTED
)
onResult(true)
else
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
onResult(it)
}.launch(ACTION_USB_PERMISSION)
}
The other one is:
val intent: PendingIntent = PendingIntent.getBroadcast(
context,
0,
Intent(ACTION_USB_PERMISSION),
PendingIntent.FLAG_MUTABLE
)
manager.requestPermission(m_device, intent)
Both dosnt show me the request on the device and also i dont see in debug that permission was granted
And also when i try doing the fallowing without permission my app crash
var intf = m_device?.getInterface(0)!!
endpoint = intf.getEndpoint(0)
if (m_connection!!.claimInterface(intf, true)) { // Crashed here
Log.i("serial", "The interface was claimed successfully")
} else {
Log.i("serial", "The interface could not be claimed")
}
I found a way to solve this in case anyone else has encountered it too,
you need to ask permission for the app, in my case, it was
Manifest.permission.CAMERA
Manifest.permission.RECORD_AUDIO
and after that ask for permission to access the device and it will broadcast the intent.

Return to app immediately when user has granted the manage external storage permission on Android - Non-deprecated way

I am making an android app that needs the MANAGE_EXTERNAL_STORAGE permission (and the read/write permission before android 11). The app requests the permission the first time it starts (using the code of the accepted answer from here).
However, when the user provides the permission they have to manually press the back button to return to the app so it can continue its flow.
I have a file manager app on my phone that returns to the app automatically once the permission is granted. So I am looking for a way to implement this in my app as well, preferably using the new method google suggest instead of the now deprecated startActivityForResult
The app I mention is available on playstore here
What I tried?
Replaced the startActivityForResult using ActivityResultLauncher, which is the way google recommends, because startActivityForResult is now deprecated, but it didn't really change the app's behavior/solve the problem. In fact, it seems to be receiving a rejected result whether the user accepts it or not.
After searching more thoroughly I found this post and I used part 3) of this answer, which seems to be doing the trick. I also tried replacing the startActivityForResult with the ActivityResultLauncher that Google recommends and it works fine. So the final code is:
Paste this code on the start of MainActivity(or in the activity you want), just after the properties' declarations:
Handler handler = new Handler();
Runnable checkSettingOn = new Runnable() {
#Override
public void run() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
return;
} else {
if (Environment.isExternalStorageManager()) {
//You have the permission, re-launch MainActivity
Intent i = new Intent(MainActivity.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
return;
}
handler.postDelayed(this, 200);
}
}
};
After this, create an ActivityResultLauncher, which will handle the user's denial part:
ActivityResultLauncher<Intent> storageLauncher =registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
if (SDK_INT >= Build.VERSION_CODES.R)
if (!Environment.isExternalStorageManager())
//DO STH IF USER DENIES
}
});
When asking for the permission you then start the handler:
try {
Intent storageIntentTry = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
storageIntentTry.addCategory("android.intent.category.DEFAULT");
storageIntentTry.setData(Uri.parse(String.format("package:%s", getApplicationContext().getPackageName())));
storageLauncher.launch(storageIntentTry);
handler.postDelayed(checkSettingOn, 1000);
} catch (Exception e) {
Intent storageIntentCatch = new Intent();
storageIntentCatch.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
storageLauncher.launch(storageIntentCatch);
handler.postDelayed(checkSettingOn, 1000);
}
(Ignore names of intents - can be anything that makes sense)

Require code snippet to find auto start permission in MIUI is enabled or not for my app?

We are developing a application like google calendar where we need to notify the user at the right time on OFFLINE. Other than MIUI, it is working fine. But in MIUI devices, the user should enable the AUTO_START permission for our application. We are using below code snippet to open the AUTO_START page programmatically (Right me, If I am wrong).
public boolean invokeAutoStartPermission(Context context) {
try {
Intent intent = new Intent();
intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity");
context.startActivity(intent);
} catch (Exception e) {
return false;
}
return true;
}
But we have to ask this permission to the user when it is disabled. Unfortunately we couldn't able to find the code snippet to check the status of the AUTO_START permission for my application.

Context.checkCallingPermission checking always fails?

I'm encountering such a scenario in Android.
App A has permission PERM to get some information. Instead of directly getting this information, it sends an intent to one BroadCastReceiver inside App B (of course B has PERM). In order to ensure all such apps like A has the permission, I use a context.checkCallingPermission (with the help of this answer).
However it always fails.
public void onReceive(Context context, Intent intent) {
String info;
String perm = Manifest.permission.READ_PHONE_STATE;
Log.i(TAG, "callPid="+ Binder.getCallingPid()+" myPid="+ Process.myPid()); /// SAME PID
if (context.checkCallingPermission(perm) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "not granted " + perm);
info = "denied perm " + perm;
} else {
Log.i(TAG, perm + " already granted");
info = dumpDeviceInfoImpl(context);
}
}
Specially, the comment line always return SAME pid (B's), when I send intent from A. I can confirm A and B have different PIDs.
update
Previously I was thinking it is due to BroadCastReceiver, so I tried to startActivity from A and then start an activity in B. Once again, during checkCallingPermission, it fails again. Surprisingly, still returning the SAME pid.
So what's the correct way to use checkCallingPermission?
use this methdos
checkCallingPermission(Context context, String permission, String packageName)
Checks whether the IPC you are handling has a given permission and whether the app op that corresponds to this permission is allowed.

Android 6 bluetooth

I upgraded to Android 6 and my applications who use Bluetooth doesn't work with this new API version. It's the same problem with application on Play Store: Bluetooth spp tools pro (good application to view if bluetooth works) which doesn't discovery of devices.
The problem seems to be in Bluetooth discovery:
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mBluetoothAdapter.startDiscovery()
Log.i("BLUETOOTH", String.valueOf(mBluetoothAdapter.isDiscovering())); // Return false
My applications work well with Android 4/5 and I followed : http://developer.android.com/guide/topics/connectivity/bluetooth.html
Staring with Android 6.0 it is not enough to include permissions on manifest.
You have to ask the user explicitly about each permission that is considered "dangerous".
BluetoothDevice.ACTION_FOUND requires BLUETOOTH and ACCESS_COARSE_LOCATION permissions
http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#ACTION_FOUND
The ACCESS_COARSE_LOCATION
http://developer.android.com/reference/android/Manifest.permission.html#ACCESS_COARSE_LOCATION
is a "dangerous" permission and therefore you have to ask for it using requestPermission before doing actual discovery.
public void doDiscovery() {
int hasPermission = ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);
if (hasPermission == PackageManager.PERMISSION_GRANTED) {
continueDoDiscovery();
return;
}
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{
android.Manifest.permission.ACCESS_COARSE_LOCATION},
REQUEST_COARSE_LOCATION_PERMISSIONS);
}
then on you will get the user answer on onRequestPermissionsResult
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_COARSE_LOCATION_PERMISSIONS: {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
continueDoDiscovery();
} else {
Toast.makeText(this,
getResources().getString(R.string.permission_failure),
Toast.LENGTH_LONG).show();
cancelOperation();
}
return;
}
}
}
To work with previous versions of android you should use compatibility libraries and make the calls using ActivityCompat
I've spent some time investigating the problem.
Created bug report on Android bug tracker here
The problem is that system does not forward BluetoothDevice.ACTION_FOUND intents to the registered BroadcastReceiver. Logcat shows lines like this:
10-16 07:34:09.147 786-802/? W/BroadcastQueue﹕ Permission Denial: receiving Intent { act=android.bluetooth.device.action.FOUND flg=0x10 (has extras) } to ProcessRecord{5ce2d92 21736:com.example.mvl.bluetoothtest/u0a74} (pid=21736, uid=10074) requires android.permission.ACCESS_COARSE_LOCATION due to sender com.android.bluetooth (uid 1002)
Which themes for me that the application needs android.permission.ACCESS_COARSE_LOCATION permission to receive this intents. i personaly don't understand why I need that permission to get the Bluetooth devices around.
So if you add this permission to you Manifest, then it should work with one more precondition - You have to set target SDK and compile with SDK not higher, then 22.
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
When checking the source code in GattService.java,you will find some code comments in method onScanResult:
// Do no report if location mode is OFF or the client has no location permission
// PEERS_MAC_ADDRESS permission holders always get results
if (hasScanResultPermission(client) && matchesFilters(client, result)) {
try {
ScanSettings settings = client.settings;
if ((settings.getCallbackType() &
ScanSettings.CALLBACK_TYPE_ALL_MATCHES) != 0) {
app.callback.onScanResult(result);
}
} catch (RemoteException e) {
Log.e(TAG, "Exception: " + e);
mClientMap.remove(client.clientIf);
mScanManager.stopScan(client);
}
}
this clarified what is needed to get a Bluetooth LE advertising report.

Categories

Resources