13

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.

Imdad
  • 683
  • 1
  • 9
  • 27

3 Answers3

16

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.

Matt Taylor
  • 3,360
  • 1
  • 20
  • 34
Artur Szymański
  • 1,639
  • 1
  • 19
  • 22
  • 1
    Thanks man. Got it here - http://developer.android.com/about/versions/marshmallow/android-6.0-changes.html – Imdad Oct 09 '15 at 12:14
  • @Jack's retarded code - Request if you can explain how you resolved your issue. I'm facing the exact same issue... Thanks! – Kanchu Jan 31 '16 at 14:57
  • 1
    @Kanchu you need Runtime permissions for Android M, simply declaring it in Manifest won't be enough. Ask runtime permission when using the feature that reauires the permission. To implement Runtime permissions see android developers guide or simply google it(plenty of links). – Imdad Feb 03 '16 at 13:11
  • 2
    Thanks, I was struggling with this for 2 days, this solved the issue- https://developer.android.com/training/permissions/requesting.html – Harshveer Singh Jun 11 '16 at 11:09
10

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:

  1. 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

  2. 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:

  1. If you need to use PermissionManager.check inside Fragment instance, use: getActivity() as its first parameter.

  2. 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

Nikita Kurtin
  • 5,889
  • 4
  • 44
  • 48
  • This doesn't resemble the answer of this problem. I think permission has nothing to do with doze mode and not calling broadcast. – Mostafa Imran Nov 14 '17 at 08:54
3

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.

FinHead
  • 517
  • 4
  • 12