Implement a timeout in BluetoothSocket inputstream.read() in Android - android

Is it possible to implement a timeout in an inputstream.read() function from a BluetoothSocket in Android?
I've tried using Thread.sleep() but this only pauses my activity.
---Update---
I had an idea, make 2 thread code herereads(t1 & t2) where each thread interrupt other, one of them(t1) do a sleep(5000) then interrupt the other thread(t2), from the other side the other thread(t2) if in read the inputstream detects some character as 0x0D interrupt the other thread(t1), but here is my question, does anybody can help me? because i didn't use interrupt() method of threads, I hope someone can help me, thank you...
---Update---
public void run(){
while(true){
try {
char r;
String respuesta = "";
while (true) {
r = (char) mmInStream.read();
respuesta += r;
if (r == 0x3e) {
break;
}
}
respuesta = respuesta.replaceAll(" ", "");
Log.d("respuesta", respuesta);
rHandler.obtainMessage(MESSAGE_READ, -1, -1, respuesta).sendToTarget();
} catch (IOException readException) {
Log.e("ServicioGeneral", "Error de lectura", readException);
this.interrupt();
connectionLost();
// posibly break();
}
}
}
This is my implementation when something comes in a different Thread, the problem is that the timeout will be reached if i dont get the 0x3e character from de mmInStream.
I supposed that in the second example i must use a notifyAll(), but, when do I have to start the readThread()?
Thank you, #weeman

You could do something like this:
InputStream in = someBluetoothSocket.getInputStream();
int timeout = 0;
int maxTimeout = 8; // leads to a timeout of 2 seconds
int available = 0;
while((available = in.available()) == 0 && timeout < maxTimeout) {
timeout++;
// throws interrupted exception
Thread.sleep(250);
}
byte[] read = new byte[available];
in.read(read);
This way you are able to initially read from a stream with a specific timeout. If u want to implement a timeout at any time of reading you can try something like this:
Thread readThread = new ReadThread(); // being a thread you use to read from an InputStream
try {
synchronized (readThread) {
// edit: start readThread here
readThread.start();
readThread.wait(timeOutInMilliSeconds);
}
catch (InterruptedException e) {}
using this you may need some kind of event handler to notify your application if the thread actually read something from the input stream.
I hope that helps!
----edit:
I implemented an example without using any handlers.
Socket s = new Socket("localhost", 8080);
final InputStream in = s.getInputStream();
Thread readThread = new Thread(new Runnable() {
public void run() {
int read = 0;
try {
while((read = in.read()) >= 0) {
System.out.println(new String(new byte[]{ (byte) read }));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
synchronized (readThread) {
readThread.start();
try {
readThread.wait(2000);
if(readThread.isAlive()) {
// probably really not good practice!
in.close();
System.out.println("Timeout exceeded!");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

A Kotlin extension function for socket read with timeout:
fun InputStream.read(
buffer: ByteArray,
offset: Int,
length: Int,
timeout: Long
): Int = runBlocking {
val readAsync = async {
if (available() > 0) read(buffer, offset, length) else 0
}
var byteCount = 0
var retries = 3
while (byteCount == 0 && retries > 0) {
withTimeout(timeout) {
byteCount = readAsync.await()
}
delay(timeout)
retries--
}
byteCount
}

Related

Can not browse anything after connecting to a tunnel

So, I was going through the guide of connecting to a VPN using an applicaton from here guide
. What I really want is to make my own VPN app by using free DNS available on the internet. Because I want to have DoH (DNS over Https)and full security. So, I want CleanBrowsing to be my DNS. (I know there is already an app for it but I want to do it from scratch). So I went to this CleanBrowsing DNS GUIDE. I am using the follwing free filter provided by them
family-filter-dns.cleanbrowsing.org
So, I am able to connect my tunnel to the server but when I open a browser it does not do anything. here is the mini version of the configuration here.
final SocketAddress serverAddress = new InetSocketAddress("family-filter-dns.cleanbrowsing.org", 53);
VpnService.Builder builder = mService.new Builder();
builder.addAddress("10.1.10.1", 32);
builder.addDnsServer("185.228.168.168");
builder.addDnsServer("9.9.9.9");
builder.addRoute("0.0.0.0", 0);
builder.setMtu(1000);
My complete file looks like this
public ToyVpnConnection(final VpnService service, final int connectionId,
final String serverName, final int serverPort, final byte[] sharedSecret,
final String proxyHostName, final int proxyHostPort, boolean allow,
final Set<String> packages) {
mService = service;
mConnectionId = connectionId;
mServerName = serverName;
mServerPort = serverPort;
mSharedSecret = sharedSecret;
if (!TextUtils.isEmpty(proxyHostName)) {
mProxyHostName = proxyHostName;
}
if (proxyHostPort > 0) {
// The port value is always an integer due to the configured inputType.
mProxyHostPort = proxyHostPort;
}
mAllow = allow;
mPackages = packages;
}
/**
* Optionally, set an intent to configure the VPN. This is {#code null} by default.
*/
public void setConfigureIntent(PendingIntent intent) {
mConfigureIntent = intent;
}
public void setOnEstablishListener(OnEstablishListener listener) {
mOnEstablishListener = listener;
}
#Override
public void run() {
try {
Log.i(getTag(), "Starting");
// If anything needs to be obtained using the network, get it now.
// This greatly reduces the complexity of seamless handover, which
// tries to recreate the tunnel without shutting down everything.
// In this demo, all we need to know is the server address.
final SocketAddress serverAddress = new InetSocketAddress("family-filter-dns.cleanbrowsing.org", 53);
// We try to create the tunnel several times.
// TODO: The better way is to work with ConnectivityManager, trying only when the
// network is available.
// Here we just use a counter to keep things simple.
// for (int attempt = 0; attempt < 10; ++attempt) {
// Reset the counter if we were connected.
if (run(serverAddress)) {
// attempt = 0;
}
// Sleep for a while. This also checks if we got interrupted.
// Thread.sleep(3000);
// }
Log.i(getTag(), "Giving up");
} catch (IOException | InterruptedException | IllegalArgumentException e) {
Log.e(getTag(), "Connection failed, exiting", e);
}
}
private static final String TAG = "ToyVpnConnection";
private boolean run(SocketAddress server)
throws IOException, InterruptedException, IllegalArgumentException {
ParcelFileDescriptor iface = null;
boolean connected = false;
// Create a DatagramChannel as the VPN tunnel.
try (DatagramChannel tunnel = DatagramChannel.open()) {
// Protect the tunnel before connecting to avoid loopback.
if (!mService.protect(tunnel.socket())) {
throw new IllegalStateException("Cannot protect the tunnel");
}
// Connect to the server.
tunnel.connect(server);
Log.d(TAG, "run: connected to the tunnel");
// For simplicity, we use the same thread for both reading and
// writing. Here we put the tunnel into non-blocking mode.
tunnel.configureBlocking(false);
// Authenticate and configure the virtual network interface.
iface = configure("");
// Now we are connected. Set the flag.
connected = true;
// Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(iface.getFileDescriptor());
// Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(iface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(MAX_PACKET_SIZE);
// Timeouts:
// - when data has not been sent in a while, send empty keepalive messages.
// - when data has not been received in a while, assume the connection is broken.
long lastSendTime = System.currentTimeMillis();
long lastReceiveTime = System.currentTimeMillis();
// We keep forwarding packets till something goes wrong.
while (true) {
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
// Write the outgoing packet to the tunnel.
packet.limit(length);
tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
lastReceiveTime = System.currentTimeMillis();
}
// Read the incoming packet from the tunnel.
length = tunnel.read(packet);
if (length > 0) {
// Ignore control messages, which start with zero.
if (packet.get(0) != 0) {
// Write the incoming packet to the output stream.
out.write(packet.array(), 0, length);
}
packet.clear();
// There might be more incoming packets.
idle = false;
lastSendTime = System.currentTimeMillis();
}
// If we are idle or waiting for the network, sleep for a
// fraction of time to avoid busy looping.
if (idle) {
Thread.sleep(IDLE_INTERVAL_MS);
final long timeNow = System.currentTimeMillis();
if (lastSendTime + KEEPALIVE_INTERVAL_MS <= timeNow) {
// We are receiving for a long time but not sending.
// Send empty control messages.
packet.put((byte) 0).limit(1);
for (int i = 0; i < 3; ++i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
lastSendTime = timeNow;
} else if (lastReceiveTime + RECEIVE_TIMEOUT_MS <= timeNow) {
// We are sending for a long time but not receiving.
throw new IllegalStateException("Timed out");
}
}
}
} catch (SocketException e) {
Log.e(getTag(), "Cannot use socket", e);
} finally {
if (iface != null) {
try {
iface.close();
} catch (IOException e) {
Log.e(getTag(), "Unable to close interface", e);
}
}
}
return connected;
}
private ParcelFileDescriptor handshake(DatagramChannel tunnel)
throws IOException, InterruptedException {
// To build a secured tunnel, we should perform mutual authentication
// and exchange session keys for encryption. To keep things simple in
// this demo, we just send the shared secret in plaintext and wait
// for the server to send the parameters.
// Allocate the buffer for handshaking. We have a hardcoded maximum
// handshake size of 1024 bytes, which should be enough for demo
// purposes.
ByteBuffer packet = ByteBuffer.allocate(1024);
// Control messages always start with zero.
packet.put((byte) 0).put(mSharedSecret).flip();
// Send the secret several times in case of packet loss.
for (int i = 0; i < 3; ++i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
return configure(new String());
// Wait for the parameters within a limited time.
// for (int i = 0; i < MAX_HANDSHAKE_ATTEMPTS; ++i) {
// Thread.sleep(IDLE_INTERVAL_MS);
//
// // Normally we should not receive random packets. Check that the first
// // byte is 0 as expected.
// int length = tunnel.read(packet);
// if (length > 0 && packet.get(0) == 0) {
//
// }
// }
// throw new IOException("Timed out");
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private ParcelFileDescriptor configure(String parameters) throws IllegalArgumentException {
// Configure a builder while parsing the parameters.
VpnService.Builder builder = mService.new Builder();
builder.addAddress("10.1.10.1", 32);
// builder.addAddress("185.228.148.168", 32);
// builder.addAddress("192.168.1.1", 24);
builder.addDnsServer("185.228.168.168");
builder.addDnsServer("9.9.9.9");
builder.addRoute("0.0.0.0", 0);
builder.setMtu(1000);
// Create a new interface using the builder and save the parameters.
final ParcelFileDescriptor vpnInterface;
try {
builder.addDisallowedApplication("com.example.android.toyvpn");
} catch (PackageManager.NameNotFoundException e) {
Log.w(getTag(), "Package not available: " + "packageName", e);
}
// for (String packageName : mPackages) {
// try {
// if (mAllow) {
// builder.addAllowedApplication(packageName);
// } else {
//
// }
// } catch (PackageManager.NameNotFoundException e){
//
// }
// }
builder.setSession(mServerName).setConfigureIntent(mConfigureIntent);
if (!TextUtils.isEmpty(mProxyHostName)) {
// builder.setHttpProxy(ProxyInfo.buildDirectProxy(mProxyHostName, mProxyHostPort));
}
synchronized (mService) {
vpnInterface = builder.establish();
if (mOnEstablishListener != null) {
mOnEstablishListener.onEstablish(vpnInterface);
}
}
Log.i(getTag(), "New interface: " + vpnInterface + " (" + parameters + ")");
return vpnInterface;
}
private final String getTag() {
return ToyVpnConnection.class.getSimpleName() + "[" + mConnectionId + "]";
}
}
Change the route address:
builder.addRoute("10.1.10.0", 32);

Android: VPN connection using VPNService

I am trying to establish and connect to our own vpn (Not the default vpn providers i.e, PPTP, L2TP etc which is present in the Android Setting -> Wireless and Networks) programmatically.
I would like to know if this is already possible as of 2017.
There are reference I use
http://www.thegeekstuff.com/2014/06/android-vpn-service/
https://android.googlesource.com/platform/development/+/master/samples/ToyVpn/src/com/example/android/toyvpn
While using Datagram Channel I get a PortUnreachableException. This is what my Codes look like :
#Override
public void run() {
try {
Log.i(getTag(), "Starting");
// If anything needs to be obtained using the network, get it now.
// This greatly reduces the complexity of seamless handover, which
// tries to recreate the tunnel without shutting down everything.
// In this demo, all we need to know is the server address.
final SocketAddress serverAddress = new InetSocketAddress(mServerName, mServerPort);
// We try to create the tunnel several times.
// TODO: The better way is to work with ConnectivityManager, trying only when the
// network is available.
// Here we just use a counter to keep things simple.
for (int attempt = 0; attempt < 10; ++attempt) {
// Reset the counter if we were connected.
if (run(serverAddress)) {
attempt = 0;
}
// Sleep for a while. This also checks if we got interrupted.
Thread.sleep(3000);
}
Log.i(getTag(), "Giving up");
} catch (IOException | InterruptedException | IllegalArgumentException e) {
Log.e(getTag(), "Connection failed, exiting", e);
}
}
private boolean run(SocketAddress server)
throws IOException, InterruptedException, IllegalArgumentException {
ParcelFileDescriptor iface = null;
boolean connected = false;
// Create a DatagramChannel as the VPN tunnel.
try (DatagramChannel tunnel = DatagramChannel.open()) {
// Protect the tunnel before connecting to avoid loopback.
if (!mService.protect(tunnel.socket())) {
throw new IllegalStateException("Cannot protect the tunnel");
}
// Connect to the server.
tunnel.connect(server);
// For simplicity, we use the same thread for both reading and
// writing. Here we put the tunnel into non-blocking mode.
tunnel.configureBlocking(false);
// Authenticate and configure the virtual network interface.
iface = handshake(tunnel);
// Now we are connected. Set the flag.
connected = true;
// Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(iface.getFileDescriptor());
// Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(iface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(MAX_PACKET_SIZE);
// Timeouts:
// - when data has not been sent in a while, send empty keepalive messages.
// - when data has not been received in a while, assume the connection is broken.
long lastSendTime = System.currentTimeMillis();
long lastReceiveTime = System.currentTimeMillis();
// We keep forwarding packets till something goes wrong.
while (true) {
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
// Write the outgoing packet to the tunnel.
packet.limit(length);
tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
lastReceiveTime = System.currentTimeMillis();
}
// Read the incoming packet from the tunnel.
length = tunnel.read(packet);
if (length > 0) {
// Ignore control messages, which start with zero.
if (packet.get(0) != 0) {
// Write the incoming packet to the output stream.
out.write(packet.array(), 0, length);
}
packet.clear();
// There might be more incoming packets.
idle = false;
lastSendTime = System.currentTimeMillis();
}
// If we are idle or waiting for the network, sleep for a
// fraction of time to avoid busy looping.
if (idle) {
Thread.sleep(IDLE_INTERVAL_MS);
final long timeNow = System.currentTimeMillis();
if (lastSendTime + KEEPALIVE_INTERVAL_MS <= timeNow) {
// We are receiving for a long time but not sending.
// Send empty control messages.
packet.put((byte) 0).limit(1);
for (int i = 0; i < 3; ++i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
lastSendTime = timeNow;
} else if (lastReceiveTime + RECEIVE_TIMEOUT_MS <= timeNow) {
// We are sending for a long time but not receiving.
throw new IllegalStateException("Timed out");
}
}
}
} catch (SocketException e) {
Log.e(getTag(), "Cannot use socket", e);
} finally {
if (iface != null) {
try {
iface.close();
} catch (IOException e) {
Log.e(getTag(), "Unable to close interface", e);
}
}
}
return connected;
}
And the Error message:
E/ToyVpnConnection[1]: Cannot use socket java.net.PortUnreachableException at sun.nio.ch.DatagramDispatcher.read0(Native Method)
at sun.nio.ch.DatagramDispatcher.read(DatagramDispatcher.java:42)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
at sun.nio.ch.IOUtil.read(IOUtil.java:197)
at sun.nio.ch.DatagramChannelImpl.read(DatagramChannelImpl.java:566)
at org.droidplanner.android.fragments.control.ToyVpnConnection.handshake(ToyVpnConnection.java:219)
at org.droidplanner.android.fragments.control.ToyVpnConnection.run(ToyVpnConnection.java:120)
at org.droidplanner.android.fragments.control.ToyVpnConnection.run(ToyVpnConnection.java:93)
MyVpnService:
class MyVpnService extends VpnService{
private static final String TAG = MyVpnService.class.getSimpleName();
private Thread mThread;
private ParcelFileDescriptor mInterface;
//a. Configure a builder for the interface.
Builder builder = new Builder();
public static final String ACTION_CONNECT = "com.example.android.toyvpn.START";
public static final String ACTION_DISCONNECT = "com.example.android.toyvpn.STOP";
private Handler mHandler;
private PendingIntent mConfigureIntent;
private final AtomicReference<Thread> mConnectingThread = new AtomicReference<>();
private final AtomicReference<Connection> mConnection = new AtomicReference<>();
private AtomicInteger mNextConnectionId = new AtomicInteger(1);
private static class Connection extends Pair<Thread, ParcelFileDescriptor> {
public Connection(Thread thread, ParcelFileDescriptor pfd) {
super(thread, pfd);
}
}
#Override
public void onCreate() {
Log.e("MyVpnService","onCreate");
// The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler();
}
//Create the intent to "configure" the connection (just start ToyVpnClient).
mConfigureIntent = PendingIntent.getActivity(this, 0, new Intent(this, ToyVpnClient.class),
PendingIntent.FLAG_UPDATE_CURRENT);
}
// Services interface
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Start a new session by creating a new thread.
mThread = new Thread(new Runnable() {
#Override
public void run() {
try {
//a. Configure the TUN and get the interface.
mInterface = builder.setSession("MyVPNService")
.addAddress("192.168.0.1", 24)
.addDnsServer("8.8.8.8")
.addRoute("0.0.0.0", 0).establish();
//b. Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(
mInterface.getFileDescriptor());
//b. Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(
mInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
//c. The UDP channel can be used to pass/get ip package to/from server
DatagramChannel tunnel = DatagramChannel.open();
// Connect to the server, localhost is used for demonstration only.
tunnel.connect(new InetSocketAddress("61.31.92.159", 1723));
//tunnel.connect(new InetSocketAddress("127.0.0.1", 8087));
//d. Protect this socket, so package send by it will not be feedback to the vpn service.
protect(tunnel.socket());
//e. Use a loop to pass packets.
while (true) {
//get packet with in
//put packet to tunnel
//get packet form tunnel
//return packet with out
//sleep is a must
Log.e("MyVpnService","true");
Thread.sleep(100);
}
} catch (Exception e) {
// Catch any exception
Log.e(TAG,"Exception:"+e.toString());
e.printStackTrace();
} finally {
try {
if (mInterface != null) {
mInterface.close();
mInterface = null;
}
} catch (Exception e) {
Log.e(TAG,"Exception2:"+e.toString());
}
}
}
}, "MyVpnRunnable");
//start the service
mThread.start();
if (intent != null && ACTION_DISCONNECT.equals(intent.getAction())) {
disconnect();
return START_NOT_STICKY;
} else {
connect();
return START_STICKY;
}
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
if (mThread != null) {
mThread.interrupt();
}
super.onDestroy();
}
private void connect() {
// Become a foreground service. Background services can be VPN services too, but they can
// be killed by background check before getting a chance to receive onRevoke().
updateForegroundNotification(R.string.connecting);
mHandler.sendEmptyMessage(R.string.connecting);
// Extract information from the shared preferences.
final SharedPreferences prefs = getSharedPreferences(ToyVpnClient.Prefs.NAME, MODE_PRIVATE);
final String server = "61.31.92.159";//prefs.getString(ToyVpnClient.Prefs.SERVER_ADDRESS, "");
final byte[] secret = "123456789".getBytes();//= prefs.getString(ToyVpnClient.Prefs.SHARED_SECRET, "").getBytes();
final int port;
try {
port = Integer.parseInt("1723");//Integer.parseInt(prefs.getString(ToyVpnClient.Prefs.SERVER_PORT, ""));
} catch (NumberFormatException e) {
Log.e("MyVPN", "Bad port: " + prefs.getString(ToyVpnClient.Prefs.SERVER_PORT, null), e);
return;
}
// Kick off a connection.
startConnection(new ToyVpnConnection(
this, mNextConnectionId.getAndIncrement(), server, port, secret));
}
private void disconnect() {
mHandler.sendEmptyMessage(R.string.disconnected);
setConnectingThread(null);
setConnection(null);
stopForeground(true);
}
private void updateForegroundNotification(final int message) {
startForeground(1, new Notification.Builder(this)
//.setSmallIcon(R.drawable.ic_vpn)
.setContentText(getString(message))
.setContentIntent(mConfigureIntent)
.build());
}
private void startConnection(final ToyVpnConnection connection) {
// Replace any existing connecting thread with the new one.
final Thread thread = new Thread(connection, "ToyVpnThread");
setConnectingThread(thread);
// Handler to mark as connected once onEstablish is called.
connection.setConfigureIntent(mConfigureIntent);
connection.setOnEstablishListener(new ToyVpnConnection.OnEstablishListener() {
public void onEstablish(ParcelFileDescriptor tunInterface) {
mHandler.sendEmptyMessage(R.string.connected);
mConnectingThread.compareAndSet(thread, null);
setConnection(new Connection(thread, tunInterface));
}
});
thread.start();
}
private void setConnectingThread(final Thread thread) {
final Thread oldThread = mConnectingThread.getAndSet(thread);
if (oldThread != null) {
oldThread.interrupt();
}
}
private void setConnection(final Connection connection) {
final Connection oldConnection = mConnection.getAndSet(connection);
if (oldConnection != null) {
try {
oldConnection.first.interrupt();
oldConnection.second.close();
} catch (IOException e) {
Log.e(TAG, "Closing VPN interface", e);
}
}
}
}
UPDATE:
a. ToyVPN does not use PPTP protocol (it uses its own)
b. ToyVPN is just a proof-of-concept demo, it does not support multiple {username, password} pairs.
c. API is one for OpenVPN: http://code.google.com/p/ics-openvpn/
This provides one potential VPN solution that you are fully in control of (the server is open-source also), but it is not PPTP or IPSec. If you understand the PPTP protocol, it should be possible to use this as a model to implement such a VPN client.
ToyVPN and OpenVPN doesn't work.
Although it's possible, won't be easy since:
The "VpnService" class is just a Virtual Network Adapter/Interface which can be considered/used as simple Fire-Wall like NetGuard is.
If you want to create a VPN app, that class will just ensure you do not need to root the device.
But all connection and data transfer must be coded from your side, which is hard network stuff.
On the other hand, there are people who did/are doing that even if it's hard to like.

android.net.wifi.WIFI_HOTSPOT_CLIENTS_CHANGED alternative

I'm trying to implement a way to listen to a client's connection event on the smartphone hotspot. I see that android.net.wifi.WIFI_HOTSPOT_CLIENTS_CHANGED is no longer avaible. How can i do this? I think that this is possible because the smartphone notify me when i client make a connection to the smartphone hotspot.
You can't use the Intent Action...You have to use a custom method, i'l suggest you create a background thread that checks/reads the I.P table (/proc/net/arp) constantly and update you...here's a snippet I've used.
Read i.p list table
public ArrayList<String> getConnectedDevices() {
ArrayList<String> arrayList = new ArrayList();
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader("/proc/net/arp"));
while (true) {
String readLine = bufferedReader.readLine();
if (readLine == null) {
break;
}
String[] split = readLine.split(" +");
if (split != null && split.length >= 4) {
arrayList.add(split[0]);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return arrayList;
}
Create runnable to check
class CheckHotSpotConnection implements Runnable {
private CheckHotSpotConnection() {
}
public void run() {
int i = 0;
while (discoverClient()) {
i = getConnectedDevices().size();
if (i > 1) {
//client discovered
//disable client discovery to end thread
} else {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Start Thread
new Thread(new CheckHotSpotConnection()).start();

Checking for escape character(0x1B,\033) while reading from socket

Ok, so I'm designing an Android MUD client as part of my school project. I'm having an issue, however, while implementing ANSI color parsing. I read in the data on a byte-by-byte basis. I've tried setting the character "hex" as '\033', '27', and '0x1B' but I can never seem to get it to detect the escape character. Is there anything you guys can see wrong with my checking of it? Also, the line "char check = String.valueOf(j).charAt(0);" is temporary, I was originally trying to check the character variable "hex" against the byte "j". Is there possibly a better way of checking for the character?
while(isConnected) {
int j = 0;
try {
int i = arrayOfByte.length;
j = streamInput.read(arrayOfByte, 0, i);
char check = String.valueOf(j).charAt(0);
Log.d("Console","Char is - " + check);
if (j == -1)
{
Log.d("Console","j = -1");
throw new Exception("Error while reading socket.");
} else if (j == 0) {
Log.d("Console","Continuing");
continue;
} else if (check == hex) {
Log.d("Console","Yo, daddio!");
} else {
final String strData = new String(arrayOfByte, 0, j).replace("\r", "");
runOnUiThread(new Runnable() {
public void run() {
textContent.append(strData);
scrollToBottom();
}
});
}
} catch (Exception e) {
Handler handlerException = GameWindow.this.mHandler;
String strException = e.getMessage();
final String strMessage = "Error while receiving from server:\r\nConnection terminated";
Runnable rExceptionThread = new Runnable()
{
public void run()
{
Toast.makeText(context, strMessage, 3000).show();
}
};
handlerException.post(rExceptionThread);
if(strException.indexOf("reset") != -1 || strException.indexOf("rejected") != -1)
{
isConnected = false;
try
{
connectionSocket.close();
}
catch (IOException e1)
{
e1.printStackTrace();
}
}
isConnected = false;
}
}
Well, you're checking the number of bytes read instead of each individual byte.
j = streamInput.read(arrayOfByte, 0, i);
returns the number of bytes read and put in arrayOfByte those bytes.
Therefore you need to do the following:
for (int n=0; n < j; n++)
{
if (arrayOfByte[n] == hex) Log.d("Console", "Yo, daddio!");
}

Wait for input for only X amount of time

I am trying to read in data from an input stream, but if the program does not receive data for X amount of time, I would like to terminate the attempt and return a -1. I was previously using Thread.sleep( X ) but then realized that thats a completely incorrect approach. If anyone has any ideas please let me know. Here is my code for reading from the input stream...
try {
// Read from the InputStream
bytes = mmInStream.read(buffer, 0, length);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(MainMenu.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothService.this.start();
//break;
}
You can use Future to do this.
First, you need a class which will be returned as "future" value:
public class ReadResult {
public final int size;
public final byte[] buffer;
public ReadResult(int size, byte[] buffer) {
this.size = size;
this.buffer = buffer;
}
}
Then you need to use executor service and use get(long timeout, TimeUnit unit) like this:
ExecutorService service = Executors.newSingleThreadExecutor();
Future<ReadResult> future = service.submit(new Callable<ReadResult>() {
#Override
public ReadResult call() throws Exception {
bytes = mInStream.read(buffer, 0, length);
return new ReadResult(bytes, buffer);
}
});
ReadResult result = null;
try {
result = future.get(10, TimeUnit.SECONDS);
} catch (InterruptedException e1) {
// Thread was interrupted
e1.printStackTrace();
} catch (ExecutionException e1) {
// Something bad happened during reading
e1.printStackTrace();
} catch (TimeoutException e1) {
// read timeout
e1.printStackTrace();
}
if (result != null) {
// here you can use it
}
In that way you will be able to achieve your goal. Plz note that its better to subclass Callable class which will accept inputstream as constructor argument then using class variables.
You could start a new Thread and in there wait for x amount of time. Pass a reference to your activity and once the time is over, you can call a method in your activity from the Time Thread.
eg.
Thread time = new Thread() {
Activity foo;
public addActivity(Activity foo) {
this.foo = foo;
}
public void run() {
Thread.sleep(x);
// Once done call method in activity
foo.theTimeHasCome();
}
}.start();
I hope this helps!

Categories

Resources