ByteBuffer byteBuffer = ByteBuffer.allocate(9);;
UsbRequest request = new UsbRequest();
request.initialize(mConnection,mEndpointIntr);
boolean b = request.queue(byteBuffer, 9);
Log.d(TAG, "start the request wait");
UsbRequest ur = mConnection.requestWait();
I want to use Android USB interrupt. The above code is a thread to receive data from my own USB board. But when I try to call UsbRequest ur = mConnection.requestWait(); the function does not return, it always runs into requestWait(). Why does this happen?
The requestWait() in your code will wait for the result of the request.queue(byteBuffer, 9)
Here are some possible reasons why it is not returning:
Your request queue is on a different endpoint than what your USB device is actually sending data on. Double check that you are listening on the correct interface and endpoint.
On the USB device firmware side, do not create your interrupt endpoint on common interface class such as HID. Create a new vendor specific interface, otherwise kernel may get hold of the interface if it is HID and request queue may fail, this is what happened to me.
On my own USB HID device with two endpoints (IN and OUT) connected to MK802, I encountered the same problem (queuing a request returned false). I had claimInterface called with false. Setting the following helped, I receive data alright.
c.claimInterface(device.getInterface(0), true);
Related
I started my adventure with AoT (I have basic toolkit).
1rst Idea that I try to implement is to communicate via USB with Card Reader (USB Card Reader HID Prox v3).
But I don't get it correctly.
This is "sample" code:
usbRequest = new UsbRequest();
usbConnection = mUsbManager.openDevice(device);
usbRequest.initialize(usbConnection, device.getInterface(0).getEndpoint(0));//communication from card scanner
//In handler:
byte[] byteArray = new byte[16];
int transfer = usbConnection.bulkTransfer(device.getInterface(0).getEndpoint(0), byteArray, 16, 300);
transfer result is = -1, did anyone has the same issue?
Assumption: Your USB device conforms to the USB CCID Device Class. If this is not true, you will need to provide the datasheet for your specific card reader.
Before you can execute any communications with USB endpoints, your app has to claim the interface first. In other words, there should be a call to claimInterface() in your code before any requests are sent.
Next, you are mixing two different forms of communication. Your app should EITHER use UsbRequest for asynchronous use OR bulkTransfer() for synchronous use. You don't need to initialize a UsbRequest if you are using bulkTransfer() instead.
You should verify what the max packet size of your UsbEndpoint is. Bulk CCID endpoints can support up to 512 byte packets, so a fixed length of 16 bytes may not be enough to read a full packet response (assuming this transaction was on the Bulk IN endpoint). Match your array size with your endpoint's packet size.
Background:
I have a BLE peripheral with two modes: "Application" and "Bootloader". In both modes, the device advertises with the same MAC address.
To switch from one mode to the other, the BLE peripheral must reboot itself. In doing so, it has to disconnect any active BLE connection.
The BLE peripheral only stays in Bootloader mode for about 5 seconds. If nobody connects to it within that window, it switches to Application mode.
The Problem:
Android takes a very long time to reconnect to the BLE device, long enough that I'm missing the 5 second window. The raw code has a few layers down to the BluetoothGATT and BluetoothAdapter layers, but the sequence of calls boils down to:
BluetoothGattCharacteristic c = mCharacteristics.get(POWER_STATE_UUID);
c.setValue(SHUTDOWN_VALUE);
mBluetoothGatt.writeCharacteristic(c);
// Signalled by BluetoothGattCallback.onCharacteristicWrite
bleWriteCondition.await();
mBluetoothGatt.disconnect();
// Wait for the underlying layer to confirm we're disconnected
while( mConnectionState != BluetoothProfile.STATE_DISCONNECTED ) {
// Signalled by BluetoothGattCallback.onConnectionStateChange
bleStateCondition.await();
}
mBluetoothGatt.connect();
while (mConnectionState != BluetoothProfile.STATE_CONNECTED) {
// Signalled by BluetoothGattCallback.onConnectionStateChange
bleStateCondition.await();
if (bleStateCondition.stat != 0) {
break;
}
}
Am I going about this entirely the wrong way? I've tried calling close() on the BluetoothGatt instance, then generating a new one with BluetoothDevice.connectGatt, but I get the same extremely slow behavior.
I'm testing on a Samsung Galaxy S4, API level 21.
The problem here is that the gatt connect call issues a background connection request. It can take quite a long time for this call to result in a connection. A description of the two types of connection request is here : Direct vs Background connections
The absolute fastest way to get a connection is to do a scan and upon finding your device issue a direct connection request to it. As the scan has just found it, you know it is there and the connection will complete quickly. This is more complicated than your example code, but will be most effective given your small window. A scan is the most aggressive way to find a device. However, if you already have the device object, you could just call a direct connection request on the device.
Scans are issued using code like this :
scanner = bluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.build();
filters = new ArrayList<ScanFilter>();
ScanFilter uuidFilter = new ScanFilter.Builder()
.setServiceUuid(YOUR_SERVICE_UUID).build();
filters.add(uuidFilter);
scanner.startScan(filters, settings, myScanCallback);
Upon finding your device (using the scan callback), issue a direct connection request via this method call :
myGatt = myDevice.connectGatt(this, false, myGattCallback);
The key part being the parameter of false. The connection request will time out in around 30s if the device is not found.
All the questions here point to classes of the same app or different apps in separate processes yet in the same device. I would like to send data to and from two separate apps in two separate devices. I tried using broadcastreceiver but it didn't work. Here is my snippet to send the data.
addressstring = String.valueOf(acrilocation.getText());
if (addressstring != null && addressstring.length() > 0){
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Constants.LOCATION_DATA_EXTRA, addressstring);
intent.setType("text/plain");
sendBroadcast(intent);
} else{
Toast.makeText(getApplicationContext(), "Enter valid location address", Toast.LENGTH_SHORT).show();
}
but when I receive the data in my other app using the following code snippet, It fails. When I debug the app I get null exception.
Intent intent = getIntent();
String action = intent.getAction();
String data = intent.getStringExtra(Intent.EXTRA_INTENT);
String type = intent.getType();
useraddress.setText(data);
startActivity(intent);
Is there another way to achieve this? I mean to send data to and from another app which is installed in another device?
Connecting over networks that accept incoming socket connections
The usual way to do this between Android devices (or between any peer devices) is to use sockets.
You set up one or both devices to 'listen' for connections on a socket and then accept a connection from the other when they want to communicate (or you can have a dedicated client and server and the client always initiates the connections).
Once the connection is established you can send messages back and forth.
There are many examples of Android client server socket applications, but one I found useful was:
Android Server/Client example - client side using Socket (and its companion server side blog article - link included in the client blog)
Note that you may have to add your own 'protocol' on top of this - for example if you are sending a file of unknown length without any special 'end' character, you may want to add a byte (or several byte to represent an int, long etc) at the start to indicate the length of the transmission so the receiving side knows when it has received everything (or that it has not received everything in case of an error).
Connecting over networks which do not allow incoming connections (e.g. most 3G/4G)
In these scenarios, while there is nothing theoretically stopping sockets working, in practice many mobile operators will not allow incoming socket connections. In addition you would need to find the public IP address of the Mobile, which is possible but is extra complexity. If your solution will only ever run on a single operators network you can experiment and see if it works, but if not you may find it better and easier to use a server in the 'middle':
Device A connectes to server
Device B connectes to server
Device A asks server for addresses of connected devices and 'discovers' device B
Device A send a message for device B. It actually sends the messages to the server with an indication that it is to be sent to device B
The server notifies device B that a message is available for it (using some sort of message notification like Google Cloud Messaging for example, or simply by the devices polling regularly to see if they have any messages).
Device B retrieves the messages from the server
The above will work on pretty much any network that allows connectivity to the internet. It does have the disadvantage of requiring a server but it is likely a necessary approach over most mobile networks.
If you want the two instances of your Android app on two different devices located on the different parts of the world to communicate with each other directly without the server, then the best way to do it is to use Tor Hidden Services. Tor Hidden Services allow the apps to bypass the firewall or NAT (if Tor is not blocked, of course), and the devices can easily communicate with each other without the need for a central server. Here, I will try to give some code examples that you can try. The best library suitable to this stuff is this.
Step 1: Add dependencies to your gradle.build in app module:
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
dependencies {
compile 'com.github.jehy:Tor-Onion-Proxy-Library:0.0.7'
compile 'org.slf4j:slf4j-api:1.7.7'
compile 'org.slf4j:slf4j-android:1.7.7'
}
Step 2: Add permissions (Internet permissions or whatever) to your manifest file.
Step 3(i): Now we will just write the classic Client-Server programs in Java but with added Android and Tor flavor. To test this properly, try creating two different apps. One app will be the server and the other app will be a client. Preferably, you can even install the two apps on different phones.
In this example, we will try to send "Hello from Tor client" string from client app to server app.
For the server side: You can try this function inside any Activity and AsyncTask.
void server(Context context){
//For comments and documentation, visit the original repo
//https://github.com/thaliproject/Tor_Onion_Proxy_Library
String fileStorageLocation = "hiddenservicemanager";;
com.msopentech.thali.toronionproxy.OnionProxyManager onionProxyManager =
new com.msopentech.thali.android.toronionproxy.AndroidOnionProxyManager(context, fileStorageLocation);
int totalSecondsPerTorStartup = 4 * 60;
int totalTriesPerTorStartup = 5;
try {
boolean ok = onionProxyManager.startWithRepeat(totalSecondsPerTorStartup, totalTriesPerTorStartup);
if (!ok)
System.out.println("Couldn't start tor");
while (!onionProxyManager.isRunning())
Thread.sleep(90);
System.out.println("Tor initialized on port " + onionProxyManager.getIPv4LocalHostSocksPort());
int hiddenServicePort = 8080;
int localPort = 9343;
String onionAddress = onionProxyManager.publishHiddenService(hiddenServicePort, localPort);
System.out.println("Tor onion address of the server is: "+onionAddress);
ServerSocket serverSocket = new ServerSocket(localPort);
while(true) {
System.out.println("Waiting for client request");
Socket receivedSocket = serverSocket.accept();
ObjectInputStream ois = new ObjectInputStream(receivedSocket.getInputStream());
String message = (String) ois.readObject();
//Here we will print the message received from the client to the console.
/*You may want to modify this function to display the received
string in your View.*/
System.out.println("Message Received: " + message);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
Step 3(ii): For the client side try this function
//Inputs:
//'String onionAddress' should be the one obtained in server() function.
//It will be printed in the console and it will possibly remain the same
//even if the app restarts, because all the data/cache will be stored locally.
//Also, when you run the code for the first time, Tor will take about 1 or 2 mins
//to bootstrap. In the subsequent runs, Tor will start relatively faster as the
//data will be cached. 'int hiddenServicePort' is the port at which the hidden
//service has started on the server. In our example code, it is 8080. So, pass that here
void client(Context context, String onionAddress, int hiddenServicePort){
String fileStorageLocation = "clientmanager";
com.msopentech.thali.toronionproxy.OnionProxyManager onionProxyManager =
new com.msopentech.thali.android.toronionproxy.AndroidOnionProxyManager(context, fileStorageLocation);
int totalSecondsPerTorStartup = 4 * 60;
int totalTriesPerTorStartup = 5;
try {
boolean ok = onionProxyManager.startWithRepeat(totalSecondsPerTorStartup, totalTriesPerTorStartup);
int socksPort=onionProxyManager.getIPv4LocalHostSocksPort();
if (!ok)
System.out.println("Couldn't start tor in client");
while (!onionProxyManager.isRunning())
Thread.sleep(90);
System.out.println("Client Tor initialized on port " + socksPort);
System.out.println("Client is waiting for the server to get ready");
Thread.sleep(2000);
Socket clientSocket =
Utilities.socks4aSocketConnection(onionAddress, hiddenServicePort, "127.0.0.1", socksPort);
ObjectOutputStream oos = new ObjectOutputStream(clientSocket.getOutputStream());
oos.writeObject("Hello from Tor client\n");
System.out.println("Client has sent the message");
oos.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
It's done. Run your apps and test it. If you get stuck, try consulting here.
So, now your apps can communicate without any central server. Tor Hidden Services are so awesome in these use cases.
You can also use IP6, then you can do a direct socket connection from one phone to the another. I got latency as low as 60ms between two phones on different 4G operators (in the same country though). Note that you have to send some data to avoid getting down switch to lower speed to get such low latency. 10 concurrent ping was enough for me.
The listen side doesn't need any change at all, the client side just has to use an IP6-address:
s = new Socket("2a10:811:21c:22a1:7683:ae1:18c7:9827", 9343);
IP6 seems to be supported by many operators. If not, tor can be a good fallback, if latency isn't a problem.
I have two phones which are paired and connected via bluetooth. How to programmatically check at one phone's end whether the other phone is getting an incoming call? Should I use a particular profile for this, that is, PBAP or HFP? If yes, how I am to do this?
Once I detect this, if I want to receive the incoming call via the connected phone, how should I implement that?
Download Hands Free Profile pdf. It is available easily. It provides you all details about how HFP works and AT commands supported by HFP for communication. No APIs available for this.
As eliasj said, you need to implement HFP and when two phones get connected, you can communicate between them via AT commands.
Suppose you have 1st phone which is Android device and 2nd phone Android or any device and they both are connected over HFP.
I don't have complete code but I can suggest you some AT commands -
1. Using AT+CIND? command you can read indicator status of other phone.
2. To enable reporting for Indicator status change, you need to use AT+CMER=3,0,0,1 command.
3. Once you get valid response from 'AT+CMER' command, you can use AlarmManager that will start a service which continuously reads the input stream of Bluetooth Socket.
4. Because of step 2., if the 2nd phone is having any incoming call, the input stream of Bluetooth Socket will contains RING as an alert.
I have used service implementing a Runnable. Here is a sample code for step 4.-
public void run()
{
try
{
// Get input and output streams from Bluetooth socket.
m_oInputStream = m_oBluetoothSocket.getInputStream();
m_oOutputStream = m_oBluetoothSocket.getOutputStream();
// Read input stream for +CIEV response is given or not.
byte[] buffer = new byte[200];
int nNumberOfBytesRead = m_oInputStream.read(buffer);
String strResponse = new String(buffer).trim();
if(true == strResponse.contains("RING"))
{
// Contains RING Alert. Answer the call.
// Start Activity for handling Incoming Call.
Intent oIncomingCallActivityIntent = new Intent(getApplicationContext(), IncomingCallActivity.class);
oIncomingCallActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
getApplicationContext().startActivity(oIncomingCallActivityIntent);
// Stop service.
stopSelf();
}
}
catch(Exception e)
{
// Log the error.
}
}
You need to implement acivity that handles incoming call. It will accept or reject call. To accept incoming call AT+ATA command is used. You will receive "OK" as a response from 2nd phone.
I hope this will help you.
You should implement HFP (the hands-free side). When I looked at this problem over a year ago it was not possible to send the audio between to phones (Android) but it could have change now.
Look at the Q/A in How to send AT commands based on BT Hands-Free profile in android? (hit on how to connect) and in the HFP spec https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=238193 (for how the profile works (incoming call on page 36))
I am working on USB communication between an Android Galaxy S III smartphone and a device which does not conform to Android Open Accessory device definition. I want to transfer asynchronously bulk data from the device to the host. The connection between the host and device works correctly, what has been verified by sending control commands to the device.
Can this transfer be done with an endpoint of the bulk type (USB_ENDPOINT_XFER_BULK) or it has to be the interrupt type (USB_ENDPOINT_XFER_INT) as it is specified in the MissileLauncher app sample?
Does the request.queue call fill the data buffer after the connection.requestWait returns or some other conditions need to be checked?
You must do your bulk transfer with your bulk endpoints either you do asynchronous or synchronous transfer(USB_ENDPOINT_XFER_BULK).
I can not give clear answer for you second question because I have too problem about this subject. I can fill my buffer with below code. Generally connection.requestWait() method is calling after request.queu(...) method. But I have problem in this state
ByteBuffer buffer = ByteBuffer.allocate(512);
buffer.order(ByteOrder.LITTLE_ENDIAN);
UsbRequest request = new UsbRequest();
request.initialize(usbDeviceModel.getConnection(), usbEndpoint2);
request.queue(buffer, 512);
if(request == usbDeviceModel.getConnection().requestWait()){
Message msg = imageViewFragment.usbDataHandler.obtainMessage();
msg.obj = buffer.array();
imageViewFragment.usbDataHandler.sendMessage(msg);
}
I want to send data to my activity with handler after if condition but I can not send when my device plugged in to android device. Only when I plugged out my device if condition is working and I can send data to activity with handler. (https://stackoverflow.com/questions/35350251/android-asynchronous-bulk-transfer-with-usb-host-api#)