How I can kill this service:
private void startService(Class<?> service, ServiceConnection serviceConnection, Bundle extras) {
if (!UsbService.SERVICE_CONNECTED) {
Intent startService = new Intent(this, service);
if (extras != null && !extras.isEmpty()) {
Set<String> keys = extras.keySet();
for (String key : keys) {
String extra = extras.getString(key);
startService.putExtra(key, extra);
}
}
startService(startService);
}
Intent bindingIntent = new Intent(this, service);
bindService(bindingIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
I try do this :
Intent intent = new Intent(MainMenu.this, UsbService.class);
stopService(intent);
But the service works all the time.''
And this is my service :
public class UsbService extends Service {
public static final String ACTION_USB_READY = "pl.gps.connectivityservices.USB_READY";
public static final String ACTION_USB_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED";
public static final String ACTION_USB_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED";
public static final String ACTION_USB_NOT_SUPPORTED = "pl.gps.usbservice.USB_NOT_SUPPORTED";
public static final String ACTION_NO_USB = "pl..gps.usbservice.NO_USB";
public static final String ACTION_USB_PERMISSION_GRANTED = "pl.gps.usbservice.USB_PERMISSION_GRANTED";
public static final String ACTION_USB_PERMISSION_NOT_GRANTED = "pl.gps.usbservice.USB_PERMISSION_NOT_GRANTED";
public static final String ACTION_USB_DISCONNECTED = "pl.gps.usbservice.USB_DISCONNECTED";
public static final String ACTION_CDC_DRIVER_NOT_WORKING = "pl.gps.connectivityservices.ACTION_CDC_DRIVER_NOT_WORKING";
public static final String ACTION_USB_DEVICE_NOT_WORKING = "pl.gps.connectivityservices.ACTION_USB_DEVICE_NOT_WORKING";
public static final int MESSAGE_FROM_SERIAL_PORT = 1;
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
private static final int BAUD_RATE = 9600; // BaudRate. Change this value if you need
public static boolean SERVICE_CONNECTED = false;
private IBinder binder = new UsbBinder();
private Context context;
private Handler mHandler;
private UsbManager usbManager;
private UsbDevice device;
private UsbDeviceConnection connection;
private UsbSerialDevice serialPort;
private boolean serialPortConnected;
/*
* Data received from serial port will be received here. Just populate onReceivedData with your code
* In this particular example. byte stream is converted to String and send to UI thread to
* be treated there.
*/
String date = "";
public static boolean check(String s) {
if (s.contains("$GNRMC")) {
return true;
}
return false;
}
private UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() {
#Override
public void onReceivedData(byte[] arg0) {
try {
Thread.sleep(700);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
String data = new String(arg0, "UTF-8");
if (mHandler != null) {
mHandler.obtainMessage(MESSAGE_FROM_SERIAL_PORT, data).sendToTarget();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
};
private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context arg0, Intent arg1) {
if (arg1.getAction().equals(ACTION_USB_PERMISSION)) {
boolean granted = arg1.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
if (granted) // User accepted our USB connection. Try to open the device as a serial port
{
Intent intent = new Intent(ACTION_USB_PERMISSION_GRANTED);
arg0.sendBroadcast(intent);
connection = usbManager.openDevice(device);
serialPortConnected = true;
new ConnectionThread().run();
} else // User not accepted our USB connection. Send an Intent to the Main Activity
{
Intent intent = new Intent(ACTION_USB_PERMISSION_NOT_GRANTED);
arg0.sendBroadcast(intent);
}
} else if (arg1.getAction().equals(ACTION_USB_ATTACHED)) {
if (!serialPortConnected)
findSerialPortDevice(); // A USB device has been attached. Try to open it as a Serial port
} else if (arg1.getAction().equals(ACTION_USB_DETACHED)) {
// Usb device was disconnected. send an intent to the Main Activity
Intent intent = new Intent(ACTION_USB_DISCONNECTED);
arg0.sendBroadcast(intent);
serialPortConnected = false;
serialPort.close();
}
}
};
/*
* onCreate will be executed when service is started. It configures an IntentFilter to listen for
* incoming Intents (USB ATTACHED, USB DETACHED...) and it tries to open a serial port.
*/
#Override
public void onCreate() {
this.context = this;
serialPortConnected = false;
UsbService.SERVICE_CONNECTED = true;
setFilter();
usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
findSerialPortDevice();
}
/* MUST READ about services
* http://developer.android.com/guide/components/services.html
* http://developer.android.com/guide/components/bound-services.html
*/
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
UsbService.SERVICE_CONNECTED = false;
}
/*
* This function will be called from MainActivity to write data through Serial Port
*/
public void write(byte[] data) {
if (serialPort != null)
serialPort.write(data);
}
public void setHandler(Handler mHandler) {
this.mHandler = mHandler;
}
private void findSerialPortDevice() {
// This snippet will try to open the first encountered usb device connected, excluding usb root hubs
HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList();
HashMap<String, UsbDevice> usbDevices1 = new HashMap<String, UsbDevice>();
usbDevices1.clear();
if (!usbDevices.isEmpty()) {
boolean keep = true;
for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
device = entry.getValue();
int deviceVID = device.getVendorId();
int devicePID = device.getProductId();
if (deviceVID == 1659 && devicePID == 8963) {
// There is a device connected to our Android device. Try to open it as a Serial Port.
requestUserPermission();
keep = false;
if (!keep)
break;
}
}
if (!keep) {
// There is no USB devices connected (but usb host were listed). Send an intent to MainActivity.
Intent intent = new Intent(ACTION_NO_USB);
sendBroadcast(intent);
}
} else {
// There is no USB devices connected. Send an intent to MainActivity
Intent intent = new Intent(ACTION_NO_USB);
sendBroadcast(intent);
}
}
public void unReg(){
// if(usbReceiver != null)
// unregisterReceiver(usbReceiver);
}
private void setFilter() {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(ACTION_USB_DETACHED);
filter.addAction(ACTION_USB_ATTACHED);
registerReceiver(usbReceiver, filter);
}
private void requestUserPermission() {
PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(device, mPendingIntent);
}
public class UsbBinder extends Binder {
public UsbService getService() {
return UsbService.this;
}
}
private class ConnectionThread extends Thread {
#Override
public void run() {
serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
if (serialPort != null) {
if (serialPort != null && serialPort.open()) {
serialPort.setBaudRate(BAUD_RATE);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
serialPort.read(mCallback);
Intent intent = new Intent(ACTION_USB_READY);
context.sendBroadcast(intent);
} else {
if (serialPort instanceof CDCSerialDevice) {
Intent intent = new Intent(ACTION_CDC_DRIVER_NOT_WORKING);
context.sendBroadcast(intent);
} else {
Intent intent = new Intent(ACTION_USB_DEVICE_NOT_WORKING);
context.sendBroadcast(intent);
}
}
} else {
Intent intent = new Intent(ACTION_USB_NOT_SUPPORTED);
context.sendBroadcast(intent);
}
}
}
}
But my intent service steal is working. I try did whis when I destroyed my activity in which I created this service but when this activity is destroyed in logs I see that all the time this intent service is steel working
Try this
use stopSelf();
Once requested to stop with stopSelf() the system destroys the service as soon as possible.
pass some action with intent
Intent intent = new Intent(MainMenu.this, UsbService.class);
intent.setAction(Constants.ACTION.STOPTFOREGROUND_ACTION);
stopService(intent);
in your Service onStartCommand()
if(intent.getAction()==Constants.ACTION.STOPTFOREGROUND_ACTION){
stopForeground(true);
stopSelf();
}
public class Constants {
public interface ACTION {
String STOPFOREGROUND_ACTION = "com.package.packageName.action.stopforeground";
}
}
Related
This is my first app working with Bluetooth in Androind and I'm having a kinda unique problem: the bluetooth receiver isn't working on the device that is advertising the bluetooth service.
I have tested the application in 2 phones at the same time (I'll call them phone A and B to explain better). At first I start the advertising with the phone A, then I start the discovery with the phone B and finally I press the button in phone B to send data. This button should first start the Gatt connection and if it's working it should then broadcast a message that confirms the connection. To see it I have used a Log in the Broadcast receiver but the result I get is this messsagge appearing only in the logcat of the phone B but not on the one of phone A.
I have looked at a lot of examples and post on Stackoverflow but I can't seem to find the solution to this problem.
So I really can't find what the real problem here is. Maybe I'm just using badly the Bluetooth classes or I just lack knowledge. In any case, here there is all the code of the MainActivity as it is the only class of this simple project.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView mText;
private Button mAdvertiseButton;
private Button mDiscoverButton;
private Button mSendButton;
private String TAG = "INFOBLERESULTS";
private BluetoothLeScanner mBluetoothLeScanner;
private BluetoothDevice bluetoothDevice;
private Handler mHandler = new Handler();
private ScanCallback mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.d(TAG, result.getDevice().getAddress());
super.onScanResult(callbackType, result);
if( result == null
|| result.getDevice() == null
|| TextUtils.isEmpty(result.getDevice().getAddress()) )
return;
StringBuilder builder = new StringBuilder( result.getDevice().getAddress() );
builder.append("\n").append(result.getDevice().getName());
//builder.append("\n").append(new String(result.getScanRecord().getServiceData(result.getScanRecord().getServiceUuids().get(0)), Charset.forName("UTF-8")));
mText.setText(builder.toString());
bluetoothDevice = result.getDevice();
bluetoothLeService = new BluetoothLeService();
bluetoothLeService.setAddress(result.getDevice().getAddress());
}
#Override
public void onBatchScanResults(List<ScanResult> results) {
super.onBatchScanResults(results);
}
#Override
public void onScanFailed(int errorCode) {
Log.e( TAG, "Discovery onScanFailed: " + errorCode );
super.onScanFailed(errorCode);
}
};
private BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private boolean connected = false;
//Inner classes
class BluetoothLeService extends Service {
public final static String ACTION_GATT_CONNECTED =
"com.example.bluetooth.le.ACTION_GATT_CONNECTED";
public final static String ACTION_GATT_DISCONNECTED =
"com.example.bluetooth.le.ACTION_GATT_DISCONNECTED";
public final static String ACTION_GATT_SERVICES_DISCOVERED =
"com.example.bluetooth.le.ACTION_GATT_SERVICES_DISCOVERED";
public final static String ACTION_DATA_AVAILABLE =
"com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTED = 2;
private int connectionState;
public Context ctx;
protected BluetoothGatt bluetoothGatt;
protected final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.i(TAG, "GATT status = "+ status + " newState = " + newState);
if(status == BluetoothGatt.GATT_SUCCESS){
if (newState == BluetoothProfile.STATE_CONNECTED) {
// successfully connected to the GATT Server
connectionState = STATE_CONNECTED;
broadcastUpdate(ACTION_GATT_CONNECTED);
bluetoothGatt = gatt;
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
// disconnected from the GATT Server
connectionState = STATE_DISCONNECTED;
broadcastUpdate(ACTION_GATT_DISCONNECTED);
gatt.close();
}
}else{
gatt.close();
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(
BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status
) {
if (status == BluetoothGatt.GATT_SUCCESS) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
}
#Override
public void onCharacteristicChanged(
BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic
) {
broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
}
};
private Binder binder = new LocalBinder();
private String address = "";
public void setAddress(String address) {
this.address = address;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
private void close() {
if (bluetoothGatt == null) {
return;
}
bluetoothGatt.close();
bluetoothGatt = null;
}
public boolean connect() {
if (bluetoothAdapter == null || this.address == null || this.address.equals("")) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}
try {
final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(address);
bluetoothGatt = device.connectGatt(MainActivity.this.getApplicationContext(), false, gattCallback);
Log.d(TAG,"GATT "+ bluetoothGatt);
return true;
} catch (IllegalArgumentException exception) {
Log.w(TAG, "Device not found with provided address.");
return false;
}
}
private void broadcastUpdate(final String action) {
final Intent intent = new Intent(action);
Log.i(TAG, intent + "");
MainActivity.this.getApplicationContext().sendBroadcast(intent);
}
private void broadcastUpdate(final String action, BluetoothGattCharacteristic characteristic) {
final Intent intent = new Intent(action);
sendBroadcast(intent);
}
public List<BluetoothGattService> getSupportedGattServices() {
if (bluetoothGatt == null) return null;
return bluetoothGatt.getServices();
}
public void readCharacteristic(BluetoothGattCharacteristic characteristic) {
if (bluetoothGatt == null) {
Log.w(TAG, "BluetoothGatt not initialized");
return;
}
bluetoothGatt.readCharacteristic(characteristic);
}
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic,boolean enabled) {
if (bluetoothGatt == null) {
Log.w(TAG, "BluetoothGatt not initialized");
return;
}
bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
}
class LocalBinder extends Binder {
public BluetoothLeService getService() {
return BluetoothLeService.this;
}
}
}
private BluetoothLeService bluetoothLeService = new BluetoothLeService();
private final ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
bluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
if (bluetoothLeService != null) {
if (!bluetoothAdapter.isEnabled()) {
Log.e(TAG, "Unable to initialize Bluetooth");
}
else{
bluetoothLeService.connect();
Log.i(TAG, "Service connected");
}
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
bluetoothLeService = null;
}
};
private final BroadcastReceiver gattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
Log.d(TAG, "RECEIVED " + action);
if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
connected = true;
//Log.d(TAG, "CONNECTED");
} else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
connected = false;
//Log.d(TAG, "DISCONNECTED");
}
}
};
private final ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
Log.i("RESULT", result.getResultCode() + "");
setup();
}
});
private void setup() {
bluetoothLeService.ctx = this.getApplicationContext();
Log.d("APPLICATIONCONTEXT", bluetoothLeService.ctx + "");
mDiscoverButton.setOnClickListener(this);
mAdvertiseButton.setOnClickListener(this);
mSendButton.setOnClickListener(this);
mBluetoothLeScanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
if (!BluetoothAdapter.getDefaultAdapter().isMultipleAdvertisementSupported()) {
Toast.makeText(this, "Multiple advertisement not supported", Toast.LENGTH_SHORT).show();
mAdvertiseButton.setEnabled(false);
mDiscoverButton.setEnabled(false);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull #org.jetbrains.annotations.NotNull String[] permissions, #NonNull #org.jetbrains.annotations.NotNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 2) {
final LocationManager manager = (LocationManager) getSystemService( Context.LOCATION_SERVICE );
if(!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)){
Intent enableLocationIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
someActivityResultLauncher.launch(enableLocationIntent);
}
else{
setup();
}
}
}
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mText = (TextView) findViewById( R.id.text );
mDiscoverButton = (Button) findViewById( R.id.discover_btn );
mAdvertiseButton = (Button) findViewById( R.id.advertise_btn );
mSendButton = (Button) findViewById( R.id.send_btn );
this.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 2);
}
#Override
protected void onResume() {
super.onResume();
MainActivity.this.getApplicationContext().registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter());
}
#Override
protected void onPause() {
super.onPause();
MainActivity.this.getApplicationContext().unregisterReceiver(gattUpdateReceiver);
}
#Override
public void onClick(View v) {
Log.d(TAG, getString( R.string.ble_uuid ));
if( v.getId() == R.id.discover_btn ) {
discover();
} else if( v.getId() == R.id.advertise_btn ) {
advertise();
//MainActivity.this.getApplicationContext().registerReceiver(gattUpdateReceiver, makeGattUpdateIntentFilter());
} else if (v.getId() == R.id.send_btn){
//MainActivity.this.getApplicationContext().unregisterReceiver(gattUpdateReceiver);
send();
}
}
public void advertise(){
BluetoothLeAdvertiser advertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
AdvertiseSettings settings = new AdvertiseSettings.Builder().setTimeout(0)
.setAdvertiseMode( AdvertiseSettings.ADVERTISE_MODE_BALANCED )
.setTxPowerLevel( AdvertiseSettings.ADVERTISE_TX_POWER_HIGH )
.setConnectable( true )
.build();
ParcelUuid pUuid = ParcelUuid.fromString( getString( R.string.ble_uuid ) ) ;
AdvertiseData data = new AdvertiseData.Builder()
.addServiceUuid( pUuid ).setIncludeDeviceName(false)
.build();
AdvertiseCallback advertisingCallback = new AdvertiseCallback() {
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
Log.d(TAG, "START ADVERTISING");
super.onStartSuccess(settingsInEffect);
}
#Override
public void onStartFailure(int errorCode) {
Log.e( TAG, "Advertising onStartFailure: " + errorCode );
super.onStartFailure(errorCode);
}
};
advertiser.startAdvertising( settings, data, advertisingCallback );
}
public void discover(){
ScanFilter filter = new ScanFilter.Builder()
.setServiceUuid( ParcelUuid.fromString( getString(R.string.ble_uuid ) ) )
.build();
List<ScanFilter> filters = new ArrayList<>();
filters.add( filter );
ScanSettings settings = new ScanSettings.Builder()
.setScanMode( ScanSettings.SCAN_MODE_BALANCED )
.build();
mBluetoothLeScanner.startScan(filters, settings, mScanCallback);
Log.d(TAG, "Discovery started");
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
Log.d(TAG, "Discovery stopped");
mBluetoothLeScanner.stopScan(mScanCallback);
}
}, 10000);
}
public void send(){
Log.d(TAG, "START CONNECTIONG GATT");
mBluetoothLeScanner.stopScan(mScanCallback);
//boundGatt();
connectGatt();
}
public void boundGatt(){
Intent gattServiceIntent = new Intent(MainActivity.this.getApplicationContext(), BluetoothLeService.class);
bindService(gattServiceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
public void connectGatt(){
bluetoothLeService.connect();
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE);
return intentFilter;
}
}
Your Peripheral (phone A) does only advertisement, but BluetoothGattServer is not set up. That could be a reason of the described behavior - advertisement & scanning work, but connection doesn't.
BluetoothGatt + BluetoothGattCallback are for Central role (you call it phone B).
BluetoothGattServer + BluetoothGattServerCallback are for Peripheral (phone A).
Notes:
Connection from Central side (phone B) looks good, because when advertised device found, you get it using bluetoothAdapter.getRemoteDevice(address), then you call device.connectGatt
To transfer some data, you will need to add BluetoothGattService with BluetoothGattCharacteristic to your BluetoothGattServer - example of setup in Kotlin
Example project on github: BLEProof - it's in Kotlin, 2 apps communicate with each other: Central and Peripheral, all code in MainActivity.kt
I am quite proficient with programming in general but new to android. I am trying to send a string to a Bluetooth module from the app with an alarm trigger. I am able to send this string with click event but when the same function is invoked with an alarm trigger the Bluetooth module receives the null string. I believe the problem occurs when the value is getting written when the alarm is triggered. Any ideas to solve the problem will be appreciated. Please let me know if the framing of the problem is not clear as I am still new I am not familiar with the jargons.
public static final String TAG = "MyAPP";
private static final int UART_PROFILE_CONNECTED = 20;
private static final int UART_PROFILE_DISCONNECTED = 21;
private int mState = UART_PROFILE_DISCONNECTED;
UartService mService = new UartService();
TimePicker timePicker;
public Button s1,s2,s3,s4,s5;
public Data1()
{
sample();
}
private void sample() {
Log.e(TAG, "Working");
String value = "5";
//send data to service
// value = message.getBytes("UTF-8");
Log.d(TAG, "ByteValue(Data5) = " + value);
UartService mService = new UartService();
mService.WritetoTimer(value);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(activity_main2);
service_init();
s1=findViewById(R.id.Data1);
s2=findViewById(R.id.Data2);
s3=findViewById(R.id.Data3);
s4=findViewById(R.id.Data4);
s5=findViewById(R.id.Data5);
s5.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String message = "5";
byte[] value;
try {
//send data to service
value = message.getBytes("UTF-8");
Log.d(TAG, "ByteValue(Data5) = " + value);
mService.writeRXCharacteristic(value);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
//UART service connected/disconnected
public ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder rawBinder) {
UartService mService = new UartService();
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) {
UartService mService = new UartService();
mService = null;
}
};
#SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
#Override
//Handler events that received from UART service
public void handleMessage(Message msg) {
}
};
public final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
assert action != null;
if (action.equals(UartService.ACTION_GATT_CONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "UART_CONNECT_MSG");
mState = UART_PROFILE_CONNECTED;
}
});
}
if (action.equals(UartService.ACTION_GATT_DISCONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "UART_DISCONNECT_MSG");
mState = UART_PROFILE_DISCONNECTED;
mService.close();
}
});
}
//*********************//
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);
runOnUiThread(new Runnable() {
public void run() {
try {
String text = new String(txValue, "UTF-8");
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
});
}
//*********************//
if (action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_UART)) {
showMessage("Device doesn't support UART. Disconnecting");
mService.disconnect();
}
}
};
public void service_init() {
Intent bindIntent = new Intent(this, UartService.class);
bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
LocalBroadcastManager.getInstance(this).registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter());
}
public 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_UART);
return intentFilter;
}
#Override
public void onStart() {
service_init();
super.onStart();
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(UARTStatusChangeReceiver);
} catch (Exception ignore) {
Log.e(TAG, ignore.toString());
}
I am trying to send a broadcast receiver from a service and i have a issue, the receiver leak and i don't know why.
Here is the code:
public class CameraCapture extends AppCompatActivity {
static final int REQUEST_IMAGE_CAPTURE = 30;
String URL;
VolleyService mVolleyService;
IResult mResultCallback = null;
final String POSTREQUEST = "POSTCALL";
Map<String, String> params;
String token;
BroadcastReceiver receiver;
IntentFilter filter;
MyReceiver reciver;
boolean mBounded;
GoogleLocation mlocation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
token = checkForToken();
URL = "http://10.0.2.2:3000/fotos/Tulipa";
filter = new IntentFilter("com.myapp.LOCATION_CHANGED");
reciver = new MyReceiver();
registerReceiver(reciver,filter);
String imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/picture.jpg";
File imageFile = new File(imageFilePath);
Uri imageFileUri = Uri.fromFile(imageFile); // convert path to Uri
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_IMAGE_CAPTURE);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);
}
}
#Override
protected void onStart() {
super.onStart();
Intent mIntent = new Intent(this, GoogleLocation.class);
bindService(mIntent, mConnection, BIND_AUTO_CREATE);
}
public void onResume() {
super.onResume();
Log.d("RESUME","RESUME");
reciver = new MyReceiver();
registerReceiver(reciver, filter);
}
public void onPause() {
super.onPause();
if(reciver != null){
unregisterReceiver(reciver);
reciver= null;
}
}
public void onStop() {
super.onStop();
if(mBounded) {
unbindService(mConnection);
mBounded = false;
}
}
private byte[] encodeImage(Bitmap bm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
return b;
}
private void sendImage(byte[] b) {
ImageStore.getInstance().setCapturedPhotoData(b);
mlocation.getBroadcastData();
Intent i = new Intent(CameraCapture.this, SimiliarPhotos.class);
startActivity(i);
finish();
//inicialize a map with pair key value
//params = new HashMap<String, String>();
// Add form fields to the map
//GoogleLocation l = new GoogleLocation(this);
//l.getPosition();
//Log.d("myLat",String.valueOf(l.getLat()));
//params.put("base64", encodedImage);
//params.put("token",token);
//Log.d("latitudeOP",String.valueOf(l.getLat()));
//JSONObject sendObj = new JSONObject(params);
//initVolleyCallback();
//mVolleyService = new VolleyService(mResultCallback, this);
//mVolleyService.postDataVolley(POSTREQUEST, URL, sendObj);
}
public void showToast(String message) {
Toast toast = Toast.makeText(this, message, Toast.LENGTH_LONG);
toast.show();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 30: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(CameraCapture.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
}
return;
}
}
}
void initVolleyCallback() {
mResultCallback = new IResult() {
#Override
public void notifySuccess(String requestType, JSONObject response) {
}
#Override
public void notifySuccess(String requestType, JSONArray response) {
}
#Override
public void notifyError(String requestType, VolleyError error) {
String body;
if (error.networkResponse.data != null) {
String statusCode = String.valueOf(error.networkResponse.statusCode);
try {
body = new String(error.networkResponse.data, "UTF-8");
JSONObject jsonObj = new JSONObject(body);
Log.d("body", String.valueOf(jsonObj.get("message")));
showToast(String.valueOf(jsonObj.get("message")));
} catch (UnsupportedEncodingException e) {
showToast("You need to connect to the internet!");
} catch (JSONException e) {
Log.d("json:", "problems decoding jsonObj");
}
}
}
};
}
ServiceConnection mConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
mBounded = false;
mlocation = null;
}
public void onServiceConnected(ComponentName name, IBinder service) {
mBounded = true;
GoogleLocation.LocalBinder mLocalBinder = (GoogleLocation.LocalBinder)service;
mlocation = mLocalBinder.getServerInstance();
}
};
as you guys can see i register the receiver 2 times, oncreate and onResume, and then i destroy it onStop.
The problem is you are registering it twice. remove the code from onCreate and keep it only in onResume. Also if you are registering it in onResume then unRegister it in onPause to match the lifecycle events properly.
Always register receiver in onStart() and unregister in onStop().
Since you registering receiver in onCreate(), you have to unregister in onDestroy() as well as there is a chance that activity ends up with only onCreate() and onDestroy() call backs.
Do not forget to unregister a dynamically registered receiver by using Context.unregisterReceiver() method. If you forget this, the Android system reports a leaked broadcast receiver error. For instance, if you registered a receive in onResume() methods of your activity, you should unregister it in the onPause() method.
I am developing mobile app which working with sensor, that use UART. Example from official github page works perfect, but code extracted from doesnt work. Only thing that i have changed, is a device search, but this code works perfect with Polar H7 device(only discovering device name and device adress and sending to next activity). On this activity i am trying to connect to UART device, here is code :
public class UartRecordingActivity extends AppCompatActivity {
private final static String TAG = UartRecordingActivity.class.getSimpleName();
// BLE stuff
public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
//private BleService bleService;
private String deviceName;
private String deviceAddress;
//private BleServicesAdapter gattServiceAdapter;
private boolean isConnected = false;
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;
private static final int UART_PROFILE_DISCONNECTED = 21;
private static final int STATE_OFF = 10;
private int mState = UART_PROFILE_DISCONNECTED;
private UartService mService = null;
private BluetoothDevice mDevice = null;
private BluetoothAdapter mBtAdapter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recording_uart);
Log.i(TAG, "onCreate");
final Intent intent = getIntent();
deviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
deviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
final Intent gattServiceIntent = new Intent(this, UartService.class);
bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
}
#Override
protected void onStart() {
super.onStart();
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
service_init();
mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceAddress);
mService.connect(deviceAddress);
}
private void service_init() {
Intent bindIntent = new Intent(this, UartService.class);
bindService(bindIntent, mServiceConnection, BIND_AUTO_CREATE);
LocalBroadcastManager.getInstance(this).registerReceiver(UARTStatusChangeReceiver,
makeGattUpdateIntentFilter());
}
//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 = null;
}
};
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
if (menuItem.getItemId() == android.R.id.home) {
Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(menuItem);}
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
#Override
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, "UART_CONNECT_MSG");
mState = UART_PROFILE_CONNECTED;
}
});
}
//*********************//
if (action.equals(UartService.ACTION_GATT_DISCONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
String currentDateTimeString = DateFormat.getTimeInstance().format(new Date());
Log.d(TAG, "UART_DISCONNECT_MSG");
mState = UART_PROFILE_DISCONNECTED;
mService.close();
}
});
}
//*********************//
if (action.equals(UartService.ACTION_GATT_SERVICES_DISCOVERED)) {
mService.enableTXNotification();
}
//*********************//
if (action.equals(UartService.ACTION_DATA_AVAILABLE)) {
Log.i("data","received");
final byte[] txValue = intent.getByteArrayExtra(UartService.EXTRA_DATA);
//handle data
}
//*********************//
if (action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_UART)) {
}
}
};
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_UART);
return intentFilter;
}
}
Error is caused by this line(mService causing NullPointerException):
mService.connect(deviceAddress);
Method OnServiceConnected is guarantees that you have been connected to service by binding. In OnStart callback you have NullPointer because when you call bindService, it needs a little time to make a connection. Just make your code something like that:
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();
}
mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceAddress);
mService.connect(deviceAddress);
}
I'm developing an Android chat app in Java. Now I finally got my service to work but as soon as I fully kill the app the connection in my service dies.
I am using asmack as library for the XMPP connection. The goal is to receive messages even if the app is killed by the user (so it's not in the background).
It does work when I use a foreground service, but I don't want to use a foreground service because of high memory useage and because I don't want the foreground message in the notification center.
My service class
public class MessagingService extends Service {
private final String TAG = "MessagingService";
private final IBinder mBinder = new MessagingBinder();
public Context context;
public XMPPConnection Connection;
public static Handler mHandler = new Handler();
private final int ONGOING_NOTIFICATION_ID = 2344;
#Override
public void onCreate() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "onUnbind");
return true;
}
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
Log.d(TAG, "onRebind");
}
#Override
public void onDestroy() {
}
public class MessagingBinder extends Binder {
MessagingService getService() {
Log.d(TAG + " - MessagingBinder", "getService");
return MessagingService.this;
}
}
public Boolean isConnected() {
return (Connection != null);
}
public void Connect(final AuthorizeActivity authorize, final String username, final String password) {
Thread XMPPConnect = new Thread(new Runnable() {
public final String TAG = "XMPPConnect Thread";
#Override
public void run() {
AndroidConnectionConfiguration connConfig = new AndroidConnectionConfiguration(Configuration.HOST, Configuration.PORT, Configuration.SERVICE);
SmackConfiguration.setDefaultPingInterval(100);
connConfig.setReconnectionAllowed(true);
connConfig.setSASLAuthenticationEnabled(true);
connConfig.setRosterLoadedAtLogin(true);
Connection = new XMPPConnection(connConfig);
try {
Connection.connect();
Log.i(TAG, "Connected to " + Connection.getHost());
} catch (XMPPException ex) {
Log.e(TAG, "Failed to connect to " + Connection.getHost());
Log.e(TAG, ex.toString());
Connection = null;
}
if(authorize != null)
authorize.mServiceConnectCallback();
if(username != null && password != null)
Login(username, password, null);
}
});
XMPPConnect.start();
}
public void Login(final String username, final String password, final AuthorizeActivity authorize) {
Thread XMPPLogin = new Thread(new Runnable() {
public final String TAG = "XMPPConnect Thread";
#Override
public void run() {
try {
Connection.login(username, password);
Log.i(TAG, "Logged in as " + Connection.getUser());
Presence presence = new Presence(Presence.Type.available);
Connection.sendPacket(presence);
PacketFilter filter = new MessageTypeFilter(Message.Type.chat);
Connection.addPacketListener(new PacketListener() {
#Override
public void processPacket(Packet packet) {
final Message message = (Message) packet;
if (message.getBody() != null) {
final String fromName = StringUtils.parseName(message.getFrom());
Log.i(TAG, "Text Recieved " + message.getBody() + " from " + fromName );
mHandler.post(new Runnable() {
public void run() {
Receiver.recieveMessage(fromName, message.getBody());
if(!VisibilityHelper.IsVisible()) {
showNotification(fromName, message.getBody());
}
}
});
}
}
}, filter);
} catch (XMPPException ex) {
Log.e(TAG, "Failed to log in as " + "test");
Log.e(TAG, ex.toString());
Connection = null;
}
if(authorize != null)
authorize.mServiceLoginCallback();
}
});
XMPPLogin.start();
}
public void showNotification(String from, String message) {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
CharSequence notiText = message;
long meow = System.currentTimeMillis();
Notification notification = new Notification(R.drawable.ic_launcher, notiText, meow);
Context context = getApplicationContext();
CharSequence contentTitle = from;
CharSequence contentText = message;
Intent notificationIntent = new Intent(context, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
notification.flags = Notification.DEFAULT_LIGHTS | Notification.FLAG_AUTO_CANCEL;
int SERVER_DATA_RECEIVED = 1;
notificationManager.notify(SERVER_DATA_RECEIVED, notification);
}
public void Logout() {
if(Connection.isConnected()) {
Log.i(TAG, "Logout");
Connection.disconnect();
}
}
public HashMap<String, String> getVCard(String user) {
Log.d(TAG, "getVCard");
//String email = user + "#" + Configuration.HOST;
String email = user;
VCard card = new VCard();
ProviderManager.getInstance().addIQProvider("vCard", "vcard-temp", new VCardProvider());
try {
card.load(MainActivity.mService.Connection, email);
String jabber_id = card.getJabberId();
String firstname = card.getFirstName();
String middlename = card.getMiddleName();
String lastname = card.getLastName();
HashMap<String, String> vcard = new HashMap<String, String>();
vcard.put("jabber_id", jabber_id);
vcard.put("firstname", firstname);
vcard.put("middlename", middlename);
vcard.put("lastname", lastname);
return vcard;
} catch (XMPPException e) {
e.printStackTrace();
}
return null;
}
public void retrieveContactsFromList() {
if(this.isConnected()) {
Roster roster = Connection.getRoster();
Collection<RosterEntry> entries = roster.getEntries();
for(RosterEntry entry : entries) {
Receiver.onRetrieveContactFromList(entry);
}
}
}
}
My activity to start the service
public class ConnectionBinder extends FragmentActivity {
private final String TAG = "ConnectionBinder";
public static MessagingService mService;
public boolean mBound = false;
public Database DB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(!this.messagingServiceIsRunning())
{
startService(new Intent(this, MessagingService.class));
}
}
private boolean messagingServiceIsRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (MessagingService.class.getName().equals( service.service.getClassName())) {
return true;
}
}
return false;
}
#Override
protected void onResume() {
super.onResume();
doBindService();
}
#Override
protected void onPause() {
super.onPause();
doUnbindService();
}
private void doBindService() {
Intent intent = new Intent(this, MessagingService.class);
bindService(intent, mMessagingService, Context.BIND_AUTO_CREATE);
}
private void doUnbindService() {
if (mBound) {
unbindService(mMessagingService);
}
}
private void doXMPPLogin() {
HashMap<String, String> user = DB.getUser();
mService.Connect(null, user.get("username"), user.get("password"));
}
private ServiceConnection mMessagingService = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d(TAG, "mMessagingService.onServiceConnected()");
MessagingBinder binder = (MessagingBinder) service;
mService = binder.getService();
mBound = true;
if(!mService.isConnected()) {
doXMPPLogin();
}
mService.retrieveContactsFromList();
}
public void onServiceDisconnected(ComponentName arg0) {
Log.d(TAG, "mMessagingService.onServiceDisconnected()");
mBound = false;
}
};
}
Traditional XMPP implementations (and XMPP RFCs) does not define a way to maintain persistent user "sessions" when client disconnects - they all closing user session when underlying TCP/IP or HTTP connection is lost.
On the other hand, typical Android enviroment have "always-connected" Google Cloud Services, which can deliver messages for your application even if it is not connected. In fact, most chat and social networking applications are using GCM to inform user about new messages.
So, depend on your needs, you need to make some changes on the server side of your chat application:
Most XMPP server implementations are able to store messages which was received when user was "offline" and delivers it when user connects again. You can "hook" offline message receiving and inform user via Google Cloud Messaging about availability of new messages, user will receive it when open your application again and your XMPPConnection will established.
Use XMPP Stream Management extension - if you need to share same session across multiple user reconnections - and "resume" previous session when user open your app again. And you still should inform user about new events in his "session" via GCM.
Your server-side XMPP software should keep GCM registration ids for every user device, so when user device is registered in GCM - you need to inform your server about newly registered id - it can be achieved by sending custom <iq> packet to server with your GCM id.
Some commercial XMPP products already implement steps above and will sell you "Push-enabled XMPP service" which is in fact XMPP server with GCM backend, as I describe.