I'm trying to capture the ACTION_MEDIA_BUTTON intent using a broadcastreceiver in Android 3.0+.
My receiver is a static inner class of my MainActivity class. It is static, because it is registered in my AndroidManifest.xml and it has to find the class. However, this means that my BroadcastReceiver has no way of getting back to my activity when the play/pause button is pressed. The onReceive method gets called, but because the class is static, I can't inform my activity.
Using a reference to my activity or a Handler object also does not work, since I can't acquire the BroadcastReceiver object that is being called by the Android system.
Dynamically declaring the receiver should also work, but this does not work on Android 3.0+, for some strange reason. It has something to to with:
AudioManager.registerMediaButtonEventReceiver(ComponentName)
Which is required to be called.
Some illustration of my class:
public class MainActivity extends Activity {
public static class MicReceiver extends BroadcastReceiver {
// onReceive is called
// How do I inform MainActivity of the press?
}
}
Do you have any ideas for a fix?
Thanks!
[EDIT]
See my code below for registering my receiver dynamically: (This is currently not working)
mReceiver = new RemoteControlReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
filter.setPriority(2147483647);
registerReceiver(mReceiver, filter);
AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
am.registerMediaButtonEventReceiver(new ComponentName(getPackageName(), RemoteControlReceiver.class.getName()));
AFAIK, registerMediaButtonEventReceiver() is if you want to receive media button events in the background. A foreground activity can find out about media button events using the standard onKeyDown() callback.
Declaring receiver in Manifest will try to instantiate the receiver and call onRecieve(), even when activity is not around.
To make it an activity bound receiver, make it a non static class and instantiate it in onCreate(). Then, register and unregister it in onResume() and onPause() respectively. Since class is non static and registered only when activity is active, you can safely call parent activity methods from inner receiver class.
The code should look like this if you want to process something in BroadcastReceiver
public class MainActivity extends Activity {
public static class MicReceiver extends BroadcastReceiver {
public MicReceiver() {
// TODO Auto-generated constructor stub
super();
}
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String intentAction = intent.getAction();
if (!Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
return;
}
KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (event == null) {
return;
}
int action = event.getAction();
if (action == KeyEvent.ACTION_DOWN) {
Toast.makeText(context, "BUTTON PRESSED! ", Toast.LENGTH_SHORT).show();
}
abortBroadcast();
}
}
}
Related
How can I get current/running Activity from Android Service? I am working on Screen Locker and I need to getActivity() and getWindow() in order to getDecorView() to make navigation bar hidden. If anyone knows better solution, please comment. Thanks!
There is no way to get a reference to the Activity as far as I know.
A classic aproach to communicate between a Service and an Activity is by using a BroadcastReceiver.
Here is an Example:
on your Activity you can create a Inner class that extends BroadcastReceiver:
private class ServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
if (arg1.hasExtra(Constants.SOME_ACTION)) {
//DO YOUR THING
}
}
}
Don't forget to register it on onCreate:
serviceReceiver = new ServiceReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Constants.SERVICE_RECEIVER);
registerReceiver(serviceReceiver, intentFilter);
and to unRegister it on onPause()
if (serviceReceiver != null)
unregisterReceiver(serviceReceiver);
Then from your Service you can send a Broadcast on an Event, something like this:
Intent intent = new Intent();
intent.setAction(Constants.SERVICE_RECEIVER);
intent.putExtra(Constants.SOME_ACTION, true);
sendBroadcast(intent);
This way your Activity can react to Events on your Service.
I have two activities: one is the main (A), and the second one which is started from A (B). I start B with startActivityForResult(intent, id).
I know I can send the result back to A via the setResult() method, but as far as I know, the result isn't sent until finish() is called. I need to send data from B to A without closing B (even several times before closing). Is there a way to achieve that?
As far as I've read, there are not many options to achieve this. I could use SharedPreferences but then I'd need also some kind of event to inform A that it has to read a value!
Any ideas appreciated.
------ FINAL SOLUTION ------
Finally I got it thanks to #Nathaniel Waggoner's advice. Here's what I did:
Inside my activity I declared the extension of BroadcastReceiver:
class ActivityBroadcast extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
final String txt2send = intent.getStringExtra("txt2send");
if ((txt2send != null) && (!txt2send.isEmpty())) {
// Do the needed stuff
...
}
}
}
So now I declared the ActivityBroadcast instance in my class and initialized it:
private static ActivityBroadcast broadcast_signal;
broadcast_signal = new ActivityBroadcast();
The way I control that it's just my Intent the one who triggers the onReceive method is with an IntentFilter set to the SENDTXT2SOCK customized action, this way:
// CustomActions.SENDJOIN2CHAN is just a constant from a customized public class
// where I define my own constants to not interfere with the "official" ones
registerReceiver(broadcast_signal, new IntentFilter(CustomActions.SENDTXT2SOCK));
This way I'm saying that on broadcast_signal will just be registered the CustomActions.SENDTXT2SOCK action, so any other is ignored. Now we just have to send a signal from the desired activity to that receiver:
final Intent intentResult = new Intent(CustomActions.SENDTXT2SOCK);
intentResult.putExtra("txt2send", "blabla");
sendBroadcast(intentResult);
And that's all, works like a charm!
Use broadcasts and intents.
Broadcast Receivers:
http://developer.android.com/reference/android/content/BroadcastReceiver.html
You can also give a shot to OnsharedPreferenceChangelistner
you can use eventBus simple library.
first register eventbus in receiver activity
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
then set a subscriber method
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {/* Do something */};
then in other activity post your entity like this
EventBus.getDefault().post(new MessageEvent());
You can use broadcasts and observers to call a method of one activity from another activity. You will use an intent to call a broadcast from activity B, and then you will use an observer to call a method in activity A from the broadcast.
For example, if you want to call ActivityA.someMethod from ActivityB, you can do the following (don't forget implements Observer on ActivityA):
public class ActivityA extends AppCompatActivity implements Observer{
//This is the method you want to call from ActivityB
public void someMethod(Intent intent){
//intent will be the Intent object created in ActivityB, you can pass data to this method by setting extras in the intent
}
//Define the observer and broadcast receiver classes
private static class MyObservable extends Observable{
private static final MyObservable instance = new MyObservable();
public void updateValue(Object data){
synchronized(this){
setChanged();
notifyObservers(data); //This method calls ActivityA.update
}
}
}
public static class MyBroadcastReceiver extends BroadcastReceiver{
//This class must be public and static and must be added to the manifest
//To add this class to the manifest in Android Studio put the cursor on the name of the class, press Alt+Enter and choose "Add to manifest"
#Override
public void onReceive(Context context, Intent intent){ //This method will be called when the broadcast is sent from ActivityB
MyObservable.instance.updateValue(intent);
}
}
//Connect the observer to the activity in the onCreate method
#Override
protected void onCreate(Bundle savedInstanceState){
MyObservable.instance.addObserver(this);
//Do everything else in onCreate as usual
}
//This method will be called when the notifyObservers method is called from the oberver
#Override
public void update(Observable observable, Object data){
this.someMethod((Intent) data); //Call the method that you need
}
}
public class ActivityB extends AppCompatActivity{
public void callSomeMethodOnActivityB(){
Intent intent = new Intent(this, ActivityA.MyBroadcastReceiver.class);
//Add some extras to the intent to pass data
sendBroadcast(intent); //Calls ActivityA.MyBroadcastReceiver.onReceive
}
}
Most of this answer is based on ilw's answer to "Communication between BroadcastReceiver and Activity", credits to them.
Hi i am trying to understand Broadcast Receiver , i went through many sample codes , but still have some doubts. I wanted to know when we have to extend the Broadcast Receiver class and when should we use registerReceiver() method and when should we create object for BroadcastReceiver. In some programs i came across registerReceiver methods being used but without extending the Broadcast Receiver class. I also wanted to know how the onReceive method gets called.
Which approach should be used when?
here is the registerReceiver method:
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
switch (getResultCode()) {
........
}
}
}, new IntentFilter(SENT));
Object being created for BroadcastReceiver:
private BroadcastReceiver intentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
.................
}
};
Android has intent action for broadcast receiver. BroadCast receiver will be trigger when it listen any action which registered within it.
Now we will take one example :
That we need to listen the action of "whenever any bluetooth device connect to our device". For that android has it fix action android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED
So you can get it via manifest & registration also
BY Manifest Registration:
Put this in your manifest
<receiver android:name="MyBTReceiver">
<intent-filter>
<action android:name="android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED" />
</intent-filter>
</receiver>
Create MyBTReceiver.class
public class MyBTReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED")){
Log.d(TAG,"Bluetooth connect");
}
}
}
That was the simplest broadcast Receiver.
Now,
if you are only interested in receiving a broadcast while you are running, it is better to use registerReceiver(). You can also register it within your existing class file. you also need to unregister it onDestroy().
here, you dont need any broadcast registration in manifest except activity registration
For example
public class MainActivity extends Activity {
IntentFilter filter1;
#Override
public void onCreate() {
filter1 = new IntentFilter("android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED");
registerReceiver(myReceiver, filter1);
}
//The BroadcastReceiver that listens for bluetooth broadcasts
private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equalsIgnoreCase("android.bluetooth.BluetoothDevice.ACTION_ACL_CONNECTED")) {
Log.d(TAG,"Bluetooth connect");
}
}
};
#Override
public void onDestroy() {
unregisterReceiver(myReceiver);
}
}
In both cases BroadcastReceiver will be extended. In your second example you create so called anonymous class. New class has no specific name, that is why it's called so. Anyway this new class extends BroadcastReceiver and overrides onReceive() method.
Now back to your question. There are two kinds of receivers - statically and dynamically defined ones.
If you declare your receiver in AndroidManifest file, then it is statically defined. In this case you need to refer to a class implementing BroadcastReceiver by name. As you can see, you cannot use an anonymous class, because the last has no name. You have to explicitly implement a receiver. It's worth to mention, that in this case you do not use registerReceiver() method. Android does it for you automatically.
If you declare receivers dynamically (for instance in activity's onResume() method), then you can use anonymous class for that. To register a receiver you call registerReceiver() method. You can also use a named class too. Both options are valid in this case.
Hope this explains the difference.
In both case you are creating object.But in first case there is not any reference for
the receiver object so it can not be unregistered later but second one has so it can be
unregistered after registering object using below methods:
registerReceiver(intentReceiver );
unregisterReceiver(intentReceiver );
I have an Activity that calls a Broadcast Receiver. The Broadcast Receiver waits and listens to GPS. When the listener gets the new point I want to send that new point to Activity. How can I send data from Broadcast Receiver to Activity?
I need a listener in my Activity waiting for response from Broadcast Receiver. How can I do that?
You can call the receiver from your activity. If you don't want to add the logic of the receiver in you activity you can use an abstract receiver.
You abstract receiver:
public abstract class SmsReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Add you receiver logic here
...
...
onNewPosition();
}
protected abstract void onNewPosition();
}
In your activity:
public class MyActivity extends Activity {
private smsReceiver smsReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_one_position);
smsReceiver = new smsReceiver() {
// this code is call asyncrously from the receiver
#Override
protected void onNewPosition() {
//Add your activty logic here
}
};
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
intentFilter.setPriority(999);
this.registerReceiver(smsReceiver, intentFilter);
}
#Override
protected void onPause() {
super.onPause();
this.unregisterReceiver(this.smsReceiver);
}
}
I hope it will help you...
I defined a listener for my receiver and use it in activity and it is running perfect now. Is it possible to happen any problem later?
public interface OnNewLocationListener {
public abstract void onNewLocationReceived(Location location);
}
in My receiver class wich is named as ReceiverPositioningAlarm:
// listener ----------------------------------------------------
static ArrayList<OnNewLocationListener> arrOnNewLocationListener =
new ArrayList<OnNewLocationListener>();
// Allows the user to set an Listener and react to the event
public static void setOnNewLocationListener(
OnNewLocationListener listener) {
arrOnNewLocationListener.add(listener);
}
public static void clearOnNewLocationListener(
OnNewLocationListener listener) {
arrOnNewLocationListener.remove(listener);
}
// This function is called after the new point received
private static void OnNewLocationReceived(Location location) {
// Check if the Listener was set, otherwise we'll get an Exception when
// we try to call it
if (arrOnNewLocationListener != null) {
// Only trigger the event, when we have any listener
for (int i = arrOnNewLocationListener.size() - 1; i >= 0; i--) {
arrOnNewLocationListener.get(i).onNewLocationReceived(
location);
}
}
}
and in one of my activity's methods:
OnNewLocationListener onNewLocationListener = new OnNewLocationListener() {
#Override
public void onNewLocationReceived(Location location) {
// do something
// then stop listening
ReceiverPositioningAlarm.clearOnNewLocationListener(this);
}
};
// start listening for new location
ReceiverPositioningAlarm.setOnNewLocationListener(
onNewLocationListener);
you have couple of ways you can do it and several considerations.
you can poll, meaning check every now an again using either Handler
or Timer to see if info has arrived.
you can register the broadcast receiver as an inner class of your activity and then you can call methods in your activty.
you can have the Broadcast send Intent to your class with the info, but if your activity is not in foreground you might bring it there , and that's not 100% what you want...
Regarding some consideration, BroadCastReciver is mainly used as a listener, not notider so inner class, is best practice, in my opinion, for use with Activities, for Services you can use it as a standalone class and register it in the Manifest.xml...
Now you got to remember that when broadcast is being broadcast your Activity might be inactive due to orientation change or event that pauses your app so you might miss the event. i don't listen to system events but to my own events so i use sticky broadcast to prevent that issue.
Just need to implement the broadcast receiver in the activity. register the receiver with activity's context.
When i have a broadcastReceiver say android.intent.action.MEDIA_BUTTON and i want to update the current activity's UI without creating a new activity, is there any good practice on this one?
What i know (might not be correct)
1) I can put the BroadcastReceiver in the same class as the activity and call the updateUI function after certain activity
2) Create a ContentObserver?
3) Communicate to a service created by the activity, use aidl. (I dont know how to get the current service if its registered from an activity)
4) Create a custom filter on the broadcastReceiver located on the same class as the activity, and use context.sendBroadcast(msg of custom filter) and in the custom filter call updateUI (same as one but more generic?)
The final flow is it would come from a BroadcastReceiver and ends up updating the UI without renewing the activity (unless the activity is dead?)
Kindly provide links/source code on your how you tackle this kind of problem. Thanks a lot in advance :)
The easiest way to provide this functionality is to put the broadcast receiver in you Activity and bind / unbind it using registerReceiver and unregisterreceiver:
public class MyActivity extends Activity {
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MyActivity.this.receivedBroadcast(intent);
}
};
#Override
public void onResume() {
super.onResume();
IntentFilter iff = new IntentFilter();
iff.addAction("android.intent.action.MEDIA_BUTTON");
// Put whatever message you want to receive as the action
this.registerReceiver(this.mBroadcastReceiver,iff);
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(this.mBroadcastReceiver);
}
private void receivedBroadcast(Intent i) {
// Put your receive handling code here
}
}
Depending on the intent you wish to receive, you may need to add the appropriate permissions to your AndroidManifest.xml file.
What I recently had to do to change a Button's text after receiving data from a LocalBroadcastManager is to store the value in a private field and then do the UI stuff in my onResume() method.
public class myClass extends Activity {
private String myString;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// register to receive data
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter("myAction"));
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// get the extra data included in the intent
myString = intent.getStringExtra("myString");
}
};
#Override
public void onResume() {
super.onResume();
System.out.println("onResume");
// do something to the UI
myButton.setText(myString != null ? myString : "Default");
}
}