0

In my application I am sending a port SMS to the mobile. And when the message is recieved I need to perform some task in my activity and update the UI.

Manifest Declaration of receiver

 <receiver android:name="com.vfi.BinarySMSReceiver" >
        <intent-filter android:priority="10" >
            <action android:name="android.intent.action.DATA_SMS_RECEIVED" />

            <data
                android:host="*"
                android:port="9512"
                android:scheme="sms" />
        </intent-filter>
    </receiver>

Receiver class

public class BinarySMSReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    Bundle bundle = intent.getExtras();
    SmsMessage[] msgs = null;

    if (null != bundle) {
        String info = "SMS from ";
        String sender = "";
        String msg = "";

        Object[] pdus = (Object[]) bundle.get("pdus");

        msgs = new SmsMessage[pdus.length];
        byte[] data = null;

        for (int i = 0; i < msgs.length; i++) {
            msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
            sender += msgs[i].getOriginatingAddress();
            info += msgs[i].getOriginatingAddress() + "\n";

            data = msgs[i].getUserData();

            for (int index = 0; index < data.length; ++index) {
                info += Character.toString((char) data[index]);
                msg += Character.toString((char) data[index]);
            }
        }
        Log.e("SakjsdMS", "akjsdhkas" + msg);
        Log.e("sender", "asdasdasdasdasdasd" + info);

        ((VerifyActivity)context).msgReceived(msg);
    }
}
}

Method in activity

public  void msgReceived(String msgContent)
{
    if(msgContent.equalsIgnoreCase(etMobile.getText().toString().trim())){
        showToast("Number Verified");
    }else{
        showToast("Sorry wrong number. Input your number again.");
    }

}

The exception I get

java.lang.RuntimeException: Unable to start receiver com.vfi.BinarySMSReceiver: java.lang.ClassCastException: android.app.ReceiverRestrictedContext cannot be cast to com.vfi.VerifyActivity
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2467)
        at android.app.ActivityThread.access$1700(ActivityThread.java:145)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1319)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5127)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:825)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:641)
        at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.ClassCastException: android.app.ReceiverRestrictedContext cannot be cast to com.vfi.VerifyActivity
        at com.vfi.BinarySMSReceiver.onReceive(BinarySMSReceiver.java:46)
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2460)

            at android.app.ActivityThread.access$1700(ActivityThread.java:145)

How can I get activity context in reciever to call my method??

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
WISHY
  • 11,067
  • 25
  • 105
  • 197
  • use `startActivity` if you want to talk to your Activity – pskink Jun 04 '15 at 09:19
  • I want to call a method in my activity after receiving the msg.... – WISHY Jun 04 '15 at 09:21
  • yes i know, use `startActivity()` – pskink Jun 04 '15 at 09:23
  • Your `context` isn't an `Activity`, that's why you can't cast it. Also your `Activity` may not be running when the broadcast is received, which is why you can't just "call a method on it". If you want to start your `Activity` when it's not running you have to use `startActivity()`, if not, you can use a local broadcast to communicate with a running instance if it exists. – ci_ Jun 04 '15 at 09:23
  • @ci_ no need for another local broadcast: `startActivity()` will be enough in both cases – pskink Jun 04 '15 at 09:25
  • @pskink no it's not (necessarily), if you call `startActivity()` and an instance of that `Activity` already exists, it will be brought to the foreground, but a new `Intent` will not be delivered. Unless you launch it as `singleTop` ... and override `onNewIntent()`, which has other implications. – ci_ Jun 04 '15 at 09:27
  • @ci_ what other implications do you mean? this is a std way of passing data to running Activities – pskink Jun 04 '15 at 09:28
  • @pskink Well, singleTop is a different launchmode, you may not want that behaviour of only having one instance of it. Another standard way of passing data to running Activities is a local broadcast. – ci_ Jun 04 '15 at 09:31
  • @ci_ `LocalBroadcastManager` is in support library so it is no so "standard" – pskink Jun 04 '15 at 09:33

5 Answers5

2

I was able to solve it by declaring receiver programmatically:

In the activity befor sending the message

private void sendSMS() {
    BinarySMSReceiver smsReceiver = null;
    smsReceiver = new BinarySMSReceiver();
    smsReceiver.setActivityHandler(this);
    IntentFilter portIntentFilter = new IntentFilter("android.intent.action.DATA_SMS_RECEIVED");
    portIntentFilter.addDataAuthority("*", "9512");
    portIntentFilter.addDataScheme("sms");
    registerReceiver(smsReceiver, portIntentFilter);



        String messageText = etMobile.getText().toString().trim();
        short SMS_PORT = 9512;
        SmsManager smsManager = SmsManager.getDefault();
        smsManager.sendDataMessage(etMobile.getText().toString().trim(), null, SMS_PORT, messageText.getBytes(), null, null);
}

In receiver class

 public class BinarySMSReceiver extends BroadcastReceiver {
    VerifyActivity vAct = null;

    void setActivityHandler(VerifyActivity main) {
        vAct = main;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getExtras();
        SmsMessage[] msgs = null;

        if (null != bundle) {
            String info = "SMS from ";
            String sender = "";
            String msg = "";

            Object[] pdus = (Object[]) bundle.get("pdus");

            msgs = new SmsMessage[pdus.length];
            byte[] data = null;

            for (int i = 0; i < msgs.length; i++) {
                msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
                sender += msgs[i].getOriginatingAddress();
                info += msgs[i].getOriginatingAddress() + "\n";

                data = msgs[i].getUserData();

                for (int index = 0; index < data.length; ++index) {
                    info += Character.toString((char) data[index]);
                    msg += Character.toString((char) data[index]);
                }
            }

            Log.e("message", "receiver " + msg);
            Log.e("sender", "from " + info);
            vAct.msgReceived(msg);  //activity method
        }
    }
}

Unregister the receiver

 @Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(smsReceiver);
}
mohammadReza Abiri
  • 1,759
  • 1
  • 9
  • 20
WISHY
  • 11,067
  • 25
  • 105
  • 197
  • You need to unregister the receiver somewhere or it will be registered every time you send an sms from your activity. – ci_ Jun 04 '15 at 11:02
1

The error you get is that you are wrongly casting a android.app.ReceiverRestrictedContext to a com.vfi.VerifyActivity.

If you want to achieve what you want to do simply start your activity by giving it some extra information.

public class BinarySMSReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
    Bundle bundle = intent.getExtras();
    SmsMessage[] msgs = null;

    if (null != bundle) {
        String info = "SMS from ";
        String sender = "";
        String msg = "";

        Object[] pdus = (Object[]) bundle.get("pdus");

        msgs = new SmsMessage[pdus.length];
        byte[] data = null;

        for (int i = 0; i < msgs.length; i++) {
            msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
            sender += msgs[i].getOriginatingAddress();
            info += msgs[i].getOriginatingAddress() + "\n";

            data = msgs[i].getUserData();

            for (int index = 0; index < data.length; ++index) {
                info += Character.toString((char) data[index]);
                msg += Character.toString((char) data[index]);
            }
        }
        Log.e("SakjsdMS", "akjsdhkas" + msg);
        Log.e("sender", "asdasdasdasdasdasd" + info);

        // HERE COMES THE CHANGE
        Intent intent = new Intent(context, YourActivityToLaunch.class);
        intent.putExtra("message_received", msg);
        context.startActivity(intent);
    }
}
}

And in your other class simply retrieve your message this way :

Intent intent = getIntent();
String message = intent.getStringExtra("message_received");

That's it.

Hope this help !

WannaGetHigh
  • 3,826
  • 4
  • 23
  • 31
0

The Context that your BinarySMSReceiver is passed in onReceive is not an Activity - it is the Context in which the receiver is running. To start an Activity, you need to use context.startActivity(Intent) and pass any additional data to the Activity using the Intent.

AesSedai101
  • 1,502
  • 2
  • 23
  • 37
-1

that ((VerifyActivity)context).msgReceived(msg); that's your mistake. Why are you assuming that this context is your activity?

The best way (without 3rd party libraries) to do this is to send a local broadcast.

On this other answer I gave a general idea on how to use LocalBroadcast Best practice to launch AsyncTask from custom view

if you're Ok using 3rd party libraries I suggest you check Otto from Square

Community
  • 1
  • 1
Budius
  • 39,391
  • 16
  • 102
  • 144
-3

Your BroadcastReceiver doesn't know anything about any activity by default. You will have to give the context to it, for example in your constructor when you create the broadcastReceiver.

private Activity activity;
public BroadcastReceiver(Activity activity) {
    super();
    this.activity = activity;
}

In you onReceive method you will now be able to use your activity in whatever way you like.

Aster
  • 809
  • 2
  • 8
  • 13
  • 1
    That's not correct. That constructor will not be used by the system to instantiate the `BroadcastReceiver`. – ci_ Jun 04 '15 at 09:24
  • getting this error "can't instantiate class com.vfi.BinarySMSReceiver; no empty constructor" – WISHY Jun 04 '15 at 09:26
  • Ok, wasn't aware that you couldn't use the constructor in this, because I didn't know how you instantiated your BroadcastReceiver in this case. You could still use the principle: give your broadcastReceiver a reference to your activity that you store in a private field. If you do this directly after creation, you have your reference to your Activity to use later on. – Aster Jun 04 '15 at 09:33
  • 1
    @Aster "give your broadcastReceiver a reference to your activity" it is impossible, you cannot do that – pskink Jun 04 '15 at 09:39
  • @Aster read the question again, the receiver is declared in the manifest, it's not manually instantiated in any way, the system does it, and there is no way you can pass it an activity context – ci_ Jun 04 '15 at 09:44