Problems with Reflection for createRfcommSocket - java

This is odd. I am trying to set up Bluetooth SPP on a Droid X Android 2.3.4. I have included a few different methods from attempting to open an rfcomm Socket, one being reflection (needed for support of certain phones)
However, with the Droid X a strange thing happens. When I connect the first time to a Bluetooth device my app opens up and attempts SPP by first:
Method m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
mmSocket = (BluetoothSocket) m.invoke(mmDevice, Integer.valueOf(1));
And if it can't find the method, it tries the normal
mmSocket = mmDevice.createRfcommSocketToServiceRecord(SerialPortServiceClass_UUID);
This works correctly the first time through. But if I close my program then reopen it for some reason the reflection method then actually finds the method, attempts to connect doesn't have any errors, but it doesn't actually connect.
If I close the app, power cycle the bluetooth adapter on the phone and try again it will work correctly.
I am at a loss on what's going on, so any help would be greatly appreciated.

Well I came up with a bandaid type fix that I am not happy with, but will work until I can find the root cause or better solution. I simply make a shared preference object that contains a "level" of which methods to try.
The levels are labeled 1-4, and if the level is set to a number <= to the current level it will try that method if no connection has been established.
if(level<=1){
success set level = 1
fail set level = 0
}
if(level<=2){
success set level = 2
fail set level = 0
}
...
if(level<=4){
success set level = 4
fail set level = 0
}

Related

Android show no output from Inputstream reader and Procees return exit code 1

i am trying to run a process and to read it's data from InputStreamReader, but it fails in a weird way.
The executable is "ip neigh show"
When trying to run the command from connected device via adb shell the command executes OK and also displays data correctly.
But when trying to execute it from kotlin code it exit with exit code 1 and InputStreamReader show empty data also.
This is how i am trying it :
val p = Runtime.getRuntime().exec("ip neigh show")
InputStreamReader(p!!.inputStream).forEachLine fori#{ line ->
val teDhenat = line.split("\\s+".toRegex())
if (teDhenat[0] == ip) {
if (teDhenat.size < 4) {
return#fori
} else {
uGjet = true
macAddress = teDhenat[4]
return#fori
}
}
}
The problem seems to happen in that line : val p = Runtime.getRuntime().exec("ip neigh show") but i don't understand why.
Also tried with val p = Runtime.getRuntime().exec("/system/bin/ip neigh show") and it's still the same.
Also i have tried using ProcessBuilder() and it doesn't work too.
The Compile and Target SDK is 31
The phone is Xiaomi running Android 11 (SDK 30)
PS: Also i am using same logic for other executables and they work very fine like "ping", "top" etc...
Since Android 11 (SDK 30) :
In addition, non-privileged apps can't access the device’s MAC
address; only network interfaces with an IP address are visible. This
impacts the getifaddrs() and NetworkInterface.getHardwareAddress()
methods, as well as sending RTM_GETLINK Netlink messages.
The following is a list of the ways that apps are affected by this
change:
NetworkInterface.getHardwareAddress() returns null for every
interface.
Apps cannot use the bind() function on NETLINK_ROUTE
sockets.
The ip command does not return information about interfaces.
Apps cannot send RTM_GETLINK messages. Note that most developers
should use the higher-level APIs of ConnectivityManager rather than
lower-level APIs like NetworkInterface, getifaddrs(), or Netlink
sockets. For example, an app that needs up-to-date information on the
current routes can get this information by listening for network
changes using ConnectivityManager.registerNetworkCallback() and
calling the network's associated LinkProperties.getRoutes().

Java usb4java reading from usb device on windows 10 platform

I am trying to read a message from RFID reader connected via USB to windows 10pro machine with usb4java library.
I have managed to claim the interface, opened pipe and registered listener for the data, however the listener is never triggered. The reader acts as keyboard and whatever it reads ends up in active application, such as IDE i have open, instead of in listener.
UsbInterface usbInterface = activeInteface(device);
// there is only one endpoint in the list
UsbEndpoint endpoint = (UsbEndpoint)usbInterface.getUsbEndpoints().get(0);
UsbPipe pipe = endpoint.getUsbPipe();
try {
usbInterface.claim();
// true
System.out.println("claimed usb interface: " + usbInterface.isClaimed());
pipe.open();
// true
System.out.println("pipe open: " + pipe.isOpen());
pipe.addUsbPipeListener(new MessageListener());
// true
System.out.println("pipe active: " + pipe.isActive());
// keep main thread alive, async call should be done from another thread i guess
Thread.sleep(15000);
}
catch (Exception any) {System.out.println(any);}
}
And the listener:
private static class MessageListener implements UsbPipeListener {
#Override
public void errorEventOccurred(UsbPipeErrorEvent event) {
System.out.println(event.toString() + " , " +event.getUsbException());
}
#Override
public void dataEventOccurred(UsbPipeDataEvent event) {
// this code block never triggers
System.out.println("listener ...);
int actualLength = event.getActualLength();
System.out.println("length: " + actualLength);
byte[] data = event.getData();
System.out.println("data length " + data.length);
}
}
i have also tried synchronous read instead of asynchronous in the block above, like this:
byte[] buffer = new data[8];
// this fails on its own, don't even need to read something with RFID reader
int received = pipe.syncSubmit(buffer);
fails with:
USB error1: Transfer error on interrupt endpoint: Input/Output error
There is some windows specific property that library supports: org.usb4java.javax.useUSBDK = true
but this fails when i try to set it with an exception.
I have 0 experience with USB devices so not sure how to proceed from here. Is there something wrong with the code, do i need USBDK or device does not support libUSB driver ? Sadly this is not my device and i don't have access to documentation of the device so cannot be sure if it is device driver issue.
I know that this is 2 years old, but i've had similar issue and this was one of the first questions that i ran into looking for solution, which took me hours.
So, basically, windows doesn't let to read/write keyboard devices directly, to do so, you have to override it's driver (That's why you're getting Input/Output error, and it's written in the hid4java's FAQ).
First way to override device driver is described in libusb wiki.
As far as i know you would have to install a new driver every time you connect the device to a new USB port, which is why i recommend you to read further.
Second way is what you've already mentioned, which is using UsbDk (Usb Drivers Development Kit for Windows). It makes the device accessible for you by detaching the kernel driver and reattaching it back after you're done playing with it.
In order to use it, you need to do two things:
Set the org.usb4java.javax.useUSBDK = true in you javax.usb.properties file as stated in the manual (this can also be done manually in low-level usb4java, see OPTION_USE_USBDK and setOption(Context, int)).
Download and install UsbDk on your system (simplest way is to download x64 or x86 version msi installer which has GUI and is fully automated), which is sadly not in the manual (maybe it's obvious for some people, but took me amount of time that i am not proud of to realize).
Im guessing that the lack of second step is why OP has been getting an exception.
Hope that this will help someone, knowing all this two days ago would save me a lot of headache.
RFID readers operate in keyboard emulation mode by default.
You can normally get a tool from the manufacturer's website to configure the RFID reader.
This will allow you to change the reader to HID mode.
This should resolve your issues.
Sorry for the late response but I hope it helps others.

ELM327 returns `?` when trying to use it with ODB Java API

I'm trying to use ODB Java API (this library) to get the data from ELM327 via Bluetooth from my car, but in returns ? on every request, and library raises MisunderstoodException
Here is my code:
socket = device.createInsecureRfcommSocketToServiceRecord(uuid);
socket.connect();
final CustomRPMCommand engineRpmCommand = new CustomRPMCommand();
final SpeedObdCommand speedObdCommand = new SpeedObdCommand();
while (!Thread.currentThread().isInterrupted()) {
engineRpmCommand.run(socket.getInputStream(), socket.getOutputStream());
speedObdCommand.run(socket.getInputStream(), socket.getOutputStream());
runOnUiThread(new Runnable() {
#Override
public void run() {
speedometerGauge.setSpeed(engineRpmCommand.getRPM(), true);
rpmGauge.setSpeed(speedObdCommand.getMetricSpeed(), true);
}
});
}
What's wrong?
I also used the same library for the first steps into trying out OBD, so I can say at least at the time I used it, it worked fine.
From my experience however, getting ? back can sometimes happen with cheap Bluetooth devices (maybe even with expensive ones? never had one). I guess this happens, if some bits are lost during the transmission, because then command will be misunderstood.
What I did to circumvent this problem is setting up a process where I sent all AT commands up to 10 times until I get the desired response of OK (except for ATZ, which will respond with ELM327). As for value requests like RPM etc. I usually just throw away the erroneous values.
That's the short answer, but since such problems with the devices can annoy a lot, I will guide you into debugging the whole process...
Setting up a terminal on windows
First of all to test the functionality of the ELM device, you can send commands to the serial interface directly. On windows, this is possible using for example TeraTerm and then setting up new Bluetooth connection on your windows as a COM device (search for Bluetooth in start -> search box and then choose Change Bluetooth settings or similar). From there, go to COM connections and then add a new one Outgoing for the Bluetooth OBDII device. Wait a bit for windows to calculate the new COM port number, you will need it.
If you cannot find OBDII in the dropdown box, you have to bond your PC with your Bluetooth device first. This can be done via devices and printers, there you should see the OBDII device, so you only have to connect it (PIN usually is 1234).
If you're on Linux, it might be somewhat easier, but I haven't done it :)
Sending some commands via terminal
Once you have your Bluetooth connection and TeraTerm installed, you can start TeraTerm and connect to the adapter. Choose Serial and then the port you just set up. Ensure, that no other device is connected to the OBD adapter (also not your phone). Only one device can be connected at a time.
If connection was successful, you should be able to type letters. Usually, in default settings you should be able to see the letters you type (Echo mode on), but since this is not certain, just type ATZ and hit <Enter>. The ELM should respond with "ELM327" in the same line now (which for me usually results in odd display if echo mode was on, but you should get any response).
From terminal I usually send these commands in order:
ATZ
E1
L1
010c
This will trigger:
Reset of the OBD device
Make sure that echo is on, so I see what I am typing
Make sure Line feed is on, so we get responses in the next line
Request RPM from the vehicle
Between each command I'll check what is the reply of the device. For all AT commands (1., 2. and 3.) it must be OK. If I get back ?, which can happen, I will repeat the command another time. You will see that in such a case the device indeed did not follow the instructions, e.g. did not set line feed on if it was off. So we really have to send it again.
In programming mode on the other hand, we will set e0 and l0 (echo mode off and line feed off), because we do not want to get sent back what we already sent out.

USB HID on Android

I'm trying to read data from the custom made USB device (working as slave) in Android. I was able to write the data to the device with this code:
UsbRequest request = new UsbRequest();
request.initialize(_outConnection, _outEndpoint);
int bufferDataLength = _outEndpoint.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferDataLength + 1);
buffer.put(bytes);
if (request.queue(buffer, bufferDataLength)) {
UsbRequest req = _outConnection.requestWait(); }
I see the result on the debug board that my device is connected to.
I'm trying the same approach for reading data, but apparently that doesn't work:
int siz = 1;
ByteBuffer res = ByteBuffer.allocate(siz + 1);
UsbRequest request = new UsbRequest();
request.initialize(_inConnection, _inEndpoint);
request.queue(res, siz); // This return false always
What am I doing wrong? I have no idea of the size of the packet sent back - but I assume that 1 byte I would be always able to read.
My device has HID interface with two interrupt endpoints (IN and OUT)
I have no idea what fixed the problem, but now it works. I have rewritten everything from scratch. I think I didn't use this code (I thought it is for user notification and I don't need that. But appears it is something else) - and that was the main reason why it didn't work:
// Create and intent and request a permission.
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(_context, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
_context.registerReceiver(mUsbReceiver, filter);
Several things that I did and which helped me to implement stable connection are:
1) Closing and opening the connection each time I need it. I know this is sounds strange, but this is the only way I could make it stable. If I try to use long-living connection, for some reason it gets corrupted and stops from working after some time.
2) Reading continously in never-ending while loop. I also put some short sleeps in all my threads - that helped to read in more real time manner.
3) Locking the device (synchronized). I do not open both write and read connections simultaneously.
I didn't have much hours assigned for this project, and this project is only a demo - so all of this suited us well. I think if spent a little more time, some of these things could have been rewritten to more nice ones.

Java Desktop.browse occasionally returning "requested lookup key not found in any active activation context"

I am really struggling with this issue as it seems to occur randomly for me. When I call,
Desktop.browse("some url");
Internet Explorer will not display. The exception message is as follows,
The requested lookup key was not found in any active activation context.
When it occurs it occurs consistently until I restart the machine, but it eventually occurs again.
The workstations that seem to have this problem are running Windows XP with Internet Explorer 8 set as the default browser.
EDIT: I forgot to mention that if I open up Internet Explorer directly and navigate to the URL in question then it will work fine.
EDIT2: This seems to happen if Desktop.browse is invoked and then is called again at least 15 minutes later. Restarting the application now seems to fix the problem.
I narrowed down the problem and discovered what was TRULY causing this, it had nothing to do with the time after all.
java.awt.Desktop.browse("some url"); was throwing this error because in a previous step in the application an ActiveXObject was opened programmatically using the JACOB framework.
The developer that wrote this code using this ActiveXObject neglected to bother releasing his resources at all. For some reason, this ActiveXObject in memory was preventing or screwing with the Dispatch call to the default OS browser in java.awt.Desktop class. I suppose this makes sense.
I fixed this by declaring a JACOB transaction, and by releasing all resources in a finally block like so:
ActiveXObject ao1 = null;
ActiveXObject ao2 = null;
ComThread.initMTA();
try {
ao1 = new ActiveXObject("blaa.blaa");
ao2 = new ActiveXObject("haa.haa");
// business logic
} finally {
if (ao1 != null) {
ao1.safeRelease();
ao1 = null;
}
if (ao2 != null) {
ao2.safeRelease();
ao2 = null;
}
ComThread.Release();
}

Categories