Well some months ago I learned the basics of android and now I'm triying to practice to remember what I learned. So the problem is that I'm doing an app that when it catches a change in the status of the screen (screen on/screen off) it does something. I want that when the app is not running (becausethe user killed it by pressing the home button or something like that) it still does what I want. I have decided to use receiver but I don't know if it's the correct option.
If the app is minimized it works but the problem whenthe user presses the "recent apps" button and slides the app. Then the receiver doesn't catch anything.
In the manifest I've declared:
<receiver android:name=".MyReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.SCREEN_ON"/>
<action android:name="android.intent.action.SCREEN_OFF"/>
</intent-filter>
</receiver>
My main activity (maybe I have something wrong there):
public class MainActivity extends Activity {
private MyReceiver myReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
myReceiver = new MyReceiver();
registerReceiver(myReceiver, filter);
}
#Override
protected void onDestroy() {
if (myReceiver != null) {
unregisterReceiver(myReceiver);
myReceiver = null;
}
super.onDestroy();
}
}
and my receiver:
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.intent.action.SCREEN_OFF")) {
Log.e("In on receive", "In Method: ACTION_SCREEN_OFF");
Toast.makeText(context, "DO SOMETHING",Toast.LENGTH_LONG).show();
}
else if (action.equals("android.intent.action.SCREEN_ON")) {
Log.e("In on receive", "In Method: ACTION_SCREEN_ON");
Toast.makeText(context, "DO SOMETHING2",Toast.LENGTH_LONG).show();
}
}
}
Really appreciate if you could take a look :D.
Thank you
You have registered the receiver in the manifest. So don't register and unregister it in the MainActivity. That's the problem. So once the app is killed, onDestroy() gets called and your receiver is unregistered and will no longer listen.
Declaring the the receiver in the manifest means that your app will always listen to broadcasts. And that's exactly what you want. So remove the register/unregister part from the MainActivity.
UPDATE: It seems that SCREEN_ON and SCREEN_OFF can't be registered via the manifest. This might possibly be for a security reason. So in this case you have to register this via code. But the problem here is that, once you quit the app, onDestroy() is called and you are no longer listening. If you are app really need this feature, you have to create a service and have that run constantly in the the background. You can use that to listen to the broadcast.
Related
I have a foreground service uploading images and broadcasting status using intent with action "myAction".
My app needs to react on the broadcast, like send a server request after receiving success message or pop up a notification after receiving failure message. I'm following this https://developer.android.com/training/run-background-service/report-status.html
Sending an broadcast Intent doesn't start or resume an Activity. The
BroadcastReceiver for an Activity receives and processes Intent
objects even when your app is in the background, but doesn't force
your app to the foreground. If you want to notify the user about an
event that happened in the background while your app was not visible,
use a Notification. Never start an Activity in response to an incoming
broadcast Intent.
I first try to register my broadcast receiver statically in Manifest. It doesn't work. Then, I follow this instruction, Keep broadcast receiver running after application is closed, to start a service to register my broadcast receiver. Both don't work(no log shows) when I swipe out or close the app.To be specific, I can see "HAHAHAHA" and "HEHEHEHE" logs come out when is in the foreground. It doesn't come out once I swipe it out from app lists or click back to exit the app.
Here is my code. Where do I miss?
In my manifest
<application...>
<receiver android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="false">
<intent-filter android:priority="0">
<action android:name="myAction"/>
</intent-filter>
</receiver>
<service
android:name=".MyService"
android:exported="false"/>
</application>
MyBroadcastReceive.java
public class MyBroadcastReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Log.d("HAHAHAHA", "Broadcast received.");
}
}
MyService.java
public class MyService extends Service {
BroadcastReceiver mReceiver;
// use this as an inner class like here or as a top-level class
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// do something
Log.d("HEHEHEHE", "Broadcast received.");
}
}
#Override
public void onCreate() {
// get an instance of the receiver in your service
IntentFilter filter = new IntentFilter();
filter.addAction("myAction");
mReceiver = new MyReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Log.d("HEHEHEHE", "onDestroy");
super.onDestroy();
}
}
MainActivity.java
onStart() {
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
Broadcast is called like below:
LocalBroadcastManager.getInstance(service).sendBroadcast(intent);
I first try to register my broadcast receiver statically in Manifest. It doesn't work.
You cannot use manifest-registered receivers with LocalBroadcastManager. Only receivers registered via LocalBroadcastManager.getInstance().registerReceiver() will respond to local broadcasts.
My app needs to react on the broadcast, like send a server request after receiving success message or pop up a notification after receiving failure message.
Get rid of the broadcast and do that work in the service.
I'm very new to Android and Programming in general, so I'm playing around with different
tutorials and info gathered here on stackoverflow.
What I would like to accomplish, is having the app with my SMS BroadcastReceiver run as a service, so I can get all the SMS broadcasts when app is in the background.
Also, how can I add a BroadcastReceiver for receiving broadcast of BOOT_COMPLETED and start app automatically?
Would I need several services for this, or is 1 service sufficient? (for detecting SMS + BOOT_COMPLETED continuously)
Currently I have a created a BroadcastReceiver for getting SMS, like this;
public class SMS extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
.. etc ..
.. etc ..
}
and my AndroidManifest.xml file has receiver and intent-filter with the
additional android.provider.Telephony.SMS_RECEIVED
Getting the SMS broadcast works fine, but I'm not sure where to go from here.
All help is much appreciated :)
Thanks.
To start your service on BOOT_COMPLETED event and to receive SMS intent continuously.
AndroidManifest.xml:
<receiver android:name="BootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
BootReceiver.java:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, SMSService.class);
context.startService(service);
}
}
SMSService.java:
public class SMSService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
if (Intent.BOOT_COMPLETED.equals(action)) {
//write your code to process BOOT_COMPLETED intent here
}
else if(Intent.SMS_RECEIVED.equals(action)) {
//Write your code for processing SMS intent here
}
}
}
As, Fildor has pointed out, it is unnecessary to start service on BOOT_COMPLETED intent. InentService would do the work. So, above two code snippets are not required. Just the last snippet would do the work.
I am working in Android 2.1, and I want to detect when the headset is plugged in/taken out. I'm pretty new to android.
I think the way to do it is using a Broadcast receiver. I sublcassed this, and I also put the following in my AndroidManifest.xml. But do you have to register the receiver somehwere else, like in the activity? I'm aware there are lots of threads on this, but I don't really understand what they're talking about. Also, what's the difference between registering in AndroidManifest.xml versus registering dynamically in your activity?
<receiver android:enabled="true" android:name="AudioJackReceiver" >
<intent-filter>
<action android:name="android.intent.action.HEADSET_PLUG" >
</action>
</intent-filter>
</receiver>
And this was the implementation of the class (plus imports)
public class AudioJackReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.w("DEBUG", "headset state received");
}
}
I was just trying to see if it works, but nothing shows up when I unplug/plug in the headset while running the application.
EDIT: the documentation doesn't say this, but is it possible that this one won't work if registered in the manifest? I was able to get it to respond when I registered the receiver in one of my applications (or do you have to do that anyway?)
Just complementing Greg`s answer, here is the code that you need divided in two parts
Register the Service in the first Activity (here its called MainActivity.java).
Switch over the result of the ACTION_HEADSET_PLUG action in the BroadCastReceiver.
Here it goes:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private MusicIntentReceiver myReceiver;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myReceiver = new MusicIntentReceiver();
}
#Override public void onResume() {
IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
registerReceiver(myReceiver, filter);
super.onResume();
}
private class MusicIntentReceiver extends BroadcastReceiver {
#Override public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
int state = intent.getIntExtra("state", -1);
switch (state) {
case 0:
Log.d(TAG, "Headset is unplugged");
break;
case 1:
Log.d(TAG, "Headset is plugged");
break;
default:
Log.d(TAG, "I have no idea what the headset state is");
}
}
}
}
Here are two sites that may help explain it in more detail:
http://www.grokkingandroid.com/android-tutorial-broadcastreceiver/
http://www.vogella.com/articles/AndroidBroadcastReceiver/article.html
You have to define your intent; otherwise it won't access the system function. The broadcast receiver; will alert your application of changes that you'd like to listen for.
Every receiver needs to be subclassed; it must include a onReceive(). To implement the onReceive() you'll need to create a method that will include two items: Context & Intent.
More then likely a service would be ideal; but you'll create a service and define your context through it. In the context; you'll define your intent.
An example:
context.startService
(new Intent(context, YourService.class));
Very basic example. However; your particular goal is to utilize a system-wide broadcast. You want your application to be notified of Intent.ACTION_HEADSET_PLUG.
How to subscribe through manifest:
<receiver
android:name="AudioJackReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.HEADSET_PLUG" />
</intent-filter>
</receiver>
Or you can simply define through your application; but. Your particular request; will require user permissions if you intend to detect Bluetooth MODIFY_AUDIO_SETTINGS.
You need to enable the broadcast receiver and set the exported attribute to true:
<receiver
android:name="AudioJackReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.HEADSET_PLUG" />
</intent-filter>
</receiver>
I am trying to start up a BroadcastReceiver within a Service. What I am trying to do is have a background running service going that collects incoming text messages, and logs incoming phone calls. I figured the best way to go about this is to have a service running that incorporates a broadcast receiver that can catalog either.
How do i go about doing this? I already have my service up and running.
as your service is already setup, simply add a broadcast receiver in your service:
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals("android.provider.Telephony.SMS_RECEIVED")){
//action for sms received
}
else if(action.equals(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED)){
//action for phone state changed
}
}
};
in your service's onCreate do this:
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
filter.addAction(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction("your_action_strings"); //further more
filter.addAction("your_action_strings"); //further more
registerReceiver(receiver, filter);
and in your service's onDestroy:
unregisterReceiver(receiver);
and you are good to go to receive broadcast for what ever filters you mention in onCreate. Make sure to add any permission if required. for e.g.
<uses-permission android:name="android.permission.RECEIVE_SMS" />
The better pattern is to create a standalone BroadcastReceiver. This insures that your app can respond to the broadcast, whether or not the Service is running. In fact, using this pattern may remove the need for a constant-running Service altogether.
Register the BroadcastReceiver in your Manifest, and create a separate class/file for it.
Eg:
<receiver android:name=".FooReceiver" >
<intent-filter >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
When the receiver runs, you simply pass an Intent (Bundle) to the Service, and respond to it in onStartCommand().
Eg:
public class FooReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// do your work quickly!
// then call context.startService();
}
}
I'm just trying this little sample project, all it does:
Activity one has a Button that sends a Broadcast. Activity two displays a toast when received.
Below is the code, the Broadcast is never received. What do I do wrong?
Sending the Broadcast
public class SendBroadcast extends Activity {
public static String BROADCAST_ACTION = "com.unitedcoders.android.broadcasttest.SHOWTOAST";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void sendBroadcast(View v){
Intent broadcast = new Intent();
broadcast.setAction(BROADCAST_ACTION);
sendBroadcast(broadcast);
}
}
Receiving it
public class ToastDisplay extends Activity {
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT);
}
};
#Override
protected void onResume() {
IntentFilter filter = new IntentFilter();
filter.addAction(SendBroadcast.BROADCAST_ACTION);
registerReceiver(receiver, filter);
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(receiver);
super.onPause();
}
}
Manifest
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".SendBroadcast" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ToastDisplay">
<intent-filter>
<action android:name="com.unitedcoders.android.broadcasttest.SHOWTOAST"></action>
</intent-filter>
</activity>
</application>
What do I do wrong?
The source code of ToastDisplay is OK (mine is similar and works), but it will only receive something, if it is currently in foreground (you register receiver in onResume). But it can not receive anything if a different activity (in this case SendBroadcast activity) is shown.
Instead you probably want to startActivity ToastDisplay from the first activity?
BroadcastReceiver and Activity make sense in a different use case. In my application I need to receive notifications from a background GPS tracking service and show them in the activity (if the activity is in the foreground).
There is no need to register the receiver in the manifest. It would be even harmful in my use case - my receiver manipulates the UI of the activity and the UI would not be available during onReceive if the activity is not currently shown. Instead I register and unregister the receiver for activity in onResume and onPause as described in
BroadcastReceiver documentation:
You can either dynamically register an instance of this class with Context.registerReceiver() or statically publish an implementation through the tag in your AndroidManifest.xml.
Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT);
makes the toast, but doesnt show it.
You have to do Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT).show();
Extends the ToastDisplay class with BroadcastReceiver and register the receiver in the manifest file,and dont register your broadcast receiver in onResume() .
<application
....
<receiver android:name=".ToastDisplay">
<intent-filter>
<action android:name="com.unitedcoders.android.broadcasttest.SHOWTOAST"/>
</intent-filter>
</receiver>
</application>
if you want to register in activity then register in the onCreate() method e.g:
onCreate(){
sentSmsBroadcastCome = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "SMS SENT!!", Toast.LENGTH_SHORT).show();
}
};
IntentFilter filterSend = new IntentFilter();
filterSend.addAction("m.sent");
registerReceiver(sentSmsBroadcastCome, filterSend);
}
You need to define the receiver as a class in the manifest and it will receive the intent:
<application
....
<receiver android:name=".ToastReceiver">
<intent-filter>
<action android:name="com.unitedcoders.android.broadcasttest.SHOWTOAST"/>
</intent-filter>
</receiver>
</application>
And you don't need to create the class manually inside ToastDisplay.
In the code you provided, you must be inside ToastDisplay activity to actually receive the Intent.
I think your problem is that you send the broadcast before the other activity start ! so the other activity will not receive anything .
The best practice to test your code is to sendbroadcast from thread or from a service so the activity is opened and its registered the receiver and the background process sends a message.
start the ToastDisplay activity from the sender activity ( I didn't test that but it may work probably )
You forget to write .show() at the end, which is used to show the toast message.
Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT).show();
It is a common mistake that programmer does, but i am sure after this you won't repeat the mistake again... :D
Your also have to register the receiver in onCreate(), like this:
IntentFilter filter = new IntentFilter();
filter.addAction("csinald.meg");
registerReceiver(receiver, filter);