I'm trying to add a simple broadcast receiver to my audio application, so that I can mute everything when the user clicks their ACTION_MEDIA_BUTTON on their headset. I've read that you can either register it in the manifest, or dynamically in the code. I have gone down the path of registering it in the code, as I need to call methods within my main activity class to react to the media button press. For some reason however, my BroadcastReceiver just will not register, and I can't find anything that explains why (grey hairs increasing).
The following is what I have in MainActivity.java:
public class MainActivity extends Activity {
public IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
public BroadcastReceiver MediaButtonIntentReceiver =
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
KeyEvent event = (KeyEvent) intent
.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
int action = event.getAction();
if (action == KeyEvent.ACTION_DOWN) {
Log.e("INFO", "Media Button Pressed");
MuteAll();
}
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Register media button event receiver
intentFilter.addAction("android.intent.action.ACTION_MEDIA_BUTTON");
intentFilter.setPriority(10000);
this.registerReceiver(MediaButtonIntentReceiver, intentFilter);
}
#Override
protected void onDestroy() {
super.onDestroy();
// Unregister media button event receiver
unregisterReceiver(MediaButtonIntentReceiver);
}
};
I am certain that the BroadcastReceiver doesn't register, as wrapping the register as below gives me a toast confirming it is null:
if (registerReceiver(MediaButtonIntentReceiver, intentFilter) == null)
{
Toast.makeText(this, "Could not register receiver", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Receiver registered", Toast.LENGTH_LONG).show();
}
EDIT:
I've also tried the following based on suggestions so far:
Reading through - http://developer.android.com/training/managing-audio/volume-playback.html
I tried registering my receiver within the manifest like so...
<receiver android:name="com.mydomain.myapp.MainActivity$MediaButtonIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
And then added the following example code:
public AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// Start listening for button presses
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
Eclipse complained that mContext didn't resolve to anything, so I added the following:
private Context mContext;
Then it complained about the "mContext.getSystemService(Context.AUDIO_SERVICE)" portion, saying "Type mismatch: cannot convert from Object to AudioManager"
So I added a cast to AudioManager:
public AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
And then added the suggested receiver registration code:
am.registerMediaButtonEventReceiver(MediaButtonIntentReceiver);
To which it complained about "registerMediaButtonEventReceiver" saying "The method registerMediaButtonEventReceiver(ComponentName) in the type AudioManager is not applicable for the arguments (BroadcastReceiver)"
Clearly I'm doing something wrong here. I've entered their example code as shown, yet it doesn't even compile.
--- END EDIT -----------------------------
Hoping someone out there can please help me. Please let me know if I need to supply anything further.
A Receiver for the ACTION_MEDIA_BUTTON action should be registered with AudioManager's registerMediaButtonEventReceiver() method, instead of the regular registerReceiver() method in the Activity. Unlike normal dynamic Receiver registration, however, this method takes the class as the parameter, instead of an instance of the class. The easiest way to this is to create a separate class file for it:
public class MediaButtonIntentReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
...
}
}
And we would need this Receiver listed in the manifest, as well:
<receiver android:name=".MediaButtonIntentReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
Now, the example in the link we've referred to is wrong, as the registerMediaButtonEventReceiver() method is expecting a ComponentName object, not just the name of the Receiver class itself. We need to change the example as follows:
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
am.registerMediaButtonEventReceiver(
new ComponentName(this, MediaButtonIntentReceiver.class));
And, as we've established, you don't need the mContext field, as you are in anActivity Context, and can just use getSystemService() without qualification. You can also do away with the IntentFilter object, as the listing in the manifest takes care of that already.
Related
My app that uses TextToSpeech to read some text is 90% finishes but has been stuck at this part for a few days. All I want is have the play/pause button of my bluetooth headset (Xiaomi's Mi Sports Bluetooth Earphones) to play/pause the TextToSpeech. I think it is the android.intent.action.MEDIA_BUTTON I need to catch, so I added these:
In AndroidManifest.xml:
<receiver android:name=".ButtonReceiver">
<intent-filter
android:priority="10000">
<action android:name="android.intent.action.MEDIA_BUTTON"/>
</intent-filter>
</receiver>
Then the class ButtonReceiver.java
public class ButtonReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "debug media button test", Toast.LENGTH_LONG).show();
// will finish the code once I catch this intent
}
}
The debug text does not show up. Though if I changed <action android:name="android.intent.action.MEDIA_BUTTON"/> to <action android:name="android.media.VOLUME_CHANGED_ACTION"/>, it does show the text when I press the volume up or down of the headset but this is not exactly what I want. I only want the app to respond to the play/pause button.
Then I read that I need to use registerMediaButtonEventReceiver, so I tried adding this in my MainActivity.java:
private AudioManager audioManager;
private ComponentName componentName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
audioManager = (AudioManager) this.getSystemService(AUDIO_SERVICE);
componentName = new ComponentName(this, ButtonReceiver.class);
audioManager.registerMediaButtonEventReceiver(componentName);
}
Still not working. Also, it says the registerMediaButtonEventReceiver is deprecated, so I am wondering if this is the reason that it does not work.
Further reading from the official document page, it tells this:
If you are running Android 5.0 (API level 21) or later, call
FLAG_HANDLES_MEDIA_BUTTONS
MediaBrowserCompat.ConnectionCallback.onConnected. This will
automatically call your media controller's dispatchMediaButtonEvent(),
which translates the key code to a media session callback.
I find this stupid, as I do not need this extra module to play media. All I need is the detection of the headset button press. Anyway, I tried to implement the MediaSession but gave up soon as it quickly ended up with too many codes that were useless for my app since my app is NOT an audio player app!
Any suggestion? What should I do?
I found the solution myself finally! Instead of making a separate BroadcastReceiver class, I added a public static class in my MainActivity.java:
public static class ButtonReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
Toast.makeText(context, "debug media button test", Toast.LENGTH_SHORT).show();
...
}
}
Then added this line in onCreate:
((AudioManager)getSystemService(AUDIO_SERVICE))
.registerMediaButtonEventReceiver(new ComponentName(this, ButtonReceiver.class));
And finally in AndroidManifest.xml:
<receiver android:name=".MainActivity$ButtonReceiver"
android:enabled="true">
<intent-filter
android:priority="10000">
<action android:name="android.intent.action.MEDIA_BUTTON"/>
</intent-filter>
</receiver>
It works! The app can now catch the MEDIA_BUTTON intent with this setting!
I'm developing lock screen app. Here Lock screen is displayed on the top of the screen using this command "WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;"
But my problem is I can't See the Incoming call Window when the custom lock screen is displayed. Incoming call window is not overrided over my custom lock screen.
1) Is there any permission required for displaying the incoming call window.?
2) We have to add any other codes for answering the incoming class
This is my Lockscreen receiver class
public class LockScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals(Intent.ACTION_SCREEN_OFF) || action.equals(Intent.ACTION_BOOT_COMPLETED))
{
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
In the normal lock screen apps -> They can attend the incoming calls and after attending that call, lock screen is displayed. How ????
Please help me. Thanks in advance
Add receiver in the manifest and ask for permission
<receiver android:name=".IncomingCall">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
Create class IncomingCall
public class IncomingCall extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
try {
TelephonyManager telephonyManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
MyPhoneStateListener PhoneListener = new MyPhoneStateListener();
// Register listener for LISTEN_CALL_STATE
telephonyManager.listen(PhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
} catch (Exception e) {
e.printStackTrace();
}
Implement PhoneStateListener in LockScreen and call onCallStateChanged
private class LockScreen extends AppCompatActivity implements PhoneStateListener{
public void onCallStateChanged(int state, String incomingNumber) {
//Disable lockscreen when calls come
}
I'm trying to add a simple broadcast receiver to my audio application, so that I can mute everything when the user clicks their ACTION_MEDIA_BUTTON on their headset. I've read that you can either register it in the manifest, or dynamically in the code. I have gone down the path of registering it in the code, as I need to call methods within my main activity class to react to the media button press. For some reason however, my BroadcastReceiver just will not register, and I can't find anything that explains why (grey hairs increasing).
The following is what I have in MainActivity.java:
public class MainActivity extends Activity {
public IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
public BroadcastReceiver MediaButtonIntentReceiver =
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String intentAction = intent.getAction();
if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
KeyEvent event = (KeyEvent) intent
.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
int action = event.getAction();
if (action == KeyEvent.ACTION_DOWN) {
Log.e("INFO", "Media Button Pressed");
MuteAll();
}
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Register media button event receiver
intentFilter.addAction("android.intent.action.ACTION_MEDIA_BUTTON");
intentFilter.setPriority(10000);
this.registerReceiver(MediaButtonIntentReceiver, intentFilter);
}
#Override
protected void onDestroy() {
super.onDestroy();
// Unregister media button event receiver
unregisterReceiver(MediaButtonIntentReceiver);
}
};
I am certain that the BroadcastReceiver doesn't register, as wrapping the register as below gives me a toast confirming it is null:
if (registerReceiver(MediaButtonIntentReceiver, intentFilter) == null)
{
Toast.makeText(this, "Could not register receiver", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Receiver registered", Toast.LENGTH_LONG).show();
}
EDIT:
I've also tried the following based on suggestions so far:
Reading through - http://developer.android.com/training/managing-audio/volume-playback.html
I tried registering my receiver within the manifest like so...
<receiver android:name="com.mydomain.myapp.MainActivity$MediaButtonIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
And then added the following example code:
public AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// Start listening for button presses
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
Eclipse complained that mContext didn't resolve to anything, so I added the following:
private Context mContext;
Then it complained about the "mContext.getSystemService(Context.AUDIO_SERVICE)" portion, saying "Type mismatch: cannot convert from Object to AudioManager"
So I added a cast to AudioManager:
public AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
And then added the suggested receiver registration code:
am.registerMediaButtonEventReceiver(MediaButtonIntentReceiver);
To which it complained about "registerMediaButtonEventReceiver" saying "The method registerMediaButtonEventReceiver(ComponentName) in the type AudioManager is not applicable for the arguments (BroadcastReceiver)"
Clearly I'm doing something wrong here. I've entered their example code as shown, yet it doesn't even compile.
--- END EDIT -----------------------------
Hoping someone out there can please help me. Please let me know if I need to supply anything further.
A Receiver for the ACTION_MEDIA_BUTTON action should be registered with AudioManager's registerMediaButtonEventReceiver() method, instead of the regular registerReceiver() method in the Activity. Unlike normal dynamic Receiver registration, however, this method takes the class as the parameter, instead of an instance of the class. The easiest way to this is to create a separate class file for it:
public class MediaButtonIntentReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
...
}
}
And we would need this Receiver listed in the manifest, as well:
<receiver android:name=".MediaButtonIntentReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
Now, the example in the link we've referred to is wrong, as the registerMediaButtonEventReceiver() method is expecting a ComponentName object, not just the name of the Receiver class itself. We need to change the example as follows:
AudioManager am = (AudioManager) getSystemService(AUDIO_SERVICE);
am.registerMediaButtonEventReceiver(
new ComponentName(this, MediaButtonIntentReceiver.class));
And, as we've established, you don't need the mContext field, as you are in anActivity Context, and can just use getSystemService() without qualification. You can also do away with the IntentFilter object, as the listing in the manifest takes care of that already.
I am using this to work with Shake, and that works fine for me, but i wanna launch application when user shake their device,
see my code below:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
transcript=(TextView)findViewById(R.id.transcript);
scroll=(ScrollView)findViewById(R.id.scroll);
shaker=new Shaker(this, 1.25d, 500, this);
}
#Override
public void onDestroy() {
super.onDestroy();
shaker.close();
}
public void shakingStarted() {
Log.d("ShakerDemo", "Shaking started!");
transcript.setText(transcript.getText().toString()+"Shaking started\n");
scroll.fullScroll(View.FOCUS_DOWN);
}
public void shakingStopped() {
Log.d("ShakerDemo", "Shaking stopped!");
transcript.setText(transcript.getText().toString()+"Shaking stopped\n");
scroll.fullScroll(View.FOCUS_DOWN);
}
So here is my question, how can i launch an application by shaking my device ?
You should write Android Service that will start your activity during shake. That is all. Services run in the background even if Activity is not visible
Service can be started eg. during device boot. This can be achieved using BroadCastReceiver.
Manifest:
<application ...>
<activity android:name=".ActivityThatShouldBeLaunchedAfterShake" />
<service android:name=".ShakeService" />
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
BootReceiver:
public class BootReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
Intent intent = new Intent(context, ShakeService.class);
context.startService(intent);
}
}
Service:
public class ShakeService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
... somewhere
if(shaked) {
Intent intent = new Intent(getApplicationContext(), ActivityThatShouldBeLaunchedAfterShake.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
Write a separate app for Shake detection. On detection of shake, fire an intent with the package name of app, you want to launch:
Intent intent = new Intent (<PackageNameOfAppToBeLaunched>);
startActivity (intent);
Well What you need is Two different activity Where first One Detects your Shake which need to run all time in background and than call the new actual app you want to run on shake.
You can run your background activity you have to use class which will keep your activity run in background for long time(Continuously) you can use classes Like FutureTask or Executor (you can not use AsyncTask for this).
Whenever the thread passes command to Your Application open after Shake the Background process stops and command goes to app means you need to again immediately start background process after the actual app closed.
You need to write the code to launch the application to foreground from background while the shake started. This link will help you to do so.
I have a headset with single button and want to do a simple Toast when the button is pressed.
Right now I have the following code:
public class MediaButtonIntentReceiver extends BroadcastReceiver {
public MediaButtonIntentReceiver() {
super();
}
#Override
public void onReceive(Context context, Intent intent) {
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) {
// do something
Toast.makeText(context, "BUTTON PRESSED!", Toast.LENGTH_SHORT).show();
}
abortBroadcast();
}
}
And my main activity is the following:
public class mainActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
MediaButtonIntentReceiver r = new MediaButtonIntentReceiver();
registerReceiver(r, filter);
}
}
Nothing happens though when I push the button though.
I'm pretty sure something is wrong with my permissions/xml in the manifest. Here's the receiver XML so far:
<receiver android:name=".MediaButtonIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
....
and:
<uses-permission android:name="android.permission.BLUETOOTH" />
I notice in LogCat that when I press the button I get an error from "BluetoothIntentReceiver" saying "onReceive() Action : android.intent.action.MEDIA_BUTTON"
Just wanted to answer my own question in case others come across similar issues.
The code does work, just I wasn't seeing the Toast because I had another headset button controller app installed (and running in the background), so I guess it took priority over mine. However when I put
IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);//"android.intent.action.MEDIA_BUTTON"
MediaButtonIntentReceiver r = new MediaButtonIntentReceiver();
filter.setPriority(1000); //this line sets receiver priority
registerReceiver(r, filter);
It was able to work even with the other app installed. Also, you don't need both the above AND the XML, one or the other is fine as ways of registering the intent receiver.
Here's what I've got that's working in Android 4.2.2
In my manifest.xml I do this:
<receiver android:name=".MediaButtonIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
NB: this is instead of calling registerReceiver.
In my Main Activity's onCreate I need to call the AudioManager:
((AudioManager)getSystemService(AUDIO_SERVICE)).registerMediaButtonEventReceiver(
new ComponentName(
getPackageName(),
MediaButtonIntentReceiever.class.getName()));
I have found it will work without the AudioManager call, but not for long!
You shouldn't use setPriority
You register your broadcast receiver in the manifest
You then register your broadcast receiver using:
AudioManager#registerMediaButtonEventReceiver
The argument to registerMediaButtonEventReceiver is a ComponentName that points your broadcast receiver.
For a fully documented answer for Android >4.0 have a look here:
BroadcastReceiver for ACTION_MEDIA_BUTTON not working
If you don't want to use BroadcastReceiver, you can do this for Android >5.0 (API level 21 LOLLIPOP) using the MediaSession described here: https://stackoverflow.com/a/39413753/1386969