Related
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
Geofences are not being triggered using Broadcast Receiver. It was working with IntentService, however it wasn't working when the application is background.. I have changed to Broadcast receiver to make it work irrespective if the application is running in Foreground or background. After I changed it to Broadcast receiver by looking the below example, it stopped working even for Entry and Dwell...
https://github.com/googlesamples/android-play-location/tree/master/Geofencing/app/src/main/java/com/google/android/gms/location/sample/geofencing
Main Activity
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback<Status> {
private static final String TAG = "Geofence example";
private static final int MULTIPLE_PERMISSIONS = 1;
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
private static final String ADDRESS_REQUESTED_KEY = "address-request-pending";
private static final String LOCATION_ADDRESS_KEY = "location-address";
String[] permissions = new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.READ_SMS,
Manifest.permission.RECEIVE_SMS,
Manifest.permission.SEND_SMS};
private GeofencingClient mGeofencingClient;
private PendingIntent mGeofencePendingIntent;
private Context mContext;
/**
* Provides access to the Fused Location Provider API.
*/
private FusedLocationProviderClient mFusedLocationClient;
/**
* Represents a geographical location.
*/
private Location mLastLocation;
/**
* Tracks whether the user has requested an address. Becomes true when the user requests an
* address and false when the address (or an error message) is delivered.
*/
private boolean mAddressRequested;
/**
* The formatted location address.
*/
private String mAddressOutput;
/**
* Receiver registered with this activity to get the response from FetchAddressIntentService.
*/
private AddressResultReceiver mResultReceiver;
/**
* Displays the location address.
*/
private TextView mLocationAddressTextView;
/**
* Visible while the address is being fetched.
*/
private ProgressBar mProgressBar;
/**
* Kicks off the request to fetch an address when pressed.
*/
private Button mFetchAddressButton;
private List<Geofence> mGeofenceList;
private GoogleApiClient mGoogleApiClient;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mResultReceiver = new AddressResultReceiver(new Handler());
mLocationAddressTextView = (TextView) findViewById(R.id.location_address_view);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
mFetchAddressButton = (Button) findViewById(R.id.fetch_address_button);
// Set defaults, then update using values stored in the Bundle.
mAddressRequested = false;
mAddressOutput = "";
mContext = this;
updateValuesFromBundle(savedInstanceState);
mGeofencingClient = LocationServices.getGeofencingClient(this);
//LatLng latLng = getLocationFromAddress(mContext, "517 Carrville Rd, Richmond Hill, ON L4C 6E5");
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
SmsReceiver.bindListener(new SMSListener() {
#Override
public void messageReceived(String messageText) {
//From the received text string you may do string operations to get the required OTP
//It depends on your SMS format
Log.d("Message", messageText);
Toast.makeText(MainActivity.this, "Message: " + messageText, Toast.LENGTH_LONG).show();
//startIntentService();
}
});
Log.d(GeofenceTransitionsIntentService.TAG, "OnCreate - Building google API client");
buildGoogleApiClient();
Log.d(GeofenceTransitionsIntentService.TAG, "OnCreate - Before permission check");
if (checkPermissions()) {
Log.d(GeofenceTransitionsIntentService.TAG, "OnCreate - inside Permission ");
getAddress();
}
Log.d(GeofenceTransitionsIntentService.TAG, "mGoogleApiClient = " + mGoogleApiClient);
//test_sendNotification("testing");
updateUIWidgets();
}
#Override
public void onStart() {
super.onStart();
Log.d(GeofenceTransitionsIntentService.TAG, "onStart - before Permission ");
if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnecting() || mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
private PendingIntent getGeofencePendingIntent() {
// Reuse the PendingIntent if we already have it.
if (mGeofencePendingIntent != null) {
return mGeofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);
// We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
// calling addGeofences() and removeGeofences().
mGeofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.
FLAG_UPDATE_CURRENT);
Log.d(GeofenceTransitionsIntentService.TAG, "getGeofencePendingIntent " + mGeofencePendingIntent);
return mGeofencePendingIntent;
}
/**
* Updates fields based on data stored in the bundle.
*/
private void updateValuesFromBundle(Bundle savedInstanceState) {
if (savedInstanceState != null) {
// Check savedInstanceState to see if the address was previously requested.
if (savedInstanceState.keySet().contains(ADDRESS_REQUESTED_KEY)) {
mAddressRequested = savedInstanceState.getBoolean(ADDRESS_REQUESTED_KEY);
}
// Check savedInstanceState to see if the location address string was previously found
// and stored in the Bundle. If it was found, display the address string in the UI.
if (savedInstanceState.keySet().contains(LOCATION_ADDRESS_KEY)) {
mAddressOutput = savedInstanceState.getString(LOCATION_ADDRESS_KEY);
displayAddressOutput();
}
}
}
/**
* Runs when user clicks the Fetch Address button.
*/
#SuppressWarnings("unused")
public void fetchAddressButtonHandler(View view) {
if (mLastLocation != null) {
Log.d(GeofenceTransitionsIntentService.TAG, "fetchAddressButtonHandler - mLastLocation " + mLastLocation);
startIntentService();
return;
}
// If we have not yet retrieved the user location, we process the user's request by setting
// mAddressRequested to true. As far as the user is concerned, pressing the Fetch Address button
// immediately kicks off the process of getting the address.
mAddressRequested = true;
updateUIWidgets();
}
/**
* Creates an intent, adds location data to it as an extra, and starts the intent service for
* fetching an address.
*/
private void startIntentService() {
// Create an intent for passing to the intent service responsible for fetching the address.
Intent intent = new Intent(this, FetchAddressIntentService.class);
// Pass the result receiver as an extra to the service.
intent.putExtra(Constants.RECEIVER, mResultReceiver);
// Pass the location data as an extra to the service.
intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation);
// Start the service. If the service isn't already running, it is instantiated and started
// (creating a process for it if needed); if it is running then it remains running. The
// service kills itself automatically once all intents are processed.
startService(intent);
Log.d(GeofenceTransitionsIntentService.TAG, "startIntentService - addGeoFenceList " + (mGeofenceList != null));
addGeoFence();
}
/**
* Gets the address for the last known location.
*/
#SuppressWarnings("MissingPermission")
private void getAddress() {
Log.d(GeofenceTransitionsIntentService.TAG, "MainActivity - getAddress () ");
mFusedLocationClient.getLastLocation()
.addOnSuccessListener(this, new OnSuccessListener<Location>() {
#Override
public void onSuccess(Location location) {
if (location == null) {
Log.w(GeofenceTransitionsIntentService.TAG, "onSuccess:null");
return;
}
mLastLocation = location;
// Determine whether a Geocoder is available.
if (!Geocoder.isPresent()) {
showSnackbar(getString(R.string.no_geocoder_available));
return;
}
// If the user pressed the fetch address button before we had the location,
// this will be set to true indicating that we should kick off the intent
// service after fetching the location.
if (mAddressRequested) {
startIntentService();
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "getLastLocation:onFailure", e);
}
});
}
private GeofencingRequest getGeofencingRequest() {
Log.d(GeofenceTransitionsIntentService.TAG, "MainActivity - getGeofencingRequest ");
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_DWELL | GeofencingRequest.INITIAL_TRIGGER_EXIT);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private void addGeoFence() {
Log.d(GeofenceTransitionsIntentService.TAG, "MainActivity - mGeofenceList () ");
mGeofenceList = new ArrayList<Geofence>();
for (Map.Entry<String, LatLng> entry : Constants.GEO_FENCE_LIST.entrySet()) {
mGeofenceList.add(new Geofence.Builder()
// Set the request ID of the geofence. This is a string to identify this
// geofence.
.setRequestId(entry.getKey())
// Set the circular region of this geofence.
.setCircularRegion(
entry.getValue().latitude,
entry.getValue().longitude,
Constants.GEOFENCE_RADIUS_IN_METERS
)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(6000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
Geofence.GEOFENCE_TRANSITION_EXIT | Geofence.GEOFENCE_TRANSITION_DWELL)
// Create the geofence.
.build());
}
Log.d(GeofenceTransitionsIntentService.TAG, "addGeoFenceList - mGeofenceList " + mGeofenceList);
//getGeofencingRequest();
if (!mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
Toast.makeText(this, "not connected", Toast.LENGTH_SHORT).show();
return;
}
Log.d(GeofenceTransitionsIntentService.TAG, "addGeoFenceList - mGoogleApiClient " + mGoogleApiClient.isConnected());
try {
LocationServices.GeofencingApi.addGeofences(
mGoogleApiClient,
// The GeofenceRequest object.
getGeofencingRequest(),
// A pending intent that that is reused when calling removeGeofences(). This
// pending intent is used to generate an intent when a matched geofence
// transition is observed.
getGeofencePendingIntent()
).setResultCallback(this); // Result processed in onResult().
} catch (SecurityException securityException) {
// Catch exception generated if the app does not use ACCESS_FINE_LOCATION permission.
Log.d(GeofenceTransitionsIntentService.TAG, "addGeoFenceList - error " + securityException.getLocalizedMessage());
}
}
/**
* Updates the address in the UI.
*/
private void displayAddressOutput() {
mLocationAddressTextView.setText(mAddressOutput);
}
/**
* Toggles the visibility of the progress bar. Enables or disables the Fetch Address button.
*/
private void updateUIWidgets() {
if (mAddressRequested) {
mProgressBar.setVisibility(ProgressBar.VISIBLE);
mFetchAddressButton.setEnabled(false);
} else {
mProgressBar.setVisibility(ProgressBar.GONE);
mFetchAddressButton.setEnabled(true);
}
}
/**
* Shows a toast with the given text.
*/
private void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save whether the address has been requested.
savedInstanceState.putBoolean(ADDRESS_REQUESTED_KEY, mAddressRequested);
// Save the address string.
savedInstanceState.putString(LOCATION_ADDRESS_KEY, mAddressOutput);
super.onSaveInstanceState(savedInstanceState);
}
#Override
public void onConnected(#Nullable Bundle bundle) {
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
#Override
public void onResult(Status status) {
if (status.isSuccess()) {
Toast.makeText(
this,
"Geofences Added",
Toast.LENGTH_SHORT
).show();
} else {
// Get the status code for the error and log it using a user-friendly message.
Toast.makeText(
this,
"Geofences error - onResult",
Toast.LENGTH_SHORT
).show();
}
}
/**
* Shows a {#link Snackbar} using {#code text}.
*
* #param text The Snackbar text.
*/
private void showSnackbar(final String text) {
View container = findViewById(android.R.id.content);
if (container != null) {
Snackbar.make(container, text, Snackbar.LENGTH_LONG).show();
}
}
private void showSnackbar(final int mainTextStringId, final int actionStringId,
View.OnClickListener listener) {
Snackbar.make(findViewById(android.R.id.content),
getString(mainTextStringId),
Snackbar.LENGTH_INDEFINITE)
.setAction(getString(actionStringId), listener).show();
}
/**
* Return the current state of the permissions needed.
*/
private boolean checkPermissions() {
int result;
List<String> listPermissionsNeeded = new ArrayList<>();
for (String p : permissions) {
result = ContextCompat.checkSelfPermission(getApplicationContext(), p);
if (result != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(p);
}
}
if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case MULTIPLE_PERMISSIONS: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permissions granted.
getAddress();
} else {
String perStr = "";
for (String per : permissions) {
perStr += "\n" + per;
}
// permissions list of don't granted permission
}
return;
}
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
if (!mGoogleApiClient.isConnecting() || !mGoogleApiClient.isConnected()) {
mGoogleApiClient.connect();
}
Log.d(GeofenceTransitionsIntentService.TAG, "buildGoogleApiClient - mGoogleApiClient " + mGoogleApiClient);
}
private class AddressResultReceiver extends ResultReceiver {
AddressResultReceiver(Handler handler) {
super(handler);
}
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// Display the address string or an error message sent from the intent service.
mAddressOutput = resultData.getString(Constants.RESULT_DATA_KEY);
displayAddressOutput();
// Show a toast message if an address was found.
if (resultCode == Constants.SUCCESS_RESULT) {
showToast(getString(R.string.address_found));
}
Log.d(GeofenceTransitionsIntentService.TAG, "onReceiveResult - onReceiveResult ");
// Reset. Enable the Fetch Address button and stop showing the progress bar.
mAddressRequested = false;
updateUIWidgets();
}
}
}
JobIntentService:
public class GeofenceTransitionsIntentService extends JobIntentService {
protected static final String TAG = "geofence-transitions";
private static final int JOB_ID = 573;
#Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "GeofenceTransitionsIntentService onCreate ");
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
Log.e(TAG, "GeofenceTransitionsIntentService intent " + intent);
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = "error";
Log.e(TAG, errorMessage);
return;
}
// Get the transition type.
int geofenceTransition = geofencingEvent.getGeofenceTransition();
String geofenceTransitionString = getTransitionString(geofenceTransition);
Log.e(TAG, "geofence_transition_geofenceTransition " + geofenceTransition);
// Test that the reported transition was of interest.
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
geofenceTransition == Geofence.GEOFENCE_TRANSITION_DWELL || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
// Get the geofences that were triggered. A single event can trigger multiple geofences.
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
// Get the transition details as a String.
String geofenceTransitionDetails = getGeofenceTransitionDetails(
this,
geofenceTransition,
triggeringGeofences
);
// Send notification and log the transition details.
sendNotification(geofenceTransitionDetails, geofenceTransitionString);
Log.i(TAG, geofenceTransitionDetails);
} else {
// Log the error.
Log.e(TAG, "geofence_transition_invalid_type" + geofenceTransition);
}
}
/**
* Convenience method for enqueuing work in to this service.
*/
public static void enqueueWork(Context context, Intent intent) {
enqueueWork(context, GeofenceTransitionsIntentService.class, JOB_ID, intent);
}
private String getGeofenceTransitionDetails(
Context context,
int geofenceTransition,
List<Geofence> triggeringGeofences) {
String geofenceTransitionString = getTransitionString(geofenceTransition);
// Get the Ids of each geofence that was triggered.
ArrayList triggeringGeofencesIdsList = new ArrayList();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
String triggeringGeofencesIdsString = TextUtils.join(", ", triggeringGeofencesIdsList);
return geofenceTransitionString + ": " + triggeringGeofencesIdsString;
}
private String getTransitionString(int transitionType) {
switch (transitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
return "Entered";
case Geofence.GEOFENCE_TRANSITION_EXIT:
return "Exited";
case Geofence.GEOFENCE_TRANSITION_DWELL:
return "Dwell";
default:
return "unkwn";
}
}
private void sendNotification(String notificationDetails, String geofenceTransitionString) {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(getApplicationContext(), "notify_geofence");
Intent ii = new Intent(getApplicationContext(), MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, ii, 0);
//Assign BigText style notification
NotificationCompat.BigTextStyle bigText = new NotificationCompat.BigTextStyle();
bigText.bigText(notificationDetails);
bigText.setSummaryText(geofenceTransitionString);
mBuilder.setContentIntent(pendingIntent);
mBuilder.setSmallIcon(R.mipmap.ic_launcher_round);
mBuilder.setContentTitle("Geofence notification");
mBuilder.setContentText(notificationDetails);
mBuilder.setPriority(Notification.PRIORITY_MAX);
mBuilder.setStyle(bigText);
NotificationManager mNotificationManager =
(NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("notify_001",
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
mNotificationManager.createNotificationChannel(channel);
}
mNotificationManager.notify(new Random().nextInt(61) + 20, mBuilder.build());
}
}
Broadcast receiver:
public class GeofenceBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Enqueues a JobIntentService passing the context and intent as parameters
GeofenceTransitionsIntentService.enqueueWork(context, intent);
}
}
Logs:
2018-10-30 12:40:02.850 24811-24811/com.lakshmiapps.findme D/geofence-transitions: fetchAddressButtonHandler - mLastLocation Location[fused 43.849304,-79.449305 hAcc=14 et=+2d21h3m43s23ms alt=161.3000030517578 vAcc=2 sAcc=??? bAcc=??? {Bundle[mParcelledData.dataSize=52]}]
2018-10-30 12:40:02.857 24811-24811/com.lakshmiapps.findme D/geofence-transitions: startIntentService - addGeoFenceList false
2018-10-30 12:40:02.857 24811-24811/com.lakshmiapps.findme D/geofence-transitions: MainActivity - mGeofenceList ()
2018-10-30 12:40:07.819 24811-24811/com.lakshmiapps.findme D/geofence-transitions: addGeoFenceList - mGeofenceList [Geofence[CIRCLE id:Ross Doan transitions:7 43.857670, -79.443370 1000m, resp=0s, dwell=6000ms, #-1], Geofence[CIRCLE id:Niagara falls transitions:7 43.078350, -79.081910 1000m, resp=0s, dwell=6000ms, #-1], Geofence[CIRCLE id:Taste of Malayalees transitions:7 43.635190, -79.622830 1000m, resp=0s, dwell=6000ms, #-1], Geofence[CIRCLE id:Home transitions:7 43.849301, -79.449306 1000m, resp=0s, dwell=6000ms, #-1], Geofence[CIRCLE id:Luv2Play transitions:7 43.855660, -79.430200 1000m, resp=0s, dwell=6000ms, #-1]]
2018-10-30 12:40:09.534 24811-24811/com.lakshmiapps.findme D/geofence-transitions: addGeoFenceList - mGoogleApiClient true
2018-10-30 12:40:09.534 24811-24811/com.lakshmiapps.findme D/geofence-transitions: MainActivity - getGeofencingRequest
2018-10-30 12:40:13.598 24811-24811/com.lakshmiapps.findme D/geofence-transitions: getGeofencePendingIntent PendingIntent{5fddab6: android.os.BinderProxy#47dc3b7}
2018-10-30 12:40:13.631 4938-5579/? I/GeofencerStateMachine: addGeofences called by com.lakshmiapps.findme
2018-10-30 12:40:13.631 4726-4773/? E/GmsLocationManagerService_FLP: [GeofencingApi] AddGeofence from com.lakshmiapps.findme and size = 5
2018-10-30 12:40:13.632 4726-4773/? D/GeofenceRequestInfo_FLP: removeExpiredGeofences - com.lakshmiapps.findme: 0 fences
2018-10-30 12:40:13.632 4726-4773/? E/GeofenceRequestManager_FLP: [GeofencingApi] AddGeofence 5 fences from com.lakshmiapps.findme
2018-10-30 12:40:13.632 4726-4773/? D/GeofenceRequestManager_FLP: 1540668973552 gpslastknowntime: 243443714 / nlplastknowntime: 248290794
2018-10-30 12:40:16.290 24811-24811/com.lakshmiapps.findme D/geofence-transitions: onReceiveResult - onReceiveResult
2018-10-30 12:44:08.692 4938-24505/? I/GeofencerStateMachine: removeGeofences: removeRequest=RemoveGeofencingRequest[REMOVE_BY_PENDING_INTENT pendingIntent=PendingIntent[creatorPackage=com.marriott.mrt], packageName=null]
Thanks,
Ramesh
Adding
<uses-permission android:name="android.permission.WAKE_LOCK" />
to AndroidManifest.xml seems to solve this issue in my case
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
I need to get continuous location updates from the application for my application. To do so, I followed the Android Developer Guide to get location updates. Because location updates can't be received in background in API 26, I added a foreground service (Background location limits). However, I still only receive updates when an other activity which requests location updates is in the foreground.
Location Service:
public class LocationUpdateService extends Service {
private static final String TAG = LocationUpdateService.class.getSimpleName();
private static final String NOTIFICATION_CHANNEL_ID = "TrackNotification";
private static final int FOREGROUND_SERVICE_ID = 1;
private static final int NOTIFICATION_ID = 1;
public static final String STATUS_INTENT = "status";
private static final int CONFIG_CACHE_EXPIRY = 600;
private NotificationManager mNotificationManager;
private NotificationCompat.Builder mNotificationBuilder;
private DatabaseReference mDatabaseReference;
private FusedLocationProviderClient mFusedLocationProviderClient;
private LocationRequest mLocationRequest;
private FirebaseRemoteConfig mFirebaseRemoteConfig;
private String uid;
#Override
public void onCreate() {
super.onCreate();
uid = FirebaseAuth.getInstance().getUid();
if(uid == null)
stopSelf();
mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder().build();
mFirebaseRemoteConfig.setConfigSettings(configSettings);
mFirebaseRemoteConfig.setDefaults(R.xml.remode_config_defaults);
fetchRemoteConfig();
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
mLocationRequest = new LocationRequest()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setFastestInterval(mFirebaseRemoteConfig.getLong("LOCATION_REQUEST_INTERVAL"))
.setFastestInterval(mFirebaseRemoteConfig.getLong("LOCATION_REQUEST_INTERVAL_FASTEST"));
bindNotification();
setStatusMessage(R.string.connecting);
startLocationTracking();
}
private LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
Log.d(TAG,"Got location update!");
if(locationResult == null)
return;
for(Location location : locationResult.getLocations()) {
CustomLocation customLocation = LocationAdapter.toDatabaseLocation(location);
mDatabaseReference.child("locations").child(uid).setValue(customLocation);
}
}
#Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
locationAvailability.isLocationAvailable();
// TODO handle no location here
super.onLocationAvailability(locationAvailability);
}
};
#SuppressWarnings({"MissingPermission"})
private void startLocationTracking() {
mFusedLocationProviderClient.requestLocationUpdates(mLocationRequest,mLocationCallback, Looper.myLooper());
}
private void fetchRemoteConfig() {
mFirebaseRemoteConfig.fetch(CONFIG_CACHE_EXPIRY)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
Log.i(TAG,"Remote config fetched");
mFirebaseRemoteConfig.activateFetched();
}
});
}
#Override
public void onDestroy() {
setStatusMessage(R.string.not_tracking);
mNotificationManager.cancel(NOTIFICATION_ID);
mFusedLocationProviderClient.removeLocationUpdates(mLocationCallback);
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) { return null; }
private void bindNotification() {
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this,0,
new Intent(this, MainActivity.class),PendingIntent.FLAG_UPDATE_CURRENT);
mNotificationBuilder = new NotificationCompat.Builder(this,NOTIFICATION_CHANNEL_ID)
.setCategory(NotificationCompat.CATEGORY_STATUS)
.setShowWhen(false)
.setSmallIcon(R.drawable.ic_car)
// .setColor(getColor(R.color.colorPrimary))
.setContentTitle(getString(R.string.app_name))
.setOngoing(true)
.setContentIntent(resultPendingIntent);
startForeground(FOREGROUND_SERVICE_ID, mNotificationBuilder.build());
}
/**
*
* #param message Status message to display
*/
private void setStatusMessage(String message) {
mNotificationBuilder.setContentText(message);
mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
Intent intent = new Intent(STATUS_INTENT);
intent.putExtra(getString(R.string.status),message);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void setStatusMessage(int resID) {
setStatusMessage(getString(resID));
}
}
And I gets started with
startService(new Intent(this,LocationUpdateService.class));
Android Manifest:
<service android:name=".LocationUpdateService" />
EDIT1: I now tested it on older API versions (22) and the problem is still the same: As long as some app with location requests is in the foreground it works, otherwise not.
Maybe it's a problem with the FusedLocationProviderClient but I don't know what. I only found code examples with the old FusedLocationProvider API which is now deprecated.
Have you tried debugging to make sure your service is being hit?
This might sound silly, but have you checked if your service is registered in your manifest? I know I've definitely run into that issue.
<service android:name=".LocationService"
android:label="Location Service"
android:exported="true"
android:enabled="true"
android:process=":location_background_service"/>
For getting the location, when I set mine up, I created a class that implemented android.location.LocationListener.
private class LocationListener implements android.location.LocationListener {
Location mLastLocation;
public LocationListener(String provider) {
Log.e(TAG, "LocationListener " + provider);
mLastLocation = new Location(provider);
}
#Override
public void onLocationChanged(Location location) {
Log.e(TAG, "onLocationChanged: " + location);
mLastLocation.set(location);
}
#Override
public void onProviderDisabled(String provider) {
Log.e(TAG, "onProviderDisabled: " + provider);
}
#Override
public void onProviderEnabled(String provider) {
Log.e(TAG, "onProviderEnabled: " + provider);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.e(TAG, "onStatusChanged: " + provider);
}
}
You can create multiple instances for different providers. In my case, I ended up using 2.
LocationListener[] mLocationListeners = new LocationListener[]{
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};
Then I initialized a LocationManager that can set a polling rate for each a LocationListener.
private void initializeLocationManager() {
Log.e(TAG, "initializeLocationManager");
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
Then in your Service onCreate function, initialize your LocationManager, and use one of the listeners as your main source and the other as a fallback.
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
5 * 60 * 1000, //5 Minutes
1F /*METERS*/,
mLocationListeners[0]
);
} catch (java.lang.SecurityException ex) {
Log.e(TAG, "failed to request location update. Insufficient permissions. ", ex);
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
5 * 60 * 1000, //5 Minutes
1F /*METERS*/,
mLocationListeners[1]
);
} catch (java.lang.SecurityException e) {
Log.e(TAG, "failed to request location update. Insufficient permissions. ", e);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Network provider does not exist.", e);
}
} catch (IllegalArgumentException ex) {
Log.e(TAG, "Network provider does not exist.", ex);
}
}
(Sorry if this code is gross, it's a quick and dirty example.)
Hey I m going to develop an location tracker app in which, this app in client device which constantly send it location to the firebase db.
Here the problem is that it will send the data to firebase only first 3 minutes then it wont. I don't know whats happening. ?
For that even i put a log message that log message is printed perfectly even after three minutes
Any one please help on this........!
Here i attached 3 file One BackgroundLocation: Which is the service in background which will extract the device location and call the LocationReceiver which extends broadcast receiver where it will print log message and send the data to firebase through FBSender.
Thanks in advance
BackgroundLocation.java
Which runs in Background to get the location details and call the broadcast Reveiver. LocationReveiver.java
/**
* Created by geekyint on 1/7/16.
*/
public class BackgroundLocation extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
IBinder mBinder = new LocalBinder();
private GoogleApiClient mGoogleApiClient;
private PowerManager.WakeLock mWakeLock;
private LocationRequest mlocationRequest;
//Flag for boolean request
private boolean mInProgress;
private boolean serviceAvailabe = false;
public class LocalBinder extends Binder {
public BackgroundLocation getServerInstance() {
return BackgroundLocation.this;
}
}
#Override
public void onCreate() {
super.onCreate();
mInProgress = false;
//Create the lcoation request object
mlocationRequest = LocationRequest.create();
//Use the acurecy
mlocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//The INTERVAL
mlocationRequest.setInterval(Constants.UPDATE_INTERVAL);
//The FAST INTERVAL
mlocationRequest.setFastestInterval(Constants.FAST_INTERVAL);
serviceAvailabe = serviceConnected();
setUpALocationClientIfNeeded();
ComponentName receiver = new ComponentName(this, LocationReceiver.class);
PackageManager pm = this.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
/*ComponentName receiver1 = new ComponentName(this, FireBaseSender.class);
PackageManager pm1 = this.getPackageManager();
pm1.setComponentEnabledSetting(receiver1,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);*/
}
private void setUpALocationClientIfNeeded() {
if (mGoogleApiClient == null) {
buildGoogleApiClient();
}
}
//Create the new Connection to the client
private void buildGoogleApiClient() {
this.mGoogleApiClient = new GoogleApiClient.Builder(this)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.build();
}
private boolean serviceConnected() {
//Check the google Play service availibility
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
//IF AVAILABLE
if (resultCode == ConnectionResult.SUCCESS) {
return true;
} else {
return false;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
PowerManager mgr = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (this.mWakeLock == null) {
this.mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
}
if (!this.mWakeLock.isHeld()) {
this.mWakeLock.acquire();
}
if (!serviceAvailabe || mGoogleApiClient.isConnected() || mInProgress) {
return START_STICKY;
}
setUpALocationClientIfNeeded();
if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() || !mInProgress) {
// appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
mInProgress = true;
mGoogleApiClient.connect();
}
return START_STICKY;
}
#Override
public void onLocationChanged(Location location) {
String msg = Double.toString(location.getLatitude()) + "," +
Double.toString(location.getLongitude());
Log.d("debug", msg);
// Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
// appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ":" + msg, Constants.LOCATION_FILE);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public String getTime() {
SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return mDateFormat.format(new Date());
}
public void appendLog(String text, String filename) {
File logFile = new File(filename);
if (!logFile.exists()) {
try {
logFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(text);
buf.newLine();
buf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onDestroy() {
// Turn off the request flag
this.mInProgress = false;
if (this.serviceAvailabe && this.mGoogleApiClient != null) {
this.mGoogleApiClient.unregisterConnectionCallbacks(this);
this.mGoogleApiClient.unregisterConnectionFailedListener(this);
this.mGoogleApiClient.disconnect();
// Destroy the current location client
this.mGoogleApiClient = null;
}
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ":
// Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
if (this.mWakeLock != null) {
this.mWakeLock.release();
this.mWakeLock = null;
}
// appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Stopped", Constants.LOG_FILE);
ComponentName receiver = new ComponentName(this, LocationReceiver.class);
PackageManager pm = this.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
/*
ComponentName receiver1 = new ComponentName(this, FireBaseSender.class);
PackageManager pm1 = this.getPackageManager();
pm1.setComponentEnabledSetting(receiver1,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);*/
super.onDestroy();
}
/*
* Called by Location Services when the request to connect the
* client finishes successfully. At this point, you can
* request the current location or start periodic updates
*/
#Override
public void onConnected(Bundle bundle) {
// Request location updates using static settings
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;
}
Intent intent = new Intent (this, LocationReceiver.class);
PendingIntent pendingIntent = PendingIntent
.getBroadcast(this, 54321, intent, PendingIntent.FLAG_CANCEL_CURRENT);
LocationServices.FusedLocationApi.requestLocationUpdates(this.mGoogleApiClient,
mlocationRequest, pendingIntent);
}
/*
* Called by Location Services if the connection to the
* location client drops because of an error.
*/
#Override
public void onConnectionSuspended(int i) {
// Turn off the request flag
mInProgress = false;
// Destroy the current location client
mGoogleApiClient = null;
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
// appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected", Constants.LOG_FILE);
}
/*
* Called by Location Services if the attempt to
* Location Services fails.
*/
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
mInProgress = false;
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
// If no resolution is available, display an error dialog
} else {
}
}
}
Here The LocationReceiver Code:
public class LocationReceiver extends BroadcastReceiver {
private String TAG = this.getClass().getSimpleName();
private LocationResult mLocationResult;
private double latitude;
private double longitude;
private double speed;
private String time;
#Override
public void onReceive(Context context, Intent intent) {
// Need to check and grab the Intent's extras like so
if(LocationResult.hasResult(intent)) {
this.mLocationResult = LocationResult.extractResult(intent);
//new SaveToFireB().insertToFireBase(mLocationResult.getLastLocation());
new FBSender().put(mLocationResult.getLastLocation());
Log.i(TAG, "Location Received: " + this.mLocationResult.toString());
String msg = String.valueOf(mLocationResult.getLastLocation().getLongitude()) + " " +
String.valueOf(mLocationResult.getLastLocation().getLatitude());
// appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ":" + msg, Constants.LOCATION_FILE);
}
}
public void appendLog(String text, String filename) {
File logFile = new File(filename);
if (!logFile.exists()) {
try {
logFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(text);
buf.newLine();
buf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Here Which will call FBSender to send the data to firebase.
Ther real problems comes here.
It will send the data only in first three minutes then it wont send the data to firebase
For confirmation whether the control going there or not i put log message there that log message will be printed perfectly even after 3 minutes from the start of the app
Here is FBSender.Java
public class FBSender extends Service {
private String TAG = "FBSender";
private double latitude;
private double longitude;
private double speed;
private String time;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
public void put (Location location) {
latitude = location.getLatitude();
longitude = location.getLongitude();
speed = location.getSpeed();
time = DateFormat.getTimeInstance().format(new Date());
Log.e(TAG, "Entering the run ()");
final FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference reference = database.getReference("users/" + user.getUid() + "/vehicles");
Log.e(TAG, "I M in the middle");
Map mLocations = new HashMap();
mLocations.put("latitude", latitude);
mLocations.put("longitude", longitude);
mLocations.put("speed", speed);
mLocations.put("time", time);
reference.setValue(mLocations);
Log.e(TAG, "Exiting The run ()");
}
}
To get more information about why the database writes are not completing after 3 minutes, add a CompetionListener to your setValue():
reference.setValue(mLocations, new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (databaseError == null) {
Log.i(TAG, "onComplete: OKAY");
} else {
Log.e(TAG, "onComplete: FAILED " + databaseError.getMessage());
}
}
});
When you hit the 3 minute mark, if the callback fires with an error, such as permission failure, you can investigate why. If it stops firing at all, that probably means you've lost connection with the Firebase server. You can monitor the connection status using a listener, as described in the documentation.