I'm using a PendingIntent launched by AlarmManager (with setRepeating) to start wifi scans (using IntentService) every few minutes.
On most devices and in most cases, there is no problem with that.
However, on several devices I get the following error (Couldn't reproduce the error on any test device. This is a crash log from a user's device):
java.lang.RuntimeException: Unable to start service com.myapp.android.service.MyService#44a9701 with Intent { act=com.myapp.android.ACTION_PERFORM_WIFI_SCAN flg=0x4 cmp=com.myapp/com.mayapp.android.service.MyService (has extras) }: java.lang.SecurityException: Permission Denial: broadcast from android asks to run as user -1 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL or android.permission.INTERACT_ACROSS_USERS
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3021)
at android.app.ActivityThread.-wrap17(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1443)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5415)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:725)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:615)
Caused by: java.lang.SecurityException: Permission Denial: broadcast from android asks to run as user -1 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL or android.permission.INTERACT_ACROSS_USERS
at android.os.Parcel.readException(Parcel.java:1599)
at android.os.Parcel.readException(Parcel.java:1552)
at android.net.wifi.IWifiManager$Stub$Proxy.startScan(IWifiManager.java:1045)
at android.net.wifi.WifiManager.startScan(WifiManager.java:1088)
...
I'm creating the PendingIntent from my app so I see no reason for the SecurityException thrown from WifiManager (Especially since this happens rarely).
The IntentService launched from the PendingIntent code is as follows:
mContext.registerReceiver(mWifiScanReceiver, new IntentFilter(
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
boolean ok = mWifiManager.startScan();
Any ideas on what might be causing this?
This is happening because of the new app permissions for android m.
See the comment above the source code of wifimanager's getScanResults() for api 23-
/**
* Return the results of the latest access point scan.
* #return the list of access points found in the most recent scan. An app must hold
* {#link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
* {#link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
* in order to get valid results.
*/
public List<ScanResult> getScanResults() {
try {
return mService.getScanResults(mContext.getOpPackageName());
} catch (RemoteException e) {
return null;
}
}
Hence, you will have to ask the user for permissions on runtime. Put these permissions in your manifest-
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
From api 23 onwards you require a permission to access user location to use it. I suggest you use a permissions check based on the api level and start intent only if the permissions have been granted.
Something like this-
if (Build.VERSION.SDK_INT >= 23) {
int hasReadLocationPermission = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
if (hasReadLocationPermission != PackageManager.PERMISSION_GRANTED) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(HomeActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)) {
showMessageOKCancel("You need to allow access to GPS",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(HomeActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, GPS_ENABLE_REQUEST);
}
});
return;
}
ActivityCompat.requestPermissions(HomeActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, GPS_ENABLE_REQUEST);
return;
}
if (locationManager != null && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
gotoGPSEnableScreen();
} else {
//Permissions granted and gps is on
launchService(true);
}
}
Further to check results-
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case GPS_ENABLE_REQUEST:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
gotoGPSEnableScreen();
}
} else {
launchService(false);
}
default:
return;
}
}
UPDATE:
android.permission.INTERACT_ACROSS_USERS_FULL is a signature level permission.
Just add this android:protectionLevel="signature" in your manifest .
For more details you can check this
http://developer.android.com/guide/topics/manifest/permission-element.html
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" android:protectionLevel="signature"/>
If you're going to override
onCreate()
in your
IntentService,
then make sure you call
super.onCreate()
in it. That seems to quite likely be your problem.
Your issue is you are calling from different user and asking to run on different user and that requires android.permission.INTERACT_ACROSS_USERS_FULL and that is signature level permission. Just add this android:protectionLevel="signature" in your manifest .
For more details you can check this
http://developer.android.com/guide/topics/manifest/permission-element.html
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" android:protectionLevel="signature"/>
Related
i am using this permission in my app and working fine in all devices and also in Marhshmallow 6.0 device.
There no need to WAKE_LOCK permission runtime because its normal permission but getting issue in Nougat 7.0 devices.
App getting crashed and error occur "java.lang.SecurityException: Neither user 10799 nor current process has android.permission.WAKE_LOCK" on line wakelock.acquire();
How to fix that?
Use
<uses-permission android:name="android.permission.WAKE_LOCK" />
only, no extra code needed.
Call acquire() to acquire the wake lock and force the device to stay on at the level that was requested when the wake lock was created.
Call release() when you are done and don't need the lock anymore. It is very important to do this as soon as possible to avoid running down the device's battery excessively.
Add all the uses-permission at the end of the manifest
Find the solution
As per my knowledge this is enough in Manifest file
<uses-permission android:name="android.permission.WAKE_LOCK"/>
For Screen continously ON write below logic
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
You have ask for the permission at run time:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ContextCompat.checkSelfPermission(this, Manifest.permission.WAKE_LOCK) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WAKE_LOCK},
REQUEST_PERMISSION);
}
#Override
public void onRequestPermissionsResult(final int requestCode, #NonNull final String[] permissions, #NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted.
} else {
// User refused to grant permission.
}
}
}
Lastly I ran into problem that, I can't scan for beacons because of lack of ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION.
I tried to fix it by using code found here, but it actually help me partially.
When this view appears
I click allow. After that I doesn't get this java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results error anymore, but I can't still see my beacons and when I open settings view the location is turned off like on picture bellow.
When I turn on location by finger everything works ok, so I can see my beacons and app works as it should. And here is the question is these some kind of bug or I missed something to turn on location from code behind after access to device location is turned on?
For developing I use Nexus 5x with android 7.1.1.
EDITED:
Code is copied from tutorial linked above, the fragment with button which starts beacon scanner:
public void onBleClicked(View view)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect beacons.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
}
});
builder.show();
}
BleManager bleManager = new BleManager(this);
bleManager.tryToTurnOnBle();
}
Fragment of manifest where permissions are declared:
<!-- app only for phones -->
<uses-feature android:name="android.hardware.telephony"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
The bluetooth permissions are apparently in library.
What I found right now is fact that there is similar question to mine here.
But this solution with redirecting user to location option screen is not seems to be clean one for me.
Location can be determined by two ways:
1.Using NETWORK_PROVIDER
2.Using GPS_PROVIDER
NETWORK_PROVIDER: It determines the location of the users using cell towers,wifi access points. It is commonly used for determining location inside the rooms or buildings. Here the GPS coordinates are not able to be obtained.
You can specify either
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION” />
or
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
in order to get location using the NETWORK_PROVIDER.
GPS_PROVIDER:
It determines the location of the users using satellites. For this, the GPS coordinates are obtained and used for positioning. The GPS receiver in the smartphone receives the signals from satellites. These signals are processed and precise locations are determined.It works better in outdoors – direct sky/satellite views and communication occurs.
You need specify the permission
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
in order to use location from GPS_PROVIDER.
Fine locations:
It gives better and accurate locations. So, that I recommend you to use this to get your beacon locations. It gives permission for using both GPS_PROVIDER and NETWORK_PROVIDER or GPS_PROVIDER only for determining the position.
Coarse locations:
It provides less accurate locations.It gives permission for using NETWORK_PROVIDER only for determining the position.
Now, come to the implementation.
- Declare the above said two permissions in the AnroidManifest.xml file:
- In the java part, do the following:
Request the permission if it not granted yet:
private void requestPermission(Activity activity) {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CALL_PHONE}, MainActivity.PERMISSION_REQUEST_CODE_LOCATION);
}
When the above method is called, a dialog asking permission will appear. On selecting Allow or Deny, the below callback gets triggered.
In the onRequestPermissionsResult
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_REQUEST_CODE_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isGpsProviderEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean isNetworkProviderEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
//Location permission is given. Check if the providers are available and start location updates.
if (isGpsProviderEnabled && isNetworkProviderEnabled) {
startLocationUpdates();
} else {
Log.d(TAG, "GPS and Network providers are disabled");
}
} else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
boolean should = ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION);
if (should) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MainActivity.PERMISSION_REQUEST_CODE_LOCATION);
} else {
promptSettings();
}
}
}
}
In the promptSettings() method, let the user to enable location from the Settings screen.
private void promptSettings() {
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(getResources().getString(R.string.unable_to_find_location));
builder.setMessage(getResources().getString(R.string.message_denied_location_permission));
builder.setCancelable(false);
builder.setPositiveButton(getResources().getString(R.string.go_to_settings), (dialog, which) -> {
dialog.dismiss();
builder = null;
if (!checkPermission(MainActivity.this)) {
goToSettings();
}
});
builder.show();
}
In the check permissions method:
public boolean checkPermission(Context context) {
int result = ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);
return result == PackageManager.PERMISSION_GRANTED;
}
The goToSettings() allows the user to go to Settings screen:
private void goToSettings() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, 1);
}
Note: You need to give the below permissions in the manifest to scan the beacons. I hope you are doing that, if not please do it.
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
As of Android Marshmallow (6.0), Location must be turned on in settings for apps to scan for Bluetooth LE devices including beacons. This requirement is in addition to the requirement that apps get dynamic permissions. You can see code below to query for location services being turned on and to prompt the user to turn it on if needed.
private void verifyLocationServices() {
final LocationManager manager = (LocationManager) getSystemService(this.LOCATION_SERVICE);
if (!manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("This app requires that location services be enabled. Please enable location in settings.")
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int id) {
startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
});
final AlertDialog alert = builder.create();
alert.show();
}
}
I'm trying to start a call intent action on a device who has Marshmallow as OS, Using the same steps as usual (This is working on versions below):
Add permission:
<uses-permission android:name="android.permission.CALL_PHONE" />
Open the intent:
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + getString(R.string.connect_phone)));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
This is the log I'm getting:
FATAL EXCEPTION: main
Process: com.app.calling, PID: 4250
java.lang.SecurityException: Permission Denial: starting Intent {
act=android.intent.action.CALL dat=tel:xxxxxxxxxxxxx flg=0x10000000
cmp=com.android.server.telecom/.components.UserCallActivity
VirtualScreenParam=Params{mDisplayId=-1, null, mFlags=0x00000000)} }
from ProcessRecord{1618b01 4250:com.app.calling/u0a234} (pid=4250,
uid=10234) with revoked permission android.permission.CALL_PHONE
at android.os.Parcel.readException(Parcel.java:1620)
at android.os.Parcel.readException(Parcel.java:1573)
at
android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:3130)
at
android.app.Instrumentation.execStartActivity(Instrumentation.java:1540)
at android.app.Activity.startActivityForResult(Activity.java:4283)
at android.app.Activity.startActivityForResult(Activity.java:4230)
at
android.support.v4.app.FragmentActivity.startActivityFromFragment(FragmentActivity.java:849)
at
android.support.v4.app.FragmentActivity$HostCallbacks.onStartActivityFromFragment(FragmentActivity.java:907)
at android.support.v4.app.Fragment.startActivity(Fragment.java:919)
at
com.app.calling.activity.fragment.ConnectFragment$2.onGroupClick(ConnectFragment.java:44)
at
android.widget.ExpandableListView.handleItemClick(ExpandableListView.java:676)
at
android.widget.ExpandableListView.performItemClick(ExpandableListView.java:654)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3821)
at android.widget.AbsListView$3.run(AbsListView.java:5841)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
Again, this process is working fine in the previous version (Lollipop and kitkat)unfortunately isn't on Marshmallow, does anybody know why or what I'm missing?
Method to make call
public void onCall() {
int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.CALL_PHONE},
"123");
} else {
startActivity(new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:12345678901")));
}
}
Check permission
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case 123:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
onCall();
} else {
Log.d("TAG", "Call Permission Not Granted");
}
break;
default:
break;
}
}
Beginning in android 6.0 (API 23), dangerous permissions must be declared in the manifest AND you must explicitly request that permission from the user. According to this list, CALL_PHONE is considered a dangerous permission.
Every time you perform an operation that requires a dangerous permission, you must check if that permission has been granted by the user. If it has not, you must request that it be granted. See Requesting Permissions at Run Time on Android Developers.
For Marshmallow version and above you need to ask the permission at runtime not only in the manifest file. Here is the documentation:
Requesting Permissions at Run Time
Hope it helps.
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.