Android bluetooth get response with BluetoothGatt - java

I'm new in connection bluetooth. I use code of
https://github.com/Fakher-Hakim/android-BluetoothLeGatt. When I try to
obtain the information nothing happened.
public String response() {
if (mConnected) {
mBluetoothLeService.readCharacteristic(characteristica);
byte response[] = characteristica.getValue();
String respuesta = ReadBytes(response);
mBluetoothLeService.disconnect();
return respuesta;
} else {
return null;
}
}
I execute after function
private final ExpandableListView.OnChildClickListener servicesListClickListner
How I can obtain information of the Bluetoothdevice?

The BLE operations are asynchronous, you have to deal with the result in the callback.
In your example: https://github.com/Fakher-Hakim/android-BluetoothLeGatt/blob/master/Application/src/main/java/com/example/android/bluetoothlegatt/BluetoothLeService.java
Check the onCharacteristicRead method.

Related

Using incoming data from bluetooth connection for specific objects? C# Windows Form App & Java Android App

first post here. I've tried to look for a question I have but no luck so I figure I ask it myself.
I am working on 2 programs. An Android app in Java and a C# Windows Form App on windows. They are both simply scorekeeping calculators to keep track of the score of 2 players.
The goal of the 2 programs is to use a Bluetooth connection to send data back and forth between each other so that they are "synced". Android app is a client, c# app is a server (32feet library).
Using the Bluetooth Chat example on Android and some code i put together in VS, I managed to get the 2 programs to connect and send and receive data to each other, great!
But now my main goal is that I need to find out a way to take the incoming data coming from the Android app and change the appropriate labels/text on the windows app.
So for example:
on the Windows App, there are 2 Labels: one for Player1, one for Player2 that both say "10".
On the Android App, I have 2 buttons that separately subtract from either Player1 or Player2's score.
On the android app, if I touch the button that subtracts(-) 1 from Player1 it would be 9. I now want that change to apply to Player1's score label on the windows app, where it would also show 9.
I then want the same thing for Player2's score.
This is the best I can describe my goal, and I would like to know if it's possible, and if so, be pointed in the right direction.
Here is some provided code for what I have so far:
C# windows form app:
private void button1_Click(object sender, EventArgs e)
{
if (serverStarted == true)
{
updateUI("Server already started");
return;
}
if (radioButton1.Checked)
{
connectAsClient();
}
else
{
connectAsServer();
}
}
private void connectAsServer()
{
Thread bluetoothServerThread = new Thread(new ThreadStart(ServerConnectThread)); //creates new thread and runs "ServerConnectThread"
bluetoothServerThread.Start();
}
private void connectAsClient()
{
throw new NotImplementedException();
}
Guid mUUID = new Guid("fa87c0d0-afac-11de-8a39-0800200c9a66");
bool serverStarted = false;
public void ServerConnectThread()
{
serverStarted = true;
updateUI("Server started, waiting for client");
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
BluetoothClient conn = blueListener.AcceptBluetoothClient();
updateUI("Client has connected");
Stream mStream = conn.GetStream();
while (true)
{
try
{
//handle server connection
byte[] received = new byte[1024];
mStream.Read(received, 0, received.Length);
updateUI("Received: " + Encoding.ASCII.GetString(received));
byte[] sent = Encoding.ASCII.GetBytes("hello world");
mStream.Write(sent, 0, sent.Length);
}
catch (IOException exception)
{
updateUI("Client disconnected");
}
}
}
private void updateUI(string message)
{
Func<int> del = delegate ()
{
textBox1.AppendText(message + Environment.NewLine);
return 0;
};
Invoke(del);
}
}
Android App (snippet from the Bluetooth Chat example - i think this is the only relevant part):
/**
* Sends a message.
*
* #param message A string of text to send.
*/
private void sendMessage(String message) {
// Check that we're actually connected before trying anything
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
// Check that there's actually something to send
if (message.length() > 0) {
// Get the message bytes and tell the BluetoothChatService to write
byte[] send = message.getBytes();
mChatService.write(send);
// Reset out string buffer to zero and clear the edit text field
mOutStringBuffer.setLength(0);
mOutEditText.setText(mOutStringBuffer);
}
}
You will want to have to add the clients to alist of streams for reference and also store the scores of each client on a list and then send the data coming from each client to the rest of the clients
so from the server youd have basically something like this
List<Stream> clients=new List<Stream>();
List<String> client_scores=new List<String>();
public void ServerConnectThread()
{
serverStarted = true;
updateUI("Server started, waiting for client");
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
BluetoothClient conn = blueListener.AcceptBluetoothClient();
updateUI("Client has connected");
Stream mStream = conn.GetStream();
clients.add(mStream);
client_scores.add(new Random().Next()+"");
int index_cnt = clients.IndexOf(mStream);
while (true)
{
try
{
//handle server connection
byte[] received = new byte[1024];
mStream.Read(received, 0, received.Length);
updateUI("Received: " + Encoding.ASCII.GetString(received));
client_scores[client_scores.FindIndex(ind=>ind.Equals(index_cnt))] = Encoding.ASCII.GetString(received);
byte[] sent = Encoding.ASCII.GetBytes("hello world");
mStream.Write(sent, 0, sent.Length);
foreach(Stream str in clients)
{
byte[] my_score = Encoding.ASCII.GetBytes(clients.ToArray()[index_cnt]+"");
str.Write(my_score, 0, my_score.Length);
}
}
catch (IOException exception)
{
updateUI("Client disconnected");
}
}
}
You can then serialize the data being sent in some sort of json so as to send multiple fields of data comfortably for example :
{
"data type": "score",
"source_id": "client_unique_id",
"data": "200"
}
On your displaying side,just get the values of (in our example case source_id and data) and display on a label

How can i store pushy tokens to database

am using pushy for push notifications but am not able to store the device token in the database.
private class RegisterForPushNotificationsAsync extends AsyncTask<Void, Void, Exception> {
protected Exception doInBackground(Void... params) {
try {
// Assign a unique token to this device
String deviceToken = Pushy.register(getApplicationContext());
// Log it for debugging purposes
Log.d("MyApp", "Pushy device token: " + deviceToken);
// Send the token to your backend server via an HTTP GET request
new URL("https://key}/register/device?token=" + deviceToken).openConnection();
} catch (Exception exc) {
// Return exc to onPostExecute
return exc;
}
// Success
return null;
}
#Override
protected void onPostExecute(Exception exc) {
// Failed?
if (exc != null) {
// Show error as toast message
Toast.makeText(getApplicationContext(), exc.toString(), Toast.LENGTH_LONG).show();
return;
}
// Succeeded, optionally do something to alert the user
}
}
I am using retrofit for the http requests and am not using any kind of backend system
What you're doing is well enough to get you a Device Token from Pushy service.
If you want to capture the returned device token and make it accessible to the AsyncTask class and the enclosing class in general (as you stated in the comments), then you can declare a global/instance String variable, say pushy_device_token, in the enclosing class.
Then in doInBackground() method of the AsyncTask, go ahead and assign the global variable as follows:
pushy_device_token = Pushy.register(getApplicationContext());
Complete code:
public class EnclosingClass {
String pushy_device_token;
// Additional class code
private class RegisterForPushNotificationsAsync extends AsyncTask<Void, Void, Exception> {
#Override
protected Exception doInBackground(Void... params) {
try {
// Assign a unique token to this device
pushy_device_token = Pushy.register(getApplicationContext());
// Log it for debugging purposes
Log.d("MyApp", "Pushy device token: " + deviceToken);
// Send the token to your backend server via an HTTP GET request
new URL("https://key}/register/device?token=" + deviceToken).openConnection();
} catch (Exception exc) {
// Return exc to onPostExecute
return exc;
}
// Success
return null;
}
#Override
protected void onPostExecute(Exception exc) {
// Failed?
if (exc != null) {
// Show error as toast message
Toast.makeText(getApplicationContext(), exc.toString(), Toast.LENGTH_LONG).show();
return;
}
// Succeeded, optionally do something to alert the user
}
}
}
Best practice recommendation:
It's best to have the result of processing in doInBackground(), returned in the onPostExecute() method, especially if you're going to do some UI work. So from onPostExecute(), you can do anything you want with the result, e.g. display to the user, report an error, etc.
To do this, you'll have to modify your doInBackground() method to return something as generic as Object. And so onPostExecute() will take in an Object as a parameter variable.
You'll modify by:
private class RegisterForPushNotificationsAsync extends AsyncTask<Void, Void, Object> { . . .
From this, you can check if the Object taken in by onPostExecute() is of type Exception, in which case, you'll display an error notification, or check if it's of type String, in which case you'll have the device token which you can then proceed to save in your DB (Firebase, SQLite, etc.).

Retrofit2 - Unable to create string from non-null response body

I'm attempting to make an API call then use it's response as a string. Thus far I am able to successfully get and log the response... however the string I'm attempting to create using the response is empty and I'm unsure why this might be happening.
Any suggestions are appreciated:
api.getUser().enqueue(new API.SimpleCallback<ResponseBody>() {
#Override
public void onResponse(ResponseBody data) {
try {
Log.d("RAW BODY", data.string());
final SharedPreferences.Editor editor = App.sharedPrefs.edit();
String responseString = data.string().toString();
editor.putString(NOTIFICATION_PREFERENCES_ENABLED_STATUS,responseString);
editor.apply();
} catch (IOException e) {
e.printStackTrace();
}
}
});
The response body can be consumed only once. https://square.github.io/okhttp/3.x/okhttp/okhttp3/ResponseBody.html
In your code, you are attempting to consume the body multiple times. (once when you log it, and another time when you try to put it in the shared preferences).
Instead do something like:
#Override
public void onResponse(ResponseBody responseBody) {
String data = responseBody.string();
Log.d("RAW_DATA", data);
sharedPreferences.edit().putString(myKey, data);
}

Fetch JSON Data from URL and Repeatedly Update SQLite Database

In my app, I create a SQLite database. Then I populate it with JSON data fetched from a URL using an instance of the HttpAsyncTask class in my main activity. That works fine, but I also want to update the database. New data (one row in the database) is added to the URL page once per day, and I want to implement a "synchronize" button in the app that updates the database with only the new information. Could I get some advice on how to do this? My HttpAsyncTask is below, if that helps - I'm thinking I might need an if/else clause in the onPostExecute() method that adds all the rows only if the database is getting created for the first time. I thought about trying to put an HttpAsyncTask class in my DatabaseHelper, but that doesn't really make sense.
private class HttpAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String...urls) {
return GET(urls[0]);
}
#Override
protected void onPostExecute(String result) {
try {
JSONObject main = new JSONObject(result);
JSONObject body = main.getJSONObject("body");
JSONArray measuregrps = body.getJSONArray("measuregrps");
// get measurements for date, unit, and value (weight)
for (int i = 0; i < measuregrps.length(); i++) {
JSONObject row = measuregrps.getJSONObject(i);
// a lot of getting & parsing data happens
db.addEntry(new Entry(date, weight, null, null));
//adds all the lines every time this is run, but I only want to add all
//the lines once and then add new rows one by one from there
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
public static String GET(String url) {
InputStream is = null;
String result = "";
try {
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
HttpResponse httpResponse = client.execute(get);
is = httpResponse.getEntity().getContent();
if (is != null)
result = convertInputStream(is);
else
result = "Did not work!";
} catch (Exception e) {
Log.d("input stream", e.getLocalizedMessage());
}
return result;
}
private static String convertInputStream(InputStream is) throws IOException {
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = "";
while((line = reader.readLine()) != null)
builder.append(line);
is.close();
return builder.toString();
}
Your implementation totally depends on the project requirements.
If there are continuously changes over the server, the right way to implement the synchronization process is:
1.
Implement the sync process, which works totally in background. This sync will be customized to call specific API calls/Service classes which will be required to sync.
2.
Server will prompt the mobile client for the data change.
3.
To get server updates, A continuously running service/Sync at some predefined intervals will be run and checks for the updates or implements the GCM.
Sync Adapter would be the best for the sync services.
Ohh, also don't forget to apply the content provider, as database calls would be concurrent from UI and background both.
Hope it may help to decide.
You have to check there is similar data available in the table if yes update the table and if no insert new data to table

Phonegap jabber plugin for android

For jabber support i use library Smack. Android port asmack.
I have class SmackAPI which implements MessageListener interface and contains methods to connect, login, send message. In the same time this class contains method:
#Override
public void processMessage(Chat chat, Message message) {
String from = message.getFrom();
String body = message.getBody();
System.out.println(String.format("Received message '%1$s' from %2$s", body, from));
this.recievedMessage = message;
}
It provides by MessageListener interface. All new messages processed by this method.
I write jabber plugin to connect, login, send message from phonegap.
My question: how i can in javascript listen for new messages?
I did it. I dont know however it is right way, but it works!
Cordova plugin class:
public class SmackJabber extends CordovaPlugin {
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
this.cbContext = callbackContext;
switch (action) {
case LISTEN_MESSAGE:
res = new PluginResult(PluginResult.Status.NO_RESULT);
res.setKeepCallback(true);
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
String callbackId = cbContext.getCallbackId();
while (true) {
String msg = getMsg();
if (msg != null) {
res = new PluginResult(PluginResult.Status.OK, msg);
res.setKeepCallback(true);
CallbackContext cb = new CallbackContext(callbackId, webView);
cb.sendPluginResult(res);
}
}
}
});
cbContext.sendPluginResult(res);
break;
And easy javascript. Just call plugin method:
window.plugins.smackJabber.listenMessage(function(result) {
alert(result)
}, function(error) {
alert(error)
}
);
Explanation:
I call plugin method "listenMessage" (calling "execute" method with action "LISTEN_MESSAGE"). There i start thread from cordova threadpool with runnable, in runnable i got recursive function which check message. But before start runnable i have to take callbackId of method who call method execute. Also, for exit from method, i create new PluginResult with status "NO_RESULT" and set it option "keepCallback" to true - it means, that method calls in javascript awaiting one more callback result from me. When i got message, i create new callbackcontext based on callbackid and my webview, do setKeepCallback to true for futher possible responses for pluginresult, putting in pluginresult my message with status "OK" and sending it to callbackcontext. That's all.

Categories