My team and I are currently trying to get our android app to send a signal to our arduino with a bluetooth shell on it. The signal doesn't need to be meaningful in anyway only that the arduino knows a signal has been sent. I have seen allot of online material on this, but none of it seems to coincide and none of it seems to work for me.
My current code: (we only want to send a signal when onRecieve() is called)
package com.example.alarmquiz2;
import android.provider.Settings.Secure;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.util.UUID;
import android.telephony.TelephonyManager;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
import android.bluetooth.BluetoothClass.Device;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.widget.Toast;
import android.content.Intent;
import android.content.BroadcastReceiver;
public class AlarmReceiver
extends BroadcastReceiver
{
Sound s = new Sound();
private BluetoothAdapter blue;
private Context contexxt;
private Device arduino;
private BluetoothSocket btSocket;
private TelephonyManager tManager;
private UUID uuid;
private OutputStream outStream;
private InputStream inStream;
private static String address = "00:14:03:18:42:19";
public void onReceive(Context context, Intent intent)
{
TelephonyManager tManager =
(TelephonyManager)context
.getSystemService(Context.TELEPHONY_SERVICE);
uuid = UUID.fromString(tmanager.getDeviceID());
contexxt = context;
this.CheckBt();
this.Connect();
this.writeData("meh");
if (!s.isPlaying())
{
s.setSound(context);
s.startSound();
Intent i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
else if (s.isPlaying())
{
s.stopSound();
Intent i = new Intent(context, SecondscreenActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
private void CheckBt()
{
blue = BluetoothAdapter.getDefaultAdapter();
if (!blue.isEnabled())
{
Toast
.makeText(contexxt, "Bluetooth Disabled !", Toast.LENGTH_SHORT)
.show();
/*
* It tests if the bluetooth is enabled or not, if not the app will
* show a message.
*/
}
if (blue == null)
{
Toast.makeText(contexxt, "Bluetooth null !", Toast.LENGTH_SHORT)
.show();
}
}
public void Connect()
{
BluetoothDevice device = blue.getRemoteDevice(address);
Log.d("", "Connecting to ... " + device);
blue.cancelDiscovery();
try
{
btSocket = device.createRfcommSocketToServiceRecord(uuid);
/*
* Here is the part the connection is made, by asking the device to create a
* RfcommSocket (Unsecure socket I guess), It map a port for us or something
* like that
*/
btSocket.connect();
Log.d("", "Connection made.");
}
catch (IOException e)
{
try
{
btSocket.close();
}
catch (IOException e2)
{
Log.d("", "Unable to end the connection");
}
Log.d("", "Socket creation failed");
}
/*
* this is a method used to read what the Arduino says for example when
* you write Serial.print("Hello world.") in your Arduino code
*/
}
private void writeData(String data)
{
try
{
outStream = btSocket.getOutputStream();
}
catch (IOException e)
{
Log.d("", "Bug BEFORE Sending stuff", e);
}
String message = data;
/* In my example, I put a button that invoke this method and send a string to it */
byte[] msgBuffer = message.getBytes();
try
{
outStream.write(msgBuffer);
}
catch (IOException e)
{
Log.d("", "Bug while sending stuff", e);
}
}
}
Ive also give myself all the required permissions in my manifest. The problem I am presently getting on my friends phone is that the "getDeviceID()" is returning a 14 digit number as opposed to the "00000000-0000-0000-0000-000000000000" format. Any suggestions, scoldings, or advice would be most welcome.
This:
uuid = UUID.fromString(tmanager.getDeviceID());
...
btSocket = device.createRfcommSocketToServiceRecord(uuid);
is most certainly not what you want to do.
What makes you think that the "device ID" of the phone(?) is in some way related to the UUID which is used to identify a certain bluetooth service at the other device?
Btw, did you read the docs?
You definitely need to find out which UUID you have to use to connect to the specific service the destination device provides on its BT interface. A list of well-known, standard UUIDs can be found here for example.
Many devices provide the "serial port profile" (SPP) for basic, stream-oriented data exchange. You may want to try that first.
Here's another source which may help.
Related
I am pretty new to STOMP, just learning it for a few weeks only. I have been trying for some time to send data from Browser to Android mobile App using STOMP, so far I have been successful in sending data from my browser to Android emulator, however if I try it on my mobile phone, the app will crash.
What I did:
I ran the Spring Boot Websocket Server before running the Android studio emulator
Used the same wifi for my phone and laptop where the server is run on.
My code is based off of xlui/WebSocketExample. (Search on google and you can find the code)
I am using NaikSoftware/StompProtocolAndroid in Android Studio, the Android client uses StompProtocolAndroid which implements protocol STOMP on Android, to subscribe or send message to server.
The Spring Boot WebSocket Server is ran on Intelliji full Version.
changed from 10.0.2.2/8080/im/websocket to Stomp.over(Stomp.ConnectionProvider.OKHTTP, "ws://MY LAPTOP IP ADDRESS/8080/im/websocket");
My Code in Android Studio for the Broadcast activity:
package app.xlui.example.im.activities;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Arrays;
import app.xlui.example.im.R;
import app.xlui.example.im.conf.Const;
import app.xlui.example.im.util.StompUtils;
import ua.naiksoftware.stomp.Stomp;
import ua.naiksoftware.stomp.StompClient;
import ua.naiksoftware.stomp.dto.StompCommand;
import ua.naiksoftware.stomp.dto.StompHeader;
import ua.naiksoftware.stomp.dto.StompMessage;
#SuppressWarnings({"FieldCanBeLocal", "ResultOfMethodCallIgnored", "CheckResult"})
public class BroadcastActivity extends AppCompatActivity {
private Button broadcastButton;
private Button groupButton;
private Button chatButton;
private EditText nameText;
private Button sendButton;
private TextView resultText;
private EditText nameput;
private void init() {
broadcastButton = findViewById(R.id.broadcast);
broadcastButton.setEnabled(false);
groupButton = findViewById(R.id.groups);
chatButton = findViewById(R.id.chat);
nameText = findViewById(R.id.name);
sendButton = findViewById(R.id.send);
resultText = findViewById(R.id.show);
nameput=findViewById(R.id.name2);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
this.init();
StompClient stompClient = Stomp.over(Stomp.ConnectionProvider.OKHTTP, "ws://MY LAPTOP IP ADDRESS/im/websocket");
StompUtils.lifecycle(stompClient);
Toast.makeText(this, "Start connecting to server", Toast.LENGTH_SHORT).show();
// Connect to WebSocket server
stompClient.connect();
// 订阅消息
Log.i(Const.TAG, "Subscribe broadcast endpoint to receive response");
stompClient.topic(Const.broadcastResponse).subscribe(stompMessage -> {
JSONObject jsonObject = new JSONObject(stompMessage.getPayload());
Log.i(Const.TAG, "Receive: " + stompMessage.getPayload());
runOnUiThread(() -> {
try {
resultText.append(jsonObject.getString("response") + "\n");
nameput.setText(jsonObject.getString("response"));
} catch (JSONException e) {
e.printStackTrace();
}
});
});
sendButton.setOnClickListener(v -> {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("name", nameText.getText());
} catch (JSONException e) {
e.printStackTrace();
}
stompClient.send(new StompMessage(
// Stomp command
StompCommand.SEND,
// Stomp Headers, Send Headers with STOMP
// the first header is required, and the other can be customized by ourselves
Arrays.asList(
new StompHeader(StompHeader.DESTINATION, Const.broadcast),
new StompHeader("authorization", "this is a token generated by your code!")
),
// Stomp payload
jsonObject.toString())
).subscribe();
nameText.setText("");
});
groupButton.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(BroadcastActivity.this, GroupActivity.class);
startActivity(intent);
this.finish();
});
chatButton.setOnClickListener(v -> {
Intent intent = new Intent();
intent.setClass(BroadcastActivity.this, ChatActivity.class);
startActivity(intent);
this.finish();
});
}
}
My Code in Android Studio for the Const activity:
public class Const {
public static final String TAG = "xlui";
public static final String placeholder = "placeholder";
/**
* <code>im</code> in address is the endpoint configured in server.
* If you are using AVD provided by Android Studio, you should uncomment the upper address.
* If you are using Genymotion, nothing else to do.
* If you are using your own phone, just change the server address and port.
*/
private static final String address = "ws://10.0.2.2:8080/im/websocket";//for android vm
//public static final String address = "ws://10.0.3.2:8080/im/websocket";//for Genymotion
public static final String broadcast = "/broadcast";
public static final String broadcastResponse = "/b";
// replace {#code placeholder} with group id
public static final String group = "/group/" + placeholder;
public static final String groupResponse = "/g/" + placeholder;
public static final String chat = "/chat";
// replace {#code placeholder} with user id
public static final String chatResponse = "/user/" + placeholder + "/msg";
}
My Code in Android Studio for the StompUtils activity:
import android.util.Log;
import app.xlui.example.im.conf.Const;
import ua.naiksoftware.stomp.StompClient;
import static app.xlui.example.im.conf.Const.TAG;
public class StompUtils {
#SuppressWarnings({"ResultOfMethodCallIgnored", "CheckResult"})
public static void lifecycle(StompClient stompClient) {
stompClient.lifecycle().subscribe(lifecycleEvent -> {
switch (lifecycleEvent.getType()) {
case OPENED:
Log.d(TAG, "Stomp connection opened");
break;
case ERROR:
Log.e(TAG, "Error", lifecycleEvent.getException());
break;
case CLOSED:
Log.d(TAG, "Stomp connection closed");
break;
}
});
}
}
I do not know what I did wrong, I you have any suggestions please do say.
I've been following these two posts SPP Server and Client and this stackoverflow post. I have the server running on a Linux VM and the Android app running on a Samsung Galaxy S6. When I run the server code in Intellij, it says:
"Server Started. Waiting for clients to connect".
When I run the Android app, I get the following Alert box saying:
"Fatal Error. In OnResume()and an exception occurred during write: socket closed.
Check that the SPP UUID: 00001101-0000-1000-8000-00805F9B34FB exists on server. Press OK to exit.
Why is this happening and how can I resolve it so the server will connect and receive a string from the Android app?
SPP Server Code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import javax.bluetooth.*;
import javax.microedition.io.*;
public class SampleSPPServer {
//start server
private void startServer() throws IOException{
//Create a UUID for SPP
UUID uuid = new UUID("0000110100001000800000805F9B34FB", false);
//Create the servicve url
String connectionString = “btspp://localhost:” + uuid +”;name=Sample
SPP Server”;
//open server url
StreamConnectionNotifier streamConnNotifier =
(StreamConnectionNotifier)Connector.open( connectionString );
//Wait for client connection
System.out.println(“\nServer Started. Waiting for clients to connect…”);
StreamConnection connection=streamConnNotifier.acceptAndOpen();
RemoteDevice dev = RemoteDevice.getRemoteDevice(connection);
System.out.println(“Remote device address: “+dev.getBluetoothAddress());
System.out.println(“Remote device name: “+dev.getFriendlyName(true));
//read string from spp client
InputStream inStream=connection.openInputStream();
BufferedReader bReader=new BufferedReader(new
InputStreamReader(inStream));
String lineRead=bReader.readLine();
System.out.println(lineRead);
//send response to spp client
OutputStream outStream=connection.openOutputStream();
PrintWriter pWriter=new PrintWriter(new OutputStreamWriter(outStream));
pWriter.write(“Response String from SPP Server\r\n”);
pWriter.flush();
pWriter.close();
streamConnNotifier.close();
}
public static void main(String[] args) throws IOException {
//display local device address and name
LocalDevice localDevice = LocalDevice.getLocalDevice();
System.out.println(“Address: “+localDevice.getBluetoothAddress());
System.out.println(“Name: “+localDevice.getFriendlyName());
SampleSPPServer sampleSPPServer=new SampleSPPServer();
sampleSPPServer.startServer();
}
}
Android Client Code:
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.DialogInterface;
import android.content.Intent;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.UUID;
public class BluetoothClient extends AppCompatActivity {
TextView out;
private static final int REQUEST_ENABLE_BT = 1;
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
// Well known SPP UUID
private static final UUID MY_UUID =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Insert your server's MAC address
private static String address = "00:10:60:AA:B9:B2";
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bluetooth_client);
out = (TextView) findViewById(R.id.out);
out.append("\n...In onCreate()...");
btAdapter = BluetoothAdapter.getDefaultAdapter();
CheckBTState();
}
public void onStart() {
super.onStart();
out.append("\n...In onStart()...");
}
public void onResume() {
super.onResume();
out.append("\n...In onResume...\n...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) {
AlertBox("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.
try {
btSocket.connect();
out.append("\n...Connection established and data link opened...");
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
AlertBox("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + ".");
}
}
// Create a data stream so we can talk to server.
out.append("\n...Sending message to server...");
String message = "Hello from Android.\n";
out.append("\n\n...The message that we will send to the server is: "+message);
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
AlertBox("Fatal Error", "In onResume() and output stream creation failed:" + e.getMessage() + ".");
}
byte[] msgBuffer = message.getBytes();
try {
outStream.write(msgBuffer);
} catch (IOException e) {
String msg = "In onResume() and an exception occurred during write: " + e.getMessage();
if (address.equals("00:00:00:00:00:00"))
msg = msg + ".\n\nUpdate your server address from 00:00:00:00:00:00 to the correct address on line 37 in the java code";
msg = msg + ".\n\nCheck that the SPP UUID: " + MY_UUID.toString() + " exists on server.\n\n";
AlertBox("Fatal Error", msg);
}
}
public void onPause() {
super.onPause();
//out.append("\n...Hello\n");
InputStream inStream;
try {
inStream = btSocket.getInputStream();
BufferedReader bReader=new BufferedReader(new InputStreamReader(inStream));
String lineRead=bReader.readLine();
out.append("\n..."+lineRead+"\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
out.append("\n...In onPause()...");
if (outStream != null) {
try {
outStream.flush();
} catch (IOException e) {
AlertBox("Fatal Error", "In onPause() and failed to flush output stream: " + e.getMessage() + ".");
}
}
try {
btSocket.close();
} catch (IOException e2) {
AlertBox("Fatal Error", "In onPause() and failed to close socket." + e2.getMessage() + ".");
}
}
public void onStop() {
super.onStop();
out.append("\n...In onStop()...");
}
public void onDestroy() {
super.onDestroy();
out.append("\n...In onDestroy()...");
}
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) {
AlertBox("Fatal Error", "Bluetooth Not supported. Aborting.");
} else {
if (btAdapter.isEnabled()) {
out.append("\n...Bluetooth is enabled...");
} else {
//Prompt user to turn on Bluetooth
Intent enableBtIntent = new Intent(btAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
}
public void AlertBox( String title, String message ){
new AlertDialog.Builder(this)
.setTitle( title )
.setMessage( message + " Press OK to exit." )
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface arg0, int arg1) {
finish();
}
}).show();
}
}
Android Studio Logcat:
android.view.WindowLeaked: Activity com.example.toby.btclientapp.BluetoothClient has leaked window com.android.internal.policy.PhoneWindow$DecorView{b73d40d V.E...... R.....I. 0,0-1368,1249} that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:569)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:326)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.app.Dialog.show(Dialog.java:350)
at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:955)
at com.example.toby.btclientapp.BluetoothClient.AlertBox(BluetoothClient.java:181)
at com.example.toby.btclientapp.BluetoothClient.onResume(BluetoothClient.java:107)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1286)
at android.app.Activity.performResume(Activity.java:6987)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4145)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4250)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3361)
at android.app.ActivityThread.access$1100(ActivityThread.java:222)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
07-26 13:09:21.574 3857-3857/? E/WindowManager: android.view.WindowLeaked: Activity com.example.toby.btclientapp.BluetoothClient has leaked window com.android.internal.policy.PhoneWindow$DecorView{9723488 V.E...... R....... 0,0-1368,1249} that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:569)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:326)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.app.Dialog.show(Dialog.java:350)
at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:955)
at com.example.toby.btclientapp.BluetoothClient.AlertBox(BluetoothClient.java:181)
at com.example.toby.btclientapp.BluetoothClient.onResume(BluetoothClient.java:107)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1286)
at android.app.Activity.performResume(Activity.java:6987)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4145)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4250)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1839)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
07-26 13:09:21.574 3857-3857/? E/WindowManager: android.view.WindowLeaked: Activity com.example.toby.btclientapp.BluetoothClient has leaked window com.android.internal.policy.PhoneWindow$DecorView{cea821b V.E...... R....... 0,0-1368,799} that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:569)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:326)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.app.Dialog.show(Dialog.java:350)
at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:955)
at com.example.toby.btclientapp.BluetoothClient.AlertBox(BluetoothClient.java:181)
at com.example.toby.btclientapp.BluetoothClient.onPause(BluetoothClient.java:135)
at android.app.Activity.performPause(Activity.java:7033)
at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1339)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4577)
at android.app.ActivityThread.performPauseActivity(ActivityThread.java:4550)
at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:4525)
at android.app.ActivityThread.access$1300(ActivityThread.java:222)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1813)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7229)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
I needed to change the MAC address of the Bluetooth adapter. It works now.
Can an Android application get the list of available sockets on a remote device which are SDP registered to a specific UUID? I can see how to connect to a single socket with the given UUID, but I cannot find a way to iterate through all the sockets which share that UUID.
I know my code is crap. I know I'm not supposed to do blocking operations in the Activity, and that everything here is completely hacky. I'm only trying to get a proof of concept running before I architect this correctly.
That said, here's my code. I took an approach which isn't working.
package {intentionally removed};
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;
import java.util.UUID;
import android.os.Bundle;
import android.app.Activity;
import android.bluetooth.*;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final int REQUEST_ENABLE_BT = 1;
private String MY_TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
}
if (!mBluetoothAdapter.isEnabled()) {
//Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
//startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
Toast error = Toast.makeText(getApplicationContext(), "Enable BT and try again", Toast.LENGTH_LONG);
error.show();
Log.e(MY_TAG, "BT not enabled. Quitting.");
}
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
Log.i(MY_TAG, "Found " + pairedDevices.size() + " bonded devices");
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
int i = 1;
while (true) {
Log.i(MY_TAG, "Device " + device.getAddress() + " with name " + device.getName());
//Repeatedly try to connect to the SDP UUID; move to the next device when this fails.
BluetoothSocket s = null;
try {
s = device.createRfcommSocketToServiceRecord(UUID.fromString("{intentionally removed}"));
Thread.sleep(1000);
try{
s.connect();
}
catch (Exception e) {
Log.i(MY_TAG, "could not connect to socket.");
break;
}
Log.i(MY_TAG, "Connected to a socket! Whee! " + i + " found.");
InputStream is = s.getInputStream();
Log.i(MY_TAG, "got the stream");
while (true) {
Log.i(MY_TAG, "began read loop");
int j = -1;
try {
j = is.read();
}
catch (Exception e)
{
//RESUME NEXT...mwahahaha
}
if (j == -1) {
Log.i(MY_TAG, "ran out of ibytes");
break;
}
Log.i(MY_TAG, "ibyte: " + is.read());
}
i++;
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e(MY_TAG, "Unable to connect.", e);
break;
}
}
}
}
}
#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
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
}
}
(the UUID I pulled because I'd rather not reveal what I'm up to. It's someone else's.)
I know there to be multiple sockets serving the same UUID on the other end. The code I've just given tries to connect to each socket, forcing createRfcommSocketToServiceRecord to grab another socket. However, one of the sockets I am unable to connect to...leaving me no way to iterate to the next one (as createRfcommSocketToServiceRecord just returns the same socket next iteration).
Is there a saner way to do this? I want a nice function I can call which lists out all of the sockets I can connect to with a given UUID. Does such a thing exist?
Thanks
Yes, it exists. How it works:
You create a class i.e. GattAttributes that includes known UUIDs.
Discover Services and Characteristics in your Service class
Loop through the discovered Services and Characteristics in your Activity (optionally, you can populate a list for the user to see)
This gives you the available Services and Characteristics in a list.
Look at this Google Bluetooth LE example to see the code.
The example lets user choose the Characteristic, but if you want to connect to the concrete Characteristic, that you know beforehand (as I did):
In your Service class, within onServicesDiscovered put:
BluetoothGattCharacteristic characteristic = gatt.getService(SERVICE_UUID).getCharacteristic(CHARACTERISTIC_UUID);
If you want to also add notifications and utilize onCharacteristicChanged(), use this code:
// Enable notifications for this characteristic locally
gatt.setCharacteristicNotification(characteristic, true);
// Write on the config descriptor to be notified when the value changes
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG);
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
gatt.writeDescriptor(descriptor);
CLIENT_CHARACTERISTIC_CONFIG needs to be defined, see the Google code referenced above.
thanks for taking the time to read this. I am experiencing a very strange 'NoSuchMethodError' in a project I'm working on involving Android. I can't figure this out as it defies all of my logic.
package com.project.qrcode
import android.security.KeyStore;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import jim.h.common.android.lib.zxing.config.ZXingLibConfig;
import jim.h.common.android.lib.zxing.integrator.IntentIntegrator;
import jim.h.common.android.lib.zxing.integrator.IntentResult;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private ZXingLibConfig zxingLibConfig;
private Handler handler = new Handler();
private TextView txtScanResult;
KeyStore ks = KeyStore.getInstance();
SecretKeyStore secretKeyStore = new SecretKeyStore();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream( );
byte[] hashedBytes;
String decoded;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
startActivity(new Intent("android.credentials.UNLOCK"));
} else {
startActivity(new Intent("com.android.credentials.UNLOCK"));
}
} catch (ActivityNotFoundException e) {
Log.e(getPackageName(), "No UNLOCK activity: " + e.getMessage(), e);
}
zxingLibConfig = new ZXingLibConfig();
zxingLibConfig.useFrontLight = true;
txtScanResult = (TextView) findViewById(R.id.scan_result);
Button scanButton = (Button) findViewById(R.id.scan_button);
//Set a listener on the scan button
scanButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!checkIfKeyStored()) {
Toast keyerror = Toast.makeText(getBaseContext(), "You need to complete setup first", Toast.LENGTH_SHORT);
keyerror.show();
return;
}
IntentIntegrator.initiateScan(MainActivity.this, zxingLibConfig);
}
});
Log.v(getPackageName(), "Listener set on scan button");
Button setupButton = (Button) findViewById(R.id.setup_button);
// Set a listener on the setup button
setupButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (checkIfKeyStored()) {
Log.v(getPackageName(), "Key is already stored");
Toast keyerror = Toast.makeText(getBaseContext(), "You have already completed setup", Toast.LENGTH_SHORT);
keyerror.show();
return;
}
Log.v(getPackageName(), "Key not stored, proceeding with setup");
IntentIntegrator.initiateScan(MainActivity.this, zxingLibConfig);
}
});
Log.v(getPackageName(), "Listener set on setup button");
}
protected boolean checkIfKeyStored() {
String[] keyNames = ks.saw("");
if( keyNames.length == 0 ) {
return false;
}
return true;
}
// IF setup is done i.e. key is stored send to server
// Otherwise store on phone
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.v(getPackageName(), "Scanned QRCode");
if (requestCode == IntentIntegrator.REQUEST_CODE) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (scanResult == null) {
Log.v(getPackageName(), "Scanned nothing");
return;
}
//Contents of the QRCode
Log.v(getPackageName(), "Scan complete, getting result");
final String result = scanResult.getContents();
Log.v(getPackageName(), "Scanned the following code "+ result);
//If there is already a secret key stored i.e. setup already done
if (checkIfKeyStored()) {
Log.v(getPackageName(), "Key already stored, encrypting");
try {
MessageDigest digest = MessageDigest.getInstance("SHA1PRNG");
Log.v(getPackageName(), "Got SHA1PRNG instance");
byte[] keyBytes = ks.get("twofactorkey");
byte[] resultBytes = result.getBytes("UTF-8");
Log.v(getPackageName(), "Got Bytes");
outputStream.write( resultBytes );
outputStream.write( keyBytes );
Log.v(getPackageName(), "Wrote Bytes to output stream");
byte[] bytesToEncrypt = outputStream.toByteArray( );
Log.v(getPackageName(), "Wrote to Byte array");
hashedBytes = digest.digest(bytesToEncrypt);
decoded = new String(hashedBytes, "UTF-8");
Log.v(getPackageName(), "Coverted bytes to String");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
txtScanResult.setText(decoded);
Log.v(getPackageName(), "Set TextView");
}
});
}
else //This is the first time scanning a QRCode, i.e. Setup
{
Log.v(getPackageName(), "Key not stored, first time setup");
byte[] resultBytes;
try {
resultBytes = result.getBytes("UTF-8");
Log.v(getPackageName(), "Result byte array: " + resultBytes);
boolean success = ks.put("twofactorkey", resultBytes);
if (!success) {
int errorCode = ks.getLastError();
throw new RuntimeException("Keystore error: " + errorCode);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Log.v(getPackageName(), "Stored in keystore");
Toast setupComplete = Toast.makeText(getBaseContext(), "You have completed setup", Toast.LENGTH_SHORT);
setupComplete.show();
}
}
}
}
package android.security;
public class KeyStore {
private boolean put(byte[] key, byte[] value) {
execute('i', key, value);
return mError == NO_ERROR;
}
public boolean put(String key, byte[] value) {
Log.v("KEYSTORE", "Attempting put");
return put(getBytes(key), value);
}
}
The error I am getting is..
02-24 15:25:55.689: E/AndroidRuntime(11016): java.lang.NoSuchMethodError: android.security.KeyStore.put which occurs in the onActivityResult() method.
If you need the full logcat I can post that too.
You can see I have some Log messages planted throughout the code. The one inside put never prints out.
EDIT 24/02/14:
The above NoMethod exception has been solved by moving KeyStore.java into the same package as MainActivity.java - Thank you Lars
However I now have a new problem. Any time I try using ks.state() or ks.put() I get back a response back of AssertError: 5 - Which, according to KeyStore.java is a protocol error.
Final Edit
I figured out the above problem. Turns out the version of the KeyStore I am using from AOSP is for versions of Android below 4.2 only.
what is the reason for java.lang.NoSuchMethodError
java doc says
Thrown if an application tries to call a specified method of a class
(either static or instance), and that class no longer has a definition
of that method. Normally, this error is caught by the compiler; this
error can only occur at run time if the definition of a class has
incompatibly changed.
in your code you call put method here
boolean success = ks.put("twofactorkey", resultBytes);
and you have a required method is in the KeyStore class
public boolean put(String key, byte[] value) {
Log.v("KEYSTORE", "Attempting put");
return put(getBytes(key), value);
}
but the problem is your compiled KeyStore(KeyStore.class file) has no required put method. I assume you have mistakenly altered the above put method and compiled both classes alone and ran MainActivity class. that's why you get that error
that kind of error appear when you are running some code on a older virtual machine.
in general thisd appen when your bitcode call a function that does not exist.
As far as i know android.security; does not exist, but java.security; does.
If that your custom class, i don't think you can put it into android's path, but i exoect a compiling error
I have a tcp/ip application in which Client 'A' gets it's coordinates and sends them to the server running on my pc. I am using local ips etc. This was running fine, I came out this morning however and I had an issue with my tp-link router and the lan, so I re installed my router and all connections (wi-fi) are back up and running. However, now when I try to run my app it won't work with my device.
If I run it through the emulator (i just have a string for testing) it works, I know that this is because both the server and the emulator are both on the same machine. My ip is correct, it is that of the machine the server is running on...I'm trying to teach myself this technology and do a project for college and I keep coming up against massive headaches like this. I've posted my client and server code below, is there anyone that might have any ideas? All setting are the same on the router and i'm sure as this is just connecting over a lan I don't have to forward any ports?
CLIENT A
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class Child extends Activity implements LocationListener {
private Socket s;
private PrintWriter p;
public static double latitude;
public static double longitude;
String coordinates;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.child);
LocationManager mlocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
LocationListener mlocationListener = new MyLocationListener();
mlocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
mlocationListener);
String hello = "hello"; //FOR TESTING PURPOSES
Transmit (hello);
Log.d("test", "test");
}
public class MyLocationListener implements LocationListener {
public void onProviderDisabled(String provider) {
Toast.makeText(getApplicationContext(), "Gps Disabled",
Toast.LENGTH_SHORT).show();
}
public void onProviderEnabled(String provider) {
Toast.makeText(getApplicationContext(), "Gps Enabled",
Toast.LENGTH_SHORT).show();
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
latitude = location.getLatitude();
longitude = location.getLongitude();
coordinates = ("TESTING " + latitude + longitude);
//Transmit(coordinates);
}
}
private void Transmit(final String message) {
Thread trans = new Thread(new Runnable() {
public void run() {
Log.d("TRANSMIT", "CALLED");
// TODO Auto-generated method stub
try {
s = new Socket("192.168.3.103", 1111); // connect to
// server
Log.d("CONNECTED", "Connected");
DataOutputStream _OutPut = new DataOutputStream(
s.getOutputStream());
_OutPut.writeBytes(message + "\n");
_OutPut.flush();
_OutPut.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
trans.start();
}
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
}
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
SERVER
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TCPServer {
public static void main(String[] args) throws Exception {
Socket s;
ServerSocket ss = new ServerSocket(1111);
System.out.println("Server started. Listening to the port 2001");
System.out.println("Server: waiting for connection ..");
while (true) {
try {
s = ss.accept();
if (s != null) {
InputStream fromChild = s.getInputStream();
while (s.isConnected()) {
System.out.println("Child Connected");
Scanner r = new Scanner(fromChild);
String location;
location = r.nextLine();
System.out.println(location);
}
}
} catch (IOException ex) {
System.out.println("Problem in message reading");
}
}
}
}
So please, if anyone can help or throw some light on the situation I would be extremely grateful as I can't develop any further until I sort this problem.
Regards,
Gary
It certainly sounds like a connectivity issue between the phone and the server.
Double-check your ip address on the server and the phone and make sure they are on the SAME SUBNET (192.168.3.X), if not then you need to set up a forwarding rule on the router.
You can also verify connectivity by running a basic html server on the server box and point the browser on the phone to the server. Apache tomcat right of the box is easy to start and has a dashboard app already configured to run on startup. You can also test this from another computer on the same network to rule out your code and the phone altogether.
Read this:
http://developer.android.com/tools/devices/emulator.html#emulatornetworking
an excerpt from there :
Network Address Description
10.0.2.1 Router/gateway address
10.0.2.2 Special alias to your host loopback interface (i.e., 127.0.0.1 on your development machine)
10.0.2.3 First DNS server
10.0.2.4 / 10.0.2.5 / 10.0.2.6 Optional second, third and fourth DNS server (if any)
10.0.2.15 The emulated device's own network/ethernet interface
127.0.0.1 The emulated device's own loopback interface
basically if you run your server locally you should try and hit 10.0.2.2 address
from the emulator ---
Cheers,