Related
I want to connect with VPN server but I don't want to use secret key. Currently the code snippet i found to programmatically create vpn connection is as follows:
MyVpnClient:
package com.example.android.toyvpn;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.os.Bundle;
import android.widget.TextView;
public class ToyVpnClient extends Activity {
public interface Prefs {
String NAME = "connection";
String SERVER_ADDRESS = "server.address";
String SERVER_PORT = "server.port";
String SHARED_SECRET = "shared.secret";
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.form);
final TextView serverAddress = (TextView) findViewById(R.id.address);
final TextView serverPort = (TextView) findViewById(R.id.port);
final TextView sharedSecret = (TextView) findViewById(R.id.secret);
final SharedPreferences prefs = getSharedPreferences(Prefs.NAME, MODE_PRIVATE);
serverAddress.setText(prefs.getString(Prefs.SERVER_ADDRESS, ""));
serverPort.setText(prefs.getString(Prefs.SERVER_PORT, ""));
sharedSecret.setText(prefs.getString(Prefs.SHARED_SECRET, ""));
findViewById(R.id.connect).setOnClickListener(v -> {
prefs.edit()
.putString(Prefs.SERVER_ADDRESS, serverAddress.getText().toString())
.putString(Prefs.SERVER_PORT, serverPort.getText().toString())
.putString(Prefs.SHARED_SECRET, sharedSecret.getText().toString())
.commit();
Intent intent = VpnService.prepare(ToyVpnClient.this);
if (intent != null) {
startActivityForResult(intent, 0);
} else {
onActivityResult(0, RESULT_OK, null);
}
});
findViewById(R.id.disconnect).setOnClickListener(v -> {
startService(getServiceIntent().setAction(ToyVpnService.ACTION_DISCONNECT));
});
}
#Override
protected void onActivityResult(int request, int result, Intent data) {
if (result == RESULT_OK) {
startService(getServiceIntent().setAction(ToyVpnService.ACTION_CONNECT));
}
}
private Intent getServiceIntent() {
return new Intent(this, ToyVpnService.class);
}
}
MyVpnConnection:
package com.example.android.toyvpn;
import static java.nio.charset.StandardCharsets.US_ASCII;
import android.app.PendingIntent;
import android.net.VpnService;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.concurrent.TimeUnit;
public class ToyVpnConnection implements Runnable {
/**
* Callback interface to let the {#link ToyVpnService} know about new connections
* and update the foreground notification with connection status.
*/
public interface OnEstablishListener {
void onEstablish(ParcelFileDescriptor tunInterface);
}
/** Maximum packet size is constrained by the MTU, which is given as a signed short. */
private static final int MAX_PACKET_SIZE = Short.MAX_VALUE;
/** Time to wait in between losing the connection and retrying. */
private static final long RECONNECT_WAIT_MS = TimeUnit.SECONDS.toMillis(3);
/** Time between keepalives if there is no traffic at the moment.
*
* TODO: don't do this; it's much better to let the connection die and then reconnect when
* necessary instead of keeping the network hardware up for hours on end in between.
**/
private static final long KEEPALIVE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(15);
/** Time to wait without receiving any response before assuming the server is gone. */
private static final long RECEIVE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(20);
/**
* Time between polling the VPN interface for new traffic, since it's non-blocking.
*
* TODO: really don't do this; a blocking read on another thread is much cleaner.
*/
private static final long IDLE_INTERVAL_MS = TimeUnit.MILLISECONDS.toMillis(100);
/**
* Number of periods of length {#IDLE_INTERVAL_MS} to wait before declaring the handshake a
* complete and abject failure.
*
* TODO: use a higher-level protocol; hand-rolling is a fun but pointless exercise.
*/
private static final int MAX_HANDSHAKE_ATTEMPTS = 50;
private final VpnService mService;
private final int mConnectionId;
private final String mServerName;
private final int mServerPort;
private final byte[] mSharedSecret;
private PendingIntent mConfigureIntent;
private OnEstablishListener mOnEstablishListener;
public ToyVpnConnection(final VpnService service, final int connectionId,
final String serverName, final int serverPort, final byte[] sharedSecret) {
mService = service;
mConnectionId = connectionId;
mServerName = serverName;
mServerPort= serverPort;
mSharedSecret = sharedSecret;
}
/**
* 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(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;
}
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();
// 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) {
return configure(new String(packet.array(), 1, length - 1, US_ASCII).trim());
}
}
throw new IOException("Timed out");
}
private ParcelFileDescriptor configure(String parameters) throws IllegalArgumentException {
// Configure a builder while parsing the parameters.
VpnService.Builder builder = mService.new Builder();
for (String parameter : parameters.split(" ")) {
String[] fields = parameter.split(",");
try {
switch (fields[0].charAt(0)) {
case 'm':
builder.setMtu(Short.parseShort(fields[1]));
break;
case 'a':
builder.addAddress(fields[1], Integer.parseInt(fields[2]));
break;
case 'r':
builder.addRoute(fields[1], Integer.parseInt(fields[2]));
break;
case 'd':
builder.addDnsServer(fields[1]);
break;
case 's':
builder.addSearchDomain(fields[1]);
break;
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Bad parameter: " + parameter);
}
}
// Create a new interface using the builder and save the parameters.
final ParcelFileDescriptor vpnInterface;
synchronized (mService) {
vpnInterface = builder
.setSession(mServerName)
.setConfigureIntent(mConfigureIntent)
.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 + "]";
}
}
MyVpnService:
package com.example.android.toyvpn;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
public class ToyVpnService extends VpnService implements Handler.Callback {
private static final String TAG = ToyVpnService.class.getSimpleName();
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 static class Connection extends Pair<Thread, ParcelFileDescriptor> {
public Connection(Thread thread, ParcelFileDescriptor pfd) {
super(thread, pfd);
}
}
private final AtomicReference<Thread> mConnectingThread = new AtomicReference<>();
private final AtomicReference<Connection> mConnection = new AtomicReference<>();
private AtomicInteger mNextConnectionId = new AtomicInteger(1);
private PendingIntent mConfigureIntent;
#Override
public void onCreate() {
// The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler(this);
}
// Create the intent to "configure" the connection (just start ToyVpnClient).
mConfigureIntent = PendingIntent.getActivity(this, 0, new Intent(this, ToyVpnClient.class),
PendingIntent.FLAG_UPDATE_CURRENT);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && ACTION_DISCONNECT.equals(intent.getAction())) {
disconnect();
return START_NOT_STICKY;
} else {
connect();
return START_STICKY;
}
}
#Override
public void onDestroy() {
disconnect();
}
#Override
public boolean handleMessage(Message message) {
Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
if (message.what != R.string.disconnected) {
updateForegroundNotification(message.what);
}
return true;
}
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 = prefs.getString(ToyVpnClient.Prefs.SERVER_ADDRESS, "");
final byte[] secret = prefs.getString(ToyVpnClient.Prefs.SHARED_SECRET, "").getBytes();
final int port;
try {
port = Integer.parseInt(prefs.getString(ToyVpnClient.Prefs.SERVER_PORT, ""));
} catch (NumberFormatException e) {
Log.e(TAG, "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 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);
}
}
}
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());
}
}
The above code is from the following url:
https://android.googlesource.com/platform/development/+/master/samples/ToyVpn
I have tried but I am not getting any workaround without secret key. Please help.
Unfortunately, we don't have any further requirements / spec of your VPN server.
You might want to have a look at the OpenVPN or strongSwan VPN (open source) implementations to see if they can fit your requirements. The latter for example provides the following ways of authentication on Android (https://wiki.strongswan.org/projects/strongswan/wiki/androidvpnclient):
Only IKEv2 is supported
Client authentication is limited to:
EAP authentication based on username/password (EAP-MSCHAPv2, EAP-MD5, EAP-GTC)
RSA/ECDSA authentication with private key/certificate
EAP-TLS with private key/certificate (see 1.4.5 for limitations)
I need your help!
First: I am from austria , so my english is not so good. So I apologize for the mistakes I will make!
This is my first project I try with Android Studio. I am a newbie in programming. I have not much skill in Arduino and Android program language, but I need it for my bachelor project, so I have to learn it!
I worked with a tutorial video, which was in spanish, so I have no clue what that guy was talking about, but I understood the code all in all.
My problem is, when I start the app on my phone, the first screen (paired devices) works fine. But when I press on the paired device...
This following error occurs :
Capturing and displaying logcat messages from application. This
behavior can be disabled in the "Logcat output" section of the
"Debugger" settings page. D/OpenGLRenderer:
ProgramCache.generateProgram: 103079215104 D/AndroidRuntime: Shutting
down VM E/AndroidRuntime: FATAL EXCEPTION: main
Process: bachelor_projekt.bluetoothcontroller, PID: 11061
java.lang.RuntimeException: Unable to resume activity
{bachelor_projekt.bluetoothcontroller/bachelor_projekt.bluetoothcontroller.UserInterface}:
java.lang.IllegalArgumentException: null is not a valid Bluetooth
address
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3506)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3546)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2795)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6247)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: java.lang.IllegalArgumentException: null is not a valid Bluetooth address
at android.bluetooth.BluetoothDevice.(BluetoothDevice.java:668)
at android.bluetooth.BluetoothAdapter.getRemoteDevice(BluetoothAdapter.java:553)
at bachelor_projekt.bluetoothcontroller.UserInterface.onResume(UserInterface.java:122)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1272)
at android.app.Activity.performResume(Activity.java:6917)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3477)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3546)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2795)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6247)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
I/Process: Sending signal. PID: 11061 SIG: 9 Application terminated.
After that message, the app shuts down :
I divided my app in:
Bluetooth - for the bluetooth connection
Here is the code:
package bachelor_projekt.bluetoothcontroller;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
import java.util.Set;
public class Bluetooth extends AppCompatActivity {
// Cleaning of the Logcat (Systemlog)
private static final String TAG = "Bluetooth";
// Declaration of ListView
ListView IdList;
// String which will be sended to the main frame
public static String EXTRA_DEVICE_ADDRESS = "device_address";
// Declaration of the fields
private BluetoothAdapter myBluetooth;
private ArrayAdapter<String> myPairedDevicesArray;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth);
}
#Override
public void onResume()
{
super.onResume();
//----------------------------
VerificationBT();
// Initialze the array which keeps the bluetooth devices
myPairedDevicesArray=new ArrayAdapter<String>(this, R.layout.device_name);
IdList = findViewById(R.id.idList);
IdList.setAdapter(myPairedDevicesArray);
IdList.setOnItemClickListener(myDeviceClickListener);
// Get local default bluetooth adapter
myBluetooth = BluetoothAdapter.getDefaultAdapter();
// Includes the bluetooth member which is paired with the device
Set<BluetoothDevice> pairedDevices =myBluetooth.getBondedDevices();
// Pair with an already in the array included device.
if (pairedDevices.size()>0)
{
for (BluetoothDevice device : pairedDevices){
myPairedDevicesArray.add(device.getName() + "\n" + device.getAddress());
}
}
}
// Configuration for the "on click" ability for the liste
private AdapterView.OnItemClickListener myDeviceClickListener = new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView av , View v, int arg2, long arg3) {
// Detect the MAC-Adress of the device ( last 17 caracters)
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
// 1 Try to connect if MAC adress is the same
Intent i = new Intent(Bluetooth.this, UserInterface.class);
startActivity(i);
}
};
private void VerificationBT(){
// Checks if the device has bluetooth and if it is activated
myBluetooth=BluetoothAdapter.getDefaultAdapter();
if(myBluetooth==null) {
Toast.makeText(getBaseContext(), "Device doesn't have bluetooth", Toast.LENGTH_SHORT).show();
} else{
if (myBluetooth.isEnabled()) {
Log.d(TAG, "...Bluetooth Avtivated...");
} else{
// Ask the user to activate bluetooth
Intent enableBt = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBt,1);
}
}
}
}
The second part is the user interface - Here should be the actual project which is just for start (3 Buttons, 1 for LED on, 1 for LED off, 1 for disconnect).
Here is the code:
package bachelor_projekt.bluetoothcontroller;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
public class UserInterface extends AppCompatActivity {
Button IdLedON, IdLedOFF, IdDisconnect;
TextView IdBuffer;
//-------------------------------------------------
Handler bluetoothIn;
final int handlerState = 0;
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private StringBuilder DataStringIN = new StringBuilder();
private ConnectedThread MyConnection;
// Special service - SPP UUID
private static final UUID BTMODULE_UUID = UUID.fromString
("00001101-0000-1000-8000-00211300ACCD"); //805F9B34FB
// String direction of the MAC
private static String address = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_interface);
// Connection between inferface and variables
IdLedON = (Button) findViewById(R.id.IdLedON);
IdLedOFF = (Button) findViewById(R.id.IdLedOFF);
IdDisconnect = (Button) findViewById(R.id.IdDisconnect);
IdBuffer = findViewById(R.id.IdBuffer);
bluetoothIn = new Handler(){
public void handleMessage(android.os.Message msg){
if (msg.what == handlerState) {
String readMessage = (String) msg.obj;
DataStringIN.append(readMessage);
int endOfLineIndex = DataStringIN.indexOf("#");
if (endOfLineIndex > 0) {
String dataInPrint = DataStringIN.substring(0, endOfLineIndex);
IdBuffer.setText("Data: " + dataInPrint);
DataStringIN.delete(0, DataStringIN.length());
}
}
}
};
btAdapter = BluetoothAdapter.getDefaultAdapter();
VerificationBT();
IdLedON.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyConnection.write("1");
}
});
IdLedOFF.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyConnection.write("0");
}
});
IdDisconnect.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (btSocket != null)
{
try {
btSocket.close();
} catch (IOException e) {
Toast.makeText(getBaseContext(), "Error", Toast.LENGTH_SHORT).show();;}
}
finish();
}
});
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException
{
// Creates a save Connection for the device
return device.createRfcommSocketToServiceRecord(BTMODULE_UUID);
}
#Override
public void onResume()
{
super.onResume();
// Receives MAC Adress Direction out of DeviceListActivity via intent
Intent intent = getIntent();
// Receives MAC Adress Direction out of DeviceListActivity via EXTRA
address = intent.getStringExtra(Bluetooth.EXTRA_DEVICE_ADDRESS);
// adjust MAC Adress
BluetoothDevice device = btAdapter.getRemoteDevice(address);
try
{
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
Toast.makeText(getBaseContext(), "Error while Connection with device accured ", Toast.LENGTH_SHORT).show();
}
// Creates a connection with bluetooth
try
{
btSocket.connect();
} catch (IOException e){
try{
btSocket.close();
} catch (IOException e2){}
}
MyConnection = new ConnectedThread(btSocket);
MyConnection.start();
}
#Override
public void onPause()
{
super.onPause();
try
{
// If you leave the application there can be no access to the bluetooth adapter
btSocket.close();
} catch (IOException e2){}
}
// Check if bluetooth device is available and connect with it
private void VerificationBT()
{
if (btAdapter == null) {
Toast.makeText(getBaseContext(), "Device doesn't support bluetooth", Toast.LENGTH_LONG);
} else {
Intent enableBt = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBt, 1);
}
}
// class for making a connection
private class ConnectedThread extends Thread
{
private final InputStream myInStream;
private final OutputStream myOutStream;
public ConnectedThread(BluetoothSocket socket)
{
InputStream tmpIn=null;
OutputStream tmpOut=null;
try
{
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {}
myInStream=tmpIn;
myOutStream=tmpOut;
}
public void run()
{
byte[] buffer = new byte[256];
int bytes;
// Device stays in the "try to connect" mode
while(true) {
try {
bytes = myInStream.read(buffer);
String readMessage = new String(buffer, 0, bytes);
} catch (IOException e) {
break;
}
}
}
public void write(String input)
{
try{
myOutStream.write(input.getBytes());
} catch (IOException e)
{
// If it is not possible to send data
Toast.makeText(getBaseContext(), " Connection failed", Toast.LENGTH_LONG).show();
finish();
}
}
}
}
So if you need for information, just tell me.
Hopefully someone of you understands my problem and can help me :)
Best wishes
Semi
Seems like there is an error in the code.
This error:
android.app.ActivityThread.handleResumeActivity
Appeared way too many times which means and activity froze or crashed and then tried to restart but kept on failing so many times it just gave up in the end.
Also, it looks like your using a VM to test the code so try using it with a real device.
If you cant find out the problem try writing the code from the start again or run it through a bug interpreter.
Best of luck,
Paul!
I want to build an app that can connect with a single click of button which will create a vpn profile and connect to the vpn profile by parsig the username and password of the vpn server.
The code that is developed and modified is good to create and connect vpn but my vpn requires username and password to be entered so i want to do that programatically.
Here is my project
VpnClient.java
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class VpnClient extends AppCompatActivity{
public interface Prefs {
String NAME = "connection";
String SERVER_ADDRESS = "server.address";
String SERVER_PORT = "server.port";
String SHARED_SECRET = "shared.secret";
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button disconnect = (Button) findViewById(R.id.disconnect);
Button connect = (Button) findViewById(R.id.connect);
// final TextView serverAddress = (TextView) findViewById(R.id.address);
//final TextView serverPort = (TextView) findViewById(R.id.port);
// final TextView sharedSecret = (TextView) findViewById(R.id.secret);
final SharedPreferences prefs = getSharedPreferences(Prefs.NAME, MODE_PRIVATE);
final String serverAddress = ""; !!I insert my vpnserver address in here which is my.vpnserver.com
final String serverPort = ""; !!As server port i am using 1723 for PPTP connection
connect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
prefs.edit()
.putString(Prefs.SERVER_ADDRESS,"")
.putString(Prefs.SERVER_PORT, "")
.putString(Prefs.SHARED_SECRET, "")
.commit();
Intent intent = VpnService.prepare(VpnClient.this);
if (intent != null) {
startActivityForResult(intent, 0);
} else {
onActivityResult(0, RESULT_OK, null);
}
}
});
disconnect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startService(getServiceIntent().setAction(MyVpnService.ACTION_DISCONNECT));
}
});
}
#Override
protected void onActivityResult(int request, int result, Intent data) {
if (result == RESULT_OK) {
startService(getServiceIntent().setAction(MyVpnService.ACTION_CONNECT));
}
}
private Intent getServiceIntent() {
return new Intent(this, MyVpnService.class);
}
}
MyVpnService.java
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.support.annotation.RequiresApi;
import android.support.v4.util.Pair;
import android.util.Log;
import android.widget.Toast;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.LogRecord;
public class MyVpnService extends andenter code hereroid.net.VpnService implements android.os.Handler.Callback {
private static final String TAG = MyVpnService.class.getSimpleName();
public static final String ACTION_CONNECT = "com.yaksh.vpn.START";
public static final String ACTION_DISCONNECT = "com.yaksh.vpn.STOP";
private Handler mHandler;
private static class Connection extends Pair<Thread, ParcelFileDescriptor> {
public Connection(Thread thread, ParcelFileDescriptor pfd) {
super(thread, pfd);
}
}
private final AtomicReference<Thread> mConnectingThread = new AtomicReference<>();
private final AtomicReference<Connection> mConnection = new AtomicReference<>();
private AtomicInteger mNextConnectionId = new AtomicInteger(1);
private PendingIntent mConfigureIntent;
#Override
public void onCreate() {
// The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler(this);
}
// Create the intent to "configure" the connection (just start ToyVpnClient).
mConfigureIntent = PendingIntent.getActivity(this, 0, new Intent(this, VpnClient.class),
PendingIntent.FLAG_UPDATE_CURRENT);
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && ACTION_DISCONNECT.equals(intent.getAction())) {
disconnect();
return START_NOT_STICKY;
} else {
connect();
return START_STICKY;
}
}
#Override
public void onDestroy() {
disconnect();
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public boolean handleMessage(Message message) {
Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
if (message.what != R.string.disconnected) {
updateForegroundNotification(message.what);
}
return true;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
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(VpnClient.Prefs.NAME, MODE_PRIVATE);
final String server = prefs.getString(VpnClient.Prefs.SERVER_ADDRESS, "");
final byte[] secret = prefs.getString(VpnClient.Prefs.SHARED_SECRET, "").getBytes();
final int port;
try {
port = Integer.parseInt(prefs.getString(VpnClient.Prefs.SERVER_PORT, ""));
} catch (NumberFormatException e) {
Log.e(TAG, "Bad port: " + prefs.getString(VpnClient.Prefs.SERVER_PORT, null), e);
return;
}
// Kick off a connection.
startConnection(new VpnConnection(
this, mNextConnectionId.getAndIncrement(), server, port, secret));
}
private void startConnection(final VpnConnection 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 VpnConnection.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);
}
}
}
private void disconnect() {
mHandler.sendEmptyMessage(R.string.disconnected);
setConnectingThread(null);
setConnection(null);
stopForeground(true);
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private void updateForegroundNotification(final int message) {
startForeground(1, new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_vpn)
.setContentText(getString(message))
.setContentIntent(mConfigureIntent)
.build());
}
}
VpnConnection.java
import android.app.PendingIntent;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.support.annotation.RequiresApi;
import android.util.Log;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.concurrent.TimeUnit;
/**
* Created by Yaksh on 11/3/2017.
*/
public class VpnConnection implements Runnable{
/**
* Callback interface to let the {#link MyVpnService} know about new connections
* and update the foreground notification with connection status.
*/
public interface OnEstablishListener {
void onEstablish(ParcelFileDescriptor tunInterface);
}
/** Maximum packet size is constrained by the MTU, which is given as a signed short. */
private static final int MAX_PACKET_SIZE = Short.MAX_VALUE;
/** Time to wait in between losing the connection and retrying. */
private static final long RECONNECT_WAIT_MS = TimeUnit.SECONDS.toMillis(3);
/** Time between keepalives if there is no traffic at the moment.
*
* TODO: don't do this; it's much better to let the connection die and then reconnect when
* necessary instead of keeping the network hardware up for hours on end in between.
**/
private static final long KEEPALIVE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(15);
/** Time to wait without receiving any response before assuming the server is gone. */
private static final long RECEIVE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(20);
/**
* Time between polling the VPN interface for new traffic, since it's non-blocking.
*
* TODO: really don't do this; a blocking read on another thread is much cleaner.
*/
private static final long IDLE_INTERVAL_MS = TimeUnit.MILLISECONDS.toMillis(100);
/**
* Number of periods of length {#IDLE_INTERVAL_MS} to wait before declaring the handshake a
* complete and abject failure.
*
* TODO: use a higher-level protocol; hand-rolling is a fun but pointless exercise.
*/
private static final int MAX_HANDSHAKE_ATTEMPTS = 50;
private final MyVpnService mService;
private final int mConnectionId;
private final String mServerName;
private final int mServerPort;
private final byte[] mSharedSecret;
private PendingIntent mConfigureIntent;
private OnEstablishListener mOnEstablishListener;
public VpnConnection(final MyVpnService service, final int connectionId,
final String serverName, final int serverPort, final byte[] sharedSecret) {
mService = service;
mConnectionId = connectionId;
mServerName = serverName;
mServerPort= serverPort;
mSharedSecret = sharedSecret;
}
/**
* 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;
}
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#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.
// 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);
}
}
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
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;
}
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();
// 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) {
return configure(new String(packet.array(), 1, length - 1).trim());
}
}
throw new IOException("Timed out");
}
private ParcelFileDescriptor configure(String parameters) throws IllegalArgumentException {
// Configure a builder while parsing the parameters.
MyVpnService.Builder builder = mService.new Builder();
for (String parameter : parameters.split(" ")) {
String[] fields = parameter.split(",");
try {
switch (fields[0].charAt(0)) {
case 'm':
builder.setMtu(Short.parseShort(fields[1]));
break;
case 'a':
builder.addAddress(fields[1], Integer.parseInt(fields[2]));
break;
case 'r':
builder.addRoute(fields[1], Integer.parseInt(fields[2]));
break;
case 'd':
builder.addDnsServer(fields[1]);
break;
case 's':
builder.addSearchDomain(fields[1]);
break;
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Bad parameter: " + parameter);
}
}
// Create a new interface using the builder and save the parameters.
final ParcelFileDescriptor vpnInterface;
synchronized (mService) {
vpnInterface = builder
.setSession(mServerName)
.setConfigureIntent(mConfigureIntent)
.establish();
if (mOnEstablishListener != null) {
mOnEstablishListener.onEstablish(vpnInterface);
}
}
Log.i(getTag(), "New interface: " + vpnInterface + " (" + parameters + ")");
return vpnInterface;
}
private final String getTag() {
return VpnConnection.class.getSimpleName() + "[" + mConnectionId + "]";
}
}
I've created an Android app to communicate with my Arduino using Bluetooth. But when I'm sending data from my Android device to my Arduino, the Arduino isn't responding to what I've send. I am able to get a connection from my Android device to my Arduino. So that's not the problem.
Here's my full script for Android.
package nl.handoko.LumaMini;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final String TAG = "LumaMini";
private static final int REQUEST_ENABLE_BT = 1;
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
Button fourty, thirty, twenty, twelve, automatic, manual;
TextView message;
// Well known SPP UUID
private static final UUID MY_UUID =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Server's MAC address
private static String address = "98:D3:31:30:09:43";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "In onCreate()");
setContentView(R.layout.activity_mainnn);
fourty = (Button) findViewById(R.id.button1);
thirty = (Button) findViewById(R.id.button4);
twenty = (Button) findViewById(R.id.button2);
twelve = (Button) findViewById(R.id.button5);
automatic = (Button) findViewById(R.id.button3);
manual = (Button) findViewById(R.id.button6);
message = (TextView) findViewById(R.id.textView1);
fourty.setText("40 Leds");
thirty.setText("30 Leds");
twenty.setText("20 Leds");
twelve.setText("12 Leds");
automatic.setText("Automatic");
manual.setText("Manual");
message.setText("Using this app you can take full control of the Luma Mini!" +
"When it's running on automatic please switch back to manual first before switching to other versions.");
btAdapter = BluetoothAdapter.getDefaultAdapter();
checkBTState();
fourty.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
sendData("a");
Toast msg = Toast.makeText(getBaseContext(),
"40 Leds version", Toast.LENGTH_SHORT);
msg.show();
}
});
thirty.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
sendData("b");
Toast msg = Toast.makeText(getBaseContext(),
"30 Leds version", Toast.LENGTH_SHORT);
msg.show();
}
});
twenty.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
sendData("c");
Toast msg = Toast.makeText(getBaseContext(),
"20 Leds version", Toast.LENGTH_SHORT);
msg.show();
}
});
twelve.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
sendData("d");
Toast msg = Toast.makeText(getBaseContext(),
"12 Leds version", Toast.LENGTH_SHORT);
msg.show();
}
});
automatic.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
sendData("e");
Toast msg = Toast.makeText(getBaseContext(),
"Run automatically", Toast.LENGTH_SHORT);
msg.show();
}
});
manual.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
sendData("f");
Toast msg = Toast.makeText(getBaseContext(),
"Manually switch Leds", Toast.LENGTH_SHORT);
msg.show();
}
});
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, "...In onResume - Attempting client connect...");
// Set up a pointer to the remote node using it's address.
BluetoothDevice device = btAdapter.getRemoteDevice(address);
// Two things are needed to make a connection:
// A MAC address, which we got above.
// A Service ID or UUID. In this case we are using the
// UUID for SPP.
try {
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
}
// Discovery is resource intensive. Make sure it isn't going on
// when you attempt to connect and pass your message.
btAdapter.cancelDiscovery();
// Establish the connection. This will block until it connects.
Log.d(TAG, "...Connecting to Remote...");
try {
btSocket.connect();
Log.d(TAG, "...Connection established and data link opened...");
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
errorExit("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + ".");
}
}
// Create a data stream so we can talk to server.
Log.d(TAG, "...Creating Socket...");
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and output stream creation failed:" + e.getMessage() + ".");
}
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, "...In onPause()...");
if (outStream != null) {
try {
outStream.flush();
} catch (IOException e) {
errorExit("Fatal Error", "In onPause() and failed to flush output stream: " + e.getMessage() + ".");
}
}
try {
btSocket.close();
} catch (IOException e2) {
errorExit("Fatal Error", "In onPause() and failed to close socket." + e2.getMessage() + ".");
}
}
private void checkBTState() {
// Check for Bluetooth support and then check to make sure it is turned on
// Emulator doesn't support Bluetooth and will return null
if(btAdapter==null) {
errorExit("Fatal Error", "Bluetooth Not supported. Aborting.");
} else {
if (btAdapter.isEnabled()) {
Log.d(TAG, "...Bluetooth is enabled...");
} else {
//Prompt user to turn on Bluetooth
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
}
private void errorExit(String title, String message){
Toast msg = Toast.makeText(getBaseContext(),
title + " - " + message, Toast.LENGTH_SHORT);
msg.show();
finish();
}
private void sendData(String message) {
byte[] msgBuffer = message.getBytes();
Log.d(TAG, "...Sending data: " + message + "...");
try {
outStream.write(msgBuffer);
} catch (IOException e) {
String msg = "In onResume() and an exception occurred during write: " + e.getMessage();
msg = msg + ".\n\nCheck that the SPP UUID: " + MY_UUID.toString() + " exists on server.\n\n";
errorExit("Fatal Error", msg);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
And here's my Arduino script:
#include <SoftwareSerial.h>
#include <TimerOne.h>
#define Rx 2
#define Tx 3
#define seconds 4
char serialData; // Serial data memory
int counter1; // Overflow memory
int action; // Action trigger
int once = 0; // Run only once
SoftwareSerial Bluetooth(Rx, Tx);
void setup(){
pinMode(Tx, OUTPUT); // Configure Tx as OUTPUT (Transmitter)
pinMode(Rx, INPUT);
delay(1000);
Bluetooth.begin(9600);
Serial.begin(1200);
delay(1000);
Serial.print("Bluetooth ready");
Bluetooth.flush();
TimerOneSetup(); // Run the setup for Timer One
for(int i = 5; i <= 8; i++){ // Make pins 5, 6, 7 and 8 OUTPUT
pinMode(i, OUTPUT);
}
}
void interrupt1(){ // Timer One loop
counter1++; // Count the amount of seconds has passed
if (counter1 == seconds){ // Trigger the next action after a several amount of seconds (Default: 4 seconds)
action++;
counter1 = 0;
}
if (action > 3){ // Reset action trigger when after all actions were runned
action = 0;
}
}
void loop(){ // Endless loop
if (Serial.available()){ // Wait for data recieved from Local device
serialData = Serial.read(); // Put recieved data in memory
Serial.print("Data recieved from Local device: ");
Serial.println(serialData);
}
if (Bluetooth.available()){ // Wait for data recieved from Bluetooth device
serialData = Bluetooth.read(); // Put recieved data in memory
Serial.print("Data recieved from Bluetooth device: ");
Serial.print(serialData);
}
if (once == 0){ // This script will be run only once
serialData = 'e'; // Put switch on automatic on startup
once++; // Get into the next stage which may be run only once
}
switch(serialData){ // Perform action on state of the switch
case 'a':
fourtyLeds(); // Show the 40 Leds version of the Luma Mini
break;
case 'b':
thirtyLeds(); // Show the 30 Leds version of the Luma Mini
break;
case 'c':
twentyLeds(); // Show the 20 Leds version of the Luma Mini
break;
case 'd':
twelveLeds(); // Show the 12 Leds version of the Luma Mini
break;
case 'e':
while(serialData == 'e'){ // Keep changing different Led versions of the Luma Mini automatically
switch(action){
case 0: // Wait for the action trigger to hit the first action
fourtyLeds(); // Show the 40 Leds version of the Luma Mini
break;
case 1: // Wait for the action trigger to hit the second action
twelveLeds(); // Show the 12 Leds version of the Luma Mini
break;
case 2: // Wait for the action trigger to hit the third action
twentyLeds(); // Show the 20 Leds version of the Luma Mini
break;
case 4: // Wait for the action trigger to hit the fourth action
thirtyLeds(); // Show the 30 Leds version of the Luma Mini
break;}
if (Serial.read() == 'f'){ // Wait for data recieved from Local device
serialData = Serial.read(); // Put recieved data in memory
Serial.print("Data recieved from Local device: ");
Serial.println(serialData);
}
if (Bluetooth.read() == 'f'){ // Wait for data recieved from Bluetooth device
serialData = Bluetooth.read(); // Put recieved data in memory
Serial.print("Data recieved from Bluetooth device: ");
Serial.println(serialData);
}
break;
}
}
}
void BluetoothSetup(){
pinMode(Tx, OUTPUT); // Configure Tx as OUTPUT (Transmitter)
pinMode(Rx, INPUT); // Configure Rx as INPUT (Reciever)
Bluetooth.begin(9600); // Set Bluetooth baud rate to default baud rate 38400
Bluetooth.print("\r\n+STWMOD=0\r\n"); // Set the Bluetooth to work in slave mode
Bluetooth.print("\r\n+STNA=Luma Mini\r\n"); // Set Bluetooth name to Luma Mini
Bluetooth.print("\r\n+STOAUT=1\r\n"); // Permit paired device to connect
Bluetooth.print("\r\n+STAUTO=0\r\n"); // Auto-connection should be forbidden here
delay(2000);
Bluetooth.print("\r\n+INQ=1\r\n"); // Make this Bluetooth Slave inquirable
Serial.println("The slave Bluetooth is inquirable!");
delay(2000);
Bluetooth.flush();
}
void TimerOneSetup(){
Timer1.initialize(1000000); // Initialize Timer One for an overflow exactly every 1 second
Timer1.attachInterrupt(interrupt1); // Open the Timer One loop
}
void fourtyLeds(){ // Show the 40 Leds version of the Luma Mini
for(int i = 5; i <= 8; i++){
digitalWrite(i, LOW);
}
}
void thirtyLeds(){ // Show the 30 Leds version of the Luma Mini
digitalWrite(5, HIGH);
digitalWrite(6, LOW);
digitalWrite(7, LOW);
digitalWrite(8, LOW);
}
void twentyLeds(){ // Show the 20 Leds version of the Luma Mini
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, LOW);
digitalWrite(8, HIGH);
}
void twelveLeds(){ // Show the 12 Leds version of the Luma Mini
for (int i = 5; i <= 8; i++){
digitalWrite(i, HIGH);
}
}
My question: How can I send CHAR data from an Android Device to my Arduino? And what to edit on my script?
I have not gone through your code. But looking at the question, I suggests to keep Arduino FW coding away till Android app is tested and developed to a certain level. The way forward could be:
Disconnect HC-06 from other hardware.
Make a loopback connection at HC-06 (i.e Connect TX & RX outputs of HC-06 together.
Then Test your Android application. If app is receiving same as transmitted, then your android app is ok, and you can move on perfecting Arduino FW. Else, the android app needs to be perfected.
You can have a look at a similar question HC-05 bluetooth module on Arduino + Debugging .
Here's the code I use, and it works fine for me.
On the Android side, I'm only including my bluetooth file, which should be easy to fit into your app. It's main advantage is that after your app start it by calling btConnect(), everything else is automatic. It finds and connects to your "HC-06" without further "human intervention". And if you turn off the "HC-06", Android will continue watching for the "HC-06" to come back online, and will auto-connect to it again.
The Arduino Sketch sends a signal once each second. If 10 seconds are missed, the Android assumes the connection has been lost and re-enters connect mode.
ANDROID BLUETOOTH JAVA FILE:
package com.exercise.androidanimbuttons;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.IntentFilter;
import android.widget.Toast;
import android.bluetooth.BluetoothSocket;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;
import java.util.Set;
import android.os.Handler;
public class BlueTooth extends vars {
private Set<BluetoothDevice> pairedDevices;
String address = null;
private ProgressDialog progress = null;
BluetoothAdapter myBluetooth = null;
BluetoothSocket btSocket = null;
InputStream mmInStream = null;
private Handler myHandler = new Handler();
byte[] buffer = new byte[25];
int readBytes;
files filesI = new files();
Handler btH = new Handler();
static final UUID myUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private SingBroadcastReceiver mReceiver;
Runnable btSearch;
void stopDiscovery() {
if (myBluetooth.isDiscovering()){
myBluetooth.cancelDiscovery();
}
}
void findCurrentBT() {
if (!myBluetooth.isEnabled()){
Intent enableBT = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBT, 0xDEADBEEF);
}
if (myBluetooth.isDiscovering()){
myBluetooth.cancelDiscovery();
}
closeProgress();
progress = ProgressDialog.show(BlueTooth.this, "Searching for headband...",
"MAKE SURE THE HEADBAND IS TURNED ON.");
progress.setCanceledOnTouchOutside(true);
myBluetooth.startDiscovery();
mReceiver = new SingBroadcastReceiver();
IntentFilter ifilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, ifilter);
checkSearch();
}
private class SingBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String derp = device.getName() + " - " + device.getAddress();
ta(derp);
Toast.makeText(context, derp, Toast.LENGTH_LONG);
if ((device.getName() != null) &&
(device.getName().indexOf("HC-06") == 0) &&
(device.getName().length() == 5))
{
myBluetooth.cancelDiscovery();
address = device.getAddress();
new ConnectBT().execute();
}
}
}
}
private Runnable readBT = new Runnable() {
public void run() {
int i;
int twoByte = 0;
short high = 0, low = 0;
try {
if (mmInStream.available() > 3) {
cnt = 0;
readBytes = mmInStream.read(buffer);
String S = "";
for (i = 0; i < 2; i++)
S += String.format("%03d", buffer[i] & 0xFF)+", ";
high = (short)(buffer[3] & 0xFF);
low = (short)(buffer[2] & 0xFF);
twoByte = ((high << 8) | low);
S += String.format("%03d", twoByte) + "\r\n";
filesI.writeALine("nights","data12.txt",S);
ta(S);
}
} catch (IOException e) {
ta("err:2 " + e.toString());
}
if (btSocket.isConnected())
myHandler.postDelayed(this, 100);
}
};
public void btConnect() {
Disconnect();
findCurrentBT();
}
public void btOn() {
turnOnLed();
}
public void btOff() { turnOffLed(); }
public void btDisconnect() { Disconnect(); }
private void Disconnect()
{
if (btSocket!=null)
{
try
{
btSocket.close();
}
catch (IOException e)
{ msg("Bluetooth Disconnect Error");}
}
}
private void turnOffLed()
{
if (btSocket!=null)
{
try
{
btSocket.getOutputStream().write("TF".toString().getBytes());
}
catch (IOException e)
{
msg("Error");
}
}
}
private void turnOnLed()
{
int len;
byte[] buffer = new byte[400];
if (btSocket!=null)
{
try
{
btSocket.getOutputStream().write("TO".toString().getBytes());
len = btSocket.getInputStream().available();
btSocket.getInputStream().read(buffer,0,len);
}
catch (IOException e)
{
msg("Error");
}
}
}
private void msg(String s)
{
Toast.makeText(getApplicationContext(),s,Toast.LENGTH_LONG).show();
}
void closeProgress() {
if (progress != null)
progress.dismiss();
}
private class ConnectBT extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPreExecute()
{
closeProgress();
progress = ProgressDialog.show(BlueTooth.this, "Connecting to headband...",
"");
progress.setCanceledOnTouchOutside(true);
}
#Override
protected Void doInBackground(Void... devices)
{
try
{
if (btSocket == null || (!btSocket.isConnected()))
{
BluetoothDevice dispositivo = myBluetooth.getRemoteDevice(address);
btSocket = dispositivo.createInsecureRfcommSocketToServiceRecord(myUUID);
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
btSocket.connect();
}
}
catch (IOException e) { }
return null;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
if (!btSocket.isConnected())
{
msg("Connection Failed. Is the headband turned on?");
}
else
{
msg("Connected.");
try {
mmInStream = btSocket.getInputStream();
myHandler.postDelayed(readBT, 1000);
} catch (IOException e) {
ta("err:1 " + e.toString());
}
}
closeProgress();
}
}
int cnt = 0;
void checkSearch() {
if (btSearch != null)
return;
btSearch = new Runnable(){#Override public void run(){
if ((btSocket != null) && (btSocket.isConnected())) {
cnt--;
if (cnt < -10) {
cnt = 0;
btConnect();
}
} else if (myBluetooth.isDiscovering()) {
cnt++;
}
btH.postDelayed(this, 1000);
fa(cnt);
}};
btH.postDelayed(btSearch,1000);
}
}
MATCHING ARDUINO SKETCH:
byte mini [4];
int battery;
unsigned long mill = millis();
byte moveCnt = 1;
int minuteCnt = 0;
int lastMove = 0;
int moveA, moveB, moveC, LMoveA, LMoveB, LMoveC, totMove, eyes, LEyes, totEyes;
int moveUpA = 0;
int moveDnA = 1000;
int moveUpB = 0;
int moveDnB = 1000;
int moveUpC = 0;
int moveDnC = 1000;
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3, 5); // RX, TX
void setup()
{
Serial .begin(9600);
mySerial.begin(9600);
}
void loop()
{
if (millis() > mill)
{
mill += 100;
minuteCnt++;
// *** EYES ***
eyes = analogRead(A6);
totEyes += abs(eyes-LEyes);
LEyes = eyes;
// *** MOVEMENT *** --KEEP-- moveA = max(0,analogRead(A1) >> 2);
moveA = analogRead(A0);
moveB = analogRead(A1);
moveC = analogRead(A2);
totMove += abs(moveA-LMoveA) + abs(moveB-LMoveB) + abs(moveC-LMoveC);
LMoveA = moveA; LMoveB = moveB; LMoveC = moveC;
// *** SEND SECOND ***
if (minuteCnt >= 10)
{
minuteCnt = 0;
// *** BATTERY ***
battery = analogRead(A5); // battery
mini[2] = (battery & 0xff); // battery low byte
mini[3] = ((battery >> 8) & 0xff); // battery high byte
// *** EYES ***
mini[0] = min(max(0,totEyes-10),255);
totEyes = 0;
// *** MOVEMENT ***
mini[1] = min(max(0,totMove-30),255);
totMove = 0;
Serial.print(mini[0]);
Serial.print(" ");
Serial.print(mini[1]);
Serial.print(" ");
Serial.print(mini[2]);
Serial.print(" ");
Serial.println(mini[3]);
mySerial.write(mini,4);
}
}
}
I am making some experiments with Android Open Accessory Protocol (AOA) using various phones/tablets and Arduino DUE.
I need some help to try to find the cause of a different behaviour of a simple app based on AOA that reads data from an analog input pin and that changes the status of a digital output pin of the Arduino DUE.
All phones on which I am trying the app are not rooted and I have verified that all of them have the files
/system/framework/com.android.future.usb.accessory.jar
/system/etc/permissions/android.hardware.usb.accessory.xml
that, as long as I know, are the only two requested to give support to AOA.
The named app works well on a Samsung Galaxy S2 (Android version 4.1.2, kernel v3.0.31-1211311) and on a Galaxy Pocket Neo (Android version 4.1.2, kernel v3.0.15-1456085), but works only "partially" on a Samsung Galaxy Note 3 (Android version 4.3, kernel v3.4.0-2019540).
In more detail, when I connect the accessory to all of the specified phones (also the Galaxy Note 3), it is correctly recognized and the app associated to the Arduino sketch controls correctly (an all phones) the status of the digital output pin, but the Galaxy Note seems to don't be able to receive from Arduino and to display the message containing the result of the analog-to-digital conversion (two bytes).
The app is one of the tutorial projects of the UDOO development platform and the original post is here: http://www.udoo.org/ProjectsAndTutorials/android-and-arduino-on-udoo-bidirectional-communication/?portfolioID=1394
Here is the code of MainActivity.java:
package org.udoo.androidadkdemobidirect;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.udoo.androidadkdemobidirect.R;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
public class MainActivity extends Activity implements Runnable{
private static final String TAG = "UDOO_AndroidADKFULL";
private static final String ACTION_USB_PERMISSION = "org.udoo.androidadkdemobidirect.action.USB_PERMISSION";
private UsbManager mUsbManager;
private PendingIntent mPermissionIntent;
private boolean mPermissionRequestPending;
private Message m;
UsbAccessory mAccessory;
ParcelFileDescriptor mFileDescriptor;
FileInputStream mInputStream;
FileOutputStream mOutputStream;
private static ToggleButton btn_LED = null;
private static TextView tv_adResult = null;
private boolean running = false;
// Receive the USB attached intent
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
openAccessory(accessory);
} else {
Log.d(TAG, "permission denied for accessory "+ accessory);
}
mPermissionRequestPending = false;
}
} else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
UsbAccessory accessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
if (accessory != null && accessory.equals(mAccessory)) {
closeAccessory();
}
}
}
};
#SuppressWarnings("deprecation")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
registerReceiver(mUsbReceiver, filter);
if (getLastNonConfigurationInstance() != null) {
mAccessory = (UsbAccessory) getLastNonConfigurationInstance();
openAccessory(mAccessory);
}
setContentView(R.layout.activity_main);
btn_LED = (ToggleButton) findViewById(R.id.toggleButtonLED);
tv_adResult = (TextView) findViewById(R.id.adResult);
}
#SuppressWarnings("deprecation")
#Override
public Object onRetainNonConfigurationInstance() {
if (mAccessory != null) {
return mAccessory;
} else {
return super.onRetainNonConfigurationInstance();
}
}
#Override
public void onResume() {
super.onResume();
if (mInputStream != null && mOutputStream != null) {
running = true;
return;
}
//open the accessory from the accessory list
UsbAccessory[] accessories = mUsbManager.getAccessoryList();
UsbAccessory accessory = (accessories == null ? null : accessories[0]);
if (accessory != null) {
if (mUsbManager.hasPermission(accessory)) {
openAccessory(accessory);
} else {
synchronized (mUsbReceiver) {
if (!mPermissionRequestPending) {
mUsbManager.requestPermission(accessory,mPermissionIntent);
mPermissionRequestPending = true;
}
}
}
} else {
Log.d(TAG, "mAccessory is null");
}
}
#Override
public void onPause() {
running = false;
super.onPause();
}
#Override
public void onDestroy() {
running = false;
closeAccessory();
unregisterReceiver(mUsbReceiver);
super.onDestroy();
}
// open the accessory and open the input and output stream from the descriptor
// start also the thread that reads from Arduino
private void openAccessory(UsbAccessory accessory) {
mFileDescriptor = mUsbManager.openAccessory(accessory);
if (mFileDescriptor != null) {
mAccessory = accessory;
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
Thread thread = new Thread(this, "UDOO_ADK_readfrom");
running = true;
thread.start();
Toast.makeText(getApplicationContext(), "Accessory connected", Toast.LENGTH_SHORT).show();
Log.i(TAG, "openaccessory");
}
else {
Toast.makeText(getApplicationContext(), "Accessory not connected", Toast.LENGTH_SHORT).show();
}
}
// close the accessory
private void closeAccessory() {
Log.i(TAG, "closeaccessory");
try {
if (mFileDescriptor != null) {
mFileDescriptor.close();
}
} catch (IOException e) {
} finally {
mFileDescriptor = null;
mAccessory = null;
running = false;
}
}
// ToggleButton method - send message to Arduino
public void writeToAccessory(View v){
if (mAccessory != null) {
byte[] message = new byte[1];
message[0] = (byte) (btn_LED.isChecked()?1:0);
if (mOutputStream != null) {
try {
mOutputStream.write(message);
} catch (IOException e) {
Log.e(TAG, "write failed", e);
}
}
}
else
Toast.makeText(getApplicationContext(), "Accessory not connected", Toast.LENGTH_SHORT).show();
}
// Thread to read data from Arduino
public void run() {
int ret = 0;
byte[] buffer = new byte[4];
while (running) {
try {
ret = mInputStream.read(buffer);
} catch (IOException e) {
break;
}
m = Message.obtain(mHandler);
if (ret != 0) {
m.arg1 = (int) ((buffer[0] & 0xff) << 8) + (buffer[1] & 0xff);
ret = 0;
}
mHandler.sendMessage(m);
}
}
static Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
final int temp = msg.arg1;
tv_adResult.setText(String.format("%4d (= %.2f V)", temp, 3.3/1024*temp));
}
};
}
I have also verified that this strange behaviour persists also for other apps based on the AOA Protocol, that is: the Galaxy Note 3 sends correctly the output messages to the accessory but doesn't read the input messages from it.
I am unable to find where the problem is and I would ask the StackOverflow Community to give me some hint.
Any help will be appreciated.
I am not sure if this helps, but you could try to disable USB Debugging from the Developer Options. Some phones have issue with the debugging mode on.