Bluetooth Client-Server Example in Android - java

I am making a simple client-server application which can be used to transfer integers, strings or characters.
My application compiled successfully, but no client-server connection is there.
When I try to search for a server, it gives the NullPointerException on the line
bluetooth.startDiscovery();
However, when I start the server it gives no exception.
Also, when I start a server on one device and look for a server on another, a connection is not established either due to a problem in server running correctly or a problem in the client.
I have already got an instance of BluetoothAdapter using
bluetooth = BluetoothAdapter.getDefaultAdapter();
I think that probably a null pointer is given because i am calling the method startDiscovery() inside an onclickListener, this one,
private void setupSearchButton() {
Button searchButton = (Button) findViewById(R.id.button_search);
searchButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
registerReceiver(discoveryResult, new IntentFilter(BluetoothDevice.ACTION_FOUND));
if (!bluetooth.isDiscovering()) {
try { foundDevices.clear();
bluetooth.startDiscovery(); } catch(Exception e)
{
Context c = getApplicationContext();
Toast.makeText(c, e.toString(),Toast.LENGTH_LONG).show();
}
}
}
});
}
The code for declaring a server is posted here :
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == DISCOVERY_REQUEST) {
boolean isDiscoverable = resultCode > 0;
if (isDiscoverable) {
String name = "bluetoothserver";
try {
final BluetoothServerSocket btserver = bluetooth.listenUsingRfcommWithServiceRecord(name, uuid);
AsyncTask<Integer, Void, BluetoothSocket> acceptThread = new AsyncTask<Integer, Void, BluetoothSocket>() {
#Override
protected BluetoothSocket doInBackground(Integer... params) {
try {
socket = btserver.accept(params[0] * 1000);
return socket;
} catch (Exception e) {
Log.d("BLUETOOTH SERVER EXCEPTION : ", e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(BluetoothSocket result) {
if (result != null) {
switchUI();
}
}
};
acceptThread.execute(resultCode);
} catch (IOException e) {
Log.d("BLUETOOTH", e.getMessage());
}
}
}
}
Can someone tell me what is the problem ? I am using two buttons, one to start a bluetooth server and other to search for a bluetooth server. The method that runs on clicking the start bluetooth server button triggers startActivityForResult, as a result of which the method onActivityResult is executed as shown here. The OnClickListener for search server button is already shown here.

Related

Send string from thread bluetooth service to textView in main activity

I want to send value from string (distance to obstacle) to my TextView in main activity.
I tried to use Handler, but still not working (crash) or receive nothing.
A part code which receive data from HC-05 (screen where you see in debug value assignet to variable)
enter image description here
#Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while(true){
try {
bytes = inputStream.read(buffer);
final String comingMsg = new String(buffer,0,bytes);
Log.d(TAG,"InputStream: " + comingMsg);
/*mHandler2.post(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.obj = comingMsg;
mHandler2.sendMessage(message);
}
});*/
}catch (IOException e){
Log.e(TAG,"Write: Error reading input." + e.getMessage());
active=false;
break;
}
}
}
Here It's parts of code from MainActivity where I tried put something to get values from service.
[I add, that for this moment i want to see something values from bluetooth in textView. Later I want to create parse string and send custom text to custom TextView - example: FL: (Front Left)- to one textView, FR: (Front Right) - to second textView]
There is method implementThreads(), because I wanted to do 6 Threads to 6 TextView which every time is refreshing value from string in Services (there I tried get value from Bluetooth Service)
Log.d(TAG,"Check intent - result");
if(getIntent().getIntExtra("result",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded device");
myBluetoothService = new MyBluetoothService(getApplicationContext());
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service");
checkIfActive();
}
Log.d(TAG,"Check intent - connect_to_paired");
if(getIntent().getIntExtra("connect_to_paired",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded_paired_device");
myBluetoothService = new MyBluetoothService(getApplicationContext());
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service");
checkIfActive();
}
}
#Override
public void onStart(){
super.onStart();
myBluetoothService = new MyBluetoothService(getApplicationContext());
}
public void checkIfActive(){
Log.d(TAG,"CheckIfActive: Started");
if(myBluetoothService.active){
Log.d(TAG,"CheckIfActive: Running method implementThreads()");
implementThreads();
}
}
public void implementThreads(){
Log.d(TAG,"ImplementThreads: Started");
Thread thread = new Thread(){
#Override
public void run() {
try{
sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
};
thread.start();
}
public void startConnection(BluetoothDevice device,UUID uuid){
Log.d(TAG,"StartConnection: Initializing connection");
myBluetoothService.startClient(device,uuid);
}
Thanks all for help, because It's very important for me !
Use this to interect with UI Thread for operations like updating textviews etc.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//YOUR CODE HERE
Message message = new Message();
message.obj = comingMsg;
mHandler2.sendMessage(message);
}
});

Android Service only runs whilst debugging

Background
I am creating a service that syncs a local Realm database (stored on phone) with an online database. The database stores users and measurements.
I initialise the service by calling 'startService(new Intent(this, SyncService.class));' during the splash activity's onCreate() method, and specify in the manifest that the service should run for the length of the application.
The service has a broadcast receiver. When the receiver detects a network change from 'not connected' to 'connected', it fires a method called syncDatabases().
This method finds all measurements recorded locally after the timestamp of the last API callback, and sends them to the database. The API responds to a request by returning the object + a unique ID.
When a measurement is made whilst the device is offline, it is stored locally. When an internet connection is made, the syncDatabases() method should be called in order to update the online server with the local measurements.
My steps...
Steps when debugging the project:
With wifi I open the app and with an external device make a new measurement. This appears on both the app and in the database. I then turn wifi off and make another measurement - this appears on the device.
I attach the debugger.
I turn back on wifi and this triggers the services' receivers' onReceive() method. I step through this and it all works according to plan. I reach the syncDatabases() method, and from there I receive the callback from the API, and it then updates the Realm database with the new ID value.
The problem...
If I don't attach the debugger, nothing happens. The new measurements aren't pushed to the database, and none of my Log.e calls are printed.
Why is this happening? And is there an alternative solution / fix for this problem?
Code
Service class
public class SyncService extends Service {
private static final String TAG = "SYNCSERVICE";
private boolean mConnected = false;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getExtras() != null) {
final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
if (netInfo != null) {
switch (netInfo.getState()) {
case CONNECTED:
if (!mConnected) {
Log.e("NETWORK", "Network " + netInfo.getTypeName() + " now connected");
syncDatabases();
mConnected = true;
}
break;
default:
mConnected = false;
break;
}
} else mConnected = false;
}
}
};
#Override
public void onCreate() {
super.onCreate();
initReceiver();
ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager.getActiveNetworkInfo() != null) {
mConnected = true;
}
android.util.Log.e(TAG, "onCreate: SyncService created");
}
#Override
public void onDestroy() {
super.onDestroy();
unInitReceiver();
android.util.Log.e(TAG, "onDestroy: SyncService destroyed");
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
android.util.Log.e(TAG, "onBind: SyncService bound");
return null;
}
#Override
public boolean onUnbind(Intent intent) {
android.util.Log.e(TAG, "onUnbind: SyncService unbound");
return super.onUnbind(intent);
}
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
android.util.Log.e(TAG, "onRebind: SyncService rebound");
}
private void initReceiver() {
IntentFilter filters = new IntentFilter();
filters.addAction("android.net.wifi.WIFI_STATE_CHANGED");
filters.addAction("android.net.wifi.STATE_CHANGE");
registerReceiver(mReceiver, filters);
}
private void unInitReceiver() {
unregisterReceiver(mReceiver);
}
public void syncDatabases() {
RealmResults<UserDB> users = RealmDB.getInstance(getApplicationContext()).where(UserDB.class).findAll();
if (users.size() > 0) {
int userId = users.get(0).getmUserID();
Log.e("MESSAGE", PreferenceUtils.getInstance().getLastSyncDate());
Date lastSync = null;
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.getDefault());
try {
lastSync = sdf.parse(PreferenceUtils.getInstance().getLastSyncDate());
}
catch (ParseException e) {
e.printStackTrace();
try {
lastSync = BaseFragment.FORMAT.parse(PreferenceUtils.getInstance().getLastSyncDate());
}
catch (ParseException e1) {
e1.printStackTrace();
}
}
if (lastSync != null) {
Date lastSyncOffset = new Date(lastSync.getTime() + 1000);
/** Get all local results which have been made after the last sync date
 **/
RealmResults<MeasurementDB> newLocalMeasurements = RealmDB.getInstance(getApplicationContext())
.where(MeasurementDB.class).equalTo("user_ID", userId)
.greaterThan("dateCreated", lastSyncOffset)
.findAll();
/** For each measurement made after the last sync, add it to the server
 **/
for (MeasurementDB measurement : newLocalMeasurements) {
TemperatureListener mListener = new TemperatureListener(measurement);
ApiRequest.getInstance(getApplicationContext()).registerNewMeasurement(measurement.getAverage(),
measurement.getDateCreated().toString(), mListener, mListener);
}
}
}
}
/**
* Temperature listener receives the local copy of the temperature item. onResponse can then
* directly mutate the object instead of searching local db
*/
private class TemperatureListener implements Response.Listener<Measurement>, Response.ErrorListener {
private MeasurementDB measurement;
public TemperatureListener(MeasurementDB measurement) {
this.measurement = measurement;
}
#Override
public void onErrorResponse(VolleyError error) {
Log.e("OnResponse", "Failure");
}
#Override
public void onResponse(Measurement response) {
Log.e("OnResponse", "Success");
/** Update our local measurement's ID value (supplied by server)
 **/
RealmDB.getInstance(getApplicationContext()).beginTransaction();
measurement.setMeasurement_ID(response.getmMeasurementId());
RealmDB.getInstance(getApplicationContext()).commitTransaction();
/** Update the last sync date
 **/
PreferenceUtils.getInstance().setLastSyncDate(response.getmDateCreated());
}
}
}
Initialisation of Service in splash activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mTimedOut = true;
finishActivity();
}
}, DURATION);
/** Will sync application / cloud databases in background of app when network connected. **/
startService(new Intent(this, SyncService.class));
doApiWork();
}
Manifest entry
Stop with task to kill the service at the same time as the app.
Exported 'false' stops other apps from using the service.
<service
android:name=".network.SyncService"
android:stopWithTask="true"
android:enabled="true"
android:exported="false"/>
EDIT
I removed the service and left a receiver class, registered in the manifest, which triggers methods on another class when needed. However the receiver is only triggered in debug mode.

how to debug boot receiver?

I have the following Reciever and I get an app crash on device boot.
Since it happens on boot I cannot attach the debug via eclipse nor see anything in the logcat.
How would you suggest for me to see the error causing the crash?
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent intent) {
// TODO Auto-generated method stub
if (intent != null) {
String action = intent.getAction();
if (action != null) {
if (action.equalsIgnoreCase(Intent.ACTION_BOOT_COMPLETED)) {
// GeoPushService geoPs = new GeoPushService();
ZoomerLocationService locService = new ZoomerLocationService();
locService.startService(new Intent());
// Log.d("receiver","action is: boot");
}
}
}
}
}
I have tried adding this try-catch
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent intent) {
// TODO Auto-generated method stub
if (intent != null) {
String action = intent.getAction();
try {
if (action != null) {
if (action.equalsIgnoreCase(Intent.ACTION_BOOT_COMPLETED)) {
// GeoPushService geoPs = new GeoPushService();
ZoomerLocationService locService = new ZoomerLocationService();
locService.startService(new Intent());
// Log.d("receiver","action is: boot");
}
}
} catch (Exception ex) {
Log.e(MyLogger.TAG, ex.getStackTrace().toString());
}
}
}
}
but it didn't help
I have tried to send BOOT_COMPLETE intent and i got permissions denial
You might be able to use ADB in a command line to record the logcat when your device is booting up.
http://developer.android.com/tools/help/logcat.html
http://www.herongyang.com/Android/Debug-adb-logcat-Command-Option-Log-Buffer.html
Make sure to increase the amount of data the command window can display or else use the options to save the log to a file.
Using this method you might be able to see the crash in the log on startup.
EDIT: I have tried this and it is possible, this should work for you

How to get the Incoming number from twilio third party API

I had done lot of R&D on getting the incoming number when calling is done from the Twilio number to the other Twilio number in the app using Twilio as a third party integration.
But i do not get anything regarding that incoming number, I got the call from the other Twilio number, device is listening to the incoming call, but could not able to identify the incoming number, for that I am using this method connectionCall.IncomingParameterFromKey, it only return me "From".
Below is the code for receiving the call in the app using Twilio integration.
public class Call_Answer extends Activity implements OnClickListener{
String sub_sid="",sub_auth_token="",call_from="";
SharedPreferences sharedPref;
SharedPreferences.Editor prefEdit;
TextView callanswer_btn,callreject_btn;
private Connection connectionCall;
IncomingCall phone;
private Device device;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Method onCreate created by vk hooda on Oct 30, 2012
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.callanswer);
sharedPrefValues();
initializeView();
}
private void sharedPrefValues() {
// Method sharedPrefValues created by vk hooda on Oct 31, 2012
sharedPref=PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
prefEdit=sharedPref.edit();
sub_sid=sharedPref.getString(Constant_Variables.using_sub_sid,"");
sub_auth_token=sharedPref.getString(Constant_Variables.using_sub_auth_token,"");
call_from=sharedPref.getString(Constant_Variables.using_phone_number, "");
//Initialize Calls
phone=new IncomingCall(sub_sid,sub_auth_token,call_from,getApplicationContext());
//phone=new IncomingCall(Constants.account_SID,Constants.account_Token,Constants.karl_number,getApplicationContext());
}
private void initializeView() {
// Method initializeView created by vk hooda on Oct 30, 2012
callanswer_btn=(TextView)findViewById(R.id.callanswer_btn);
callreject_btn=(TextView)findViewById(R.id.callreject_btn);
callanswer_btn.setOnClickListener(this);
callreject_btn.setOnClickListener(this);
}
#Override
public void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
setIntent(intent);
}
#Override
public void onResume()
{
super.onResume();
Intent intent = getIntent();
Device device = intent.getParcelableExtra(Device.EXTRA_DEVICE);
Connection connection = intent.getParcelableExtra(Device.EXTRA_CONNECTION);
if (device != null && connection != null) {
intent.removeExtra(Device.EXTRA_DEVICE);
intent.removeExtra(Device.EXTRA_CONNECTION);
handleIncomingConnection(device, connection);
// ringingPhone(intent);
}
}
public void handleIncomingConnection(Device inDevice, Connection inConnection)
{
Log.i("Handle incoming call", "Device received incoming connection");
connectionCall=inConnection;
device=inDevice;
if (connectionCall != null)
{
connectionCall.disconnect();
connectionCall = inConnection;
// connectionCall.reject();
Log.i("Blocktimer.blocking_call",""+Blocktimer.blocking_call);
if(Blocktimer.blocking_call == true)
{
connectionCall.reject();
Blocktimer.blocking_call = false;
}
Log.i("connectionIIIIII",""+ connectionCall.IncomingParameterAccountSIDKey);
Log.i("connectionIIIIII",""+ connectionCall.IncomingParameterAPIVersionKey);
Log.i("connectionIIIIII",""+ connectionCall.IncomingParameterCallSIDKey);
Log.i("connectionIIIIII",""+ connectionCall.IncomingParameterFromKey);
Log.i("connectionIIIIII",""+ connectionCall.IncomingParameterToKey);
Log.i("connectionIIIIII",""+ connectionCall.hashCode());
Log.i("connectionIIIIII",""+ connectionCall.CONTENTS_FILE_DESCRIPTOR);
Log.i("connectionIIIIII",""+ connectionCall.PARCELABLE_WRITE_RETURN_VALUE);
Log.i("connectionIIIIII",""+ connectionCall.getState());
Log.i("connectionIIIIII",""+ connectionCall.isIncoming());
Log.i("connectionIIIIII",""+ connectionCall.isMuted());
Log.v("Handling Incoming Call","Someone calling you.you have accepted it here.");
}
}
public void onClick(View v) {
// Method onClick created by vk hooda on Oct 30, 2012
if(v==callanswer_btn)
{
if (connectionCall != null)
{
connectionCall.accept();
Log.i("connectionaccept",""+ connectionCall.getState());
Log.v("calling answer","Conversation start.....");
}
}
if(v==callreject_btn)
{
//connectionCall.disconnect();
Log.v("calling disconnect","Conversation disconnect.....");
if (connectionCall != null)
{
connectionCall.disconnect();
Log.i("connectionReject",""+ connectionCall.getState());
connectionCall=null;
Log.v("Disconnect","Disconnecting in finalize method");
}
if (device != null)
{
Log.v("Disconnect","Release in finalize method");
device.release();
device=null;
}
finish();
}
}
}
I had also faced the same problem and I rectified by using this code
connection.IncomingParameterFromKey will returns you the parameter name only you need to pass that name to connection parameters.
code :
connection.getParameters().get(connection.IncomingParameterFromKey).replace("%2B", "");

Android Thread and class behavior question

The project i am working on needs this type of behavior. The user will be presented with a UI that will give them the option to connect and disconnect to a server. I would also like this UI to show the status of the connection, 'connected or disconnected'. Whenever the user clicks connect, the application will start a thread that handles the connection to the server. The user will still be looking at the main UI. When they start that connection and while the connection remains, i would like the status of the connection to be 'connected'. If the connection is ever broken at any point i would like it to display disconnected. Listed below is what i have so far.
My question is... Am i doing the threading right? So that the phone will not be crushed by the server connection while it is connected?
Also, how do i get the main UI to reflect the connection status of the server and display when the connection is broken?
Thanks in advance! If you have any further questions, please let me know.
The server connection thread.
public class ConnectDevice implements Runnable {
private boolean connected;
private ObjectInputStream ois;
public void run() {
try {
InetAddress host = InetAddress.getByName("192.168.234.1");
Socket socket = new Socket(host.getHostName(), 7777);
connected = true;
while (connected) {
try {
ois = new ObjectInputStream(socket.getInputStream());
String message = (String) ois.readObject();
System.out.println("Message: " + message);
}
catch (Exception e) {
e.printStackTrace();
}
}
ois.close();
} catch (UnknownHostException e) {
e.printStackTrace();
connected = false;
} catch (IOException e) {
e.printStackTrace();
connected = false;
} /*catch (ClassNotFoundException e) {
e.printStackTrace();
connected = false;
}*/
}
}
The main UI and main class.
public class SmartApp extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.intro);
final Button firstTimeButton = (Button) findViewById(R.id.firstTimeButton);
firstTimeButton.setOnClickListener(
new View.OnClickListener()
{
#Override
public void onClick(View v)
{
// TODO Auto-generated method stub
Intent userCreationIntent = new Intent(v.getContext(), UserCreation.class);
startActivityForResult(userCreationIntent, 0);
}
});
final Button connectDeviceButton = (Button) findViewById(R.id.connectDeviceButton);
connectDeviceButton.setOnClickListener(
new View.OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//Intent connectDeviceIntent = new Intent(v.getContext(), ConnectDevice.class);
//startActivityForResult(connectDeviceIntent, 0);
Thread cThread = new Thread(new ConnectDevice());
cThread.start();
}
});
}
}
Android has a UI thread, which is the only thread that is allowed to update UI elements.
You need to have a background thread doing the work, and posting back to the UI thread when its done.
AsyncTask is an Android class designed to do just that.
Once your worker thread ends its work, and will update the UI element taken by findViewById, it will automatically change on the screen without you having to do anything else.
Check out the AsyncTask, it's tailor made for this sort of thing.

Categories

Resources