We are about to switch to a new forum software. Until then we have removed the registration on this forum.
Hey all,
I've been looking through examples/tutorials on establishing a bluetooth connection in Android mode for processing using android API's (as opposed to Ketai). Ketai is really great, but I am trying to use another java library that uses android sockets.
I've been looking through tutorials like this one: http://arduinobasics.blogspot.com.au/2013/03/arduinobasics-bluetooth-android.html
Which is nice, but it was done in processing 2 and targeted SDK version 10. (I'll paste the code at the end of the post).
I am currently using Processing 3.0, targeting SDK version 23 (android 6.0). I have been having trouble with certain parts of that tutorial which I believe are due to the fact that the Android SDK has changed quite a bit since it was written. For example, startActivityForResult() has issues (function doesn't exist) -- I from what I've read it is now something launched from a fragment instead of an activity?
Anyways, I am wondering if anyone can point me to a sample/example/tutorial that might have an updated guide for dealing with bluetooth using the modern android APIs.
Thank you, B
/* ConnectBluetooth: Written by ScottC on 18 March 2013 using
Processing version 2.0b8
Tested on a Samsung Galaxy SII, with Android version 2.3.4
Android ADK - API 10 SDK platform */
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.widget.Toast;
import android.view.Gravity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import java.util.UUID;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.util.Log;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
boolean foundDevice=false; //When true, the screen turns green.
boolean BTisConnected=false; //When true, the screen turns purple.
//Get the default Bluetooth adapter
BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
/*The startActivityForResult() within setup() launches an
Activity which is used to request the user to turn Bluetooth on.
The following onActivityResult() method is called when this
Activity exits. */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode==0){
if(resultCode == RESULT_OK){
ToastMaster("Bluetooth has been switched ON");
} else {
ToastMaster("You need to turn Bluetooth ON !!!");
}
}
}
/* Create a BroadcastReceiver that will later be used to
receive the names of Bluetooth devices in range. */
BroadcastReceiver myDiscoverer = new myOwnBroadcastReceiver();
/* Create a BroadcastReceiver that will later be used to
identify if the Bluetooth device is connected */
BroadcastReceiver checkIsConnected = new myOwnBroadcastReceiver();
void setup(){
orientation(LANDSCAPE);
/*IF Bluetooth is NOT enabled, then ask user permission to enable it */
if (!bluetooth.isEnabled()) {
Intent requestBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(requestBluetooth, 0);
}
/*If Bluetooth is now enabled, then register a broadcastReceiver to report any
discovered Bluetooth devices, and then start discovering */
if (bluetooth.isEnabled()) {
registerReceiver(myDiscoverer, new IntentFilter(BluetoothDevice.ACTION_FOUND));
registerReceiver(checkIsConnected, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));
//Start bluetooth discovery if it is not doing so already
if (!bluetooth.isDiscovering()){
bluetooth.startDiscovery();
}
}
}
void draw(){
//Display a green screen if a device has been found,
//Display a purple screen when a connection is made to the device
if(foundDevice){
if(BTisConnected){
background(170,50,255); // purple screen
}else {
background(10,255,10); // green screen
}
}
}
/* This BroadcastReceiver will display discovered Bluetooth devices */
public class myOwnBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action=intent.getAction();
ToastMaster("ACTION:" + action);
//Notification that BluetoothDevice is FOUND
if(BluetoothDevice.ACTION_FOUND.equals(action)){
//Display the name of the discovered device
String discoveredDeviceName = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
ToastMaster("Discovered: " + discoveredDeviceName);
//Display more information about the discovered device
BluetoothDevice discoveredDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
ToastMaster("getAddress() = " + discoveredDevice.getAddress());
ToastMaster("getName() = " + discoveredDevice.getName());
int bondyState=discoveredDevice.getBondState();
ToastMaster("getBondState() = " + bondyState);
String mybondState;
switch(bondyState){
case 10: mybondState="BOND_NONE";
break;
case 11: mybondState="BOND_BONDING";
break;
case 12: mybondState="BOND_BONDED";
break;
default: mybondState="INVALID BOND STATE";
break;
}
ToastMaster("getBondState() = " + mybondState);
//Change foundDevice to true which will make the screen turn green
foundDevice=true;
//Connect to the discovered bluetooth device (SeeedBTSlave)
if(discoveredDeviceName.equals("SeeedBTSlave")){
ToastMaster("Connecting you Now !!");
unregisterReceiver(myDiscoverer);
ConnectToBluetooth connectBT = new ConnectToBluetooth(discoveredDevice);
//Connect to the the device in a new thread
new Thread(connectBT).start();
}
}
//Notification if bluetooth device is connected
if(BluetoothDevice.ACTION_ACL_CONNECTED.equals(action)){
ToastMaster("CONNECTED _ YAY");
BTisConnected=true; //turn screen purple
}
}
}
public class ConnectToBluetooth implements Runnable{
private BluetoothDevice btShield;
private BluetoothSocket mySocket = null;
private UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public ConnectToBluetooth(BluetoothDevice bluetoothShield) {
btShield = bluetoothShield;
try{
mySocket = btShield.createRfcommSocketToServiceRecord(uuid);
}catch(IOException createSocketException){
//Problem with creating a socket
}
}
@Override
public void run() {
/* Cancel discovery on Bluetooth Adapter to prevent slow connection */
bluetooth.cancelDiscovery();
try{
/*Connect to the bluetoothShield through the Socket. This will block
until it succeeds or throws an IOException */
mySocket.connect();
} catch (IOException connectException){
try{
mySocket.close(); //try to close the socket
}catch(IOException closeException){
}
return;
}
}
/* Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mySocket.close();
} catch (IOException e){
}
}
}
/* My ToastMaster function to display a messageBox on the screen */
void ToastMaster(String textToDisplay){
Toast myMessage = Toast.makeText(getApplicationContext(),
textToDisplay,
Toast.LENGTH_SHORT);
myMessage.setGravity(Gravity.CENTER, 0, 0);
myMessage.show();
}
Answers
@bharms=== not time enough till now to try your code; yet, reading it i think that this must work with some changes:
as you say you are n more in an activity but in a fragment and you have to take care of it (and of its lifecycle which is not the same than an activity)
you are compiling with MM, but what is your minTarget? - According to that you may have to use AppCompat.
be also aware that now permissions are not allowed (for dangerous one) as it was (only by manifest); they are always in the manifest but you have to ask them by coding on rutime.
Hi Akenaton, thanks for the reply.
for the activity vs. fragment issue, my understanding is that processing in android mode actually runs in/as a fragment, as opposed to an activity. Is this correct? If so, could I call the function startActivityForResult() from the fragments parent activity? I'm not very clear on how to deal with the lifecycle of the fragment vs. the activity. Are there any resources online for dealing with this in processing?
I am compiling with MM like you said, but I'm not sure how to specify the minTarget in processing. I downloaded a few other SDK versions with the SDK manager, but they don't show up under the target SDK dropdown item in the Android menu.
When you say permissions are not allowed, do you mean that the process of enabling permissions in processing (checking boxes next to things like "Bluetooth" or "Internet" from the permissions dropdown, is no longer allowed? If this is the case are there any examples that show the alternative method of allowing these permissions programmatically (at runtime I guess)?
Thanks again for your help, Brian
I think I've found my solution.
Instead of trying to get everything working fine in the processing IDE, I've followed the instructions here:
http://android.processing.org/tutorials/android_studio/index.html
to develop a "legit" android app that imports the processing core.jar as well as all my processing code.
Thanks again for the advice!
@bharms=== using as or eclipse with p5 is better than using p5 alone: and you can better understand what P5 is doing in the background: first of all it creates an activity then add a fragment to it; this fragment extends P5. So in a lot of cases you have to write "this.getActivity(). before calling a method. Yet, in your case i think that the problem is with the onActivityResult(), never called. Have you got some error message? - As soon as i can i ll tell you how to resolve that.
-- as for setting the minSDK if p5 now does not do that you can edit the manifest and modify it as you want.
-- as for permissions, if you are targetting MM be aware that you have to set the permissions for blueTooth as usually in the manifest BUT that you have ALSO to ask for permissions in runtime
https://developer.android.com/training/permissions/requesting.html
-- as for fragments lifecycle, see here:: https://developer.android.com/guide/components/fragments.html
usually you have to write code for onStart() && onResume().