I'm doing similar to what discussed here:
Android BroadcastReceiver within Activity
I have application that runs with or without UI. When screen is off it's just working on background. When UI is on and visible - I would like to let user know that something just happened.
So, I followed samples in topic above and registered broadcast receiver on my Activity. I register onResume and unregister on onPause
private BroadcastReceiver uiNeedToBeUpdatedReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
// TODO Auto-generated method stub
Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG);
}
};
#Override
protected void onPause()
{
Log.d(LOG_TAG, "onPause");
super.onPause();
// TODO: Unregister broadcast receiver
unregisterReceiver(uiNeedToBeUpdatedReceiver);
}
#Override
protected void onResume()
{
Log.d(LOG_TAG, "onResume");
super.onResume();
// TODO: Register for broadcast events
IntentFilter filter = new IntentFilter();
filter.addAction("com.my.uineedtobeupdated");
registerReceiver(uiNeedToBeUpdatedReceiver, filter);
Inside my AsyncTask that runs on background I do this:
// Send broadcast - if UI active it will see it:
Intent broadcast = new Intent();
broadcast.setAction("com.my.uineedtobeupdated");
MyApplication.Me.sendBroadcast(broadcast);
Well, everyting works. I get broadcasts and I see in my debugger that I'm hitting line where Toast should show. But I don't see any toast popping up.
Is that threading issue? I though if I receive broadcast it shuld be on UI thread? Why do I observe this behavior?
It's important not only to create the Toast, but actually display it. The easy way:
Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG).show();
You can also, of course:
Toast myToast = Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG);
myToast.show();
Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG);
You are making a Toast, but you are not showing it. You need to call show on it, like this:
Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG).show();
Related
Hello fellow overflowers. I have a problem with a BroadcastReciever - there are, I know a multitude of questions and answers exist because I have been trying each one for the last 2 days so please if you do want to mark this as a duplicate check that the code doesn't match what I've already written (as I have almost certainly copied it form a SO answer).
And so here we go:
I want to detect the lock screen being turned on or off in my base activity - from which all my other activities extend
public abstract class BaseActivity extends AppCompatActivity{////
in here I have member variables
BroadcastReceiver receiver;
IntentFilter filter;
which I assign like this:
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//do some code
} else {
//do something else
}
}
};
filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
This works as expected if I put it in onCreate() or in onResume() and I can successfully call registerReceiver(receiver, filter) in either create or resume and it works fine.
I don't want this to be active when the app is paused, so as all the various answers and tutorials suggest I unregister it in onPause
#Override
protected void onPause() {
//I have commented both out to demonstrate that I have tried both before and after the calling the superclass
// this.unregisterReceiver(receiver);
super.onPause();
// unregisterReceiver(receiver);
}
When I include this unregister call it stops the registration from ever happening. I have tried registering in onCreate,onResume and both. I can move around the combination all through the activity but as soon as I introduce the unregister it doesn't work at all - not even an error or a crash (otherwise I would include a stack trace here).
The closes thing I have been able to achieve is:
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//do some code
unregisterReceiver(receiver);
by putting the unregister into the onRecieve I am am able to deregister the receiver and re-register it correctly, EXCEPT that if I have multiple activities in the stack for my app I get a memory leak error and the trace requests, rather patronisingly if I have forgotten to add an unregister call.
So has anyone any idea why adding the unregister call to the onPause() would cause the receiver to cancel altogether?
As I thought, you have this issue because system sends ACTION_SCREEN_OFF after onStop() method, so you can not handle it, because you already unregistered it. Don't know why you can not handle SCREEN_ON event, because when I tested this, I see that system send it after onResume(). This is what I have in my logs:
D/TEST: onPause:
D/TEST: onStop:
D/TEST: onReceive: action = android.intent.action.SCREEN_OFF
D/TEST: onStart:
D/TEST: onResume:
D/TEST: onReceive: action = android.intent.action.SCREEN_ON
I think, it was sent earlier than onResume called, but delivered after it.
So, my solution is to register receiver in onCreate(#Nullable Bundle savedInstanceState) and unregister in onDestroy(), that is how I got this logs.
Update 1: This is how I registered receiver in onCreate(#Nullable Bundle savedInstanceState)
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(new TestReceiver(), filter);
Update 2: I missed, that you don't need to receive events if your activity is paused. If there is some code that you don't want to execute when activity is paused, I can suggest you to create simple enum:
enum ActivityState {
STARTED, RESUMED, PAUSED, STOPPED
}
and private variable ActivityState currentState. Then in lifecycle methods assign proper state to currentState. Then in your receiver onReceive() method you can check current state and do what you want depend on state.
Logs when app is in active:
D/TEST: onReceive: action = android.intent.action.SCREEN_OFF, current Activity state = STOPED
D/TEST: onReceive: action = android.intent.action.SCREEN_ON, current Activity state = RESUMED
And logs when app was not active:
D/TEST: onReceive: action = android.intent.action.SCREEN_OFF, current Activity state = STOPED
D/TEST: onReceive: action = android.intent.action.SCREEN_ON, current Activity state = STOPED
I hope it helps!
I suggest delaying unregister for some times and I tried for 1 second and it's working.
override fun onResume() {
super.onResume()
registerReceiver(broadcast, IntentFilter().apply {
addAction(Intent.ACTION_SCREEN_ON)
addAction(Intent.ACTION_SCREEN_OFF)
})
}
override fun onPause() {
super.onPause()
Handler().postDelayed({
unregisterReceiver(broadcast)
}, 1000)
}
I'm trying to send messages through in built sms app through Intent. Its working fine. Here is my code
public class Main_Act extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button startBtn = (Button) findViewById(R.id.button);
startBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if(sendSMS()) {
Intent intent = new Intent(Main_Act.this, Sample.class);
startActivity(intent);
}
}
});
}
protected boolean sendSMS() {
ArrayList<String> nums = new ArrayList<String>();
nums.add("111111111");
nums.add("222222222");
Log.i("Send SMS", "");
Intent smsIntent = new Intent(Intent.ACTION_VIEW);
smsIntent.setData(Uri.parse("smsto:"));
smsIntent.setType("vnd.android-dir/mms-sms");
smsIntent.putExtra("address" ,nums);
smsIntent.putExtra("sms_body" , "Test ");
try {
startActivity(smsIntent);
finish();
return true;
}
catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(Main_Act.this,
"SMS faild, please try again later.", Toast.LENGTH_SHORT).show();
return false;
}
}
}
But the problem is it gets navigated to another activity without clicking send button in sms application. It should goto another activity only after clicking the send button in messaging app. Can anyone help me with this problem, Thanks in advance.
Let's clear out a slight misunderstanding in your code:
You should not try to start both intents in the same part/run of the code as you do here.
A startActivity will not execute directly going to the activity and then return to the same place in the code when activity execution finishes. In stead it asynchronously queues the intent for execution. Then your code queues another intent for execution. After the current code finishes (in this case when the button onClick() method ends) Android queue mgmt can start picking off the queue. Probably the first intent is executed shortly and then directly overrun by an immediate execution of the second.
So what happens in summary is that you first add one intent to the queue in sendSMS and then add intent 2 to the queue in onClick, before leaving. Now both the intents are executed.
What you need to do is to change the sendSMS code to something like:
Intent smsIntent = new Intent(Intent.ACTION_VIEW);
smsIntent.setData(Uri.parse("smsto:"));
smsIntent.setType("vnd.android-dir/mms-sms");
smsIntent.putExtra("address" ,nums);
smsIntent.putExtra("sms_body" , "Test ");
// To force the SMS app to return immediately after sent SMS
smsIntent.putExtra("exit_on_sent", true);
startActivityForResult(smsIntent, MY_SMS_REQUEST_RESPONSE_CODE);
Note the startActivityForResult() method that indicates that we expect Android to return and the "exit_on_sent" extra, to force a swift return.
MY_SMS_REQUEST_RESPONSE_CODE is just any random code you select to recognize the returning result in the callback method (even if you currently do not expect any other returning results, you may have some in the future).
Next thing to do is to remove the second intent creation and queuing. In stead you implement the following callback method (added to this activity):
#Override
protected void onActivityResult(
int callbackIdentifier, int resultCode, Intent intent) {
// Is this the expected sendSMS callback ?
if (callbackIdentifier== MY_SMS_REQUEST_RESPONSE_CODE) {
if (resultCode == RESULT_OK) {
// Continue where you left off (e.g. execute intent 2)
Intent intent = new Intent(Main_Act.this, Sample.class);
startActivity(intent);
} else if (resultCode == RESULT_CANCELED) {
// Error handling/retrying etc
}
}
// Support inherited callback functions
super.onActivityResult(callbackIdentifier,resultCode,intent);
}
Note: if you want to pass data and type don't call method separately because will delete each other you must pass it in one method
wrong
smsIntent.setData(Uri.parse("smsto:"));
smsIntent.setType("vnd.android-dir/mms-sms");
true
smsIntent.setDataAndType(Uri.parse("smsto:"),"vnd.android-dir/mms-sms");
Is there anyway to check if onResume was called from the device waking up from sleep state in Android?
The reason why I need to check that is I don't want it to call a particular method if resumed from sleep state:
#Override
public void onResume() {
super.onResume();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())
&& !SomeCrazyMethodOrPropertyCheckingIfDeviceWakedUpFromSleep) {
processIntent(getIntent());
}
}
You might say "Take that processintent method out of onResume"... It's not an option, NFC P2P mode requires you to process the received NDEF message inside onResume.
I would recommend overriding onNewIntent() to handle the NFC intents:
#Override
public void onNewIntent(final Intent intent) {
setIntent(intent);
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
processIntent(intent);
}
}
In processIntent() you can check whether the intent was handled already:
private void processIntent(final Intent intent) {
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
// Log.v(TAG, "Ignoring intent; already treated this intent.");
return;
}
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
// new intent; process it
...
}
Likely this will solve your problem.
I think you can try to do something with ACTION_SCREEN_ON :
register a receiver for it (you need to it in code, it won't work in manifest).
in the onReceive do something like:
MY_FLAG_JUST_WAKE_UP = true;
and in the onResume() :
if(!MY_FLAG_JUST_WAKE_UP){
doStuff();
}
MY_FLAG_JUST_WAKE_UP = false;
But, it need to be tested, I don't know if you will always receive the intent before the onResume() get called.
I am loading an HTTP request in the background using loopj HTTP CLIENT and when it is done, I want to display a "success" notification (dialog, toast, etc.)
I have the code in a seperate (non-activity) class with a static method that executes the background request. In the end, the response is in a AsyncHttpResponseHandler under a onSuccess method. In this method, I can print out the response, confirm that the request went through, save data to the sd card/ Shared Preferences, but how do I access the UI thread to display a notification?
Thanks in advance.
you can do it using a Handler, or by calling Activity.runOnUiThread(). so you either pass a Handler, or an Activity object to your static method, then in your onSuccess() method, do,
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
// i'm on the UI thread!
}
}
);
or,
handler.post(new Runnable() {
#Override
public void run() {
// i'm on the UI thread!
}
}
);
I guess you mean a service as a background process. Service has many built in methods like onCreate, onStartCommand, onDestroy, etc. I suggest using a Notification, because notifications do not require a UI thread to do the job.
Create a method to generate a notification and call it after your HTML read is over.
private static void generateNotification(Context context, String message) {
int icon = R.drawable.ic_stat_gcm;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
String title = context.getString(R.string.app_name);
Intent notificationIntent = new Intent(context, MainActivity.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
}
You could fire a local broadcast with the message, and show a toast with a receiver.
Do this in the class doing the updates:
Intent intent = new Intent("ACTION_TOAST");
intent.putExtra("message", "Success!");
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
Then in any activity that might want to know about the update, do this:
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if ("ACTION_TOAST".equals(intent.getAction()) {
Toast.makeText(MyActivity.this, intent.getStringExtra("message"),
Toast.LENGTH_SHORT).show();
}
}
}
#Override
protected void onStart() {
super.onStart();
LocalBroadcastManager.getInstance(this).registerReceiver(
receiver, new IntentFilter("ACTION_TOAST"));
}
#Override
protected void onStop() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
You still need to pass a context into your static method, but this works even if that context is a Service or some other context that can't show Toasts / create UI.
I created my lockscreen application that trigerred by a SMS.. i have ListenSMS class that always listen for incoming SMS. Here's the code :
for (SmsMessage message : messages) {
String tempMessage[] = message.getDisplayMessageBody().toString().split(" ");
//checking command dan password
if (tempMessage[0].toString().equalsIgnoreCase("andro-lock") && tempMessage[1].toString().equals(tempPassword.toString())) {
//Toast.makeText(ListenSMSservice.this, "Menjalankan command andro-lock", Toast.LENGTH_LONG).show();
openDatabase();
updateStatusL();
Intent myIntent = new Intent(ListenSMSservice.this,LockScreenForm.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(myIntent);
}
else if (tempMessage[0].toString().equalsIgnoreCase("andro-unlock") && tempMessage[1].toString().equals(tempPassword.toString())) {
//Toast.makeText(ListenSMSservice.this, "Menjalankan command andro-unlock", Toast.LENGTH_LONG).show();
openDatabase();
updateStatusNL();
Intent myIntent = new Intent(ListenSMSservice.this,LockScreenForm.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Bundle myKillerBundle = new Bundle();
myKillerBundle.putString("kill","1");
myIntent.putExtras(myKillerBundle);
getApplication().startActivity(myIntent);
}
}
If ListenSMS service has received an andro-lock command, it will go to the lockscreen.java and will go to the lockscreen.java with intent extra (putExtra) kill when it receive command andro-unclock. Here's my lockscreen.java:
public class LockScreenForm extends Activity implements OnClickListener {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.lockscreen);
Bundle extra = getIntent().getExtras();
if (extra == null) {
return;
}
//Toast.makeText(this, extra.getString("kill"), 1).show();
else if(this.getIntent().getExtras().getString("kill").equalsIgnoreCase("1")) {
try {
Toast.makeText(this, "extra accepted", 1).show();
finish();
} catch (Exception e) {
// TODO: handle exception
Toast.makeText(this, e.getMessage(), 1).show();
}
}
}
}
I want to close my locksreen.java when my ListenSMS service has received "andro-unlock" command, so I put extra on intent "kill" and check it in lockscreen.java. This lockscreen.java can check the extra intent and can display a toast "extra accepted" but can close the lockscreen activity with finish().
My assumption is for now that Intent.FLAG_ACTIVITY_NEW_TASK is duplicating a locksreen activity. So it will create a double lockscreen activity and the finish method is closing another lockscreen.java that started by Intent.FLAG_ACTIVITY_NEW_TASK. That's only assumption. Am i wrong? Please correct me.
Has anyone know how to solve my problem? I really want that "andro-unlock" command can close the lockscreen activity and need it works for my college final project. Please help.
From http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_NEW_TASK:
When using this flag, if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front of the screen with the state it was last in. See FLAG_ACTIVITY_MULTIPLE_TASK for a flag to disable this behavior.
I expect your problem is somewhere else. I'd suggest having the lockscreen Activity register a BroadcastReceiver, and then when the unlock message is received send an Intent that the BroadcastReceiver will catch. The Activity can then cleanly exit.
Try this: Intent.FLAG_ACTIVITY_NEW_TASK