Broadcast receiver leaked - java

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.

Related

Android send data to broadcast receiver

I am creating an Android app that notify the users when they received a SMS from selected numbers using Foreground Service. The program only notify the user when the Service is running. My Main Activity has 3 buttons: Start Service, Stop Service and Setting which lead to another Activity that let the user change their information such as password and selected number. Currently the application can read and write data to JSON fine and the data get pass to other activities through Intent, also the Broadcast Receiver for detecting SMS also work when a message in received, and since I want it to work with Foreground Service, I register it in onStartCommand and unregister it in onDestroy in the Service and not register it in Manifest. My problem is on how to pass the user data to the Broadcast Receiver, since it is register to listen to android.provider.Telephony.SMS_RECEIVED and when I try to pass Intent to it through sentBroadcast() in my Service, it does not receive any value of the user. I tried to settle in making the user public static and it worked, but not sure if this the right way to do it. Here is my current code:
MainActivity.java
Button btnStartService, btnStopService;
TextView lblStatus;
JSONHandler jsonHandler;//for handling JSON file and data
public static User user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStartService = findViewById(R.id.buttonStartService);
btnStopService = findViewById(R.id.buttonStopService);
jsonHandler = new JSONHandler(this);
boolean isFilePresent = isFilePresent(this, "user.json");
if(isFilePresent) {
try {
user = jsonHandler.readFromFile();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} else {
user = new User();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestSmsPermission();
requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE,READ_EXTERNAL_STORAGE}, 1);
}
else {
startService();
}
}
public boolean isFilePresent(Context context, String fileName) {
String path = context.getFilesDir().getAbsolutePath() + "/" + fileName;
File file = new File(path);
return file.exists();
}
public void setBtnStartService(View view)
{
startService();
}
public void setBtnStopService(View view)
{
stopService();
}
public void startService() {
Intent serviceIntent = new Intent(this, ForegroundService.class);
serviceIntent.putExtra("inputExtra", "Message Service is running");
serviceIntent.putExtra("user", user);
ContextCompat.startForegroundService(this, serviceIntent);
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
}
public void stopService() {
Intent serviceIntent = new Intent(this, ForegroundService.class);
stopService(serviceIntent);
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
public void setBtnSetting(View view) {
Intent intent = new Intent(this, AuthenticateActivity.class);
intent.putExtra("user", user);
intent.putExtra("action", "setting");
startActivity(intent);
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == 1) {
startService();
}
}
private void requestSmsPermission() {
String permission = Manifest.permission.RECEIVE_SMS;
int grant = ContextCompat.checkSelfPermission(this, permission);
if ( grant != PackageManager.PERMISSION_GRANTED) {
String[] permission_list = new String[1];
permission_list[0] = permission;
ActivityCompat.requestPermissions(this, permission_list, 1);
}
}
ForegroundService.java
public class ForegroundService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
SMSReceiver smsListener;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
User user = (User) intent.getSerializableExtra("user");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
//do heavy work on a background thread
if(smsListener == null)
{
smsListener = new SMSReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
Intent i = new Intent(this, SMSReceiver.class);
i.putExtra("user", user);
sendBroadcast(i);
registerReceiver(smsListener, intentFilter);
}
//stopSelf();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
if(null!=smsListener)
{
unregisterReceiver(smsListener);
smsListener = null;
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
SMSReceiver.java
public class SMSReceiver extends BroadcastReceiver {
private String msgBody;
private String text = "";
private SharedPreferences preferences;
private String sender = "";
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// User user = (User) intent.getExtras().getSerializable("user"); not working
User user = MainActivity.user;
ArrayList<String> banks = user.getBankList();
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
Toast.makeText(context, "message received", Toast.LENGTH_SHORT).show();
Bundle bundle = intent.getExtras();
try {
if (bundle != null) {
final Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage smsMessage;
for (int i = 0; i < pdus.length; i++) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i], bundle.getString("format"));
else smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
msgBody = smsMessage.getMessageBody();
sender = smsMessage.getOriginatingAddress();
if(banks.contains(sender)) {
if (msgBody.contains(user.getPattern())) {
String[] tokens = msgBody.split(" ");
for (int j = 0; j < tokens.length; j++) {
if (tokens[j].contains("API")) {
text = tokens[j];
break;
}
}
}
}
}
//MainActivity.message = msgBody;
if(!text.isEmpty()) {
Toast.makeText(context, "message is: " + text, Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
Log.d("Exception caught", e.getMessage());
}
}
else {
Log.i("cs.fsu", "smsReceiver : NULL");
}
}
}
Is this the right way to maintain user data throughout the application lifecycle? By making public static for every class accessible? Or is there away to pass it through Intent? Please help me out

device list not showing in one plus 6 connected via bluetooth

Hi in the below code displaying the devices near by via bluetooth.
The below code was working fine for every device except one plus 6 phone.
I found a bug in the one plus 6 phone. If we turn on bluetooth and location then list of the near devices are listed.
can any one help me how to reslove the bug especially on one plus phones.
public class DeviceScanActivity extends AppCompatActivity {
private static final String TAG = DeviceScanActivity.class.getSimpleName();
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
#Bind(R.id.back)
TextView mBack;
#Bind(R.id.refresh)
TextView mRefresh;
#Bind(R.id.toolBar)
Toolbar mToolBar;
#Bind(R.id.scan_status)
TextView mScanStatus;
#Bind(R.id.deviceListView)
RecyclerView mDeviceListView;
#Bind(R.id.scanningProgress)
ProgressBar mScanningProgress;
private DeviceListAdapter mAdapter;
private BleService mBleService;
private List<BluetoothDevice> mBleDevices;
private SharedPreferences mPref;
private ProgressDialog mProgressDialog;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scan_device);
ButterKnife.bind(this);
mProgressDialog = new ProgressDialog(this);
mPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
initToolBar();
mBleDevices = new ArrayList<>();
mAdapter = new DeviceListAdapter(this);
mDeviceListView.setAdapter(mAdapter);
LinearLayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
mDeviceListView.setLayoutManager(manager);
mDeviceListView.addOnItemTouchListener(new RecyclerItemClickListener(this, new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, int position) {
showProgressDialog();
List<BluetoothDevice> bluetoothDevices = mAdapter.getBluetoothDevices();
if (bluetoothDevices != null) {
if (bluetoothDevices.size() > position) {
BluetoothDevice bluetoothDevice = bluetoothDevices.get(position);
if (bluetoothDevice != null) {
String address = bluetoothDevice.getAddress();
mBleService.connect(address);
}
}
}
}
}));
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BleService.ACTION_DEVICE_FOUND);
intentFilter.addAction(BleService.ACTION_GATT_CONNECTED);
intentFilter.addAction(BleService.ACTION_GAT_CONNECTING);
intentFilter.addAction(BleService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(BleService.ACTION_GAT_SERVICE_DISCOVERED);
registerReceiver(mGattUpdateReceiver, intentFilter);
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.BLUETOOTH,Manifest.permission.ACCESS_FINE_LOCATION
, Manifest.permission.BLUETOOTH_ADMIN, Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
} else {
if (mServiceConnection != null) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 101);
}
Intent intent = new Intent(this, BleService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}
}
private void showProgressDialog() {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(this);
}
mProgressDialog.setMessage(getString(R.string.loading));
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.show();
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mBleService = ((BleService.LocalBinder) iBinder).getLeService();
if (mBleService != null) {
mBleService.scanLeDevice(true);
mScanStatus.setVisibility(View.VISIBLE);
mScanStatus.setText(R.string.scanning_device);
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 101) {
if (mBleService != null) {
mBleService.scanLeDevice(true);
}
}
}
private BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case BleService.ACTION_DEVICE_FOUND:
BluetoothDevice device = (BluetoothDevice) intent.getParcelableExtra(BleService.EXTRA_DEVICE);
if (mBleDevices != null) {
if (!mBleDevices.contains(device)) {
mBleDevices.add(device);
mAdapter.udpateBluetoothDevices(mBleDevices);
mAdapter.notifyDataSetChanged();
}
}
break;
case BleService.ACTION_GATT_CONNECTED:
Log.d(TAG, "!Action gat connected...");
mBleService.scanLeDevice(false);
mScanStatus.setVisibility(View.VISIBLE);
mScanStatus.setText(getString(R.string.connected));
break;
case BleService.ACTION_GAT_CONNECTING:
mScanStatus.setVisibility(View.VISIBLE);
mScanStatus.setText(getString(R.string.connecting));
Log.d(TAG, "!Action Gat Connecting..");
break;
case BleService.ACTION_GATT_DISCONNECTED:
mScanStatus.setVisibility(View.VISIBLE);
mScanStatus.setText(getString(R.string.disconnected));
mScanningProgress.setVisibility(View.GONE);
mRefresh.setVisibility(View.VISIBLE);
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
Log.d(TAG, "!Action Gat Disconnected..");
break;
case BleService.ACTION_GAT_SERVICE_DISCOVERED:
boolean isOperator = mPref.getBoolean(Constants.IS_OPERATOR, false);
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
if (isOperator) {
Intent homeIntent = new Intent(DeviceScanActivity.this, HomeScreenActivity.class);
startActivity(homeIntent);
finish();
} else {
Intent lightControllIntent = new Intent(DeviceScanActivity.this, LightConfigurationActivity.class);
startActivity(lightControllIntent);
finish();
}
mScanStatus.setText(getString(R.string.discoveringService));
Log.d(TAG, "!Action Gat Discovering..");
break;
}
}
};
private void initToolBar() {
mRefresh.setVisibility(View.VISIBLE);
}
#OnClick(R.id.refresh)
public void onClick() {
mScanStatus.setVisibility(View.VISIBLE);
mRefresh.setVisibility(View.GONE);
mScanningProgress.setVisibility(View.VISIBLE);
mBleDevices.clear();
mAdapter.udpateBluetoothDevices(new ArrayList<BluetoothDevice>());
mAdapter.notifyDataSetChanged();
}
#Override
protected void onDestroy() {
if (mServiceConnection != null) {
unbindService(mServiceConnection);
}
if (mGattUpdateReceiver != null) {
unregisterReceiver(mGattUpdateReceiver);
}
super.onDestroy();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQUEST_COARSE_LOCATION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (mServiceConnection != null) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, 101);
}
Intent intent = new Intent(this, BleService.class);
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
} else {
finish();
}
}
}
}

Broadcast manager not working in Fragment

I have a BroadcastReceiver which is used to receive data from a BLE device. The same code is working fine in an Activity but not in Fragment.
Here is the code:
public class HomeFragment extends Fragment implements LocationListener {
Session session;
TextView textViewName;
TextView textViewSteps;
TextView textViewCalories;
TextView textViewDistance;
TextView textViewFimos;
ImageView imageViewInfo;
public static final String TAG = "StepCounter";
private UARTService mService = null;
private BluetoothDevice evolutionDevice = null;
private static final int UART_PROFILE_CONNECTED = 20;
private static final int UART_PROFILE_DISCONNECTED = 21;
private int mState = UART_PROFILE_DISCONNECTED;
MyDatabase myDatabase;
LocationManager service;
private LocationManager locationManager;
private String provider;
double latitude, longitude;
List<Byte> listBytes = new ArrayList<>();
int rowNumber = 1;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View view = inflater.inflate(R.layout.fragment_home, container, false);
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
init(view);
return view;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
service_init();
}
private void init(View view) {
session = new Session(getActivity());
myDatabase = new MyDatabase(getActivity());
service = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
boolean enabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!enabled) {
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, false);
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
Location location = locationManager.getLastKnownLocation(provider);
// Initialize the location fields
if (location != null) {
System.out.println("Provider " + provider + " has been selected.");
onLocationChanged(location);
}
textViewName = view.findViewById(R.id.textViewName);
textViewSteps = view.findViewById(R.id.textViewSteps);
textViewCalories = view.findViewById(R.id.textViewCalories);
textViewDistance = view.findViewById(R.id.textViewDistance);
textViewFimos = view.findViewById(R.id.textViewFimos);
imageViewInfo = view.findViewById(R.id.imageViewInfo);
try {
textViewName.setText("Hi, " + session.getUser().getUser().getName());
} catch (Exception e) {
}
}
private void service_init() {
System.out.println("---->>>>");
Intent bindIntent = new Intent(getActivity().getApplicationContext(), UARTService.class);
getActivity().bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter());
}
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");
getActivity().finish();
}
}
public void onServiceDisconnected(ComponentName classname) {
mService = null;
}
};
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;
}
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)) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
System.out.println("------- Device Connected: " + evolutionDevice.getName() + " - " + evolutionDevice.getAddress());
mState = UART_PROFILE_CONNECTED;
}
});
}
//*********************//
if (action.equals(UARTService.ACTION_GATT_DISCONNECTED)) {
getActivity().runOnUiThread(new Runnable() {
public void run() {
System.out.println("------- Device Disconnected");
mState = UART_PROFILE_DISCONNECTED;
mService.close();
evolutionDevice = null;
}
});
}
//*********************//
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);
List<Byte> byteList = Bytes.asList(txValue);
combineArrays(byteList);
}
//*********************//
if (action.equals(UARTService.DEVICE_DOES_NOT_SUPPORT_UART)) {
System.out.println("------- Device doesn't support UART. Disconnecting");
mService.disconnect();
}
}
};
#Override
public void onResume() {
super.onResume();
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
locationManager.requestLocationUpdates(provider, 400, 1, this);
Log.d(TAG, "onResume");
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
try {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(UARTStatusChangeReceiver);
} catch (Exception ignore) {
Log.e(TAG, ignore.toString());
}
getActivity().unbindService(mServiceConnection);
mService.stopSelf();
mService = null;
}
The complete code in the same ay with a few changes in working fine in Activity. Any idea what might be the blocker.? Do I need to do something else in the fragment to receive the data from the Local Broadcast Manager.?
Please try this way :
Create class BroadcastHelper
public class BroadcastHelper {
public static final String BROADCAST_EXTRA_METHOD_NAME = "INPUT_METHOD_CHANGED";
public static final String ACTION_NAME = "hossam";
public static void sendInform(Context context, String method) {
Intent intent = new Intent();
intent.setAction(ACTION_NAME);
intent.putExtra(BROADCAST_EXTRA_METHOD_NAME, method);
try {
context.sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void sendInform(Context context, String method, Intent intent) {
intent.setAction(ACTION_NAME);
intent.putExtra(BROADCAST_EXTRA_METHOD_NAME, method);
try {
context.sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
And in your fragment :
private Receiver receiver;
private boolean isReciverRegistered = false;
#Override
public void onResume() {
super.onResume();
if (receiver == null) {
receiver = new Receiver();
IntentFilter filter = new IntentFilter(BroadcastHelper.ACTION_NAME);
getActivity().registerReceiver(receiver, filter);
isReciverRegistered = true;
}
}
#Override
public void onDestroy() {
if (isReciverRegistered) {
if (receiver != null)
getActivity().unregisterReceiver(receiver);
}
super.onDestroy();
}
private class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
Log.v("r", "receive " + arg1.getStringExtra(BroadcastHelper.BROADCAST_EXTRA_METHOD_NAME));
String methodName = arg1.getStringExtra(BroadcastHelper.BROADCAST_EXTRA_METHOD_NAME);
if (methodName != null && methodName.length() > 0) {
Log.v("receive", methodName);
switch (methodName) {
case "Test":
Toast.makeText(getActivity(), "message", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
}
And to send your broadcast this this code :
BroadcastHelper.sendInform(context, "Test");
Or if you want to send data with it use :
Intent intent = new Intent("intent");
intent.putExtra("desc", desc);
intent.putExtra("name", Local_name);
intent.putExtra("code", productCode);
BroadcastHelper.sendInform(getActivity(), "Test" , intent);
I have a fragment where I do something similar. I put my code to setup the service in onCreateView and have a register and unregister in onPause() and onResume. Works good for me.
Can you check modify register receiver in service_init()
as
getActivity().registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter());
and for unregisterer receiver
getActivity().unregisterReceiver(UARTStatusChangeReceiver);

Location tracking in the background Android

I got some problems to keep a location tracking for my Android app.
The service we developed are all working, but depending on the phones and the API level, they are killed soon or later.
My purpose is to notify a user when he is getting out of a certain range, and this is working when the app is running.
This is the service that calculates when the user is in or out of the zone:
public class GeoFenceService extends BaseService {
#Inject
GeoFenceRepository geoFenceRepository;
SettingValueService settingValueService = new SettingValueService();
GeoFence geoFence;
private GeofencingClient mGeofencingClient;
PendingIntent mGeofencePendingIntent;
List<Geofence> mGeofenceList = new ArrayList<>();
public GeoFenceService() {
super();
Injector.getInstance().getAppComponent().inject(this);
}
public Observable<GeoFence> saveGeofence(GeoFence geoFence) {
if (geoFence.getId() == null)
geoFence.setId(CommonMethods.generateUuid());
commitToRealm(geoFence);
if (Application.getHasNetwork())
return geoFenceRepository.saveGeofence(geoFence);
else
return Observable.just(null);
}
public Observable<GeoFence> getGeofence() {
return geoFenceRepository.getGeofence();
}
public GeoFence getGeofenceFromRealm() {
Realm realm = Realm.getDefaultInstance();
RealmQuery<GeoFence> query = realm.where(GeoFence.class);
GeoFence result = query.findFirst();
if (result != null)
return realm.copyFromRealm(result);
return null;
}
public void initGeoFence(Context context) {
SettingValue autoCloking = settingValueService.getSettingByName("auto_clocking");
if (autoCloking != null && autoCloking.getValue().equals("true")) {
if (mGeofencingClient == null)
mGeofencingClient = LocationServices.getGeofencingClient(context);
geoFence = getGeofenceFromRealm();
if (geoFence != null) {
addGeofence(geoFence, context);
}
}
}
#SuppressLint("MissingPermission")
public void addGeofence(GeoFence geofence, Context context) {
mGeofenceList.clear();//only 1 geofence at the same time.
mGeofenceList.add(new Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId(geofence.getId())
.setCircularRegion(
geofence.getLatitude(),
geofence.getLongitude(),
(float) geofence.getRadius()
)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(30000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT | Geofence.GEOFENCE_TRANSITION_DWELL)
.build());
mGeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent(context));
}
private PendingIntent getGeofencePendingIntent(Context context) {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(context, GeofencingService.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
// calling addGeofences() and removeGeofences().
mGeofencePendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_EXIT);
builder.addGeofences(mGeofenceList);
return builder.build();
}
public void removeGeofence(Context context) {
if (mGeofencingClient != null)
mGeofencingClient.removeGeofences(getGeofencePendingIntent(context));
}
}
Even if this was working in the background we made a service to wake up the GPS of the phone every 60 sec following the advice of this question.
This is the service we made:
public class UpdateLocationService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final String TAG = "UpdateLocationService";
private static final int LOCATION_INTERVAL = 60000;
private Context mContext;
private LocationRequest locationRequest;
private GoogleApiClient googleApiClient;
private FusedLocationProviderApi fusedLocationProviderApi;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onCreate() {
Log.e(TAG, "onCreate");
mContext = this;
getLocation();
}
#Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
try {
if (googleApiClient != null) {
googleApiClient.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void getLocation() {
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(LOCATION_INTERVAL);
locationRequest.setFastestInterval(LOCATION_INTERVAL);
fusedLocationProviderApi = LocationServices.FusedLocationApi;
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (googleApiClient != null) {
googleApiClient.connect();
}
}
#Override
public void onConnected(Bundle arg0) {
// Location location =
fusedLocationProviderApi.getLastLocation(googleApiClient);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
fusedLocationProviderApi.requestLocationUpdates(googleApiClient, locationRequest, this);
}
#Override
public void onConnectionSuspended(int arg0) {
}
#Override
public void onLocationChanged(Location location) {
Toast.makeText(mContext, "User location :"+location.getLatitude()+" , "+location.getLongitude(), Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(ConnectionResult arg0) {
}
}
and finally this is the call in our main activity:
if (checkGpsProviderEnabled()) {
geoFenceService.initGeoFence(this);
Intent msgIntent = new Intent(this, GeofencingService.class);
startService(msgIntent);
startService(new Intent(this,UpdateLocationService.class));
}
Of course, we implement the authorization for Localisation and service déclaration in our AndroidManifest
And everything is working fine when the app isn't in the foreground
The foreground is working on some device but not all, and I wanted to know if I can do something more to force our services to run all the time in the background
Thanks in advance

AsyncTask and Handler always Start Activity twice after Logout

i have a problem to send fbid to my server after logged out once. and if i want to login again it always send twice request and start the activity twice.
MainActivity.java:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("TheGaffer", "ONCREATE");
mFacebook = new Facebook(APP_ID);
SessionStore.restore(mFacebook, this);
setContentView(R.layout.login_view);
mLoginButton = (LoginButton) findViewById(R.id.login);
SessionEvents.addAuthListener(new SampleAuthListener());
mLoginButton.init(this, mFacebook);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mFacebook.authorizeCallback(requestCode, resultCode, data);
}
public class SampleAuthListener implements AuthListener {
public void onAuthSucceed() {
new fbRequest().execute("/user_profiles/registerUser");
}
private class fbRequest extends AsyncTask<String, Void, String> {
protected void onPreExecute() {
progressDialog = ProgressDialog.show(TheGaffer.this , null,
"Loading...");
}
protected String doInBackground(String... urls) {
String fbid = null;
Bundle params = new Bundle();
params.putString("fields", "id,name");
try {
JSONObject jsonObjSend = new JSONObject();
JSONObject fbData = new JSONObject(mFacebook.request("me", params));
fbid = fbData.getString("id");
jsonObjSend.put("fbid", fbData.getString("id"));
jsonObjSend.put("username", fbData.getString("name"));
jsonObjSend.put("playerPhoto", "http://graph.facebook.com/"+ fbData.getString("id") +"/picture");
HttpClient.SendHttpPost(urls[0], jsonObjSend);
} catch (Exception e) {
Log.e("FACEBOOK", "Error parsing data " + e.toString());
}
return fbid;
}
#Override
protected void onPostExecute(String fbid) {
Toast.makeText(getApplicationContext(), "Login successful", Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
Intent intent = new Intent(TheGaffer.this, TeamActivity.class);
intent.putExtra("fbid", fbid);
startActivity(intent);
}
}
TeamActivity.java:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_create_team:
intent = new Intent(TeamActivity.this, CreateTeam.class);
return true;
case R.id.menu_logout:
Log.i("Logout", "Logged out");
Intent intent = new Intent(TeamActivity.this, TheGaffer.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Once I was trapped in similar situation where Activity call twice one after another.
To avoid this after lots of research I find a very easy solution.
May be solution is not perfect but works for me
in manifest.xml file
in your activity just add
android:launchMode="singleTask"

Categories