Get message from broadcast receiver to activity - android

I know this question has been asked many times but still i am unable to solve my problem.I want to get the OTP from the SMS in the editText of the Activity.For this i am using broadcast receiver.
Code for broadcast receiver:
private static final String TAG = ReceiveSms.class.getSimpleName();
private SmsReceivedListner smsReceived = null;
#Override
public void onReceive(Context context, Intent intent) {
//code to get sms....
Log.e(TAG, "OTP received: " + verificationCode);
if (smsReceived != null) {
smsReceived.onSmsReceived(verificationCode);
} else {
if (Constants.isLoggingEnable) {
Logger.logError(TAG, "Sms listner is null");
}
}
}
}
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.getMessage());
}
}
public void setOnSmsReceivedListener(Context context) {
this.smsReceived = (SmsReceivedListner) context;
}
Activity Code
public class EnterOtp extends MasterActivity implements View.OnClickListener, OnTaskComplete, SmsReceivedListner {
private static final String TAG = EnterOtp.class.getSimpleName();
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.otp);
context = this;
init();
}
private void init() {
setUpToolbar();
receiveSms = new ReceiveSms();
receiveSms.setOnSmsReceivedListener(this);
}
I have used interface but always i am getting it as null.So what can i do to get the otp.
P.S-
I dont want to start new Activity via intent because the activity is running only, so if via Intent can i pass the otp without starting new Activity and also maintaing the back stack as well?

If you want receive sms only when activity is running use this code:
private void init()
{
receiveSms = new ReceiveSms();
receiveSms.setOnSmsReceivedListener(this);
registerReceiver(receiveSms, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
}
And remove this receiver from AndroidManifest.xml
I hope it helped you.
EDIT:
In onDestroy you must use this code:
protected void onDestroy()
{
super.onDestroy();
// ...
unregisterReceiver(receiveSms);
}

Related

Communication between BroadcastReceiver and Activity using interface

Folks!
I'm trying to implement BroadcastReceiver for listening to incoming Message using SMSRetrieverAPI.
I'm getting messages in Broadcast's onReceive method but after that, I have to pass that Message String in activity without restarting it, So I have implemented interface.
I have tried below code but, it throws NullPointerException for mOTPReceiveListener. Something didn't work perfectly so please correct me.
SMSBroadcastReceiver is like below
public class SMSBroadcastReceiver extends BroadcastReceiver {
OTPReceiveListener mOTPReceiveListener = null;
public void InitOTPReceiveListener(OTPReceiveListener otpreceivelistener){
this.mOTPReceiveListener = otpreceivelistener;
}
#Override
public void onReceive(Context context, Intent intent) {
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
Bundle extras = intent.getExtras();
Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
switch(status.getStatusCode()) {
case CommonStatusCodes.SUCCESS:
// Get SMS message contents
String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
Log.e("VERIFY","Full Message : "+message);
if (mOTPReceiveListener != null) {
String[] temp = message.split("-");
String[] msg = temp[1].split(" ");
message = msg[0];
Log.e("VERIFY","message : "+message);
mOTPReceiveListener.onOTPReceived(message);
}
break;
case CommonStatusCodes.TIMEOUT:
// Waiting for SMS timed out (5 minutes)
mOTPReceiveListener.onOTPTimeOut();
break;
}
}
}
public interface OTPReceiveListener {
void onOTPReceived(String otp);
void onOTPTimeOut();
}
}
and the activity code
public class VerificationActivity extends BaseActivity implements SMSBroadcastReceiver.OTPReceiveListener
{
Context mContext;
Button btn_verify_submit;
TextView text_resend_otp;
private String TAG = "VERIFY";
private String PHONE = null;
private SmsRetrieverClient mSmsRetrieverClient;
private SMSBroadcastReceiver mSMSBroadcastReceiver;
SMSBroadcastReceiver.OTPReceiveListener mOTPReceiveListener;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_verification);
initView();
setClickListener();
PHONE = getIntent().getStringExtra("phone");
Log.e(TAG,"phone : "+PHONE);
mSmsRetrieverClient = SmsRetriever.getClient(this);
startVerify();
mOTPReceiveListener = this;
mSMSBroadcastReceiver = new SMSBroadcastReceiver();
mSMSBroadcastReceiver.InitOTPReceiveListener(this);
}
private void initView()
{
layout_verification_main = findViewById(R.id.layout_verification_main);
overrideFonts(layout_verification_main,VerificationActivity.this);
edt_verify_code = findViewById(R.id.edt_verify_code);
btn_verify_submit = findViewById(R.id.btn_verify_submit);
text_resend_otp = findViewById(R.id.text_resend_otp);
}
private void setClickListener()
{
btn_verify_submit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Call OTP Match API
}
});
text_resend_otp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Call Resend OTP API
}
});
}
private void startVerify() {
Task<Void> task = mSmsRetrieverClient.startSmsRetriever();
task.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.e(TAG, "SmsRetrievalResult start onSuccess.");
}
});
task.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG, "SmsRetrievalResult start failed.", e);
}
});
}
#Override
public void onOTPReceived(String otp) {
edt_verify_code.setText("" + otp);
Toast.makeText(mContext, "Message OTP : " + otp, Toast.LENGTH_SHORT).show();
Log.e("VERIFY","otp in activity : "+otp);
}
#Override
public void onOTPTimeOut() {
}
}
and I have registered in Manifest like this
<receiver android:name=".broadcast.SMSBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
</intent-filter>
</receiver>
Am I missing something?
The SMSBroadcastReceiver instance created from the definition in your manifest is NOT the same one you created in VerificationActivity.onCreate().
You can register the broadcast receiver from your activity using Context.registerReceiver().
To contact between activity and receiver what you are try is wrong as your listener is dependent on activities onCreate() i.e on lifecycle of Activity.
So to solve this you need to follow below step's:
Solution
Be sure that activity is alive by starting the activity from your receiver (startActitvity() using intent ) again. check this thread if you don't want to restart the activity again and want to be sure that activity is on screen.
Send a broadcast from your receiver to activity read this thread. No need of listener as activity can directly listen to message
you can combine both solution's for you own use case it will work.

OnDestroy exception in Main Activity using Android fragment

I am having a "Receiver no registered exception" in OnDestroy method of my app using fragments.
I have a MainActiviy class where I check if the user registered an account.
If not account created, I load the register account class fragment to allow the user create an account.
After the user create the account clicking a button I restart the MainActivity class.
I need to register a broadcastreceiver only after the user create an account.
But, after the restart the MainActivity class from Frgamnent Class, I am getting an exception of receiver not registered in event OnDestroy of Main Activity.
Any help to solve it will be appreciated.
Thanks in Advance, Luiz
My MainActivity Class
public class MainActivity extends Activity {
// if run on phone, isSinglePane = true
// if run on tablet, isSinglePane = false
static boolean isSinglePane;
private GcmUtil gcmUtil;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View v = findViewById(R.id.phone_container);
if (!AccountRegisterCreated()){
//this fragmment register an account to user, and save in Preferences
RegisterFragment myListFragment= new RegisterFragment();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.phone_container, myListFragment);
fragmentTransaction.commit();
return;
}
registerReceiver(registrationStatusReceiver, new IntentFilter(Common.ACTION_REGISTER));
}
private BroadcastReceiver registrationStatusReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null && Common.ACTION_REGISTER.equals(intent.getAction())) {
switch (intent.getIntExtra(Common.EXTRA_STATUS, 100)) {
case Common.STATUS_SUCCESS:
getActionBar().setSubtitle("online");
break;
case Common.STATUS_FAILED:
getActionBar().setSubtitle("offline");
break;
}
}
}
};
#Override
protected void onPause() {
ContentValues values = new ContentValues(1);
super.onPause();
}
#Override
protected void onDestroy() {
unregisterReceiver(registrationStatusReceiver);
super.onDestroy();
}
private boolean AccountRegisterCreated(){
SharedPreferences prefs;
prefs= PreferenceManager.getDefaultSharedPreferences(this);
String fullname = prefs.getString(DataProvider.COL_EMAIL,"");
if (!fullname.isEmpty()) {
return true;
}
return false;
}
}
My Fragment Class:
public class RegisterFragment extends Fragment {
private static SharedPreferences prefs;
static final String TAG = "pushabout";
TextView name;
TextView email;
TextView password;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.register, null);
name = (TextView) view.findViewById(R.id.reg_fullname);
email = (TextView) view.findViewById(R.id.reg_email);
password = (TextView) view.findViewById(R.id.reg_password);
if (email.getText().toString().isEmpty()){
email.setText(Common.getPreferredEmail());
}
Button mButton = (Button) view.findViewById(R.id.btnRegister);
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//checa email e reg e salva pref e registra gcm
prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
SharedPreferences.Editor editor = prefs.edit();
editor.putString(DataProvider.COL_NAME, sname);
editor.putString(DataProvider.COL_EMAIL, semail);
editor.putString(DataProvider.COL_PWD, spassword);
editor.commit();
Intent intent = new Intent(getActivity(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
});
return view;
}
}
The problem is not with the Fragment. It's the BroadcastReceiver in your Activity.
Try declaring your BroadcastReceiver as a class field:
public class MainActivity extends Activity {
...
BroadcastReceiver mBroadcastReceiver;
...
Then, you should change how you're creating and registering the receiver. The way I've done it is by registering during the activity's onResume instead of onCreate(). If you do this, you'll also need to unregister during onPause() instead of onDestroy(). It will look something like this:
#Override
public void onResume() {
super.onResume();
// Create and register your receiver here.
if (AccountRegisterCreated) {
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
....
}
}
registerReceiver(mBroadcastReceiver, new IntentFilter(Common.ACTION_REGISTER));
}
...
}
#Override
public void onPause() {
super.onPause();
// Unregister your receiver here
if (mBroadcastReceiver != null) {
unregisterReceiver(mBroadcastReceiver);
}
}
Just declare a member variable of type boolean. When you register the BroadcastReceiver, set that variable to true. In onDestroy() only call unregisterReceiver() if the variable is true.

Robospice Android - spiceRequest that begins in one activity and ends in another activity

I'm trying to start a robospice request in Activity A and then receive the results of the request in Activity B.
In Activity A
FetchSpiceRequest fetchSpiceRequest = new FetchSpiceRequest();
spiceManager.execute(fetchSpiceRequest, new ActivityB().postListener);
The PostListener implements PendingRequestListener and is sitting within Activity B.
In Activity B
We addListener for the pending request that was started in Activity A below.
#Override
protected void onStart() {
spiceManager.start( this );
spiceManager.addListenerIfPending(Post.class, 0, new PostListener());
We then implement the PostListener in Activity B below.
public final class PostListener implements PendingRequestListener<Post> {
#Override
public void onRequestFailure(SpiceException spiceException) {
Toast.makeText(MainActivity.this, "Exception: " + spiceException.toString(), Toast.LENGTH_SHORT).show();
}
#Override
public void onRequestSuccess(Post post) {
Toast.makeText(MainActivity.this, "Added", Toast.LENGTH_SHORT).show();
}
#Override
public void onRequestNotFound() {
Toast.makeText(MainActivity.this, "Request not found", Toast.LENGTH_SHORT).show();
}
}
Finally, we create a variable within Activity B called so that A can pick it up (eg. when I call new ActivityB().postListener):
public PostListener PostListener;
This doesn't work and it always calls onRequestNotFound in the PostListener.
What am I doing wrong?
I have also looked at this post: Robospice - keep spice service continue running when changing activity but #Snicolas doesn't seem to mention anything about how the spiceManager.execute statement should look like in the first activity.
Eventually, I had to use LocalBroadcastManager to achieve what I want to do:
Activity A
FetchSpiceRequest fetchSpiceRequest = new FetchSpiceRequest();
spiceManager.execute(fetchSpiceRequest, postListener);
Please note that postListener is situated within Activity A. It actually doesn't do much as all the work will now be performed inside the localbroadcastreceiver:
public final class AddPostListener implements RequestListener<Post> {
#Override
public void onRequestFailure(SpiceException spiceException) {
Toast.makeText(AddPostActivity.this, "Exception: " + spiceException.toString(), Toast.LENGTH_SHORT).show();
}
#Override
public void onRequestSuccess(Post post) {
Toast.makeText(AddPostActivity.this, "Added", Toast.LENGTH_SHORT).show();
Log.e("AddPostListener", "Background service finished"); }
Inside the fetchSpiceRequest, we perform the work asynchronously and once it is finished, we call the localbroadcast manager to send our results back to Activity B:
public class FetchSpiceRequest extends SpringAndroidSpiceRequest<Post> {
private Post mPost;
private Context mContext;
public AddPostSpiceRequest(Context context, Post post) {
super(Post.class);
mPost = post;
mContext = context;
}
#Override
public Post loadDataFromNetwork() throws Exception {
//Do some network activity to get a post and then after the network activity ends, send the post through the broadcast activity to Activity B
Intent intent = new Intent("my-event");
intent.putExtra("post", post);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
}
Activity B
Register your localBroadcast receiver:
#Override
public void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event")); }
Do something with the received message:
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
Post post = intent.getParcelableExtra("post");
Log.e("receiver", "Got message: " + post.getPostheader());
}
};

How to return values from a java class that extends another class into an Activity

Let's say that I've the following main activity:
public class MwConsoleActivity extends Activity {
private classChild child = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
child = new classChild();
}
}
Then consider the implementation of the class "classChild":
public class MwBondingAgent extends SapereAgent {
MwBondingAgent(){}
public void AddEventListener(childAddedEvent event) {
//Send the data of event back to the main activity
}
}
I've tried to use IntentServices but was not able to receive the values back to the main activity. What would be the approach I've to take?
Cheers
Ali
You can use and intentFilter to listen for broadcasts.
Add this to the activity:
IntentFilter intentFilter = new IntentFilter(
"com.unique.name");
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//extract our message from intent
String msg_for_me = intent.getStringExtra("some_msg");
}
};
//registering our receiver
this.registerReceiver(mReceiver, intentFilter);
In your class add this to the part you want to notify the activity:
Intent i = new Intent("com.unique.name").putExtra("some_msg", "I have been updated!");
this.sendBroadcast(i);
You should use the observer / listener pattern.
http://www.vogella.com/articles/DesignPatternObserver/article.html
It is one of the most used design patterns when using MVC architecture pattern.
Your question is quite unclear but I think what you are wanting is to implement a callback to your activity. You can do this using an interface.
public class MwConsoleActivity extends Activity implements MwBondingAgent{
private classChild child = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
child = new classChild();
}
#Override
public void gotEventData(EventData myEventData) {
//to whatever you want with myEventData
}
}
And in your other class.
public class MwBondingAgent extends SapereAgent {
private MwBondingAgentCallback activityCallback;
MwBondingAgent(Activity callback){
activityCallback = callback;
}
public void AddEventListener(childAddedEvent event) {
//Send the data of event back to the main activity
EventData myEventData = //got some event data;
//Send it back to activity
activityCallback.gotEventData(myEventData);
}
public interface MwBondingAgentCallback {
public void gotEventData(EventData myEventData);
}
}

NullPointerException on calling a public method from another activity

I have an Activity SaveData.class with a public method addEvent() use to add some information in a DataBase table as follows:
public class SaveData extends Activity implements OnClickListener {
public SoftCopyDatabase dB ;
public static String FILE_NAME;
String _subject, _topic,_lecturenumber,_date;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.save);
View add = findViewById(R.id.saveSave);
add.setOnClickListener(this);
View home = findViewById(R.id.saveBack);
home.setOnClickListener(this);
}public void onStart() {
super.onStart();
dB = new SoftCopyDatabase(this);
}
public void onStop() {
super.onStop();
if (dB.getReadableDatabase().isOpen()) {
//dB.close();
}
}
public void onDestroy() {
super.onDestroy();
if (dB.getReadableDatabase().isOpen()) {
dB.close();
}
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.saveBack:
Intent i = new Intent(this, OpenScreen.class);
startActivity(i);
break;
case R.id.saveSave:
EditText subject = (EditText) findViewById(R.id.subjectid);
EditText topic = (EditText) findViewById(R.id.topicid);
EditText lecturenumber = (EditText) findViewById(R.id.lecturenumberid);
EditText date = (EditText) findViewById(R.id.dateid);
_subject = ((TextView) subject).getText().toString();
_topic = ((TextView) topic).getText().toString();
_lecturenumber = ((TextView) lecturenumber).getText()
.toString();
_date = ((TextView) date).getText().toString();
FILE_NAME = _subject + _topic + _lecturenumber;
//addEvent();
Intent j = new Intent(this, LectureNoting.class);
startActivity(j);
break;
}
}
public void addEvent() {
ContentValues values = new ContentValues();
values.put(SUBJECT, _subject);
values.put(TOPIC, _topic);
values.put(LECTURENUMBER, _lecturenumber);
values.put(DATE, _date);
values.put(_DATA, FILE_NAME + ".png");
dB.getWritableDatabase().insertOrThrow(TABLE_NAME, null, values);
}
}
Another activity LectureNoting.class is used to save Drawings on the disk and updates the entry in Database Table as follows:
public class LectureNoting extends Activity implements View.OnTouchListener{
private SaveData sD=new SaveData();
private File directory = new File("/sdcard/SoftCopy");
//...remaining code
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.drawing_activity);
}
//...remaining code
public void onClick(View view){
switch (view.getId()){
case R.id.saveBtn:
addEvent();
final Activity currentActivity = this;
Handler saveHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
Toast.makeText(currentActivity, "Lecture Saved", Toast.LENGTH_SHORT).show();
}
} ;
new ExportBitmapToFile(this,saveHandler, softCopyInterface.getBitmap()).execute();
break;
//...remaining code
}
private class ExportBitmapToFile extends AsyncTask<Intent,Void,Boolean> {
private Context mContext;
private Handler mHandler;
private Bitmap nBitmap;
public ExportBitmapToFile(Context context,Handler handler,Bitmap bitmap) {
mContext = context;
nBitmap = bitmap;
mHandler = handler;
}
#Override
protected Boolean doInBackground(Intent... arg0) {
try {
if (!directory.exists()) {
directory.mkdirs();
}
final FileOutputStream out = new FileOutputStream(new File(directory + "/"+SaveData.FILE_NAME+".png"));
nBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
return true;
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return false;
}
#Override
protected void onPostExecute(Boolean bool) {
super.onPostExecute(bool);
if ( bool ){
mHandler.sendEmptyMessage(1);
}
}
}
}
And I am receiving following error:
Unable to start activity componentInfo(com.ned.LectureNoting):NullPointerException
At the addEvent(), used in the onClick method of LectureNoting.
Kindly tell me where I am going wrong. One point I would like to mention is if addEvent() is called from the same activity in which it was defined, this error does not appear.
Couple of things:
Logcat should be giving more information about the error. You may have to scroll down a bit to see the source of the problem in your code, but there should be more info.
you shouldnt be defining public methods inside of classes that extend Activity to be used by other classes. If you want to expose some database method to multiple activities, then create a separate class for that and then call that method inside of your activity. You said LectureNoting extends Activity. You sure about this? You must have it extending SaveData if you are just calling addEvent() like that.
Either way, DON'T CALL METHODS FROM ONE ACTIVITY INSIDE OF ANOTHER. If you want to expose a method to multiple activities, create it in it's own class with a sensible name related to the group of functions that you expose.

Categories

Resources