I have some code to create background service to working always.
this service will be working after app destroyed.
I test more than 20 code example and this code working in simulator, but not working in my phone marshmallow android 6.
This is service file for my app
public class locationService extends Service implements LocationListener {
private LocationManager _locMgr;
com.parse.groupbox.tools.locationTools loc;
Random RND = new Random();
Timer timer = new Timer();
#Override
public void onCreate() {
super.onCreate();
loc = new com.parse.groupbox.tools.locationTools(this);
}
#Override
public void onRebind(Intent intent) {
super.onRebind(intent);
try {
gpsSetup();
timer.cancel();
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
updateGps();
}
}, 5000, 10);
} catch (Exception ex) {
Toast.makeText(this, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
}
#Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
gpsSetup();
timer.schedule(new TimerTask() {
#Override
public void run() {
updateGps();
}
}, 5000, 10);
} catch (Exception ex) {
Toast.makeText(this, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
Toast.makeText(this, "start", Toast.LENGTH_SHORT).show();
return Service.START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
try {
gpsSetup();
timer.cancel();
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
updateGps();
}
}, 5000, 10);
} catch (Exception ex) {
Toast.makeText(this, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
Toast.makeText(this, "task service start", Toast.LENGTH_SHORT).show();
}
#Override
public void onDestroy() {
super.onDestroy();
try {
gpsSetup();
timer.cancel();
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
updateGps();
}
}, 5000, 10);
} catch (Exception ex) {
Toast.makeText(this, ex.getMessage(), Toast.LENGTH_SHORT).show();
}
Toast.makeText(this, "service destroyed", Toast.LENGTH_SHORT).show();
}
public void gpsSetup() {
try {
_locMgr = (LocationManager) getSystemService(LOCATION_SERVICE);
Criteria locationCriteria = new Criteria();
locationCriteria.setAccuracy(Criteria.ACCURACY_FINE);
locationCriteria.setPowerRequirement(Criteria.POWER_MEDIUM);
String locationProvider = _locMgr.getBestProvider(locationCriteria, true);
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
_locMgr.requestLocationUpdates(locationProvider, 1, 1, this);
Toast.makeText(this, "start service", Toast.LENGTH_SHORT).show();
}
catch (Exception Ex)
{
Toast.makeText(this, Ex.getMessage(), Toast.LENGTH_LONG).show();
}
}
public void updateGps(){
try{
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
String locationProvider = LocationManager.NETWORK_PROVIDER;
_locMgr.requestLocationUpdates(locationProvider, 1, 1, this);
}catch (Exception Ex){
Toast.makeText(this, Ex.getMessage(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onLocationChanged(Location location) {
int result = RND.nextInt(100);
if(result > 30){
try{
loc.LocationSyncToServer(location);
Toast.makeText(this, "location", Toast.LENGTH_LONG).show();
}catch (Exception Ex){
Toast.makeText(this, Ex.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
Please read my codes and give me answer to solve it.
This is the code to run the service:
Intent background = new Intent(getApplicationContext(), com.parse.groupbox.services.locationService.class);
startService(background);
try this
put this code where you want to stop service
Intent intent = new Intent(getApplicationContext(),com.parse.groupbox.services.locationService.class);
intent.setAction(Constants.ACTION.STOPTFOREGROUND_ACTION);
stopService(intent);
in your Service onStartCommand()
if(intent.getAction()==Constants.ACTION.STOPTFOREGROUND_ACTION){
stopForeground(true);
stopSelf();
}
create a class Constants
public class Constants {
public interface ACTION {
String STOPFOREGROUND_ACTION = "com.package.packageName.action.stopforeground";
}
}
Android M introduced Doze and App Standby which limits background services in order to preserve battery. How to handle Doze can be found in here android developer site.
Related
I am implementing location tracker from Android app by using foreground service.
The expectation is the foreground service should run even
when app is removed from recent open apps.
When app is in open/foreground.
When app is in background i.e. app is still open but went to background
The case 2 & 3 are working fine but case 1 is working weirdly.
In case 1, sometimes foreground service is getting restarted (notification is going off and coming back) after few seconds i.e. 1 to 3 seconds.
In some other times it is never restarted.
I want the foreground service to never go off. In short, I want it like whatsapp location tracking. The whatsapp tracking icon never goes off when the app is closed.
Please give any pointers on what else I am missing
Activity class
public void enableTracking(String planId, JSONArray trackList, CallbackContext callbackContext) {
Log.i(TAG,"In enableTracking");
Intent intent = new
Intent(cordova.getActivity().getApplicationContext(),LocationTracker.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
cordova.getActivity().startForegroundService(intent);
callbackContext.success("Location Tracking is enabled");
} else {
callbackContext.error("Build version is less than OREO");
}
}
public void disableTracking(CallbackContext callbackContext) {
Log.i(TAG,"In disableTracking");
Intent intent = new Intent(cordova.getActivity().getApplicationContext(),LocationTracker.class);
cordova.getActivity().stopService(intent);
callbackContext.success("Location Tracking is disabled");
}
Service class
public class LocationTracker extends Service {
private final IBinder mBinder = new MyBinder();
private static final String CHANNEL_ID = "2";
private static final String TAG = "LocationTracker";
private FusedLocationProviderClient mFusedLocationClient;
RequestQueue mRequestQueue;
public LocationTracker() {
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
Log.i(TAG, "onTaskRemoved");
super.onTaskRemoved(rootIntent);
}
#Override
public void onCreate() {
super.onCreate();
buildNotification();
// logic to start location tracking
}
#Override
public void onDestroy() {
super.onDestroy();
// logic to stop tracking
}
private void fetchAndSendLocation() {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.e(TAG, "No permission to fetch location");
return;
}
// mFusedLocationClient.getCurrentLocation()
Task fetchLocTask = mFusedLocationClient.getLastLocation();
fetchLocTask.addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
Location loc = (Location) o;
if (loc != null) {
Log.i(TAG, "Lat " + loc.getLatitude() + " lon " + loc.getLongitude() + " date " + (new Date()).toString());
postLocation(loc);
}
}
});
}
private void buildNotification() {
String stop = "stop";
PendingIntent broadcastIntent = PendingIntent.getBroadcast(
this, 0, new Intent(stop), PendingIntent.FLAG_UPDATE_CURRENT);
// Create the persistent notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText("Location tracking is working")
.setOngoing(true)
.setContentIntent(broadcastIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, getString(R.string.app_name),
NotificationManager.IMPORTANCE_DEFAULT);
channel.setShowBadge(false);
channel.setDescription("Location tracking is in progress");
channel.setSound(null, null);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
}
startForeground(1, builder.build());
}
public class MyBinder extends Binder {
public LocationTracker getService() {
return LocationTracker.this;
}
}
}
AndroidManifest.xml
<service android:enabled="true" android:exported="true" android:foregroundServiceType="location" android:name=".LocationTracker" />
Using LocationManager as in code below has solved this similar situation for me.
public class MyLocationService extends Service {
private static final String TAG = "MyLocationService";
private LocationManager mLocationManager = null;
private static final int LOCATION_INTERVAL = 1000;
private static final float LOCATION_DISTANCE = 10f;
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);
}
}
LocationListener[] mLocationListeners = new LocationListener[]{
new LocationListener(LocationManager.PASSIVE_PROVIDER)
};
#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");
initializeLocationManager();
try {
mLocationManager.requestLocationUpdates(
LocationManager.PASSIVE_PROVIDER,
LOCATION_INTERVAL,
LOCATION_DISTANCE,
mLocationListeners[0]
);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "network provider does not exist, " + ex.getMessage());
}
}
#Override
public void onDestroy() {
Log.e(TAG, "onDestroy");
super.onDestroy();
if (mLocationManager != null) {
for (int i = 0; i < mLocationListeners.length; i++) {
try {
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLocationManager.removeUpdates(mLocationListeners[i]);
} catch (Exception ex) {
Log.i(TAG, "fail to remove location listener, ignore", ex);
}
}
}
}
private void initializeLocationManager() {
Log.e(TAG, "initializeLocationManager - LOCATION_INTERVAL: "+ LOCATION_INTERVAL + " LOCATION_DISTANCE: " + LOCATION_DISTANCE);
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
}
You could modify this to suit your need.
So basically, i got a list view that shows a list of bands.
When i press on one of the bands in the list, it creates a band profile page via an adapter.
In this layout, i got a play button, which starts a MediaPlayer service and play a song.
So far, so good.
The problem is, im trying to update the seekBar, located in the band profile page (created by the adapter mentioned above), from the MediaPlayer service Java file, but i'm unable to reach it.
i'm trying to use :
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.activity_singleband, null, false);
seekBar = (SeekBar) layout.findViewById(R.id.seekBarBand);
but it seems that it uses another "instance" of the view, and not the one i'm currently viewing.
Here is the full MusicService Java file:
public class MusicService extends Service {
SeekBar seekBar;
Handler handler;
Runnable runnable;
NotificationManager nMN;
TextView BandName;
String songLink;
String songName;
String bandName;
String SongPlaying="";
String BandPlaying="";
public static MediaPlayer mp;
public static Boolean mpState = true;
public static Boolean mpPause = false;
public static Boolean isPlaying = false;
#Override
public void onCreate() {
super.onCreate();
}
// Play Cycle for seekBar
public void PlayCycle(){
seekBar.setProgress(mp.getCurrentPosition());
if (mp.isPlaying()){
runnable = new Runnable() {
#Override
public void run() {
PlayCycle();
}
};
handler.postDelayed(runnable, 1000);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
songLink = intent.getStringExtra("SongLink");
songName = intent.getStringExtra("SongName");
bandName = intent.getStringExtra("BandName");
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.activity_singleband, null, false);
seekBar = (SeekBar) layout.findViewById(R.id.seekBarBand);
BandName = (TextView) layout.findViewById(R.id.singleBandNameView);
BandName.setText("Bla Bla");
System.out.print("Band Name : "+ BandName.getText() );
handler = new Handler();
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean input) {
if (input){
mp.seekTo(progress);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
if (isPlaying && !songName.equals(SongPlaying) && !BandPlaying.equals(bandName)) {
Stop();
mp = new MediaPlayer();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
Uri songUri = Uri.parse(songLink);
mp.setDataSource(getApplicationContext(), songUri);
SongPlaying = songName;
Toast.makeText(getApplicationContext(), "Please wait", Toast.LENGTH_SHORT).show();
isPlaying=true;
new prepare().execute();
}
catch (IOException e) {
e.printStackTrace();
}
}
else if (!isPlaying && !songName.equals(SongPlaying) && !BandPlaying.equals(bandName) ) {
mp = new MediaPlayer();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
Uri songUri = Uri.parse(songLink);
mp.setDataSource(getApplicationContext(), songUri);
SongPlaying = songName;
Toast.makeText(getApplicationContext(), "Please wait", Toast.LENGTH_SHORT).show();
new prepare().execute();
isPlaying=true;
}
catch (IOException e) {
e.printStackTrace();
}
}
else {
Toast.makeText(getApplicationContext(), "Song is Already Playing", Toast.LENGTH_SHORT).show();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
mp.release();
handler.removeCallbacks(runnable);
}
/// Permanent Notification
private void showNotification() {
nMN = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification n = new Notification.Builder(this)
.setContentTitle(songName)
.setContentText(bandName)
.setSmallIcon(R.drawable.ic_bandcamp)
//.addAction(R.drawable.ic_play_arrow_black_24dp, "button1", new pause())
.setOngoing(true)
.build();
nMN.notify(1, n);
}
/// PREPARE SONG TO PLAY //
public class prepare extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
try {
mp.prepare();
PlayCycle();
seekBar.setMax(mp.getDuration());
mp.start();
SongPlaying = songName;
isPlaying=true;
showNotification(); // show notification
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
Toast.makeText(getApplicationContext(),"Song Finished", Toast.LENGTH_LONG).show();
new stop().execute();
}
});
} catch (IOException io){ io.printStackTrace(); }
return null; }}
/// STOP PLAYING SONG //
public static void Stop()
{
mp.reset();
mp.release();
isPlaying=false;
}
public static class stop extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
try {
mp.reset();
mp.release();
isPlaying=false;
} catch (Exception io){ io.printStackTrace(); }
return null; }}
/// PAUSE PLAYING SONG//
public static class pause extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
try {
mp.pause(); }
catch (Exception io){ io.printStackTrace(); }
return null; }}
public static class start extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
try {
mp.start(); }
catch (Exception io){ io.printStackTrace(); }
return null; }}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
Would love to have some suggestions.
Thanks in advance.
Okey Firstly I suggest you to read more about Android Service classes. Secondly Do NOT place you visual components like a SeekBar or TextView in the Service because it doesn't make any sense. Service is just a background task and do not know about the UI. Since it's executed in the background you don't even need AsyncTask inside this so thirdly remove ALL AsyncTasks in your service and run their task like they don't need to be executed in the background.
So all what you have to do is create a Fragment/Activity for the UI, then bind your Fragment/Acitivity with your Service to communicate and update UI components.
The easiest way is make the Service a Singleton like it's done here:
public class MusicService extends Service {
private static MusicService instance = null;
public static MusicService getInstance() {
return instance;
}
Handler handler;
Runnable runnable;
NotificationManager nMN;
String songLink;
String songName;
String bandName;
String SongPlaying="";
String BandPlaying="";
public static MediaPlayer mp;
public static Boolean mpState = true;
public static Boolean mpPause = false;
public static Boolean isPlaying = false;
#Override
public void onCreate() {
instance = this;
super.onCreate();
}
// Play Cycle for seekBar
public void PlayCycle(){
seekBar.setProgress(mp.getCurrentPosition());
if (mp.isPlaying()){
runnable = new Runnable() {
#Override
public void run() {
PlayCycle();
}
};
handler.postDelayed(runnable, 1000);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
songLink = intent.getStringExtra("SongLink");
songName = intent.getStringExtra("SongName");
bandName = intent.getStringExtra("BandName");
handler = new Handler();
if (isPlaying && !songName.equals(SongPlaying) && !BandPlaying.equals(bandName)) {
Stop();
mp = new MediaPlayer();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
Uri songUri = Uri.parse(songLink);
mp.setDataSource(getApplicationContext(), songUri);
SongPlaying = songName;
Toast.makeText(getApplicationContext(), "Please wait", Toast.LENGTH_SHORT).show();
isPlaying=true;
new prepare().execute();
}
catch (IOException e) {
e.printStackTrace();
}
}
else if (!isPlaying && !songName.equals(SongPlaying) && !BandPlaying.equals(bandName) ) {
mp = new MediaPlayer();
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
Uri songUri = Uri.parse(songLink);
mp.setDataSource(getApplicationContext(), songUri);
SongPlaying = songName;
Toast.makeText(getApplicationContext(), "Please wait", Toast.LENGTH_SHORT).show();
new prepare().execute();
isPlaying=true;
}
catch (IOException e) {
e.printStackTrace();
}
}
else {
Toast.makeText(getApplicationContext(), "Song is Already Playing", Toast.LENGTH_SHORT).show();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
mp.release();
handler.removeCallbacks(runnable);
}
/// Permanent Notification
private void showNotification() {
nMN = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification n = new Notification.Builder(this)
.setContentTitle(songName)
.setContentText(bandName)
.setSmallIcon(R.drawable.ic_bandcamp)
//.addAction(R.drawable.ic_play_arrow_black_24dp, "button1", new pause())
.setOngoing(true)
.build();
nMN.notify(1, n);
}
/// PREPARE SONG TO PLAY //
public class prepare extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
try {
mp.prepare();
PlayCycle();
seekBar.setMax(mp.getDuration());
mp.start();
SongPlaying = songName;
isPlaying=true;
showNotification(); // show notification
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
Toast.makeText(getApplicationContext(),"Song Finished", Toast.LENGTH_LONG).show();
new stop().execute();
}
});
} catch (IOException io){ io.printStackTrace(); }
return null; }}
/// STOP PLAYING SONG //
public static void Stop()
{
mp.reset();
mp.release();
isPlaying=false;
}
public static class stop extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
try {
mp.reset();
mp.release();
isPlaying=false;
} catch (Exception io){ io.printStackTrace(); }
return null; }}
/// PAUSE PLAYING SONG//
public static class pause extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
try {
mp.pause(); }
catch (Exception io){ io.printStackTrace(); }
return null; }}
public static class start extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
try {
mp.start(); }
catch (Exception io){ io.printStackTrace(); }
return null; }}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
return null;
}
I got location permission and made service , however I don't know how to get My Location from service without adding Map fragment.
I need to get my location and set Text on my TextView. //I don't need to get fragment at this activity
do I need to use post method in TextView? and How can I get Location from Service?
Please Help me! thanks
this is my MainActivity.java extends PermissionActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
switch (compoundButton.getId()) {
case R.id.locationSwitch:
Constants.checkFineLocationPermission(MainActivity.this);
if(compoundButton.isChecked()){
Intent intent = new Intent(MainActivity.this, LocationService.class);
startService(intent);
}else {
Intent intent = new Intent(MainActivity.this, LocationService.class);
stopService(intent);
}
break;
}
}
and this is PermissionActivity.
public void onRequestPermissionsResult(int requestCode, String permissions[],int[] grantResults){
switch (requestCode){
case MY_PERMISSIONS_REQUEST_FINE_LOCATION:{
if(grantResults.length>0 && grantResults[0]== PackageManager.PERMISSION_GRANTED){
Intent intent = new Intent(getApplicationContext(),getClass());
startActivity(intent);
finish();
}else{
// Log.d("Permission always denyed");
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.parse("package:"+ getApplicationContext().getPackageName()));
startActivity(intent);
}
return;
}
}
}
and this is service
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);
}
}
LocationListener[] mLocationListeners = new LocationListener[] {
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};
#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");
initializeLocationManager();
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[1]);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "network provider does not exist, " + ex.getMessage());
}
try {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[0]);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "gps provider does not exist " + ex.getMessage());
}
}
#Override
public void onDestroy()
{
Log.e(TAG, "onDestroy");
super.onDestroy();
if (mLocationManager != null) {
for (int i = 0; i < mLocationListeners.length; i++) {
try {
mLocationManager.removeUpdates(mLocationListeners[i]);
} catch (Exception ex) {
Log.i(TAG, "fail to remove location listners, ignore", ex);
}
}
}
}
private void initializeLocationManager() {
Log.e(TAG, "initializeLocationManager");
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
}
You should use Google Fused Location Service. It's provides most accurate position. Take a tutorial here and here. So basically just put this stuff into service.
I want to track a location every 10 minutes and send it to server through TraceDelivery async task. For this I tried to use a service and timer to get the location every 10 minutes.
But when from another activity I call the service it works only once, i.e. once TraceDelivery api gets called but not again. For testing I have given just a second delay still its not getting called again.
Also if I check if mLatLang is null and then call the TraceDelivery it it did not get called at least once. But if location is null it gets crashed with a null pointer on mLatLang.
Service code :
public class LocationTrackerService extends IntentService implements GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener{
private Handler handler;
private Timer timer;
private TimerTask timerTask;
private GoogleApiClient mGoogleApiClient;
Location mLastLocation;
private LatLng mLatLang;
LocationManager mLocationManager = null;
boolean gps_enabled = false;
boolean network_enabled = false;
LocationListener[] mLocationListeners = new LocationListener[]{
new LocationListener(LocationManager.NETWORK_PROVIDER),
new LocationListener(LocationManager.GPS_PROVIDER)
};
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public LocationTrackerService() {
super("HelloIntentService");
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
#Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
try {
Thread.sleep(1000);
buildGoogleApiClient();
mGoogleApiClient.connect();
handler = new Handler();
initializeLocationManager();
requestLocation();
startTimer(intent.getStringExtra("dl_id"), intent.getStringExtra("pt_id"), intent.getStringExtra("ur_id"),intent.getStringExtra("address"),
intent.getStringExtra("api_key"));
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
}
public void startTimer(String dlId,String ptId,String urId,String add,String key) {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask(dlId, ptId, urId,key);
//schedule the timer, after the first 5000ms the TimerTask will run every 10000ms
timer.schedule(timerTask, 1000, 1000);//
}
public void initializeTimerTask(final String dlId, final String ptId, final String urId, final String key) {
timerTask = new TimerTask() {
public void run() {
//use a handler to run a toast that shows the current timestamp
handler.post(new Runnable() {
public void run() {
TraceDeliveryAsyncTask traceDeliveryAsyncTask = new TraceDeliveryAsyncTask(LocationTrackerService.this);
traceDeliveryAsyncTask.execute(dlId, ptId, urId, String.valueOf(mLatLang.latitude),
String.valueOf(mLatLang.longitude),"", key);
Log.e("timer","success");
}
});
}
};
}
public void stoptimertask() {
//stop the timer, if it's not already null
if (timer != null) {
timer.cancel();
timer = null;
}
}
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(LocationTrackerService.this)
.addConnectionCallbacks(LocationTrackerService.this)
.addOnConnectionFailedListener(LocationTrackerService.this)
.addApi(LocationServices.API)
.build();
}
#Override
public void onConnected(Bundle bundle) {
// Toast.makeText(getActivity(),"onConnected",Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionSuspended(int i) {
// Toast.makeText(getActivity(),"onConnectionSuspended",Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
// Toast.makeText(getActivity(),"onConnectionFailed",Toast.LENGTH_SHORT).show();
}
private void initializeLocationManager() {
// Log.e(Application.TAG, "initializeLocationManager");
if (mLocationManager == null) {
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
}
try {
gps_enabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
} catch (Exception ex) {
}
try {
network_enabled = mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
} catch (Exception ex) {
}
if (!gps_enabled && !network_enabled) {
// notify user
if(!CommonUtils.isGPSEnabled(getApplicationContext()))
startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
}
}
public class LocationListener implements android.location.LocationListener {
public LocationListener() {
}
public LocationListener(String provider) {
Log.e(TAG, "LocationListener " + provider);
mLastLocation = new Location(provider);
}
#Override
public void onLocationChanged(Location location) {
Log.e(TAG, "onLocationChanged: " + location);
//get current location
if(mLastLocation != null && !mLastLocation.equals("")) {
mLastLocation.set(location);
mLatLang = new LatLng(mLastLocation.getLatitude(), mLastLocation.getLongitude());
}
else {
}
}
#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);
}
}
//request for location, first by network, then by gps
public void requestLocation() {
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, 0, 0,
mLocationListeners[0]);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "network provider does not exist, " + ex.getMessage());
}
try {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0,
mLocationListeners[1]);
} catch (java.lang.SecurityException ex) {
Log.i(TAG, "fail to request location update, ignore", ex);
} catch (IllegalArgumentException ex) {
Log.d(TAG, "gps provider does not exist " + ex.getMessage());
}
}
}
How can I achieve this?
Please help with this.Thank you..
IntentService will stop immediately one its finished the task in OnHandleIntent,
So instead of using IntentService try to use Service for long running operations.
The Android AlarmManager class can trigger an intent to be sent to your application at set intervals and execute the defined task.Probably what have you been looking for
I have a huge problem with the bump API on Android. I setup everything like in the example, the first time I start my activity containing the bump code it works great, now if I go back and start it again it just crash due to a Fatal signal error... It happen right after I call the configure of the bump API.
May I need to not call it again ? But there is nothing to check if it already configured or not.
public class BumpActivity extends Activity {
private IBumpAPI api;
private ProgressDialog mDialog;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bump);
mDialog = ProgressDialog.show(BumpActivity.this, "Preparing bump", "Loading");
bindService(new Intent(IBumpAPI.class.getName()), connection,
Context.BIND_AUTO_CREATE);
IntentFilter filter = new IntentFilter();
filter.addAction(BumpAPIIntents.CHANNEL_CONFIRMED);
filter.addAction(BumpAPIIntents.DATA_RECEIVED);
filter.addAction(BumpAPIIntents.NOT_MATCHED);
filter.addAction(BumpAPIIntents.MATCHED);
filter.addAction(BumpAPIIntents.CONNECTED);
registerReceiver(receiver, filter);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public void onBackPressed(){
Intent resultIntent = new Intent();
setResult(Activity.RESULT_CANCELED, resultIntent);
super.onBackPressed();
}
private final ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder binder) {
Log.i("BumpTest", "onServiceConnected");
api = IBumpAPI.Stub.asInterface(binder);
new Thread() {
public void run() {
try {
api.configure("9b17d663752843a1bfa4cc72d309339e",
"Bump User");
} catch (RemoteException e) {
Log.w("BumpTest", e);
}
}
}.start();
Log.d("Bump Test", "Service connected");
}
#Override
public void onServiceDisconnected(ComponentName className) {
Log.d("Bump Test", "Service disconnected");
}
};
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
try {
if (action.equals(BumpAPIIntents.DATA_RECEIVED)) {
getUserDetailFromBump(new String(
intent.getByteArrayExtra("data")));
} else if (action.equals(BumpAPIIntents.MATCHED)) {
long channelID = intent
.getLongExtra("proposedChannelID", 0);
Log.i("Bump Test",
"Matched with: "
+ api.userIDForChannelID(channelID));
api.confirm(channelID, true);
Toast toast = Toast.makeText(
getApplicationContext(),
"Matched with: "
+ api.userIDForChannelID(channelID),
Toast.LENGTH_SHORT);
toast.show();
} else if (action.equals(BumpAPIIntents.CHANNEL_CONFIRMED)) {
long channelID = intent.getLongExtra("channelID", 0);
api.send(channelID, CurrentUserManager.getSharedManager()
.getCurrentUser().getUserId().toString().getBytes());
} else if (action.equals(BumpAPIIntents.NOT_MATCHED)) {
Toast toast = Toast.makeText(getApplicationContext(),
"No match", Toast.LENGTH_SHORT);
toast.show();
} else if (action.equals(BumpAPIIntents.CONNECTED)) {
mDialog.dismiss();
api.enableBumping();
}
} catch (RemoteException e) {
}
}
};
public void getUserDetailFromBump(String data) {
Log.i("User Id", data);
LoginRequest login = new LoginRequest(getApplicationContext());
Log.i("Token", login.getArchivedToken());
AsyncHttpClient restRequest = new AsyncHttpClient();
PersistentCookieStore cookie = new PersistentCookieStore(getApplicationContext());
restRequest.setCookieStore(cookie);
RequestParams params = new RequestParams();
params.put("auth_token", login.getArchivedToken());
params.put("user_id", data);
Log.i("Request", "Preparing");
restRequest.get(Constantes.API_URL + "users/show.json", params, new AsyncHttpResponseHandler(){
public void onSuccess(String response) {
Log.i("Reponse", response);
try {
User user = new User(new JSONObject(response));
Log.i("User", user.toString());
//Driver
if (CurrentUserManager.getSharedManager().getCurrentUser().getType() == 1){
CurrentRouteManager.getSharedManager().getCurrentRoute().addPassanger(user);
Intent resultIntent = new Intent(BumpActivity.this, DriverActivity.class);
resultIntent.putExtra("PASSENGER_ADDED", true);
setResult(1, resultIntent);
finish();
}
else{
Intent p = new Intent(BumpActivity.this, RoutePassenger.class);
p.putExtra("driver", user);
startActivity(p);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onFailure(Throwable e) {
Log.i("Error", e.toString());
}
});
}
public void onStart() {
Log.i("BumpTest", "onStart");
super.onStart();
}
public void onRestart() {
Log.i("BumpTest", "onRestart");
super.onRestart();
}
public void onResume() {
Log.i("BumpTest", "onResume");
super.onResume();
}
public void onPause() {
Log.i("BumpTest", "onPause");
try {
api.disableBumping();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onPause();
}
public void onStop() {
Log.i("BumpTest", "onStop");
try {
api.disableBumping();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onStop();
}
public void onDestroy() {
Log.i("BumpTest", "onDestroy");
try {
api.disableBumping();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
unbindService(connection);
unregisterReceiver(receiver);
super.onDestroy();
}
}
I finally resolved it few days ago. As I'm not a JAVA expert I think the bug is located within the Bump library.
If you do api.configure when it is already configured it simply crash. So I ended up making a singleton, ensuring that it is called only once
Here is the code
public class BumpConnection {
protected Context context;
private IBumpAPI api;
private static BumpConnection sharedManager;
public static synchronized BumpConnection getSharedManager(Context context) {
if (sharedManager == null) {
sharedManager = new BumpConnection(context);
}
return sharedManager;
}
private BumpConnection(Context context){
this.context = context;
context.bindService(new Intent(IBumpAPI.class.getName()), connection,
Context.BIND_AUTO_CREATE);
}
public IBumpAPI getApi() {
return api;
}
public void setApi(IBumpAPI api) {
this.api = api;
}
private final ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder binder) {
Log.i("BumpTest", "onServiceConnected");
api = IBumpAPI.Stub.asInterface(binder);
new Thread() {
public void run() {
try {
api.configure("9b17d663752843a1bfa4cc72d309339e",
"Bump User");
} catch (RemoteException e) {
Log.w("BumpTest", e);
}
}
}.start();
Log.d("Bump Test", "Service connected");
}
#Override
public void onServiceDisconnected(ComponentName className) {
Log.d("Bump Test", "Service disconnected");
}
};
}
Use Latest bump api , available at git hub, read the README.md file carefully.
There is clearly mentioned that by using .aidl file (that is available in src folder) first compile it by using command
android update project -t android-15 -l path_to/bump-api-library -p path_to_your_project/
in your terminal..
If you are a Linux user then set path up to platform-tools then use this command with ./adb .
Then refresh the project , set this Library project as library in your test bump project..
Also replace your bumpapi key that you received via email