I am working on an application that uses BluetoothChat sample application.
In my main activity I am using a webview in which I load an external page. I am handling Bluetooth functionality via a javascript that loads with the external page. Basically I add a bridge between Javascript and native code via the following line:
myWebView.addJavascriptInterface(new WebAppInterface(this,myWebView), "Android");//I pass a refference to the context and a refference to the webview.
WebAppInterface is the class that has all the public methods I can call from Javascript. In this class I have methods like: enableBluetooth, disableBluetooth, listBoundedDevices, connect etc.
I am using BluetoothSerialService class from BluetoothChat sample application. My device has to connect to an embedded device which receives commands and answers back differently depending on the input I give. An example would be like: when I press a button on the webview I call the following native code:
while(true){
out.write(requestKey);//send command - where "out" is the OutputStream
key = in.read();//get response - where "in" is the InputStream
if(key==KEY1){
out.write(activateRFID);//send command - activateRFID
rfidTag = in.read();//get response - RFID Tag
updateUI(rfidTag);//perform function - update the UI with the tag
}
else if(key==KEY2){
out.write(deactivateRFID);//send command - deactivate RFID
response = in.read();//get response
}
else if(key==KEY3){
out.write(anotherCommand);//send command -
response = in.read();//get response
}
}
What I am trying to achieve is sending commands to another device(request the pressed key) and perform functions. This has to happen always (pooling the device for the key pressed and perform a particular function).
How can I start 1 SINGLE THREAD that pools the device (write to the OutputStream and read the response from the InputStream)? The BluetoothChat sample application works a little different: whenever I call BluetoothChatSevice.write() I get a response via ConnectedThread run method that sends messages to UI via a mHandler.
All suggestions are welcome.
I did it today. I suggest that you do a boolean function readWrite() that whenever you write to outputStream you also read from the inputStream and send the readBuffer to UI with mHandler. If both read and write are ok, than return true, if one of them went wrong than return false and use resetConection before closing your ConnectedThread. See my answer here for the resetConnection. Application using bluetooth SPP profile not working after update from Android 4.2 to Android 4.3
But the answer about pooling is the following:
In the ConnectedThread run() method do a while(true), call a method similar to readWrite(byte[] data) inside the loop, where in the first place you write something to the device, and then you read the data from the input stream (from the device). In this readWrite() method, if writing to outpustream went fine, then continue to read from the inputstream. if you got any data to the input stream, send the data to UI for processing with the mHandler (or do some processing before sending to the UI).
It worked very nice for me.
Related
I'm building a mobile app in flutter which pipes the mic audio (mic_stream lib) to a websocket. I’m really struggling to close down the stream pipeline when I'm done with it. I’m getting various “Bad State” exceptions such as Cannot add event while adding a stream. The particulars depend on how I set up the pipeline but it seems to be at the root because the returned addStream future never completes. Any ideas what would cause that?
As said above, the source stream is from the mic_stream lib which pulls from native via Flutter's EventChannel.receiveBroadcastStream. The docs for this method says its returned stream will only close down when there are no more listeners. I try closing my websocket and get a similar error for the same reason (websocket internal bad state b/c addStream never completes). I'm tried wrapping the mic stream in a StreamController and closing that but I get the error mentioned above.
Starting to feel like it's a bug. Maybe EventChannel's stream is special? Or is it related to it being a "broadcast" stream.
Feeling stuck. Any help appreciated...thx
Flutter makes this a little confusing by returning a stream from EventChannel that you can't really use in the normal pipeline chaining way if you ever need to close it. Perhaps they should have done internally what I'm about to show as the workaround.
First for clarity, when you use addStream on StreamController (StreamConsumer rather) it blocks you from "manual" control via the add() method and also the close() until that stream completes. This makes sense, if you think about it, since the source stream should determine when it closes. That's why addStream() returns a Future – so you know when you can resume using those methods, or add another stream. Doing so beforehand will trigger the Bad State errors mentioned above.
From the docs for EventChannel::receiveBroadcastStream()...
Stream activation happens only when stream listener count changes from 0 to 1. Stream deactivation happens only when stream listener count changes from 1 to 0.
So we need to decide when it is done, and to do this we need to control its subscription rather than bury it in a pipeline or a StreamController's private internals via the addStream() method. So instead we'll listen to it directly, capturing the subscription to close when we're done. Then we just proxy the data into a StreamController or pipeline manually via add()
Stream<Uint8List> micStream = await MicStream.microphone(
sampleRate: AUDIO_SAMPLE_RATE,
channelConfig: ChannelConfig.CHANNEL_IN_MONO,
audioFormat: AudioFormat.ENCODING_PCM_16BIT);//,
// audioSource: AudioSource.MIC); // ios only supports default at the mo'
StreamController? s;
// We need to control the listener subscription
// so we can end this stream as per the docs instructions
final micListener = micStream.listen((event) {
print('emitting...');
// Feed the streamcon manually
s!.add(event);
});
s= StreamController();
// Let the SCon's close() trigger the Listener's cancel()
s!.onCancel = () {
print("onCancel");
micListener.cancel();
};
s!.done.whenComplete(() {
print("done");
});
// Further consumers will use the _StreamCon's_ stream,
// _not_ the micStream above
s!.stream.listen((event) => print("listening..."));
// Now we can close the StreamController when we are done.
Future.delayed(Duration(seconds: 3), () {
s!.close();
});
So here I got a question! How can I send and receive data from a simple thread who's job is to keep playing songs!? I want a way to send data to the thread to stop iterating a list of songs. It can be a file descriptor, variable(global), properties/options, database entry, or even an event.
Here is the code:
def ControlPlay(ControlAction):
SongList = DarkCore.mediaPlayList().result
while ControlAction:
for Song in SongList:
if DarkCore.mediaIsPlaying(Song).result == False:
print "Now Playing:" , Song
DarkCore.mediaPlayStart(Song)
while DarkCore.mediaIsPlaying(Song).result:
continue
import android # Python For Android
DarkCore = android.Android()
import threading
t = threading.Thread(target=ControlPlay, args=(True,))
t.start()
I may get a Stop from multiple sources(devices) using different protocols like wifi via socket(ssh tunnel), bluetooth or serial that extend over a range of protocols and actions. All I want is a way to identify and declare an action based on what another thread or main loop sends.
A simple explanation.. Thanks for your understanding! Any help is appreciated.
I am making a NFC application that use ISO-DEP (ISO 14443-4) as TagTechnology.
I try to execute a authentication with a DESFire EV1.
The authentication work well if the chaining of the command is without pause.
But if for exemple, I make something that take time (like the Thread.Sleep after NATIVE_AUTHENTICATION_COMMAND_P1) I got an error 0x911C ("Command code not supported") during the authentication command part 2 from the card.
Normaly the error come when the authentication has been canceled. Like if the card got another command during the authentication procedure that have nothing about it.
The problem is that my application do nothing else that sending the selectApplication, Authentication Part 1, Sleep and the Part 2.
I have try the same code in C++ with a PCSC Reader and the Sleep is not the probleme, even with 5 second sleep the authentication have work on my computer.
So I would like to know if Android is "playing" with the card even after giving the Intent to the application or if the Frame Waiting Time (ISO 14443-4) is not working or NDEF "pull" broke the authentication or...
(The value of NATIVE_AUTHENTICATION_COMMAND_P2 is a exemple)
final byte[] NATIVE_AUTHENTICATION_COMMAND_P1 = new byte[]{(byte)0x90, (byte)0x0A, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x00};
final byte[] NATIVE_AUTHENTICATION_COMMAND_P2 = new byte[]{(byte)0x90, (byte)0xAF, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0xAB, (byte)0xB4, (byte)0x66, (byte)0xA4, (byte)0xE9, (byte)0x99, (byte)0xFF, (byte)0x5C, (byte)0xD7, (byte)0xF3, (byte)0xA7, (byte)0x81, (byte)0x62, (byte)0x2F, (byte)0xFA, (byte)0x16, (byte)0x00};
final byte[] NATIVE_SELECT_COMMAND = new byte[]{(byte)0x90,(byte)0x5A,(byte)0x00,(byte)0x00,(byte)0x03,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00};
IsoDep tag = IsoDep.get(tagFromIntent);
tag.connect();
byte[] result;
result = tag.transceive(NATIVE_SELECT_COMMAND); //SUCCESS
result = tag.transceive(NATIVE_AUTHENTICATION_COMMAND_P1); //SUCCESS
// Thread.sleep(1000);
result = tag.transceive(NATIVE_AUTHENTICATION_COMMAND_P2); //result = 0x90AE without Sleep and with Sleep 0x911C ("Command code not supported")
tag.close();
If someone have an idea because I am totally lost :)
UPDATE:
After the help of michael-roland and his tips; I have use the reader-mode API with NDEF check disable and delay presence check to 10 second to get my chaining command working perfectly !
#Override
protected void onResume() {
super.onResume();
Bundle options = new Bundle();
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 10000);
mAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, options);
}
#Override
public void onPause() {
super.onPause();
mAdapter.disableReaderMode(this);
}
You ran into a known problem with the NFC stack for Broadcom's NFC chipset. The issue is known for quite a while (see this Android bug report, something similar applies to non APDU-based tags too).
In your case, the problem is that while the connection between the phone and the tag is idle, Android automatically performs a presence check. While this presence check is correctly implemented for NXP's NFC stack, the Broadcom version uses a READ BINARY command (for IsoDep cards) or an equivalent READ command (for other tag technologies).
So, if your command sequence is slow, Android might send a READ BINARY APDU somewhere in between your commands.
Unfortunately, this bug still exists in Android 4.4.2 and to me it seems unclear if Google will eventually do something about it. UPDATE: There is a new presence check mechanism starting with Android 5.
If you use Android 4.4, there is, however, something you can do to avoid the bug: Use the new reader-mode API to tweak the presence-check timeout. If you do not use NDEF, you could even completely disable the presence-check.
I'm trying to connect a USB-Device ( build by myself ) to communicate with my development board ( ODROID-X )
Unfortunately, the examples are very little, as far as the asynchronous communication. I'd some problems with the interrupt driven data exchange - how to build the connection by using the asynchronous interrupt mode?
In one direction, the transmission was possible ... but in both it doesn't work. Is there an example like this:
send a ByteBuffer with endpoint_OUT
get a message from device on endpoint_IN
both in interrupt mode.
Thanks a lot for your support.
Hardy
Perhaps I am misunderstanding the question here.
The sample missile lanucher app that is part of the API package from level 12 onwards uses the queue() and requestWait() methods to handle interrupt type endpoints.
Requests are either In or Out and depend on the direction of the EndPoint.
The code for a pretty noddy request->reply looks something like this. You would want to structure real code differently but this gives you the gist of what needs to happen (I hope)
public void run() {
int bufferMaxLength=mEndpointOut.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferMaxLength);
UsbRequest request = new UsbRequest(); // create an URB
request.initialize(mConnection, mEndpointOut);
buffer.put(/* your payload here */;
// queue the outbound request
boolean retval = request.queue(buffer, 1);
if (mConnection.requestWait() == request) {
// wait for confirmation (request was sent)
UsbRequest inRequest = new UsbRequest();
// URB for the incoming data
inRequest.initialize(mConnection, mEndpointIn);
// the direction is dictated by this initialisation to the incoming endpoint.
if(inRequest.queue(buffer, bufferMaxLength) == true){
mConnection.requestWait();
// wait for this request to be completed
// at this point buffer contains the data received
}
}
}
If you are actually looking for a way to run this IO in an asynchronous manner without binding a thread to it, then I think you need to consider using the DeviceConnection.getFilehandle() method to return a standard file handle which in theory you can then use as if it were any other file type resource. I would note however that I have not tried this.
If neither of these addresses the issue please revise the question to clarify what you are struggling to find examples of.
I hope this helps.
I am developing a SIP application for making and receiving a call. For that purpose I did analysis on open source project SipDroid. in that project how they catch the value of dialpads pressed button which is sent to the particular method for making a SIP call.
I tried to find the code for that task but I didn't get anything.in which file the code is resides to catch that value in SipDroid project?
The calls in SipDroid are handled by the SipdroidEngine:
org.sipdroid.sipua.SipdroidEngine
The method that handles the initial operation is with signature public boolean call(String target_url,boolean force) - it transfers the call to the SipDroid UserAgent class and so on, until it reaches the network transport layer. Just check the references of this call method in the whole project and see where it's used.
The dialpad values are called DTMF (Dual-tone multi-frequency signaling).
Most of SipDroid's DTMF stuff is in dtmf.h.
You can search through the source code to see where it is used.