I am trying to implement the volume slider while casting and show the cast icon in the slider like in the Youtube app : http://imgur.com/kVxoKbM.
As of now I have overridden the dispatchKeyEvent function my activity, as explained in the cast developers documentation (shown in the code snipped below), which allows me to control the volume of the connected Chromecast perfectly. But on the device, it doesn't even show a slider at all.
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int action = event.getAction();
int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
if (action == KeyEvent.ACTION_DOWN) {
if (mApiClient != null) {
double currentVolume = Cast.CastApi.getVolume(mApiClient);
if (currentVolume < 1.0) {
try {
Cast.CastApi.setVolume(mApiClient,
Math.min(currentVolume + VOLUME_INCREMENT, 1.0));
} catch (Exception e) {
Log.e(TAG, "unable to set volume", e);
}
}
} else {
Log.e(TAG, "dispatchKeyEvent - volume up");
}
}
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
if (action == KeyEvent.ACTION_DOWN) {
if (mApiClient != null) {
double currentVolume = Cast.CastApi.getVolume(mApiClient);
if (currentVolume > 0.0) {
try {
Cast.CastApi.setVolume(mApiClient,
Math.max(currentVolume - VOLUME_INCREMENT, 0.0));
} catch (Exception e) {
Log.e(TAG, "unable to set volume", e);
}
}
} else {
Log.e(TAG, "dispatchKeyEvent - volume down");
}
}
return true;
default:
return super.dispatchKeyEvent(event);
}
}
I am not using the remoteMediaPlayer. So how can I implement a volume slider while controlling the connected Chromecast volume?
Related
I have one midi file and I have played that midi file using MediaPlayer in android using the following code:
val mMediaPlayer = MediaPlayer.create(context, R.raw.test_ring_1)
mMediaPlayer?.start()
It default play with one instrument like piano, now I want to add soundfont (sf2/sf3) file to play the midi notes with different instrument and with reverberation effects.
Please guide a way to achieve expected result.
There are two libraries that will be used to play a midi file using SoundFont.
Midi Driver
Just a synthesizer for playing MIDI note on Android. You can use it with USB/Bluetooth-MIDI library together to create your MIDI application.
SoundFont2 file is supported.
Android MIDI Library
This library provides an interface to read, manipulate, and write MIDI files. "Playback" is supported as a real-time event dispatch system. This library does NOT include actual audio playback or device interfacing.
To initialize SF2-SoundBank
SF2Soundbank sf = new SF2Soundbank(getAssets().open("test.sf2"));
synth = new SoftSynthesizer();
synth.open();
synth.loadAllInstruments(sf);
synth.getChannels()[0].programChange(0);
synth.getChannels()[1].programChange(1);
recv = synth.getReceiver();
To Play the Midi notes from midi file
MidiFile midiFile = new MidiFile(getAssets().open("test.mid"));
// Create a new MidiProcessor:
MidiProcessor processor = new MidiProcessor(midiFile);
// listen for all midi events:
processor.registerEventListener(new MidiEventListener() {
#Override
public void onStart(boolean fromBeginning) {
}
#Override
public void onEvent(MidiEvent event, long ms) {
if (event.getClass() == NoteOn.class) {
NoteOn noteOn = ((NoteOn) event);
try {
ShortMessage msg = new ShortMessage();
msg.setMessage(ShortMessage.NOTE_ON, channel, noteOn.getNoteValue(), noteOn.getVelocity());
recv.send(msg, ms);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
} else if (event.getClass() == NoteOff.class) {
NoteOff noteOff = ((NoteOff) event);
try {
ShortMessage msg = new ShortMessage();
msg.setMessage(ShortMessage.NOTE_ON, channel, noteOff.getNoteValue(), noteOff.getVelocity());
recv.send(msg, ms);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
}
}
#Override
public void onStop(boolean finished) {
}
}, MidiEvent.class);
// Start the processor:
processor.start();
Variable to define SF channel
private int channel = 0;
I have tested this it is working
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
SF2Soundbank sf = new SF2Soundbank(getAssets().open("SmallTimGM6mb.sf2"));
synth = new SoftSynthesizer();
synth.open();
synth.loadAllInstruments(sf);
synth.getChannels()[0].programChange(0);
synth.getChannels()[1].programChange(1);
recv = synth.getReceiver();
} catch (IOException e) {
e.printStackTrace();
} catch (MidiUnavailableException e) {
e.printStackTrace();
}
this.findViewById(R.id.piano).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_DOWN) {
try {
ShortMessage msg = new ShortMessage();
msg.setMessage(ShortMessage.NOTE_ON, 0, 60, 127);
recv.send(msg, -1);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
try {
ShortMessage msg = new ShortMessage();
msg.setMessage(ShortMessage.NOTE_OFF, 0, 60, 127);
recv.send(msg, -1);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
}
return true;
}
});
this.findViewById(R.id.woodblock).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_DOWN) {
try {
ShortMessage msg = new ShortMessage();
msg.setMessage(ShortMessage.NOTE_ON, 1, 60, 127);
recv.send(msg, -1);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
try {
ShortMessage msg = new ShortMessage();
msg.setMessage(ShortMessage.NOTE_OFF, 1, 60, 127);
recv.send(msg, -1);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
}
return true;
}
});
}
Dont forget to include sherlockmidi library from below repository, sample is also available in below repository.
https://github.com/agangzz/SherlockMidi
Now what is happening is it is also controlling other music players. If i have a default music player after starting that if i start playing using my music player and then i press play/pause button in headset it controls default music player.
i have implemented a heaset broadcastreceiver like this,
switch (keyEvent.getKeyCode()) {
case KeyEvent.KEYCODE_HEADSETHOOK:
Log.d("TAG", "TAG: KEYCODE_HEADSETHOOK");
if (MusicService.isPlaying()) {
MusicService.player.pause();
} else {
MusicService.player.start();
}
new MusicService().showNotification();
break;
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
Log.d("TAG", "TAG: KEYCODE_MEDIA_PLAY");
if (MusicService.isPlaying()) {
MusicService.player.pause();
} else {
MusicService.player.start();
}
new MusicService().showNotification();
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
Log.d("TAG", "TAG: KEYCODE_MEDIA_PAUSE");
break;
case KeyEvent.KEYCODE_MEDIA_STOP:
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
Log.d("TAG", "TAG: KEYCODE_MEDIA_NEXT");
if (MusicService.player.isPlaying()) {
MusicService.player.stop();
}
if (MusicService.songPosn < (MusicService.song.size() - 1)) {
MusicService.songPosn = MusicService.songPosn + 1;
if (SingleInstance.getInstance().getIndexCount()>= 1)
SingleInstance.getInstance().setIndexCount(SingleInstance.getInstance().getIndexCount()-1);
} else {
// play first song
MusicService.songPosn = 0;
}
new MusicService().playSong(true);
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
Log.d("TAG", "TAG: KEYCODE_MEDIA_PREVIOUS");
if (MusicService.player.isPlaying()) {
MusicService.player.stop();
}
if (MusicService.songPosn > 0) {
MusicService.songPosn = MusicService.songPosn - 1;
} else {
// play last song
MusicService.songPosn = MusicService.song.size() - 1;
}
new MusicService().playSong(true);
break;
}
If you are trying to get the hedsethook event in a activity follow the below code :
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_HEADSETHOOK:
// Headset key detected
// Do your stuff here
return true;// To let the os know that the event is consumed here
}
}
return super.dispatchKeyEvent(event);
}
Make sure to returt true to consume the event .To get it done in a service use BroadCast receiver as follows:
IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);//"android.intent.action.MEDIA_BUTTON"
MediaButtonIntentReceiver r = new MediaButtonIntentReceiver();
filter.setPriority(1000); //Sets receiver priority
registerReceiver(r, filter);
I am writing a game where you keep pressing the screen to let a helicopter fly. Now when the helicopter collides with the screen-borders (Hight & width of individual device) the activity finishes by
((Activity) context).finish();
It works perfectly fine when the player stops fastly after the collision, but if he holds on, I get the hated error.
Thant's why I suspect the onTouchEvent-method
#Override
public boolean onTouchEvent(MotionEvent event) {
// background music
mp.start();
mp.setLooping(true);
copter.setVolume((float) 0.2, (float) 0.2);
if (event.getAction() == MotionEvent.ACTION_DOWN && fuel > 0) {
copter.start();
copter.setLooping(true);
if (!player.getPlaying()) {
player.setPlaying(true);
player.setUp(true);
fuel--;
} else {
player.setUp(true);
fuel--;
}
return true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
copter.pause();
player.setUp(false);
return true;
}
return super.onTouchEvent(event);
}
Is there some way to ignore TouchEvents after a collision? Or is the OnTouchEvent not even the problem?
Check if Activity is null inside onTouchEvent()
Here the code:
#Override
public boolean onTouchEvent(MotionEvent event) {
Activity activity = getActivity();
if(activity != null){
// background music
mp.start();
mp.setLooping(true);
copter.setVolume((float) 0.2, (float) 0.2);
if (event.getAction() == MotionEvent.ACTION_DOWN && fuel > 0) {
copter.start();
copter.setLooping(true);
if (!player.getPlaying()) {
player.setPlaying(true);
player.setUp(true);
fuel--;
} else {
player.setUp(true);
fuel--;
}
return true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
copter.pause();
player.setUp(false);
return true;
}
return super.onTouchEvent(event);
}
//return super.onTouchEvent(event);
return false;
}
Depending on your code you should use:
if(((Activity)context) != null){
instead of
Activity activity = getActivity();
if(activity != null){
If this is not the problem, please add the error stacktrace.
Update
To send stacktrace via e-mail:
Intent mailIntent = new Intent(Intent.ACTION_SENDTO);
mailIntent.setData(Uri.parse("mailto:"));
mailIntent.putExtra(Intent.EXTRA_EMAIL, new String[]{"mail#gmail.com"});
mailIntent.putExtra(Intent.EXTRA_SUBJECT, "Subject");
mailIntent.putExtra(Intent.EXTRA_TEXT, stacktraceText);
Intent mailChooserIntent = Intent.createChooser(mailIntent, "Title");
context.startActivity(mailChooserIntent);
I'm developing an Android app in Java which must detect events from a real mouse connected in USB, and send them over the network to a computer which will use those events.
My problem : I can detect mouse wheel button events (scroll, pressed, released), but when the user presses the wheel button, the app exits, and the callback is called afterwards.
My question : is it possible to catch the event before the app exits, and prevent the default behavior ? If so, how ? Why do I catch the event too late ?
Here is the functios declared in my activity :
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
int pointerId = event.getPointerId(0);
if (event.getAction() == MotionEvent.ACTION_HOVER_MOVE) {
Log.d(name, "onGenericMotionEvent : MotionEvent.ACTION_HOVER_MOVE " + MotionEvent.ACTION_HOVER_MOVE);
return true;
} else if (event.getAction() == MotionEvent.ACTION_SCROLL) {
Log.d(name, "onGenericMotionEvent : MotionEvent.ACTION_SCROLL " + MotionEvent.ACTION_SCROLL);
return true;
} else if (event.getAction() == MotionEvent.ACTION_HOVER_EXIT) {
Log.d(name, "why does is happen after onPause ??? onGenericMotionEvent : MotionEvent.ACTION_HOVER_EXIT " + MotionEvent.ACTION_HOVER_EXIT);
return true;
} else {
//Log.d(name, "onGenericMotionEvent : " + MotionEvent.actionToString(event.getAction()) + " " + event.getAction());
}
return super.onGenericMotionEvent(event);
}
And here is how I prevented mouse right click from closing the app :
public boolean onKeyUp(int keyCode, KeyEvent event) {
int source = event.getSource();
boolean mouseRightButton = false;
if (source == InputDevice.SOURCE_TOUCHSCREEN) {
Log.e(name, "onKeyUp from touchscreen");
} else if (source == InputDevice.SOURCE_MOUSE) {
Log.e(name, "onKeyUp from mouse");
if (keyCode == KeyEvent.KEYCODE_BACK) {
Log.e(name, "right click");
mouseRightButton = true;
return true;
}
}
}
Thanks for your help
Return true if you have handled the event. Don't propagate it forward. The app will not close that way.
i have a problem with handling back button in my game on android, developed on MonoGame with MonoDroid. I can't catch back button click event.
I tried:
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
{
LoadingScreen.Load(ScreenManager, true, null, new BackgroundScreen(),
new LevelSelectScreen());
}
And on main Activity
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
if (keyCode == Keycode.Back)
{
...
return true;
}
return base.OnKeyDown(keyCode, e);
}
public override void OnBackPressed()
{
...
Toast.MakeText(this, keyCode + " key! + " + keyCode.ToString(), ToastLength.Short).Show();
}
public override bool OnKeyDown(Keycode keyCode, KeyEvent e)
{
if (keyCode == Keycode.Back)
{
...
return true;
}
return base.OnKeyDown(keyCode, e);
}
Nothing helps, on WP first variant works perfectly
YEAH!
I found solution:
When you call
GamePad.GetState(PlayerIndex.One)
in Android GamePadState cleared
public static GamePadState GetState(PlayerIndex playerIndex)
{
var instance = GamePad.Instance;
var state = new GamePadState(new GamePadThumbSticks(), new GamePadTriggers(), new GamePadButtons((Buttons)instance._buttons), new GamePadDPad());
instance.Reset(); // <- CLEAR BUTTONS
return state;
}
So, do not call GetState in Android several times.