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.
Related
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.
I have an application that is meant for "locked Android phones" meaning the application is the only application users will have access to on that phone and that is done using MySync.
Before the application had to support Android 11 (complieSdkVersion 30), the user was able to change screen brightness and other system settings from the application (Since the user did not have access to the settings app). But now the WRITE_SETTINGS and CHANGE_CONFIGURATION are deprecated and no longer have desirable effects.
I am aware that it is possible to prompt the user to accept the settings with this prompt:
boolean permission;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
permission = Settings.System.canWrite(context);
} else {
permission = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED;
}
if (permission) {
initApp();
} else {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
startActivityForResult(intent, SettingsActivity.CODE_WRITE_SETTINGS_PERMISSION);
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_SETTINGS}, SettingsActivity.CODE_WRITE_SETTINGS_PERMISSION);
}
}
But since the user does not have access to the settings application in my app eco-system, I can not give the user a prompt that would open up the settings and allow the user to stay in the settings.
Is there no way around this permission request and is there no way to do it on the manifest level or some other way?
Apparently the MIUI OS has already implemented its own Permissions system before Marshmallow does. I'm currently testing a video recording app for the Xiaomi Mi 4i, which uses a MIUI based on API 21 [Android 5.0.2], and it needs the Record Audio permission which is not granted by default by MIUI's Permissions Manager.
So far the way I've managed to alter the permissions is by accessing the Permissions Manager window for the app on clicking the OK button in the AlertDialog:
isMIUI = MIUIUtils.isMIUI();
if(isMIUI)
{
AlertDialog.Builder adb = new AlertDialog.Builder(this);
adb.setMessage("If you intend to use the video recording feature, please enable the 'Record Audio' permission in the settings menu. You will be redirected there if you press OK.")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
intent.putExtra("extra_pkgname", "com.picmix.mobile");
startActivity(intent);
}
})
.setNegativeButton("CANCEL", null)
.create();
adb.show();
}
But this isn't good enough for me. I need to check if the Record Audio permission is already checked in the MIUI Permissions Manager in order to run this only once.
How do I check for the permissions granted or to be notified in the MIUI Permissions Manager programmatically?
private boolean resourceCanBeAccessed() {
boolean response = true;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_DENIED ) {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.RECORD_AUDIO}, 1);
response = false;
}
}
return response;
}
You just need to call this method before accessing the resource. This method will return true if the permission is granted. It the permission is not granted then it will grant the permission
I just updated my Nexus 5 to android 6, until now my app was working fine, but now the broadcast receivers are not working. Has something changed in the new version?
Here is the code I tried that was working on previous versions but not in marshmallow -
Android Manifest
<intent-filter >
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
<uses-permission android:name="android.permission.READ_SMS" ></uses-permission>
Broadcast Receiver
public String TAG ="someClass";
private static String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equalsIgnoreCase(ACTION_SMS_RECEIVED)) {
Log.d(TAG, "Received...");
}
}
Service
Broadcast_receiver broadcast_receiver = new Broadcast_receiver();
IntentFilter filter1 = new IntentFilter();
filter1.addAction("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(broadcast_receiver, filter1);
Similarly the broadcast receiver for PHONE_STATE is also not working.
Your app's target API level is 23, that is android M (6.0). In android M there are huge changes related to user-permissions.
Here is nice article explaining the changes.
As stated in Android - Requesting Permissions
Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app... The user can revoke the permissions at any time...
It's also stated that:
System permissions are divided into two categories, normal and dangerous:
Normal permissions do not directly risk the user's privacy. If your app lists a normal permission in its manifest, the system grants the permission automatically
Dangerous permissions can give the app access to the user's
confidential data. If you list
a dangerous permission, the user has to explicitly give approval to
your app
Here are full lists of Dangerous Permissions and Normal Permissions
All that basically means that you need to manually request for any dangerous permission, when it's actually needed.
Since it potentially might be needed multiple times in your code, you can create a reusable method that checks whether specific permission is granted already and if it's not - to request it from user.
Here an example:
Java
public class PermissionManager {
//A method that can be called from any Activity, to check for specific permission
public static void check(Activity activity, String permission, int requestCode){
//If requested permission isn't Granted yet
if (ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
//Request permission from user
ActivityCompat.requestPermissions(activity,new String[]{permission},requestCode);
}
}
}
Kotlin
object PermissionManager {
//A method that can be called from any Activity, to check for specific permission
fun check(activity: Activity, permission: String, requestCode: Int) {
//If requested permission isn't Granted yet
if (ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
//Request permission from user
ActivityCompat.requestPermissions(activity, arrayOf(permission), requestCode)
}
}
}
Usage:
Java
//Inside your activity:
//1. Define static constant for each permission request
public static final int REQUEST_CODE_FOR_SMS=1;
//2. When needed (for example inside .onStart event) use method PermissionManager.check for requested permission
#Override
protected void onStart() {
super.onStart();
PermissionManager.check(this, Manifest.permission.RECEIVE_SMS, REQUEST_CODE_FOR_SMS);
}
//3. Handle User's response for your permission request
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if(requestCode==REQUEST_CODE_FOR_SMS){//response for SMS permission request
if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
//What to do if User allowed SMS permission
}else{
//What to do if user disallowed requested SMS permission
}
}
}
Kotlin
//Inside your activity:
//1. Define static constant for each permission request
val REQUEST_CODE_FOR_SMS = 1
//2. When needed (for example inside .onStart event) use method PermissionManager.check for requested permission
override fun onStart() {
super.onStart()
PermissionManager.check(this, Manifest.permission.RECEIVE_SMS, REQUEST_CODE_FOR_SMS)
}
//3. Handle User's response for your permission request
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (requestCode == REQUEST_CODE_FOR_SMS) {//response for SMS permission request
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//What to do if User allowed SMS permission
} else {
//What to do if user disallowed requested SMS permission
}
}
}
Note:
If you need to use PermissionManager.check inside Fragment instance, use: getActivity() as its first parameter.
You can use checkSelfPermission inside Service instance, to check if some permission is granted already, but not requestPermissions to request it. Because checkSelfPermission can be used for any Context, but requestPermissions only for Activity
Marshmallow is blocking the dangerous permissions.
This doesn't apply to the scenario listed, but it might help someone else. I kept coming to this SO for why some of our Broadcast Receiver's weren't working. We have a custom permission setup and had the android:protectionLevel="dangerous". Changed it to android:protectionLevel= "signature"and everything started working.
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.