Variables that are needed for Bluetooth Connection - android

Currently, I'm trying to figure out how to stay connected with a device via Bluetooth throughout Activities. I have a few variables that I initialize to get the connection going.
My previous activity flow is Main Page > User input Text page > Bluetooth Connection(SENDING INFO).
So in this way, every time I go back to the User Input Text Page, the Bluetooth connection will be reset because when I go the next page, it'll rerun all the receivers and stuffs.
Now I'm moving the Bluetooth Connection forward. Meaning now it is Main Page > Bluetooth Connection > User Input Text Page(SEND).
But after I connect on my Bluetooth Connection page, I'm not sure what variables I should bring over/save inside SharedPreferences, so that the Bluetooth connection stays and I can send right away.
//This method runs when I click a device on my ListView.
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// Cancel discovery because it's costly and we're about to connect
bluetoothAdapter.cancelDiscovery();
System.out.println("Bluetooth Adapter2 = "
+ bluetoothAdapter.cancelDiscovery());
SiriListItem item = delist.get(arg2);
mAdapter.notifyDataSetChanged();
// When device being clicked
count++;
click = 1;
// Get the device MAC address, which is the last 17 chars in the
// View
String info = item.message;
String address = info.substring(info.length() - 17);
BlueToothAddress = address;
if (click == 1) {
clientThread ct = new clientThread();
ct.start();
}
};
};
//This is the clientThread if click == 1, it'll start this.
private class clientThread extends Thread {
public void run() {
try {
//
bdDevice = bluetoothAdapter.getRemoteDevice(BlueToothAddress);
socket = bdDevice.createRfcommSocketToServiceRecord(UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB"));
Message msg2 = new Message();
msg2.obj = "Please wait, connecting to server: "
+ BlueToothAddress;
msg2.what = 0;
LinkDetectedHandler.sendMessage(msg2);
socket.connect();
Log.i("tag", "This is the pairing section");
Message msg = new Message();
msg.obj = "Device connected. Sending message is allowed.";
msg.what = 0;
LinkDetectedHandler.sendMessage(msg);
readThread = new readThread();
readThread.start();
click++;
} catch (IOException e) {
Message msg = new Message();
msg.obj = "Error! Can't connect to device. Please try again.";
msg.what = 0;
LinkDetectedHandler.sendMessage(msg);
click--;
}
}
};
public class readThread extends Thread {
public void run() {
byte[] buffer = new byte[1024];
int bytes;
InputStream mmInStream = null;
String tmp = null;
try {
mmInStream = socket.getInputStream();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while (true) {
try {
// read the data from the inputStream
if ((bytes = mmInStream.read(buffer)) > 0) {
for (int i = 0; i < bytes; i++) {
tmp = "" + buffer[i];
String st = new String(tmp);
tmp = null;
Message msg = new Message();
msg.obj = st;
msg.what = 1;
}
}
} catch (IOException e) {
try {
mmInStream.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
break;
}
}
}
}
//On Click it'll send the message stored in the editText.
buttonConnect.setOnClickListener(new View.OnClickListener() {
#SuppressLint("NewApi")
#Override
public void onClick(View arg0) {
if (count == 0) {
Toast.makeText(bluetoothtest.this,
"Please connect to a device first.",
Toast.LENGTH_LONG).show();
}
// Need API=14
else if (!socket.isConnected()) {
Toast.makeText(bluetoothtest.this,
"Connecting! Please wait.", Toast.LENGTH_LONG)
.show();
} else {
try {
sendMessageHandle(contentRow1.getText().toString(),
contentRow2.getText().toString(), contentRow3
.getText().toString(), contentRow4
.getText().toString());
// sendMessageHandle(contentRow2.getText().toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
So the main thing is. What method should I have in my User Input Text Page? Must I have all this method in my User Input Text Page or can I just bring over variables via SharedPreferences?
Thanks.

It is probably bad practice to be handling bluetooth connections on the main thread. You should really handle the bluetooth connection/maintenance through a Service/background thread. Your activities can then talk to the service via a BroadcastReceiver and Handles.

Related

AndroidThings UsbToUart cannot Rx data when run long times [close]

Hello I use android thing on raspberry pi 3, I have a problem my app use UsbToSerial and then my app can Tx but cannot Rx data when app run longtime but in first period of work my app can Rx data and app can Tx alway times
How can I fix the problem?
And this is my code
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UartService uart_api = new UartService();
uart_api.UartInit("USB1-1.2:1.0", 9600);
}
UartService.java
public class UartService extends Activity {
private static final String TAG = "LoopbackActivity";
// UART Configuration Parameters
private static final int DATA_BITS = 8;
private static final int STOP_BITS = 1;
private static final int CHUNK_SIZE = 512;
private UartDevice mLoopbackDevice;
private void openUart(String name, int baudRate) throws IOException {
mLoopbackDevice = PeripheralManager.getInstance().openUartDevice(name);
// Configure the UART
mLoopbackDevice.setBaudrate(baudRate);
mLoopbackDevice.setDataSize(DATA_BITS);
mLoopbackDevice.setParity(UartDevice.PARITY_NONE);
mLoopbackDevice.setStopBits(STOP_BITS);
}
public void UartInit(String UartName, int baudrate){
PeripheralManager manager = PeripheralManager.getInstance();
List<String> deviceList = manager.getUartDeviceList();
if (deviceList.isEmpty()) {
Log.i(TAG, "No UART port available on this device.");
} else {
Log.i(TAG, "List of available devices: " + deviceList);
}
// Attempt to access the UART device
try {
openUart(UartName, baudrate);
// Read any initially buffered data
Thread thread_read = new Thread(new ThreadUart(123));
thread_read.start();
} catch (IOException e) {
Log.e(TAG, "Unable to open UART device", e);
}
}
public class ThreadUart implements Runnable {
private int data_in;
public ThreadUart(int in) {
this.data_in = in;
}
#Override
public void run() {
while(true){
///////// Test Rx //////
if (mLoopbackDevice != null) {
// Loop until there is no more data in the RX buffer.
try {
byte[] buffer = new byte[CHUNK_SIZE];
int read;
while ((read = mLoopbackDevice.read(buffer, buffer.length)) > 0) { // <<<< when run long time this cannot Rx data
mLoopbackDevice.write(buffer, read);
}
} catch (IOException e) {
Log.w(TAG, "Unable to transfer data over UART", e);
}
}
// sleep 1 sec.
///////// Test Tx //////
String string = "Hello\r\n";
byte[] b = string.getBytes(StandardCharsets.UTF_8);
try {
mLoopbackDevice.write(b, b.length); // <<<< can Tx work!! always time
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
finarly I follow Example example, It work !! in example use felHR85’s USBSerial library
however I don't know cause of Rx lost when use UART API and then run long time

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.

How can I connect two Android device by socket without server

I am trying to develop an android application that can exchange data on peer to peer connection with other devices without server. So please suggest how can I do this. Thank you in advance.
This is a complete code for chat by SocketProgramming without server.
In my Application, first you are a client and you search for a server. When you do not find any server, you become a server and wait for a client.
public class MainActivity extends ActionBarActivity {
private Handler handler = new Handler();
private TextView text;
private EditText input;
private Button send;
private Socket socket;
private DataOutputStream outputStream;
private BufferedReader inputStream;
private String DeviceName = "Device";
private boolean searchNetwork() {
log("Connecting");
String range = "192.168.56.";
for (int i = 1; i <= 255; i++) {
String ip = range + i;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(ip, 9000), 50);
outputStream = new DataOutputStream(socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
DeviceName += "1";
Log.i("Server", DeviceName);
log("Connected");
return true;
} catch (Exception e) {
}
}
return false;
}
private void runNewChatServer() {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(9000);
log("Waiting for client...");
socket = serverSocket.accept();
DeviceName += "2";
log("a new client Connected");
} catch (IOException e) {
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
input = (EditText) findViewById(R.id.input);
send = (Button) findViewById(R.id.send);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
if (!searchNetwork()) {
runNewChatServer();
}
outputStream = new DataOutputStream(
socket.getOutputStream());
inputStream = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
while (true) {
String Message = inputStream.readLine();
if (Message != null) {
log(Message);
}
}
} catch (IOException e) {
log("Error: IO Exception");
e.printStackTrace();
}
}
});
send.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
if (outputStream == null) {
return;
}
try {
String Message = input.getText().toString() + "\n";
outputStream.write(Message.getBytes());
log2(input.getText().toString());
} catch (IOException e) {
e.printStackTrace();
}
input.setText("");
}
});
thread.start();
}
private void log(final String message) {
handler.post(new Runnable() {
String DeviceName2="";
#Override
public void run() {
if (DeviceName.equals("Device1")) {
DeviceName2 = "Device2";
}else if(DeviceName.equals("Device2")) {
DeviceName2 = "Device1";
}else{
DeviceName2 = "UnknowDevice";
}
text.setText(text.getText() + "\n" + DeviceName2 + " :"
+ message);
}
});
}
private void log2(final String message) {
handler.post(new Runnable() {
#Override
public void run() {
text.setText(text.getText() + "\n" + "you" + " :"
+ message);
}
});
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.exit(0);
return true;
}
return super.onKeyDown(keyCode, event);
}
}
Your design has a big problem : ...
If there is no central server some android devices should act as client and others as server but this will not work in some situations:
When the mobile telephony provider assigns private and non-public IP
When the device is connected to a Wi-Fi network but no NAT rule is defined on the router.
In both cases the problem is that the listening port of the device that must act as server is unreachable.
Java provides ServerSocket and Socket to communicate b/w devices. One of the device you can make as server and other device you can make as client and communicate b/w 'em without introducing server hosted on some machine.
The Other and better option is Using Wi-Fi Peer-to-Peer. WifiP2pManager help you to achieve your purpose.Here is an example.
If you're looking for such P2P over a local network, there are two parts to it:
Discovering peers
Communicating with peers
Among Android APIs, you can either use Network Service Discovery APIs for this or Wifi P2P Service Discovery APIs.
There's a wrapper library which which uses these internally and has comparatively better documentation - Salut, which can also be used.
I also created a library for P2P - Near, which uses sockets directly. The problem I was facing with Android APIs was that discovery wasn't happening with certainty every time and the underlying issue was unknown.
If you're looking for P2P across the internet, socket IO is a prevalent solution. Even Near should be able to facilitate the transfers if you provide the IP addresses and they're not behind NAT firewalls.

FTDI Android - create new activity

This code is able to make the android device as a USB host for the hardware model. It also can read data from the hardware correctly in Main Activity. However, as soon as I moved it to another activity, everything still works but the data reading is incorrect.
For instance, I'm trying to write the data read into file. First activity is to input filename and just a button to send to another activity. The code below is in the second activity
public class Temp extends Activity {
private FileOutputStream outputStream;
public static D2xxManager ftD2xx= null;
Handler mHandler = new Handler();
FT_Device ftDev = null;
int devCount = 0;
UsbDevice device = null;
TextView Text =null;
String temp = null;
_4DPoint P = null;
int rd = 0;
byte[] byt = null;
byte[] Fdata = null;
String outp = "";
String From_Serial = "";
int Min = -1;
String fileName;
Context c;
final Runnable updateResults = new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Text.setText("" + Min + '\n' + temp);
}
};
public void getData(){
try {
outputStream = openFileOutput(fileName, Context.MODE_PRIVATE);
byt = new byte[256];//{(byte)'a','b','c','d',};
Toast.makeText(getBaseContext(), "start " + fileName , Toast.LENGTH_LONG).show();
Text = (TextView)findViewById(R.id.test2);
device = (UsbDevice) getIntent().getParcelableExtra("USB");
ftD2xx = D2xxManager.getInstance(c);
ftD2xx.addUsbDevice(device);
devCount = ftD2xx.createDeviceInfoList(c);
if (devCount > 0) {
ftDev = ftD2xx.openByUsbDevice(c, device);
}
if( ftDev.isOpen() == true ) {
ftDev.setBitMode((byte)0 , D2xxManager.FT_BITMODE_RESET);
ftDev.setBaudRate(38400);
ftDev.setDataCharacteristics(D2xxManager.FT_DATA_BITS_8, D2xxManager.FT_STOP_BITS_1, D2xxManager.FT_PARITY_NONE);
ftDev.setFlowControl(D2xxManager.FT_FLOW_NONE, (byte) 0x0b, (byte) 0x0d);
Thread t = new Thread() {
public void run() {
int i;
while(true){
rd=0;
while (rd==0){
rd = ftDev.read(byt, 14);
}
for(i=0; i<rd; i++)
outp += (char)byt[i];
From_Serial = new String(outp);
P = new _4DPoint(From_Serial);
temp = String.format("%s: %f %f %f %f %d\n", From_Serial, P.R, P.G, P.B, P.L, P.camera);
try {
outputStream.write(temp.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
outp = "";
mHandler.post(updateResults);
}
}
};
t.start();
}
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (D2xxException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_color);
// Show the Up button in the action bar.
setupActionBar();
Intent intent = getIntent();
fileName = intent.getStringExtra("File Name");
c = this;
getData();
}
The set up should be fine since it's reading data from hardware, but the data read is incorrect.
Also, I'm wondering why we need to create new thread while reading data. I tried not creating new thread and it didn't work well, but still have no idea why? I tried to contact the person who wrote the code to read data but no reply.
Any help would be really appreciated :)
You state that you receive data, therefor I think you should look at your ftDev settings. Try for example to set ftDev.setBaudRate(115200) (this worked for me) or try playing with your other ftDev Settings a little bit.
The settings I use in my programm are:
int baudRate = 115200;
byte stopBit = 1; /*1:1stop bits, 2:2 stop bits*/
byte dataBit = 8; /*8:8bit, 7: 7bit*/
byte parity = 0; /* 0: none, 1: odd, 2: even, 3: mark, 4: space*/
byte flowControl = 1; /*0:none, 1: flow control(CTS,RTS)*/
If this won't work, it is wise to first check this data communication with a computer program e.g. or to analyse the incomming 'wrong' data.

How to get an InputStream via bluetooth and put in a Textview?

This is my first question in SO. I am new (and excited) in Android programming and here is my PROBLEM: I am building a project using my android phone and a microcontroller. The microcontroller has a distance sensor and transmits its value. I have managed to get connected to the microcontroller and send correct signals, but I can't get the distance mesurment, or anything else. The application doesn't crash or anything it just won't get the data from the microcontroller (my computer gets the data from microcontroler (data is a string)). My code from the android app is this:
public class Accelerometer extends Activity {
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static final int RECIEVE_MESSAGE = 3;
// Program variables
private byte microcOut;
private boolean ledStat;
private boolean connectStat = false;
private Button btnled;
private Button connect_button;
private TextView yAccel, xAccel, incoming;
protected static final int MOVE_TIME = 80;
private long lastWrite = 0;
OnClickListener myClickListener;
ProgressDialog myProgressDialog;
private Toast failToast;
private Handler mHandler,h;
private StringBuilder sb = new StringBuilder();
// Sensor object used to handle accelerometer
private SensorManager mySensorManager;
private List<Sensor> sensors;
private Sensor accSensor;
// Bluetooth Stuff
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
private InputStream inStream = null;
private ConnectThread mConnectThread = null;
private ConnectedThread mConnectedThread;
private String deviceAddress = null;
// Well known SPP UUID (will *probably* map to RFCOMM channel 1 (default) if not in use);
private static final UUID SPP_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
//Sound Clip to make app prettier
MediaPlayer myclip;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_accelerometer);
myclip = MediaPlayer.create(this, R.raw.cartcar);
myclip.start();
// Finds buttons in .xml layout file
btnled = (Button) findViewById(R.id.led_button1);
connect_button = (Button) findViewById(R.id.connect_button1);
yAccel = (TextView) findViewById(R.id.accText1);
xAccel = (TextView) findViewById(R.id.accText2);
incoming = (TextView) findViewById(R.id.incoming);
// Set Sensor
mySensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
sensors = mySensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
if(sensors.size() > 0) accSensor = sensors.get(0);
myProgressDialog = new ProgressDialog(this);
failToast = Toast.makeText(this, R.string.failedToConnect, Toast.LENGTH_SHORT);
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (myProgressDialog.isShowing()) {
myProgressDialog.dismiss();
}
// Check if bluetooth connection was made to selected device
if (msg.what == 1) {
// Set button to display current status
connectStat = true;
connect_button.setText(R.string.connected);
// Reset the BluCar
microcOut = 0;
ledStat = false;
write(microcOut);
}else {
// Connection failed
failToast.show();
}
}
};
h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE: // if receive massage
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
incoming.setText("Data from Arduino: " + sbprint); // update TextView
}
//Log.d(TAG, "...String:"+ sb.toString() + "Byte:" + msg.arg1 + "...");
break;
}
};
};
// Check whether bluetooth adapter exists
btAdapter = BluetoothAdapter.getDefaultAdapter();
if (btAdapter == null) {
Toast.makeText(this, R.string.no_bt_device, Toast.LENGTH_LONG).show();
finish();
return;
}
// If BT is not on, request that it be enabled.
if (!btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
/**********************************************************************
* Buttons for controlling BluCar
*/
connect_button.setOnClickListener(new View.OnClickListener() {
// Connect to Bluetooth Module
#Override
public void onClick(View v) {
if (connectStat) {
// Attempt to disconnect from the device
disconnect();
}else{
// Attempt to connect to the device
connect();
}
}
});
// Toggle Headlights
btnled.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (ledStat) {
microcOut = (byte) (microcOut & 124);
btnled.setText(R.string.ledbuttonON);
ledStat = false;
}else{
microcOut = (byte) (microcOut | 128);
btnled.setText(R.string.ledbuttonOFF);
ledStat = true;
}
write(microcOut);
}
});
}
/** Thread used to connect to a specified Bluetooth Device */
public class ConnectThread extends Thread {
private String address;
private boolean connectionStatus;
ConnectThread(String MACaddress) {
address = MACaddress;
connectionStatus = true;
}
public void run() {
// When this returns, it will 'know' about the server,
// via it's MAC address.
try {
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// We need two things before we can successfully connect
// (authentication issues aside): a MAC address, which we
// already have, and an RFCOMM channel.
// Because RFCOMM channels (aka ports) are limited in
// number, Android doesn't allow you to use them directly;
// instead you request a RFCOMM mapping based on a service
// ID. In our case, we will use the well-known SPP Service
// ID. This ID is in UUID (GUID to you Microsofties)
// format. Given the UUID, Android will handle the
// mapping for you. Generally, this will return RFCOMM 1,
// but not always; it depends what other BlueTooth services
// are in use on your Android device.
try {
btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
connectionStatus = false;
}
}catch (IllegalArgumentException e) {
connectionStatus = false;
}
// Discovery may be going on, e.g., if you're running a
// 'scan for devices' search from your handset's Bluetooth
// settings, so we call cancelDiscovery(). It doesn't hurt
// to call it, but it might hurt not to... discovery is a
// heavyweight process; you don't want it in progress when
// a connection attempt is made.
btAdapter.cancelDiscovery();
// Blocking connect, for a simple client nothing else can
// happen until a successful connection is made, so we
// don't care if it blocks.
try {
btSocket.connect();
} catch (IOException e1) {
try {
btSocket.close();
} catch (IOException e2) {
}
}
// Create a data stream so we can talk to server.
try {
outStream = btSocket.getOutputStream();
} catch (IOException e2) {
connectionStatus = false;
}
// Send final result
if (connectionStatus) {
mHandler.sendEmptyMessage(1);
}else {
mHandler.sendEmptyMessage(0);
}
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
// Show please wait dialog
myProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.pleaseWait), getResources().getString(R.string.makingConnectionString), true);
// Get the device MAC address
deviceAddress = data.getExtras().getString(DeviceList.EXTRA_DEVICE_ADDRESS);
// Connect to device with specified MAC address
mConnectThread = new ConnectThread(deviceAddress);
mConnectThread.start();
}else {
// Failure retrieving MAC address
Toast.makeText(this, R.string.macFailed, Toast.LENGTH_SHORT).show();
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled
} else {
// User did not enable Bluetooth or an error occured
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
}
}
public void write(byte data) {
if (outStream != null) {
try {
outStream.write(data);
} catch (IOException e) {
}
}
}
public void emptyOutStream() {
if (outStream != null) {
try {
outStream.flush();
} catch (IOException e) {
}
}
}
public void connect() {
// Launch the DeviceListActivity to see devices and do scan
Intent serverIntent = new Intent(this, DeviceList.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);
}
public void disconnect() {
if (outStream != null) {
try {
outStream.close();
connectStat = false;
connect_button.setText(R.string.disconnected);
} catch (IOException e) {
}
}
}
private final SensorEventListener mSensorListener = new SensorEventListener() {
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
#Override
public void onSensorChanged(SensorEvent event) {
// Checks whether to send steering command or not
long date = System.currentTimeMillis();
if (date - lastWrite > MOVE_TIME) {
yAccel.setText(" " + event.values[1]);
xAccel.setText(" " + event.values[0]);
if (event.values[1] > 2.5) {
// Turn right
microcOut = (byte) (microcOut & 248);
microcOut = (byte) (microcOut | 4);
}else if (event.values[1] < -2.5) {
// Turn left
microcOut = (byte) (microcOut & 244);
microcOut = (byte) (microcOut | 8);
}else {
// Center the steering servo
microcOut = (byte) (microcOut & 240);
}
write(microcOut);
lastWrite = date;
}
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_accelerometer, menu);
return true;
}
public void onResume() {
super.onResume();
mySensorManager.registerListener(mSensorListener, accSensor, SensorManager.SENSOR_DELAY_GAME);
}
#Override
public void onDestroy() {
emptyOutStream();
disconnect();
if (mSensorListener != null) {
mySensorManager.unregisterListener(mSensorListener);
}
super.onDestroy();
myclip.release();
}
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); // Get number of bytes and message in "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
}
}
}
}
I have read everything over the subject (BluetoothChat, projects of people on the internet ...) and I am very tired. Any help is much appreciated.
--EDIT--
I have managed to get the inputstream into my texteview. My problem now is that my application when it is trying to connect to my device (microcontroller or my pc) gets stuck in the progressdialog (it is connected to the device but the progressdialog will not go away)and waits for something to come in. After a while (like 5-6 secs) even if something comes in it remains stuck and I have to force it to close. I think the problem is in the way the handler handles the thread. In the debugger there is no problem all threads run ok.
The changes in my code are:
In my ConnectThread:
`/** Thread used to connect to a specified Bluetooth Device */
public class ConnectThread extends Thread {
private String address;
private boolean connectionStatus;
ConnectThread(String MACaddress) {
address = MACaddress;
connectionStatus = true;
}
public void run() {
// When this returns, it will 'know' about the server,
// via it's MAC address.
try {
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// We need two things before we can successfully connect
// (authentication issues aside): a MAC address, which we
// already have, and an RFCOMM channel.
// Because RFCOMM channels (aka ports) are limited in
// number, Android doesn't allow you to use them directly;
// instead you request a RFCOMM mapping based on a service
// ID. In our case, we will use the well-known SPP Service
// ID. This ID is in UUID (GUID to you Microsofties)
// format. Given the UUID, Android will handle the
// mapping for you. Generally, this will return RFCOMM 1,
// but not always; it depends what other BlueTooth services
// are in use on your Android device.
try {
btSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);
} catch (IOException e) {
connectionStatus = false;
}
}catch (IllegalArgumentException e) {
connectionStatus = false;
}
// Discovery may be going on, e.g., if you're running a
// 'scan for devices' search from your handset's Bluetooth
// settings, so we call cancelDiscovery(). It doesn't hurt
// to call it, but it might hurt not to... discovery is a
// heavyweight process; you don't want it in progress when
// a connection attempt is made.
btAdapter.cancelDiscovery();
// Blocking connect, for a simple client nothing else can
// happen until a successful connection is made, so we
// don't care if it blocks.
try {
btSocket.connect();
} catch (IOException e1) {
try {
btSocket.close();
} catch (IOException e2) {
}
}
// Create a data stream so we can talk to server.
try {
outStream = btSocket.getOutputStream();
} catch (IOException e2) {
connectionStatus = false;
}
try{
inStream = btSocket.getInputStream();
}catch (IOException e2){
connectionStatus = false;
}
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (connectionStatus) {
try {
byte[] b = new byte[64]; // buffer store for the stream
// Read from the InputStream
bytes = inStream.read(b); // Get number of bytes and message in "buffer"
mHandler.obtainMessage(RECIEVE_MESSAGE, bytes, -1, b).sendToTarget(); // Send to message queue Handler
} catch (IOException e) {
break;
}
}
// Send final result
if (connectionStatus) {
mHandler.obtainMessage(1);
}else {
mHandler.sendEmptyMessage(0);
}
}
}
`
And in my mHandler in my onCreate method:
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (myProgressDialog.isShowing()) {
myProgressDialog.dismiss();
}
// Check if bluetooth connection was made to selected device
if (msg.what == 1) {
// Set button to display current status
connectStat = true;
connect_button.setText(R.string.connected);
// Reset the BluCar
microcOut = 0;
ledStat = false;
write(microcOut);
}else if (msg.what == 2){
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("."); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
incoming.setText(sbprint); // update TextView
connectStat = true;
connect_button.setText(R.string.connected);
}else{
incoming.setText("Problem!");
}
}else {
// Connection failed
failToast.show();
}
}
};
Another thing I need is how to empty the buffer when it is full.
PS: Thanks EVERYONE for his/her help I am really grateful.
As an alternative to using the handler, just get the information in the run of the thread..
I have done it this way and it works for me.
public void run() {
byte[] buffer = new byte[128]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
bytes = mmInStream.read(buffer);
byte[] readBuf = (byte[]) buffer;
String strIncom = new String(readBuf, 0, bytes); // create string from bytes array
sb.append(strIncom); // append string
int endOfLineIndex = sb.indexOf("\r\n"); // determine the end-of-line
if (endOfLineIndex > 0) {
// add the current string to eol to a local string
String sbprint = sb.substring(0, endOfLineIndex);
// get the start and end indexes of the heading
int startHeading = sb.indexOf("HE");
int endHeading = sb.indexOf("/HE");
// set the heading
Henry.this.setCurrentHeading(sb.substring((startHeading + 2), endHeading));
// get the start and end indexes of the front range
int startFrontRange = sb.indexOf("FR");
int endFrontRange = sb.indexOf("/FR");
// get the front range
Henry.this.currentFrontRange = sb.substring((startFrontRange + 2), endFrontRange);
... ( grab all the information you need here ) ...
// debugging output what we have
// System.out.println("recv: " + sbprint);
// clean out the sb to ready next run
sb.delete(0, sb.length());
}
I save all the information retrieved from the serial connection in my Application (Henry), then any Activity that wants to use the info gets it from the application. If the view needs to have a updated perspective on the information, I add a timer to the view to kick of a refresh method as often as I like. This has the added advantage of being able to use the information from anywhere in your android application.
I send about 10 data points from the arduino to the device and about 3 data points from the device to the arduino this way. I added my own markup around the datapoints to identify them.
Hope this helps!

Categories

Resources