Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

BroadcastReceiver not working after BOOT_COMPLETED

I'm trying to intercept incoming SMS right after boot_completed but i'm having a problem with a NullPointerException in this line:

Object[] rawMsgs=(Object[])intent.getExtras().get("pdus");

Here's my manifest:

    <uses-permission android:name="android.permission.SEND_SMS"></uses-permission> 
    <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission> 
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-    permission>
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar">
        <receiver android:name=".SMSReceiver" 
            android:permission="android.permission.BROADCAST_SMS"
            > 
            <intent-filter android:priority="1000"> 
                <action     android:name="android.provider.Telephony.SMS_RECEIVED"></action>
                <action android:name="android.intent.action.BOOT_COMPLETED"></action>
            </intent-filter> 
        </receiver>
    </application>

Receiver:

public class SMSReceiver extends BroadcastReceiver 
    { 


    private final LocationListener locationListener = new LocationListener() {
          public void onLocationChanged(Location location) {


          }

          public void onProviderDisabled(String provider){}
          public void onProviderEnabled(String provider) {}
          public void onStatusChanged(String provider, int status, Bundle extras) {} 
        };

    @Override
    public void onReceive(Context context, Intent intent) {


        LocationManager lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE); 
        //Get as fine grained location as possible, while saving battery life.
        Criteria criteria = new Criteria();
        criteria.setAccuracy(Criteria.ACCURACY_FINE);
        criteria.setAltitudeRequired(false);
        criteria.setBearingRequired(false);
        criteria.setCostAllowed(true);
        criteria.setPowerRequirement(Criteria.POWER_LOW);
        String provider = lm.getBestProvider(criteria, true);
        Toast toast3 = Toast.makeText(context, "Provider: "+provider, Toast.LENGTH_LONG);
        toast3.show();

        Object[] rawMsgs=(Object[])intent.getExtras().get("pdus");

        for (Object raw : rawMsgs) {
            SmsMessage msg=SmsMessage.createFromPdu((byte[])raw);
            SmsManager sms = SmsManager.getDefault();
            if (msg.getMessageBody().toUpperCase().contains("LOC")) {
                Log.w("SMS:"+msg.getOriginatingAddress(),
                            msg.getMessageBody());
                Toast toast1 = Toast.makeText(context, "Phone Number: "+msg.getOriginatingAddress()+" Message: "+msg.getMessageBody(), Toast.LENGTH_LONG);
                toast1.show();
                abortBroadcast();

                if(provider!=null){


                    lm.requestLocationUpdates(provider, 0, 0, locationListener);

                    if(lm != null)
                    {

                        Location last_good = lm.getLastKnownLocation(provider);
                        if(last_good != null)
                        {
                            Toast.makeText(context, "Got Message from " + msg.getOriginatingAddress() + " , Sending" + last_good.toString(),     Toast.LENGTH_SHORT).show();
                            //sendSMS(msg.getOriginatingAddress(), "http://maps.google.com?q=" + last_good.convert(last_good.getLatitude(), Location.FORMAT_DEGREES) + "," + last_good.convert(last_good.getLongitude(), Location.FORMAT_DEGREES), context);

                            //sendSMS(msg.getOriginatingAddress(), last_good.getLatitude() + "," + last_good.getLongitude(), context);
                            sms.sendTextMessage(msg.getOriginatingAddress(), null, last_good.getLatitude() + "," + last_good.getLongitude(), null, null); 
                            lm.removeUpdates(locationListener);
                        }
                        else
                        {
                            lm.removeUpdates(locationListener);
                                sendSMS(msg.getOriginatingAddress(),"Location Not Available. Possible Reasons: Phone is Off, GPS is Off, No Satellites in sight", context);

                        }
                    }

                }
                else{
                    sendSMS(msg.getOriginatingAddress(),"Location Not Available. Possible Reasons: Phone is Off, GPS is Off, No Satellites in sight", context);

                }



            }
        }
     }

Thanks.

like image 240
bond Avatar asked Jul 29 '11 20:07

bond


People also ask

What is the use of BroadcastReceiver in android?

Android BroadcastReceiver is a dormant component of android that listens to system-wide broadcast events or intents. When any of these events occur it brings the application into action by either creating a status bar notification or performing a task.

How to register receiver in android?

If the receiving class is not registered using in its manifest, you can dynamically instantiate and register a receiver by calling Context. registerReceiver().

What is boot complete?

android.intent.action.BOOT_COMPLETED. It sends a message to the system that the boot has been completed. So using this broadcast we can call our MainActivity which means that when the system boot is completed then the app launches.


1 Answers

The problem here is that your BroadcastReceiver implementation has been mapped to two intents - android.provider.Telephony.SMS_RECEIVED and android.intent.action.BOOT_COMPLETED - but in the onReceive implementation you're not checking which intent you are processing.

My guess is that android.intent.action.BOOT_COMPLETED has been received and intent.getExtras() is returning null. You could confirm this by adding some logging to the method and watching the logcat window (if you're using Eclipse).

If you write a service or broadcast receiver and map it to multiple intents it is good practice - nay essential - to check which intent has been received and process it appropriately. Personally I'd go for something like this:

if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
    // boot-related processing here
}
else if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
    // SMS-related processing here
}
else {
    // intent not handled - log as a warning as you've registered to receive it
}

You can't assume fail-safe behaviour. For clarity, move the intent processing logic into a separate method:

if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
    processBootCompletedIntent(intent);
}
else if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
    processSmsReceivedIntent(intent);
}
else {
    // intent not handled - log as a warning as you've registered to receive it
}

PS - most (if not all) 'native' intent action strings are held as constants in a relevant class. For example android.intent.action.BOOT_COMPLETED is defined as Intent.ACTION_BOOT_COMPLETED. Use the constants where they exist, it'll save you making any typing errors.

like image 198
Phil Haigh Avatar answered Oct 17 '22 23:10

Phil Haigh