BLE connected with Lollipop but not connected with Nougat - android

I'm new in android develop and I'm developing an app that transmit/receive data to a BLE module via Uart service.
With smartphone android 5.x.x the app works fine, it connects with the hardware and receive/transmit data.
With smartphone android 7.x.x the app doesn't connects.
Below you can see a snippet of MainActivity.java:
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final Intent mIntent = intent;
//*********************//
if (action.equals(UartService.ACTION_GATT_CONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "HW_CONNECT_MSG");
DisconnectButton.setEnabled(true);
DeviceInfo.setText("Device Information:");
DeviceName.setText(mDevice.getName() + " - Connected");
mState = UART_PROFILE_CONNECTED;
isConnected = true;
if(isConnected) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x43; // 'C';
Connectcmd[3] = (byte) 0x54; // 'T'
Connectcmd[4] = (byte) ETX;
try {
//send data to UART service
SendData(Connectcmd);
sleep(500); // wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
else
{
isConnected = false;
}
}
});
}
It's seem that when SendData, the GATT operation is not yet finished. Smartphone show the message "Device doesn't support UART over BLE. Disconnecting..." due to action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART).
If I delete the if(isConnected)...else... statement also smartphone with android 7.x.x will connects.
My question is what's happen and how can I resolve this issue?
My goal is to send a command to hardware via BLE so when the mcu is connected, a buzzer make a sound.
Thanks for help….
EDIT
Below you can find the whole MainActivity:
public class MainActivity extends Activity implements RadioGroup.OnCheckedChangeListener {
public static final String TAG = "DEBUG ";
public static final String DEV_NAME_FILTER = "";
private static final int REQUEST_SELECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static final int UART_PROFILE_READY = 10;
private static final int UART_PROFILE_CONNECTED = 20;
public static final int UART_PROFILE_DISCONNECTED = 21;
private static final int STATE_OFF = 10;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
TextView mRemoteRssiVal;
RadioGroup mRg;
private int mState = UART_PROFILE_DISCONNECTED;
private static UartService mService = null;
private static BluetoothDevice mDevice = null;
private BluetoothAdapter mBtAdapter = null;
private ListView messageListView;
private ArrayAdapter<String> listAdapter;
private Button SelectButton, DisconnectButton;
private EditText edtMessage;
private static Context context;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
private static TextView DeviceInfo;
private static TextView DeviceName;
private static TextView Manufacturer;
public static boolean isConnected;
public static boolean isSetting;
public static boolean isReading;
public static boolean isManual;
public static boolean isFunctional;
public static boolean isBootloader;
public static byte[] SettingValues;
public static byte[] ReadingValues;
public static byte[] ManualValues;
public static byte[] FunctionalValues;
private static byte[] Connectcmd = new byte[5];
public static int STX = 0x3E; // '>'
public static int ETX = 0x23; // '#'
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DeviceInfo = (TextView) findViewById(R.id.deviceInfo);
DeviceName = (TextView) findViewById(R.id.deviceName);
Manufacturer= (TextView) findViewById(R.id.manufacturer);
isConnected = false;
isSetting = false;
isReading = false;
isManual = false;
isFunctional = false;
isBootloader = false;
context = this;
//Enable location
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android M Permission check
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect beacons.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
#TargetApi(Build.VERSION_CODES.M)
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}
}
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBtAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
SelectButton = (Button) findViewById(R.id.button);
DisconnectButton = (Button) findViewById(R.id.disconnect);
DisconnectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x44; // 'D';
Connectcmd[3] = (byte) 0x43; // 'C'
Connectcmd[4] = (byte) ETX;
try {
//send data to Banner service
SendData(Connectcmd);
sleep(500); // Wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
MainActivity.disconnected();
setContentView(R.layout.activity_main);
finish();
} catch (Exception e) {
Log.e(TAG, "Disconnect error");
}
}
});
// Handle Select device button
SelectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onClick - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} else {
if (SelectButton.getText().equals("SELECT CELU")) {
//Connect button pressed, open DeviceListActivity class, with popup windows that scan for devices
Log.i(TAG, "Push button CONNECT");
Intent newIntent = new Intent(context, DeviceListActivity.class);
((Activity) context).startActivityForResult(newIntent, MainActivity.REQUEST_SELECT_DEVICE);
} else {
//Disconnect button pressed
disconnected();
}
}
}
});
// Set initial UI state
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
//UART service connected/disconnected
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder rawBinder) {
mService = ((UartService.LocalBinder) rawBinder).getService();
Log.d(TAG, "onServiceConnected mService= " + mService);
if (!mService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
}
public void onServiceDisconnected(ComponentName classname) {
//// mService.disconnect(mDevice);
mService = null;
}
};
private Handler mHandler = new Handler() {
#Override
//Handler events that received from UART service
public void handleMessage(Message msg) {
}
};
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final Intent mIntent = intent;
//*********************//
if (action.equals(UartService.ACTION_GATT_CONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
String currentDateTimeString = DateFormat.getTimeInstance().format(new Date());
Log.d(TAG, "CELU_CONNECT_MSG");
//btnConnectDisconnect.setText("Disconnect");
//edtMessage.setEnabled(true);
DisconnectButton.setEnabled(true);
DeviceInfo.setText("Device Information:");
DeviceName.setText(mDevice.getName() + " - Connected");
mState = UART_PROFILE_CONNECTED;
isConnected = true;
//IF COMMENTED THE APP CONNECTS!!!!!!!!!!!!!!!!!!
//ELSE IF NOT COMMENTED THE APP NEVER CONNECTS
/*if(isConnected) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x43; // 'C';
Connectcmd[3] = (byte) 0x54; // 'T'
Connectcmd[4] = (byte) ETX;
try {
//send data to UART service
SendData(Connectcmd);
sleep(500); // Wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
else
{
isConnected = false;
}*/
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
});
}
//*********************//
if (action.equals(UartService.ACTION_GATT_DISCONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "HW_DISCONNECT_MSG");
DisconnectButton.setEnabled(false);
DeviceName.setText("Not Connected");
mState = UART_PROFILE_DISCONNECTED;
mService.close();
//setUiState();
}
});
}
//Enable notifivcation on UART service//
if (action.equals(UartService.ACTION_GATT_SERVICES_DISCOVERED)) {
mService.enableTXNotification();
}
//*********************//
if (action.equals(UartService.ACTION_DATA_AVAILABLE)) {
final byte[] txValue = intent.getByteArrayExtra(UartService.EXTRA_DATA);
try {
ParsingPacket(txValue);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
//*********************//
if (action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART)) {
showMessage("Device doesn't support UART over BLE Celu . Disconnecting");
mService.disconnect();
}
}
};
private static void ParsingPacket(byte[] packet) throws Exception {
if (packet.length == 0) {
// received empty packet
isConnected = false;
isSetting = false;
isReading = false;
isManual = false;
isFunctional = false;
isBootloader = false;
}
if(isSetting){
isSetting = false;
SettingValues = packet.clone();
String text = new String(SettingValues, "UTF-8");
Log.d(TAG, text);
}
if(isReading){
ReadingValues= packet;
ReadActivity.updateMeasure(ReadingValues);
//ReadActivity.addData(packet);
//String text = new String(ReadingValues, "UTF-8");
Log.d("Length ", String.format("%02d", (int) ReadingValues.length));
for(int i=0; i<ReadingValues.length; i++) {
String text = String.format("%02x", (int) ReadingValues[i]);
Log.d(TAG, text);
}
}
if(isManual){
isManual = false;
ManualValues = packet.clone();
String text = new String(ManualValues, "UTF-8");
Log.d(TAG, text);
}
if(isFunctional){
isFunctional = false;
FunctionalValues = packet.clone();
String text = new String(FunctionalValues, "UTF-8");
Log.d(TAG, text);
}
if(isBootloader){
isBootloader = false;
// do samething
}
}
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
if(DeviceName.getText()!="Not Connected") {
Intent connectedIntent = new Intent(getApplicationContext(), MenuActivity.class); //new Intent("com.antertech.mybleapplication.MenuActivity");
startActivity(connectedIntent);
}
}
};
private void service_init() {
Intent bindIntent = new Intent(this, UartService.class);
bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
LocalBroadcastManager.getInstance(this).registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter());
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(UartService.ACTION_GATT_CONNECTED);
intentFilter.addAction(UartService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(UartService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(UartService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART);
return intentFilter;
}
#Override
public void onStart() {
super.onStart();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.connect();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.start(client, getIndexApiAction());
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(UARTStatusChangeReceiver);
} catch (Exception ignore) {
Log.e(TAG, ignore.toString());
}
unbindService(mServiceConnection);
mService.stopSelf();
mService = null;
}
#Override
protected void onStop() {
Log.d(TAG, "onStop");
super.onStop();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.end(client, getIndexApiAction());
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.disconnect();
}
#Override
protected void onPause() {
Log.d(TAG, "onPause");
super.onPause();
}
#Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "onRestart");
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume");
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onResume - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_SELECT_DEVICE:
//When the DeviceListActivity return, with the selected device address
if (resultCode == Activity.RESULT_OK && data != null) {
String deviceAddress = data.getStringExtra(BluetoothDevice.EXTRA_DEVICE);
mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceAddress);
Log.d(TAG, "... onActivityResultdevice.address==" + mDevice + " mserviceValue " + mService);
mService.connect(deviceAddress);
//setContentView(R.layout.activity_setting);
((TextView) findViewById(R.id.deviceName)).setText(mDevice.getName() + " - Connecting...");
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(this, "Bluetooth has turned on ", Toast.LENGTH_SHORT).show();
} else {
// User did not enable Bluetooth or an error occurred
Log.d(TAG, "BT not enabled");
Toast.makeText(this, "Problem in BT Turning ON ", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
Log.e(TAG, "wrong request code");
break;
}
}
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
}
public static void SendData(byte[] text) {
mService.writeRXCharacteristic(text);
Log.i(TAG, "Message send to Target");
}
public static void disconnected() {
if (mDevice != null) {
mService.disconnect();
Log.i(TAG, "Push Button DISCONNECT");
}
}
private void showMessage(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
#Override
public void onBackPressed() {
if (mState == UART_PROFILE_CONNECTED) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
showMessage("CELU TPE running in background.\n Disconnect to exit");
} else {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.popup_title)
.setMessage(R.string.popup_message)
.setPositiveButton(R.string.popup_yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setNegativeButton(R.string.popup_no, null)
.show();
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[],
int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
public Action getIndexApiAction() {
Thing object = new Thing.Builder()
.setName("Main Page") // TODO: Define a title for the content shown.
// TODO: Make sure this auto-generated URL is correct.
.setUrl(Uri.parse("http://[ENTER-YOUR-URL-HERE]"))
.build();
return new Action.Builder(Action.TYPE_VIEW)
.setObject(object)
.setActionStatus(Action.STATUS_TYPE_COMPLETED)
.build();
}
}

Related

Android Studio Bluetooth ListView

I wanted to make bluetooth applications for arduino so that I could connect to the HC-05 module. And I found a tutorial on how to make a bluetooth connection (http://mcuhq.com/27/simple-android-bluetooth-application-with-arduino-example) When I downloaded the code from github, the application starts and everything works and connects. But the problem is that I can't open a new activity because the project is probably for 15 API and the new activity needs at least 16 so I decided to make such an application on my own based on the code from this website. And here I have a problem because when I make my phone search for bluetooth devices, nothing is displayed on my ListView.
This is my code `
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
offon = findViewById(R.id.BtBtn);
TV = findViewById(R.id.BtTv);
TV2 = findViewById(R.id.textView2);
TV3 = findViewById(R.id.bluetooth_status);
Next = findViewById(R.id.button2);
LV = findViewById(R.id.ListView);
disc = findViewById(R.id.button3);
ArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
adapter = BluetoothAdapter.getDefaultAdapter();
LV.setAdapter(ArrayAdapter);
LV.setOnItemClickListener(DeviceList);
handler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg){
if(msg.what == MESSAGE_READ){
String readMessage = null;
readMessage = new String((byte[]) msg.obj, StandardCharsets.UTF_8);
TV2.setText(readMessage);
}
if(msg.what == CONNECTING_STATUS){
char[] sConnected;
if(msg.arg1 == 1)
TV3.setText(getString(R.string.BTConnected) + msg.obj);
else
TV3.setText(getString(R.string.BTconnFail));
}
}
};
if (adapter.isEnabled()){
TV.setText("Bluetooth ON");
}else TV.setText("Bluetooth OFF");
disc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
discovery();
if (!adapter.isEnabled()){
Toast.makeText(getBaseContext(), getString(R.string.BTnotOn), Toast.LENGTH_SHORT).show();
}
}
});
offon.setOnClickListener(new View.OnClickListener() {
#SuppressLint("MissingPermission")
#Override
public void onClick(View view) {
if (adapter.isEnabled()) {
adapter.disable();
TV.setText("Bluetooth OFF");
}else {
adapter.enable();
TV.setText("Bluetooth ON");
}
}
});
Next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
open2activity();
}
});
}
public void open2activity(){
Intent intent = new Intent(this, MainActivity2.class);
startActivity(intent);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent Data) {
super.onActivityResult(requestCode, resultCode, Data);
}
#SuppressLint("MissingPermission")
private void discovery(){
if (adapter.isDiscovering()){
adapter.cancelDiscovery();
Toast.makeText(getApplicationContext(), getString(R.string.DisStop), Toast.LENGTH_SHORT).show();
}
else{
if (adapter.isEnabled()){
ArrayAdapter.clear();
adapter.startDiscovery();
Toast.makeText(getApplicationContext(), getString(R.string.DisStart), Toast.LENGTH_SHORT).show();
registerReceiver(blReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}
}
}
final BroadcastReceiver blReceiver = new BroadcastReceiver() {
#SuppressLint("MissingPermission")
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
ArrayAdapter.add(device.getName() + "\n" + device.getAddress());
ArrayAdapter.notifyDataSetChanged();
}
}
};
private AdapterView.OnItemClickListener DeviceList = new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TV3.setText(getString(R.string.cConnet));
String info = ((TextView)view).getText().toString();
final String address = info.substring(info.length() - 17);
final String name = info.substring(0,info.length() - 17);
new Thread()
{
#SuppressLint("MissingPermission")
#Override
public void run() {
boolean fail = false;
BluetoothDevice device = adapter.getRemoteDevice(address);
try {
BTSocket = createBluetoothSocket(device);
} catch (IOException e) {
fail = true;
Toast.makeText(getBaseContext(), getString(R.string.ErrSockCrea), Toast.LENGTH_SHORT).show();
}
try {
BTSocket.connect();
} catch (IOException e) {
try {
fail = true;
BTSocket.close();
handler.obtainMessage(CONNECTING_STATUS, -1, -1)
.sendToTarget();
} catch (IOException e2) {
Toast.makeText(getBaseContext(), getString(ErrSockCrea), Toast.LENGTH_SHORT).show();
}
}
if(!fail) {
ConnectedThread = new ConnectedThread(BTSocket, handler);
ConnectedThread.start();
handler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
.sendToTarget();
}
}
}.start();
}
};
#SuppressLint("MissingPermission")
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
try {
final Method m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", UUID.class);
return (BluetoothSocket) m.invoke(device, BT_MODULE_UUID);
} catch (Exception e) {
Log.e(TAG, "Could not create Insecure RFComm Connection",e);
}
return device.createRfcommSocketToServiceRecord(BT_MODULE_UUID);
}
}
`
I tried to do as above but nothing is displayed

bluetooth as service and send/receive from it

I'm trying to recieve/send data to arduino board using bluetooth, and I can connect to board from one activity. I know that I can make my other activities connect with bluetooth using service but I don't know how to make bluetooth as service. and i don't know how to send and recieve from it.
my Paired Devices code:
public class BTConnect extends AppCompatActivity {
private static final String TAG = "BTConnect";
ListView IdLista;
public static String EXTRA_DEVICE_ADDRESS = "device_address";
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_btconnect);
}
#Override
public void onResume()
{
super.onResume();
//---------------------------------
VerificarEstadoBT();
//
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.btconnect_nombre);
IdLista = (ListView)findViewById(R.id.Id2);
IdLista.setAdapter(mPairedDevicesArrayAdapter);
IdLista.setOnItemClickListener(mDeviceClickListener);
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
if (pairedDevices.size() > 0)
{
for (BluetoothDevice device: pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}
}
private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView av, View v, int arg2, long arg3) {
String info = ((TextView) v).getText().toString();
String address = info.substring(info.length() - 17);
Intent i = new Intent(BTConnect.this, device.class);
i.putExtra(EXTRA_DEVICE_ADDRESS, address);
startActivity(i);
}
};
private void VerificarEstadoBT() {
mBtAdapter= BluetoothAdapter.getDefaultAdapter();
if(mBtAdapter==null) {
Toast.makeText(getBaseContext(), "the device can't connect to BT", Toast.LENGTH_SHORT).show();
} else {
if (mBtAdapter.isEnabled()) {
Log.d(TAG, "...Bluetooth Activation...");
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}}
And my first activity 'device' :
public class device extends AppCompatActivity {
Button IdEncender, IdApagar,IdDesconectar,IdReset;
ArrayList<String> addArray = new ArrayList<String>();
ListView show;
//-------------------------------------------
Handler bluetoothIn;
final int handlerState = 0;
private BluetoothAdapter btAdapter = null;
private BluetoothSocket btSocket = null;
private StringBuilder DataStringIN = new StringBuilder();
private ConnectedThread MyConexionBT;
// Identificador unico de servicio - SPP UUID
private static final UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// String para la direccion MAC
private static String address = null;
//-------------------------------------------
#SuppressLint("HandlerLeak")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_device);
IdEncender = (Button) findViewById(R.id.IdEncender);
IdApagar = (Button) findViewById(R.id.IdApagar);
IdDesconectar = (Button) findViewById(R.id.IdDisconectar);
show = (ListView) findViewById(R.id.LIST1) ;
IdReset=(Button)findViewById(R.id.IdReset);
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);
String newline = "\r\n";
DataStringIN.delete(0, DataStringIN.length());
//--List adapter--//
addArray.add(dataInPrint);
ArrayAdapter<String> adapter =new ArrayAdapter<String>(device.this, android.R.layout.simple_list_item_1, addArray);
show.setAdapter(adapter);
}
}
};
btAdapter = BluetoothAdapter.getDefaultAdapter(); // get Bluetooth adapter
VerificarEstadoBT();
IdEncender.setOnClickListener(new View.OnClickListener() {
public void onClick(View v)
{
MyConexionBT.write("1");
}
});
IdApagar.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyConexionBT.write("0");
}
});
IdDesconectar.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();
}
});
configurebutton();
}
private void configurebutton() {
Button startbutton = (Button)findViewById(R.id.Start);
startbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(device.this,chart.class));
}
});
}
private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException
{
return device.createRfcommSocketToServiceRecord(BTMODULEUUID);
}
#Override
public void onResume()
{
super.onResume();
Intent intent = getIntent();
address = intent.getStringExtra(BTConnect.EXTRA_DEVICE_ADDRESS);
BluetoothDevice device = btAdapter.getRemoteDevice(address);
try
{
btSocket = createBluetoothSocket(device);
} catch (IOException e) {
Toast.makeText(getBaseContext(), "fail", Toast.LENGTH_LONG).show();
}
try
{
btSocket.connect();
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {}
}
MyConexionBT = new ConnectedThread(btSocket);
MyConexionBT.start();
}
#Override
public void onPause()
{
super.onPause();
try
{
btSocket.close();
} catch (IOException e2) {}
}
private void VerificarEstadoBT() {
if(btAdapter==null) {
Toast.makeText(getBaseContext(), "error in bluetooth connection", Toast.LENGTH_LONG).show();
} else {
if (btAdapter.isEnabled()) {
} else {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 1);
}
}
}
public void savefile(String file, String text){
try {
FileOutputStream fos = openFileOutput(file, Context.MODE_APPEND);
fos.write(text.getBytes());
fos.close();
Toast.makeText(device.this, "saved!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(device.this,"error",Toast.LENGTH_LONG).show();
}
}
//Crea la clase que permite crear el evento de conexion
private class ConnectedThread extends Thread
{
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket)
{
InputStream tmpIn = null;
OutputStream tmpOut = null;
try
{
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run()
{
byte[] buffer = new byte[256];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String readMessage = new String(buffer, 0, bytes);
bluetoothIn.obtainMessage(handlerState, bytes, -1, readMessage).sendToTarget();
} catch (IOException e) {
break;
}
}
}
public void write(String input)
{
try {
mmOutStream.write(input.getBytes());
}
catch (IOException e)
{
Toast.makeText(getBaseContext(), "fail to connect", Toast.LENGTH_LONG).show();
finish();
}
}
}
}
If shortly move your connection/message_exchange logic to Thread/Runnable and start it from Service. You can exchange data between Service and Activity/Activities with BroadcastReceivers or Messenger. I also recommend you to use Bluetooth lib:
implementation 'me.aflak.libraries:bluetooth:1.3.4' this one already have inside thread so it is become easy to embed in your service.
Example code of service which use this lib and Messenger:
private ArrayList<Messenger> mClients = new ArrayList<>();
final private Messenger inComingMessenger = new Messenger(mIncomingHandler);
#SuppressLint("HandlerLeak")
final Handler mIncomingHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
Log.d(TAG, "handleMessage: new client connected. Total: " + mClients.size());
break;
case Constants.MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
Log.d(TAG, "handleMessage: client disconnected. Total: " + mClients.size());
break;
case Constants.MSG_YOUR_MESSAGE_TYPE:
String val = (String) msg.obj;
// stuff to do
break;
}
}
};
/**
* Send message to connected activities
*/
public void sendMessageToClients(int msgSignal, Object obj) {
if (mClients.size() == 0)
return;
sendMessage(mClients.get(0), Message.obtain(null, msgSignal, obj));
for (int i = 1; i < mClients.size(); i++) {
if (mClients.get(i) == null)
continue;
sendMessage(mClients.get(i), Message.obtain(null, msgSignal, obj));
}
}
/**
* Send message to binded activity
*/
private void sendMessage(Messenger msgr, Message msg) {
try {
msgr.send((msg));
} catch (RemoteException e) {
Log.e(TAG, "can't send message", e);
e.printStackTrace();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.d(TAG, "onStartCommand");
return START_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return inComingMessenger.getBinder();
}
#Override
public void onCreate() {
super.onCreate();
bleDevices = new ArrayList<>();
if(bluetooth == null) {
bluetooth = new Bluetooth(this);
bluetooth.setBluetoothCallback(new BluetoothCallback() {
#Override
public void onBluetoothTurningOn() {}
#Override
public void onBluetoothOn() {}
#Override
public void onBluetoothTurningOff() {
bluetooth = null;
}
#Override
public void onBluetoothOff() { }
#Override
public void onUserDeniedActivation() {
// when using bluetooth.showEnableDialog()
// you will also have to call bluetooth.onActivityResult()
}
});
bluetooth.setDiscoveryCallback(new DiscoveryCallback() {
#Override public void onDiscoveryStarted() {
}
#Override public void onDiscoveryFinished() {
bleDevices.clear();
}
#Override public void onDeviceFound(BluetoothDevice device) {
if(bleDevices.indexOf(device)<0) {
bleDevices.add(device);
Log.d(TAG, "Found new device while scanning: "+device.getAddress());
sendMessageToClients(Constants.MSG_BLE_DEVICE_FOUND, device);
}
}
#Override public void onDevicePaired(BluetoothDevice device) {}
#Override public void onDeviceUnpaired(BluetoothDevice device) {}
#Override public void onError(String message) {
Log.e(TAG, "DiscoveryCallback onError "+message);
}
});
bluetooth.setDeviceCallback(new DeviceCallback() {
#Override public void onDeviceConnected(BluetoothDevice device) { }
#Override public void onDeviceDisconnected(BluetoothDevice device, String message) { }
#Override public void onMessage(String message) {
// Handle your message
yourHandleFunction(message.replaceAll(" ",""));
Log.d(TAG, message);
}
#Override public void onError(String message) {
Log.e(TAG, "DeviceCallback onError "+message);
}
#Override public void onConnectError(BluetoothDevice device, String message) { }
});
bluetooth.onStart();
}
connectToSavedDevice();
}
}
private void connectToSavedDevice() {
Log.d(TAG, "connectToSavedDevice state="+getState());
if(getState() != STATE_DISCONNECTED) return;
SharedPreferences pref = getSharedPreferences(App.TAG, 0);
String address = pref.getString(Constants.PREF_AUTO_CONNECT_TO_ADDRESS, null);
if(address == null) {
Log.d(TAG, "saved address==null start scan for devices");
scanDevices();
return;
}
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
if(device!=null) {
Log.d(TAG, "device found try to connect/bound, connect to Arduino");
bluetooth.connectToAddress(address,false);
}
}
In activity implement ServiceConnection interface:
protected synchronized void unbindService() {
if (!isBound()) {
return;
}
// lock object (prevents access to service while disconnecting)
synchronized (outComingMessenger) {
sendMessageToService(Message.obtain(null, Constants.MSG_UNREGISTER_CLIENT));
unbindService(this);
outComingMessenger = null;
}
}
protected void bindService() {
bindService(mServiceIntent, this, BIND_AUTO_CREATE);
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
outComingMessenger = new Messenger(service);
final Message msg = Message.obtain(null, Constants.MSG_REGISTER_CLIENT);
msg.replyTo = inComingMessenger;
msg.obj = getClass().getSimpleName();
sendMessageToService(msg);
sendMessageToService(Constants.MSG_CHECK_IS_CONNECTION_READY);
}
#Override
public void onServiceDisconnected(ComponentName name) {
outComingMessenger = null;
bindService();
}
/**
* Send message to service
*/
protected void sendMessageToService(Message msg) {
if (!isBound()) {
return;
}
try {
msg.replyTo = inComingMessenger;
outComingMessenger.send(msg);
} catch (RemoteException e) {
}
}
/**
* Send simple message to connected service
* #param messageId
*/
protected void sendMessageToService(int messageId) {
sendMessageToService(Message.obtain(null, messageId));
}
/**
* Send simple message to connected service
* #param messageId
*/
protected void sendMessageToService(int messageId, Object obj) {
sendMessageToService(Message.obtain(null, messageId, obj));
}
/**
* Service is connected?
*/
protected final boolean isBound() {
return outComingMessenger != null;
}
#SuppressLint("HandlerLeak")
private final Handler mIncomingHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MSG_YOUR_MESSAGE:
int res = (int) msg.obj;
break;
case Constants.MSG_CONNECTION_READY:
isReady = (boolean) msg.obj;
if(isReady) {
// show toast or what you want to do with the UI
} else {
// do something else
}
break;
case Constants.MSG_BLE_DEVICE_FOUND:
BluetoothDevice device = (BluetoothDevice)msg.obj;
SharedPreferences pref = getSharedPreferences(App.TAG, 0);
String deviceAddress = pref.getString(Constants.PREF_AUTO_CONNECT_TO_ADDRESS, null);
break;
}
}
};
final private Messenger inComingMessenger = new Messenger(mIncomingHandler);

Bluetooth Connection

I've looked at quite a lot of topics on this in different forums and none seem to help me.
I recently bought an Elegoo car kit, which is compatible with the Arduino IDE, and it comes with different types of code and what not. they even have their own Android app.
My problem is I want to create my own android Bluetooth application that connects/pairs with the module and can control the car remotely. I have my application up and running, it can scan for nearby devices and the HC-08 module appears in the list but I am not able to connect. when I try to connect it says it can't communicate with HC-08. I am pretty sure the problem lies in the android end as the elegoo Bluetooth app connects no problem at all with the Bluetooth module if there is any code on the elegoo board or not. The bluetooth module is a HC-08.
Can someone help me with this ?
Also I am following this youtube tutorial so the credit goes to him for the code.
https://www.youtube.com/watch?v=YJ0JQXcNNTA
Here is the main activity code:
public class MainActivity extends AppCompatActivity implements
AdapterView.OnItemClickListener{
private static final String TAG = "MainActivity";
BluetoothAdapter mBluetoothAdapter;
Button btnEnableDisable_Discoverable;
public ArrayList<BluetoothDevice> mBTDevices = new ArrayList<>();
public DeviceListAdapter mDeviceListAdapter;
ListView lvNewDevices;
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mBroadcastReceiver1 = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (action.equals(mBluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, mBluetoothAdapter.ERROR);
switch(state){
case BluetoothAdapter.STATE_OFF:
Log.d(TAG, "onReceive: STATE OFF");
break;
case BluetoothAdapter.STATE_TURNING_OFF:
Log.d(TAG, "mBroadcastReceiver1: STATE TURNING OFF");
break;
case BluetoothAdapter.STATE_ON:
Log.d(TAG, "mBroadcastReceiver1: STATE ON");
break;
case BluetoothAdapter.STATE_TURNING_ON:
Log.d(TAG, "mBroadcastReceiver1: STATE TURNING ON");
break;
}
}
}
};
/**
* Broadcast Receiver for changes made to bluetooth states such as:
* 1) Discoverability mode on/off or expire.
*/
private final BroadcastReceiver mBroadcastReceiver2 = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)) {
int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.ERROR);
switch (mode) {
//Device is in Discoverable Mode
case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
Log.d(TAG, "mBroadcastReceiver2: Discoverability Enabled.");
break;
//Device not in discoverable mode
case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
Log.d(TAG, "mBroadcastReceiver2: Discoverability Disabled. Able to receive connections.");
break;
case BluetoothAdapter.SCAN_MODE_NONE:
Log.d(TAG, "mBroadcastReceiver2: Discoverability Disabled. Not able to receive connections.");
break;
case BluetoothAdapter.STATE_CONNECTING:
Log.d(TAG, "mBroadcastReceiver2: Connecting....");
break;
case BluetoothAdapter.STATE_CONNECTED:
Log.d(TAG, "mBroadcastReceiver2: Connected.");
break;
}
}
}
};
/**
* Broadcast Receiver for listing devices that are not yet paired
* -Executed by btnDiscover() method.
*/
private BroadcastReceiver mBroadcastReceiver3 = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(TAG, "onReceive: ACTION FOUND.");
if (action.equals(BluetoothDevice.ACTION_FOUND)){
BluetoothDevice device = intent.getParcelableExtra (BluetoothDevice.EXTRA_DEVICE);
mBTDevices.add(device);
Log.d(TAG, "onReceive: " + device.getName() + ": " + device.getAddress());
mDeviceListAdapter = new DeviceListAdapter(context, R.layout.device_adapter_view, mBTDevices);
lvNewDevices.setAdapter(mDeviceListAdapter);
}
}
};
/**
* Broadcast Receiver that detects bond state changes (Pairing status changes)
*/
private final BroadcastReceiver mBroadcastReceiver4 = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)){
BluetoothDevice mDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//3 cases:
//case1: bonded already
if (mDevice.getBondState() == BluetoothDevice.BOND_BONDED){
Log.d(TAG, "BroadcastReceiver: BOND_BONDED.");
}
//case2: creating a bone
if (mDevice.getBondState() == BluetoothDevice.BOND_BONDING) {
Log.d(TAG, "BroadcastReceiver: BOND_BONDING.");
}
//case3: breaking a bond
if (mDevice.getBondState() == BluetoothDevice.BOND_NONE) {
Log.d(TAG, "BroadcastReceiver: BOND_NONE.");
}
}
}
};
#Override
protected void onDestroy() {
Log.d(TAG, "onDestroy: called.");
super.onDestroy();
unregisterReceiver(mBroadcastReceiver1);
unregisterReceiver(mBroadcastReceiver2);
unregisterReceiver(mBroadcastReceiver3);
unregisterReceiver(mBroadcastReceiver4);
//mBluetoothAdapter.cancelDiscovery();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnONOFF = (Button) findViewById(R.id.btnONOFF);
btnEnableDisable_Discoverable = (Button) findViewById(R.id.btnDiscoverable_on_off);
lvNewDevices = (ListView) findViewById(R.id.lvNewDevices);
mBTDevices = new ArrayList<>();
//Broadcasts when bond state changes (ie:pairing)
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mBroadcastReceiver4, filter);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
lvNewDevices.setOnItemClickListener(MainActivity.this);
btnONOFF.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.d(TAG, "onClick: enabling/disabling bluetooth.");
enableDisableBT();
}
});
}
public void enableDisableBT(){
if(mBluetoothAdapter == null){
Log.d(TAG, "enableDisableBT: Does not have BT capabilities.");
}
if(!mBluetoothAdapter.isEnabled()){
Log.d(TAG, "enableDisableBT: enabling BT.");
Intent enableBTIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(enableBTIntent);
IntentFilter BTIntent = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mBroadcastReceiver1, BTIntent);
}
if(mBluetoothAdapter.isEnabled()){
Log.d(TAG, "enableDisableBT: disabling BT.");
mBluetoothAdapter.disable();
IntentFilter BTIntent = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(mBroadcastReceiver1, BTIntent);
}
}
public void btnEnableDisable_Discoverable(View view) {
Log.d(TAG, "btnEnableDisable_Discoverable: Making device discoverable for 300 seconds.");
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
IntentFilter intentFilter = new IntentFilter(mBluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
registerReceiver(mBroadcastReceiver2,intentFilter);
}
public void btnDiscover(View view) {
Log.d(TAG, "btnDiscover: Looking for unpaired devices.");
if(mBluetoothAdapter.isDiscovering()){
mBluetoothAdapter.cancelDiscovery();
Log.d(TAG, "btnDiscover: Canceling discovery.");
//check BT permissions in manifest
checkBTPermissions();
mBluetoothAdapter.startDiscovery();
IntentFilter discoverDevicesIntent = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mBroadcastReceiver3, discoverDevicesIntent);
}
if(!mBluetoothAdapter.isDiscovering()){
//check BT permissions in manifest
checkBTPermissions();
mBluetoothAdapter.startDiscovery();
IntentFilter discoverDevicesIntent = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mBroadcastReceiver3, discoverDevicesIntent);
}
}
/**
* This method is required for all devices running API23+
* Android must programmatically check the permissions for bluetooth. Putting the proper permissions
* in the manifest is not enough.
*
* NOTE: This will only execute on versions > LOLLIPOP because it is not needed otherwise.
*/
private void checkBTPermissions() {
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP){
int permissionCheck = this.checkSelfPermission("Manifest.permission.ACCESS_FINE_LOCATION");
permissionCheck += this.checkSelfPermission("Manifest.permission.ACCESS_COARSE_LOCATION");
if (permissionCheck != 0) {
this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001); //Any number
}
}else{
Log.d(TAG, "checkBTPermissions: No need to check permissions. SDK version < LOLLIPOP.");
}
}
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
//first cancel discovery because its very memory intensive.
mBluetoothAdapter.cancelDiscovery();
Log.d(TAG, "onItemClick: You Clicked on a device.");
String deviceName = mBTDevices.get(i).getName();
String deviceAddress = mBTDevices.get(i).getAddress();
Log.d(TAG, "onItemClick: deviceName = " + deviceName);
Log.d(TAG, "onItemClick: deviceAddress = " + deviceAddress);
//create the bond.
//NOTE: Requires API 17+? I think this is JellyBean
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2){
Log.d(TAG, "Trying to pair with " + deviceName);
mBTDevices.get(i).createBond();
}
}
}
/// Here is also my DeviceListAdapter code:
public class DeviceListAdapter extends ArrayAdapter<BluetoothDevice> {
private LayoutInflater mLayoutInflater;
private ArrayList<BluetoothDevice> mDevices;
private int mViewResourceId;
public DeviceListAdapter(Context context, int tvResourceId, ArrayList<BluetoothDevice> devices){
super(context, tvResourceId,devices);
this.mDevices = devices;
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mViewResourceId = tvResourceId;
}
public View getView(int position, View convertView, ViewGroup parent) {
convertView = mLayoutInflater.inflate(mViewResourceId, null);
BluetoothDevice device = mDevices.get(position);
if (device != null) {
TextView deviceName = (TextView) convertView.findViewById(R.id.tvDeviceName);
TextView deviceAdress = (TextView) convertView.findViewById(R.id.tvDeviceAddress);
if (deviceName != null) {
deviceName.setText(device.getName());
}
if (deviceAdress != null) {
deviceAdress.setText(device.getAddress());
}
}
return convertView;
}
}
Some of the tutorials on Bluetooth are pretty old! I just got Arduino-Android Bluetooth communication working last week so this should work for you! First in your manifest file add these permissions:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
Then use this in your main.
public class MainActivity extends AppCompatActivity {
private final String DEVICE_ADDRESS="benamekhoda"; //I actually used Device Name instead of address
private final UUID PORT_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); //Serial Port Service UUID
private BluetoothDevice device; //Our Bluetooth Device
private BluetoothSocket socket;
private OutputStream outputStream;
private InputStream inputStream;
Button startButton, sendButton,clearButton,stopButton;
TextView textView;
EditText editText;
boolean deviceConnected=false;
Thread thread;
byte buffer[];
int bufferPosition;
boolean stopThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.edittext);
textView = (TextView) findViewById(R.id.textview);
startButton = (Button) findViewById(R.id.buttonStart);
startButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(BTinit())
{
if(BTconnect())
{
setUiEnabled(true);
deviceConnected=true;
beginListenForData();
textView.append("\nConnection Opened!\n");
}
else{
Toast.makeText(getApplicationContext(),"BTconnect false",Toast.LENGTH_SHORT).show();
}
}
else{
Toast.makeText(getApplicationContext(),"BTinit false",Toast.LENGTH_SHORT).show();
}
}
});
sendButton = (Button) findViewById(R.id.buttonSend);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String string = editText.getText().toString();
string.concat("\n");
try {
outputStream.write(string.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
textView.append("\nSent Data:"+string+"\n");
}
});
clearButton = (Button) findViewById(R.id.buttonClear);
clearButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onClickClear(view);
}
});
stopButton = (Button) findViewById(R.id.buttonStop);
stopButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onClickSend(view);
}
});
setUiEnabled(false);
}
public void setUiEnabled(boolean bool)
{
startButton.setEnabled(!bool);
sendButton.setEnabled(bool);
stopButton.setEnabled(bool);
textView.setEnabled(bool);
}
public boolean BTinit()
{
boolean found=false;
BluetoothAdapter bluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Toast.makeText(getApplicationContext(),"Device doesnt Support Bluetooth",Toast.LENGTH_SHORT).show();
}
if(!bluetoothAdapter.isEnabled())
{
Intent enableAdapter = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableAdapter, 0);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices(); //Something like ArrayList but no duplicate is allowed and data is unordered
if(bondedDevices.isEmpty())
{
Toast.makeText(getApplicationContext(),"Please Pair the Device first",Toast.LENGTH_SHORT).show();
}
else
{
for (BluetoothDevice iterator : bondedDevices)
{
if(iterator.getName().equals(DEVICE_ADDRESS))
{
device=iterator;
Toast.makeText(getApplicationContext(),"found the device",Toast.LENGTH_SHORT).show();
found=true;
break;
}
}
}
return found;
}
public boolean BTconnect()
{
boolean connected=true;
try {
socket = device.createRfcommSocketToServiceRecord(PORT_UUID);
socket.connect();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),"throw1",Toast.LENGTH_SHORT).show();
connected=false;
}
if(connected)
{
try {
outputStream=socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),"throw2",Toast.LENGTH_SHORT).show();
}
try {
inputStream=socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(),"throw3",Toast.LENGTH_SHORT).show();
}
}
return connected;
}
void beginListenForData()
{
final Handler handler = new Handler();
stopThread = false;
buffer = new byte[1024];
Thread thread = new Thread(new Runnable()
{
public void run()
{
while(!Thread.currentThread().isInterrupted() && !stopThread)
{
try
{
int byteCount = inputStream.available();
if(byteCount > 0)
{
byte[] rawBytes = new byte[byteCount];
inputStream.read(rawBytes);
final String string=new String(rawBytes,"UTF-8");
handler.post(new Runnable() {
public void run()
{
textView.append(string);
}
});
}
}
catch (IOException ex)
{
stopThread = true;
Toast.makeText(getApplicationContext(),"throw4",Toast.LENGTH_SHORT).show();
}
}
}
});
thread.start();
}
public void onClickSend(View view) {
String string = editText.getText().toString();
string.concat("\n");
try {
outputStream.write(string.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
textView.append("\nSent Data:"+string+"\n");
}
public void onClickStop(View view) throws IOException {
stopThread = true;
outputStream.close();
inputStream.close();
socket.close();
setUiEnabled(false);
deviceConnected=false;
textView.append("\nConnection Closed!\n");
}
public void onClickClear(View view) {
textView.setText("");
}
}
I got it from this awesome tutorial by Hariharan Mathavan from All About Circuits.

NullPointerException in `BluetoothAdapter` when startService() is invoked [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
Error I'm getting null point exception in Bluetooth when I'm starting a service.
LiveFragment.class
public class LiveFragment extends Fragment {
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
private static final int REQUEST_ENABLE_BT = 3;
private BluetoothAdapter mBluetoothAdapter =null;
public BluetoothChatService mChatService = null;
private PowerManager.WakeLock wakeLock = null;
private PowerManager powerManager = null;
private String mConnectedDeviceName = null;
private boolean isServiceBound;
private boolean preRequisites = true;
private SharedPreferences prefs;
private BroadcastReceiver broadcastReceiver;
private Context c;
private AbstractGatewayService ab;
protected ImageView blue_onoffBut, gps_Button, obd_inidca, ss_button, bluetooth_indicator, gps_indicator,obd_connectButt;
protected TextView ss_Status,btStatusTextView,obdStatusTextView,gpsStatusTextView;
private LinearLayout vv;
protected BluetoothSocket sock = null;
public LiveFragment() {
// Required empty public constructor
}
private final Runnable mQueueCommands = new Runnable() {
public void run() {
Log.d(TAG, "Runnable mQueueCommands ()");
if (ab != null && ab.isRunning() && ab.queueEmpty()) {
queueCommands();
}
// run again in period defined in preferences
new Handler().postDelayed(mQueueCommands, 4000);
}
};
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
final View view = inflater.inflate(R.layout.fragment_live, container, false);
blue_onoffBut = (ImageView) view.findViewById(R.id.blutooth_butoon);
gps_Button = (ImageView) view.findViewById(R.id.gps_button);
obd_inidca = (ImageView) view.findViewById(R.id.obd_Indicator);
ss_button = (ImageView) view.findViewById(ssButton);
gps_indicator = (ImageView) view.findViewById(R.id.gps_indicator);
bluetooth_indicator = (ImageView) view.findViewById(R.id.bluetooth_indicator);
obd_connectButt = (ImageView) view.findViewById(R.id.Obd_Connect_Button);
ss_Status = (TextView) view.findViewById(R.id.statusTx);
btStatusTextView = (TextView) view.findViewById(R.id.blue);
obdStatusTextView = (TextView) view.findViewById(R.id.obd);
gpsStatusTextView = (TextView) view.findViewById(R.id.gps);
vv = (LinearLayout) view.findViewById(R.id.fragment_live_layout);
ss_Status.setTextColor(getResources().getColor(R.color.colorGreen));
if (mBluetoothAdapter.isEnabled()) {
bluetooth_indicator.setImageResource(R.drawable.green_circle);
} else {
bluetooth_indicator.setImageResource(R.drawable.red_circle);
}
gps_Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final LocationManager manager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE );
if ( !manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
buildAlertMessageNoGps();
}
else {
showToast("Already GPS is ON");
}
}
});
blue_onoffBut.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.enable();
showToast("Bluetooth Turned ON"+"\n"+"Connect Your OBD now");
bluetooth_indicator.setImageResource(R.drawable.green_circle);
mChatService = new BluetoothChatService(getActivity(), mHandler);
if (mChatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
} else if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
mBluetoothAdapter.cancelDiscovery();
obd_inidca.setImageResource(R.drawable.red_circle);
showToast("Bluetooth Turned OFF");
bluetooth_indicator.setImageResource(R.drawable.red_circle);
}
}
});
ss_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mBluetoothAdapter.isEnabled() && mChatService.getState() == BluetoothChatService.STATE_CONNECTED) {
startLiveData();
} else if (!mBluetoothAdapter.isEnabled()) {
showToast("Turn ON Bluetooth to Continue");
}
else if (!(mChatService.getState() == BluetoothChatService.STATE_CONNECTED)){
showToast("Select your OBD to Start ");
}
}
});
obd_connectButt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mBluetoothAdapter.isEnabled()) {
Intent serverIntent = new Intent(getActivity(), DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
}
else if (!mBluetoothAdapter.isEnabled()){
showToast("Turn ON Bluetooth to Connect OBD");
}
}
});
return view;
}
private ServiceConnection serviceConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder binder) {
Log.d(TAG, className.toString() + " service is bound");
isServiceBound = true;
ab = ((AbstractGatewayService.AbstractGatewayServiceBinder) binder).getService();
ab.setContext(getActivity());
Log.d(TAG, "Starting live data");
try {
ab.startService();
if (preRequisites)
btStatusTextView.setText("Connected");
} catch (IOException ioe) {
Log.e(TAG, "Failure Starting live data");
btStatusTextView.setText("Connection failed");
doUnbindService();
}
}
#Override
protected Object clone() throws CloneNotSupportedException {
Log.d(TAG, "CloneNotSupportedException ");
return super.clone();
}
#Override
public void onServiceDisconnected(ComponentName className) {
Log.d(TAG, className.toString() + " service is unbound");
isServiceBound = false;
}
};
public static String LookUpCommand(String txt) {
Log.d(TAG, "LookUpCommand() ");
for (AvailableCommandNames item : AvailableCommandNames.values()) {
if (item.getValue().equals(txt)) return item.name();
}
return txt;
}
public void updateTextView(final TextView view, final String txt) {
Log.d(TAG, "updateTextView() ");
new Handler().post(new Runnable() {
public void run() {
view.setText(txt);
}
});
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void stateUpdate(ObdCommandJob job) {
final String cmdName = job.getCommand().getName();
String cmdResult = "";
final String cmdID = LookUpCommand(cmdName);
Log.d(TAG, "stateUpdate() ");
if (job.getState().equals(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR)) {
cmdResult = job.getCommand().getResult();
if (cmdResult != null && isServiceBound) {
obdStatusTextView.setText(cmdResult.toLowerCase());
}
} else if (job.getState().equals(ObdCommandJob.ObdCommandJobState.BROKEN_PIPE)) {
if (isServiceBound)
stopLiveData();
} else if (job.getState().equals(ObdCommandJob.ObdCommandJobState.NOT_SUPPORTED)) {
cmdResult = "NA";
} else {
cmdResult = job.getCommand().getFormattedResult();
if (isServiceBound)
obdStatusTextView.setText("Receiving data...");
}
cmdResult.replace("NODATA", "0");
if (vv.findViewWithTag(cmdID) != null) {
TextView existingTV = (TextView) vv.findViewWithTag(cmdID);
existingTV.setText(cmdResult);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
FragmentActivity activity = getActivity();
Toast.makeText(activity, "No Bluetooth Feature in Device", Toast.LENGTH_LONG).show();
activity.finish();
}
}
#Override
public void onStart() {
super.onStart();
final LocationManager manager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE );
if ( !manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
gps_indicator.setImageResource(R.drawable.red_circle);
}
if(mBluetoothAdapter.isEnabled()){
mBluetoothAdapter.disable();
bluetooth_indicator.setImageResource(R.drawable.red_circle);
}
}
#Override
public void onResume() {
super.onResume();
powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "ObdReader");
final LocationManager manager = (LocationManager) getActivity().getSystemService( Context.LOCATION_SERVICE );
if ( manager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ) {
gps_indicator.setImageResource(R.drawable.green_circle);
} else {
gps_indicator.setImageResource(R.drawable.red_circle);
}
EventBus.getDefault().register(this);
if(mBluetoothAdapter.isEnabled()) {
if (mChatService != null) {
// Only if the state is STATE_NONE, do we know that we haven't started already
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
// Start the Bluetooth chat services
mChatService.start();
}
}
}
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, "Pausing..");
releaseWakeLockIfHeld();
EventBus.getDefault().unregister(this);
}
private void showToast(String message) {
final Toast toast = Toast.makeText(getContext(), message, Toast.LENGTH_SHORT);
toast.show();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
toast.cancel();
}
}, 500);
}
#Override
public void onDestroy() {
/* unregisterReceiver(mReceiver);*/
super.onDestroy();
releaseWakeLockIfHeld();
if (mChatService != null) {
mChatService.stop();
}
if (isServiceBound) {
doUnbindService();
}
if (mBluetoothAdapter.isEnabled()) {
mBluetoothAdapter.disable();
}
showToast("Take Care!");
}
private void startLiveData() {
if (mChatService.getState() == BluetoothChatService.STATE_CONNECTED) {
Log.d(TAG, "Starting live data..");
ss_Status.setText("Stop");
ss_Status.setTextColor(getResources().getColor(R.color.colorRed));
wakeLock.acquire();
ss_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ss_Status.setText("Go Live");
ss_Status.setTextColor(getResources().getColor(R.color.colorGreen));
stopLiveData();
}
});
doBindService();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((broadcastReceiver), new IntentFilter(OBD_GATEWAY_SERVICE));
new Handler().post(mQueueCommands);
}
}
private void stopLiveData() {
Log.d(TAG, "Stopping live data..");
releaseWakeLockIfHeld();
new Handler().removeCallbacks(mQueueCommands);
ss_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ss_Status.setText("Go Live");
ss_Status.setTextColor(getResources().getColor(R.color.colorGreen));
startLiveData();
}
});
doUnbindService();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(broadcastReceiver);
}
private void queueCommands() {
Log.d(TAG, "LiveFragment queueCommands() ");
if (isServiceBound) {
for (ObdCommand Command : ObdConfig.getCommands()) {
if (prefs.getBoolean(Command.getName(), true))
ab.queueJob(new ObdCommandJob(Command));
}
}
}
private void doBindService() {
if (!isServiceBound) {
Log.d(TAG, "Binding OBD service..");
if (preRequisites) {
btStatusTextView.setText("Connecting.....");
Intent serviceIntent = new Intent(getActivity(),ObdGatewayService.class);
getActivity().bindService(serviceIntent, serviceConn, Context.BIND_AUTO_CREATE);
}
}
}
private void doUnbindService() {
if (isServiceBound) {
if (ab.isRunning()) {
ab.stopService();
if (preRequisites)
btStatusTextView.setText("Ready...");
}
Log.d(TAG, "Unbinding OBD service..");
getActivity().unbindService(serviceConn);
isServiceBound = false;
obdStatusTextView.setText("Disconnected");
}
}
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
FragmentActivity activity = getActivity();
switch (msg.what) {
case Constants.MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
obd_inidca.setImageResource(R.drawable.green_circle);
break;
case BluetoothChatService.STATE_CONNECTING:
obd_inidca.setImageResource(R.drawable.orange_circle);
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
obd_inidca.setImageResource(R.drawable.red_circle);
break;
}
break;
case Constants.MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
if (null != activity) {
Toast.makeText(activity, "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
obd_inidca.setImageResource(R.drawable.green_circle);
}
break;
case Constants.MESSAGE_TOAST:
if (null != activity) {
Toast.makeText(activity, msg.getData().getString(Constants.TOAST),
Toast.LENGTH_SHORT).show();
}
break;
}
}
};
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE_SECURE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
try {
connectDevice(data, true);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void connectDevice(Intent data, boolean secure) throws IOException {
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BluetoothDevice object
BluetoothDevice dev = mBluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mChatService.connect(dev, secure);
}.
This is ObdGateway service class:
public class ObdGatewayService extends AbstractGatewayService {
private static final String TAG = ObdGatewayService.class.getName();
#Inject
SharedPreferences prefs;
private BluetoothDevice dev = null;
private BluetoothSocket sock = null;
private BluetoothChatService mChatservice = null;
private BluetoothAdapter bluetoothAdapter =null;
public final static String JOB_NAME_STAMP = "Name";
public final static String JOB_STATE_STAMP = "State";
public final static String JOB_RESULT_STAMP = "Result";
public final static String JOB_FORMATED_RESULT_STAMP = "Formated REsult";
public final static String OBD_GATEWAY_SERVICE = "com.samplersoft.saz.Obd.ObdGatewayService";
public void startService() throws IOException {
Log.d(TAG, "Starting service..");
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// get the remote Bluetooth device
if(mChatservice.getState() != BluetoothChatService.STATE_CONNECTED){
Toast.makeText(ctx, "No Bluetooth device selected", Toast.LENGTH_LONG).show();
// log error
Log.e(TAG, "No Bluetooth device has been selected.");
stopService();
throw new IOException();
}
else
{
Log.d(TAG, "Stopping Bluetooth discovery.");
bluetoothAdapter.cancelDiscovery();
try {
startObdConnection();
} catch (Exception e) {
Log.e(
TAG,
"There was an error while establishing connection. -> "
+ e.getMessage()
);
// in case of failure, stop this service.
stopService();
throw new IOException();
}
}
}
private void startObdConnection() throws IOException {
Log.d(TAG, "Starting OBD connection..");
isRunning = true;
if(mChatservice.getState() == BluetoothChatService.STATE_CONNECTED){
// Let's configure the connection.
Log.d(TAG, "Queueing jobs for connection configuration..");
queueJob(new ObdCommandJob(new ObdResetCommand()));
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
queueJob(new ObdCommandJob(new EchoOffCommand()));
queueJob(new ObdCommandJob(new EchoOffCommand()));
queueJob(new ObdCommandJob(new LineFeedOffCommand()));
queueJob(new ObdCommandJob(new TimeoutCommand(62)));
// Get protocol from preferences
queueJob(new ObdCommandJob(new SelectProtocolCommand(ObdProtocols.valueOf("AUTO"))));
// Job for returning dummy data
queueJob(new ObdCommandJob(new AmbientAirTemperatureCommand()));
queueCounter = 0L;
Log.d(TAG, "Initialization jobs queued.");
}
else {
stopService();
throw new IOException();
}
}
#Override
public void queueJob(ObdCommandJob job) {
// This is a good place to enforce the imperial units option
//job.getCommand().useImperialUnits(prefs.getBoolean(ConfigActivity.IMPERIAL_UNITS_KEY, false));
// Now we can pass it along
super.queueJob(job);
}
protected void executeQueue() throws InterruptedException {
Log.d(TAG, "Executing queue..");
while (!Thread.currentThread().isInterrupted()) {
ObdCommandJob job = null;
try {
job = jobsQueue.take();
// log job
Log.d(TAG, "Taking job[" + job.getId() + "] from queue..");
if (job.getState().equals(ObdCommandJob.ObdCommandJobState.NEW)) {
Log.d(TAG, "Job state is NEW. Run it..");
job.setState(ObdCommandJob.ObdCommandJobState.RUNNING);
if (sock.isConnected()) {
job.getCommand().run(sock.getInputStream(), sock.getOutputStream());
} else {
job.setState(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR);
Log.e(TAG, "Can't run command on a closed socket.");
}
} else
// log not new job
Log.e(TAG,
"Job state was not new, so it shouldn't be in queue. BUG ALERT!");
} catch (InterruptedException i) {
Thread.currentThread().interrupt();
} catch (UnsupportedCommandException u) {
if (job != null) {
job.setState(ObdCommandJob.ObdCommandJobState.NOT_SUPPORTED);
}
Log.d(TAG, "Command not supported. -> " + u.getMessage());
} catch (IOException io) {
if (job != null) {
if(io.getMessage().contains("Broken pipe"))
job.setState(ObdCommandJob.ObdCommandJobState.BROKEN_PIPE);
else
job.setState(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR);
}
Log.e(TAG, "IO error. -> " + io.getMessage());
} catch (Exception e) {
if (job != null) {
job.setState(ObdCommandJob.ObdCommandJobState.EXECUTION_ERROR);
}
Log.e(TAG, "Failed to run command. -> " + e.getMessage());
}
ObdCommandJob job2 = job;
if(job2 !=null)
EventBus.getDefault().post(job2);
}
}
public void stopService() {
Log.d(TAG, "Stopping service..");
jobsQueue.clear();
isRunning = false;
if (sock != null)
// close socket
try {
sock.close();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
}
// kill service
stopSelf();
}
public boolean isRunning() {
return isRunning;
}
}.
This is Abstract Class where service method gets called from from Livefragment Class from serivceConnection().
public abstract class AbstractGatewayService extends RoboService {
private static final String TAG = AbstractGatewayService.class.getName();
private final IBinder binder = new AbstractGatewayServiceBinder();
protected Context ctx;
protected boolean isRunning = false;
protected Long queueCounter = 0L;
protected BlockingQueue<ObdCommandJob> jobsQueue = new LinkedBlockingQueue<>();
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
executeQueue();
} catch (InterruptedException e) {
t.interrupt();
}
}
});
protected LocalBroadcastManager broadcastManager;
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Creating service..");
final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
t.start();
Log.d(TAG, "Service created.");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Destroying service...");
t.interrupt();
broadcastManager = LocalBroadcastManager.getInstance(this);
Log.d(TAG, "Service destroyed.");
}
public boolean isRunning() {
return isRunning;
}
public boolean queueEmpty() {
return jobsQueue.isEmpty();
}
public void queueJob(ObdCommandJob job) {
queueCounter++;
Log.d(TAG, "Adding job[" + queueCounter + "] to queue..");
job.setId(queueCounter);
try {
jobsQueue.put(job);
Log.d(TAG, "Job queued successfully.");
} catch (InterruptedException e) {
job.setState(ObdCommandJob.ObdCommandJobState.QUEUE_ERROR);
Log.e(TAG, "Failed to queue job.");
}
}
public void setContext(Context c) {
ctx = c;
}
abstract protected void executeQueue() throws InterruptedException;
abstract public void startService() throws IOException;
abstract public void stopService();
public class AbstractGatewayServiceBinder extends Binder {
public AbstractGatewayService getService() {
return AbstractGatewayService.this;
}
}
}.
You are getting the exception because in class ObdGatewayService your class member mChatservice is not the same as mChatservice in class LiveFragment
They are just different member variables
mChatservice gets assigned like this in your Fragment
mChatService = new BluetoothChatService(getActivity(), mHandler);
You need to pass this reference to ObdGatewayService 's startService() like this where ever you are instantiating/invoking it:-
ObdGatewayService ogs;
....
ogs.startservice(mChatservice); // This is fragment's member reference
And in ObdGatewayService you have to assign it accordingly:-
public void startService(BluetoothChatService _mChatservice) throws IOException {
Log.d(TAG, "Starting service..");
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
mChatservice = _mChatservice //Assignment YOU ARE MISSING THIS
.......
.......
}

Is it possible to pass Chromcast connection info between Activities?

I am developing an app that connects to a Chromecast, everything works fine when I do it from one activity, the problem is, that I want that activity to be fullscreen with no action bar, and no soft buttons. I am achiving that, hiding them when the users connects to the Chromecast, but it would be better if the users connect from the first activity (with action bar) and then goes to the second activity and the magic occurs there. But I can't pass the session between the activities. I have follow this tutorial to make the communication with the chromecast but tried to change a little to make the 2 acitivites communication.
Of course I have tested it and it returns a NullPointerException.
ConnectionFailedListener.java
public class ConnectionFailedListener implements GoogleApiClient.OnConnectionFailedListener {
private String TAG;
private MyConnectionCallbacks myConnectionCB;
public ConnectionFailedListener(String _TAG)
{
this.TAG=_TAG;
}
private void setMyConnectionCallBack(MyConnectionCallbacks _ConnectionCallbacks)
{
this.myConnectionCB = _ConnectionCallbacks;
}
#Override
public void onConnectionFailed(ConnectionResult result)
{
Log.e(TAG, "onConnectionFailed ");
myConnectionCB.teardown();
}
}
Channel.java
public class EventChannel implements Cast.MessageReceivedCallback
{
private Context myContext;
private String TAG;
/**
* #return custom namespace
*/
public EventChannel(Context _context, String _TAG)
{
this.myContext = _context;
this.TAG = _TAG;
}
public String getNamespace()
{
return myContext.getString(R.string.namespace);
}
/*
* Receive message from the receiver app
*/
#Override
public void onMessageReceived(CastDevice castDevice, String namespace,String message)
{
Log.d(TAG, "onMessageReceived: " + message);
}
}
ConnectionCallbacks.java
public class MyConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks
{
private String TAG;
private Context myContext;
public CastDevice mSelectedDevice;
private GoogleApiClient mApiClient;
private boolean mWaitingForReconnect;
private EventChannel mEventChannel;
private String mSessionId;
private boolean mApplicationStarted;
private EventChannel myChannel;
public MyConnectionCallbacks(Context _context, String _TAG)
{
this.myContext=_context;
this.TAG = _TAG;
}
public void setApiClient(GoogleApiClient _newApiClient)
{
this.mApiClient = _newApiClient;
}
#Override
public void onConnected(Bundle connectionHint)
{
Log.d(TAG, "onConnected");
if (mApiClient == null)
{
// We got disconnected while this runnable was pending execution.
return;
}
try
{
if (mWaitingForReconnect)
{
mWaitingForReconnect = false;
// Check if the receiver app is still running
if ((connectionHint != null) && connectionHint.getBoolean(Cast.EXTRA_APP_NO_LONGER_RUNNING))
{
Log.d(TAG, "App is no longer running");
teardown();
}
else
{// Re-create the custom message channel
try
{
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,mEventChannel.getNamespace(),mEventChannel);
}
catch (IOException e)
{
Log.e(TAG, "Exception while creating channel", e);
}
}
}
else
{// Launch the receiver app because is connected
Cast.CastApi.launchApplication(mApiClient,myContext.getString(R.string.app_id), false).setResultCallback(
new ResultCallback<Cast.ApplicationConnectionResult>()
{
#Override
public void onResult(Cast.ApplicationConnectionResult result) {
Status status = result.getStatus();
Log.d(TAG,"ApplicationConnectionResultCallback.onResult: statusCode"+ status.getStatusCode());
if (status.isSuccess())
{
ApplicationMetadata applicationMetadata = result.getApplicationMetadata();
mSessionId = result.getSessionId();
String applicationStatus = result.getApplicationStatus();
boolean wasLaunched = result.getWasLaunched();
Log.d(TAG,"application name: "+ applicationMetadata.getName()
+ ", status: "+ applicationStatus
+ ", sessionId: "+ mSessionId
+ ", wasLaunched: "+ wasLaunched);
mApplicationStarted = true;
// Create the custom message channel
mEventChannel = new EventChannel(myContext,TAG);
try
{
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,mEventChannel.getNamespace(),mEventChannel);
}
catch (IOException e)
{
Log.e(TAG,"Exception while creating channel",e);
}
// set the initial instructions on the receiver
sendMessage("starting from mobile");
}
else
{
Log.e(TAG,"application could not launch");
teardown();
}
}
});
}
}
catch (Exception e)
{
Log.e(TAG, "Failed to launch application", e);
}
}
#Override
public void onConnectionSuspended(int cause)
{
Log.d(TAG, "onConnectionSuspended");
mWaitingForReconnect = true;
}
public void sendMessage(String message)
{
if (mApiClient != null && mEventChannel != null)
{
try
{
Cast.CastApi.sendMessage(mApiClient,mEventChannel.getNamespace(), message)
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(Status result)
{
if (!result.isSuccess())
{
Log.e(TAG, "Sending message failed");
}
}
});
}
catch (Exception e)
{
Log.e(TAG, "Exception while sending message", e);
}
}
else
{
Toast.makeText(myContext, message, Toast.LENGTH_SHORT).show();
}
}
public void teardown()
{
Log.d(TAG, "teardown");
if (mApiClient != null)
{
if (mApplicationStarted)
{
if (mApiClient.isConnected() || mApiClient.isConnecting())
{
try
{
Cast.CastApi.stopApplication(mApiClient, mSessionId);
if (myChannel != null)
{
Cast.CastApi.removeMessageReceivedCallbacks(mApiClient,myChannel.getNamespace());
myChannel = null;
}
}
catch (IOException e)
{
Log.e(TAG, "Exception while removing channel", e);
}
mApiClient.disconnect();
}
mApplicationStarted = false;
}
mApiClient = null;
}
mSelectedDevice = null;
mWaitingForReconnect = false;
mSessionId = null;
}
}
MediaRouterCallback.java
public class MyMediaRouterCallback extends MediaRouter.Callback {
private GoogleApiClient mApiClient;
private Cast.Listener mCastListener;
private Context myContext;
private ConnectionFailedListener mConnectionFailedListener;
public MyConnectionCallbacks mConnectionCallbacks;
public String TAG;
//private String mSessionId;
public MyMediaRouterCallback(Context _context, String _TAG)
{
this.myContext = _context;
this.TAG = _TAG;
mConnectionCallbacks = new MyConnectionCallbacks(myContext,TAG);
}
#Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
Log.d(TAG, "onRouteSelected");
mConnectionCallbacks.mSelectedDevice = CastDevice.getFromBundle(info.getExtras());
launchReceiver();
}
#Override
public void onRouteUnselected(MediaRouter router, MediaRouter.RouteInfo info) {
Log.d(TAG, "onRouteUnselected: info=" + info);
mConnectionCallbacks.teardown();
mConnectionCallbacks.mSelectedDevice = null;
}
private void launchReceiver()
{
try
{
mCastListener = new Cast.Listener() {
#Override
public void onApplicationDisconnected(int errorCode) {
Log.d(TAG, "application has stopped");
mConnectionCallbacks.teardown();
}
};
//Constructors for Google Play Services Connection
//mConnectionCallbacks = new MyConnectionCallbacks(myContext,TAG);
mConnectionFailedListener = new ConnectionFailedListener(TAG);
Cast.CastOptions.Builder apiOptionsBuilder =
Cast.CastOptions.builder(mConnectionCallbacks.mSelectedDevice, mCastListener);
// ApiClient to Connect to Google Play services
mApiClient = new GoogleApiClient.Builder(myContext)
.addApi(Cast.API, apiOptionsBuilder.build())
.addConnectionCallbacks(mConnectionCallbacks)
.addOnConnectionFailedListener(mConnectionFailedListener)
.build();
mConnectionCallbacks.setApiClient(mApiClient);//setting ApiClient to achieve sendMessage
//Connect to Google Play services
mApiClient.connect();
}
catch (Exception e)
{
Log.e(TAG, "Failed launchReceiver", e);
}
}
}
FirstActivity (where the chromecast is connected)
public class ConnectCastActivity extends ActionBarActivity {
private static final String TAG = ConnectCastActivity.class.getSimpleName();
private MediaRouter mMediaRouter;
private MediaRouteSelector mMediaRouteSelector;
private MediaRouter.Callback mMediaRouterCallback;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar actionBar = getSupportActionBar();
actionBar.setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));
setContentView(R.layout.activity_connect_cast);
// Configure Cast device discovery
mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mMediaRouteSelector = new MediaRouteSelector.Builder().addControlCategory(CastMediaControlIntent.categoryForCast(getResources().getString(R.string.app_id))).build();
mMediaRouterCallback = new MyMediaRouterCallback(getApplicationContext(),TAG);
TextView myTextView = (TextView)findViewById(R.id.txt_helloworld);
myTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(),MainActivity.class);
startActivity(i);
}
});
}
#Override
protected void onStart() {
super.onStart();
// Start media router discovery
mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
}
#Override
protected void onStop() {
// End media router discovery
Log.w(TAG, "onStop");
//mMediaRouter.removeCallback(mMediaRouterCallback);
super.onStop();
}
#Override
public void onDestroy() {
Log.w(TAG, "onDestroy");
// mMediaRouterCallback.onRouteUnselected(mMediaRouter,null);
super.onDestroy();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu_connect_cast, menu);
MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
MediaRouteActionProvider mediaRouteActionProvider = (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem);
// Set the MediaRouteActionProvider selector for device discovery.
mediaRouteActionProvider.setRouteSelector(mMediaRouteSelector);
return true;
}
}
SecondActivity (the one that will send the message)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MediaRouter mMediaRouter = MediaRouter.getInstance(getApplicationContext());
mConnectionCallbacks = new MyConnectionCallbacks(getApplicationContext(),TAG);
setContentView(R.layout.activity_main);
//What should I put here?
}
If you have an application with multiple activities, you are better off if you do not tie the cast connectivity and related states to any of those activities, instead you can have a singleton, or use your Application instance or use a background service or ... to maintain the connection and access the required pieces that are maintained in that global place. If it fits your requirement, you might want to use the CastCompanionLibrary that already does most of the routine stuff for you; if not, you can take a look at it and the see how the CastVideos sample app uses that and try to do something similar for your application.

Categories

Resources