Updating activity UI from bounded service - android

I am trying to make an app that calculates taxi/auto fare. The app will run as a background service and will keep updating the ride data like location,fare,distance etc in the background even after the user exits the app. The service will stop when user presses a stop button. Now here my problem is, each time the activty is resumed/restarted its resetting to initial state-as if the service stopped. How do I continuously update the UI so that the activity keeps updated so that whenever user comes to the page updated data is shown. I am runnng a STICKY service.
This is my service
public class LocationManager extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private static final String TAG = LocationManager.class.getSimpleName();
double last_lat = -1000.0f;
double last_lon = -1000.0f;
double dist_total = 0.0f;
double fare_total = 0.0f;
long start_time = -1;
private GoogleApiClient mGoogleApiClient;
private Context mContext;
private LocationRequest mLocationRequest;
private boolean mToStartUpdates = false;
private boolean isInited = false;
private long mLastLocationMillis = 0;
private SharedPreferences settings;
String rideTime = "00h:00m:00s";
private IBinder mBinder = new TukTukMeterBinder();
private Timer timer = new Timer();
public LocationManager(){}
public void init(boolean startUpdates) {
mToStartUpdates = startUpdates;
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
}
public class TukTukMeterBinder extends Binder{
LocationManager getBinder(){
return LocationManager.this;
}
}
public double getDistanceTraveled(){
return dist_total;
}
public double getFare_total(){
return fare_total;
}
public double getLast_lat(){
return last_lat;
}
public double getLast_lon(){
return last_lon;
}
public String getRideTime(){
return rideTime;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
mContext = this;
init(true);
}
#Override
public void onConnected(Bundle bundle) {
LogUtil.i("GoogleApiClient connection has Connected");
isInited = true;
if (mToStartUpdates && RequirementHelper.isLocationEnabled(mContext)) {
createLocationRequest();
} else {
createLocationRequestDialog();
}
}
#Override
public void onConnectionSuspended(int i) {
LogUtil.i("Could not connect to googleApiClient" + i);
if (mGoogleApiClient != null) {
mGoogleApiClient.reconnect();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(AppConstants.ACTION.STARTFOREGROUND_ACTION)) {
LogUtil.i("Received Start Foreground Intent ");
buildNotification();
start_time = System.currentTimeMillis();
mHandler.postDelayed(mUpdateTimeTask,1000);
} else if (intent.getAction().equals(AppConstants.ACTION.STOPFOREGROUND_ACTION)) {
stopForeground(true);
stopSelf();
mHandler.removeCallbacks(mUpdateTimeTask);
}
return START_STICKY;
}
private void buildNotification() {
Intent notificationIntent = new Intent(this, TukTukHomeActivity.class);
notificationIntent.setAction(AppConstants.ACTION.MAIN_ACTION);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.mipmap.ic_launcher);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("TukTuk Meter")
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(
Bitmap.createScaledBitmap(icon, 128, 128, false))
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(AppConstants.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
isInited = false;
}
/**
* This method will automatically creates a dialog for automatically turning on GPS without navigating to settings activity.
*/
public void createLocationRequestDialog() {
mLocationRequest = LocationRequest.create();
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result =
LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
#Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
final LocationSettingsStates state = result.getLocationSettingsStates();
LogUtil.d("onResult state:[" + state + "]");
LogUtil.d("onResult status:[" + status + "]");
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS://Already have a location.
if (RequirementHelper.isLocationEnabled(mContext)) {
createLocationRequest();
break;
} else {
}//$fallthrough without break
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
try {
LogUtil.d("showing request loccation dialog");
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(((Activity) mContext), TukTukHomeActivity.REQUEST_ENABLE_GPS);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the diaLogUtil.
break;
}
}
});
}
/**
* The dialog to be shown to turn on location is currently disabled.
*/
public void createLocationRequest() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(10 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
requestLocationUpdates();
}
public void requestLocationUpdates() {
if (mGoogleApiClient.isConnected() && RequirementHelper.hasAnyLocationPermission(mContext)) {
LogUtil.d("requestLocationUpdates");
LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, LocationManager.this);
}
}
#Override
public void onLocationChanged(Location location) {
LogUtil.d("Fetched AdsLocation" + location);
if (location != null) {
// DataStorePrefManager.getInstance(mContext).saveLastKnownLocation(location);
mLastLocationMillis = SystemClock.elapsedRealtime();
settings = PreferenceManager.getDefaultSharedPreferences(mContext);
double min_fare = settings.getFloat(DataStorePrefManager.KEY_BASE_FARE, 0.0f);
double min_dist = settings.getFloat(DataStorePrefManager.KEY_MIN_DISTANCE, 0.00f);
double rate_per_km = settings.getFloat(DataStorePrefManager.KEY_KM_FARE, 0.00f);
Log.i(TAG, location.getLatitude() + " , " + location.getLongitude());
if (last_lat < -90 || last_lon < -180) {
last_lat = location.getLatitude();
last_lon = location.getLongitude();
} else {
double lat1 = Math.toRadians(last_lat);
double lon1 = Math.toRadians(last_lon);
double lat2 = Math.toRadians(location.getLatitude());
double lon2 = Math.toRadians(location.getLongitude());
double R = 6371.0f;
double dLat = (lat2 - lat1);
double dLon = (lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1) * Math.cos(lat2) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = R * c;
if (d > 0.05 && location.getAccuracy() < 50) // Add only if delta > 50 m and uncertainty < 50m
{
dist_total += d;
if (dist_total > min_dist) {
fare_total = min_fare + (dist_total - min_dist) * rate_per_km;
} else {
fare_total = min_fare;
}
Log.i("Distance", Double.toString(dist_total));
last_lat = location.getLatitude();
last_lon = location.getLongitude();
}
}
DecimalFormat df = new DecimalFormat("#.0");
df.format(fare_total);
df.format(dist_total);
} else return;
}
public void onDestroy() {
isInited = false;
mHandler.removeCallbacks(mUpdateTimeTask);
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
public boolean isInited() {
return isInited;
}
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
private Runnable mUpdateTimeTask = new TimerTask() {
#Override
public void run() {
int hrs = 0,min = 0,sec= 0;
if(start_time != -1)
{
int interval = (int) (System.currentTimeMillis() - start_time)/1000;
sec = interval%60;
min = interval/60;
hrs = interval/3600;
rideTime = String.format("%02dh:%02dm:%02ds", hrs,min,sec);
}
if(isInited){
mHandler.postDelayed(this,1000);
}
}};
}
And this is my Activity
public class TukTukHomeActivity extends AppCompatActivity implements View.OnClickListener, NavigationView.OnNavigationItemSelectedListener {
LocationManager mLocationManager;
public static final int REQUEST_ENABLE_GPS = 100;
boolean bound = false;
TextView rideDistance, totalFare, rideTotalTime, mapsTv;
private DrawerLayout mDrawerLayout;
double distance = 0;
double fareTotal = 0;
String rideTime = "00h:00m:00s";
boolean isRunning = false;
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocationManager.TukTukMeterBinder mBinder = (LocationManager.TukTukMeterBinder) service;
mLocationManager = mBinder.getBinder();
bound = true;
initUI();
displayDistance();
}
#Override
public void onServiceDisconnected(ComponentName name) {
bound = false;
mLocationManager = null;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
initUI();
findViewById(R.id.startRide).setOnClickListener(this);
toolbar.setNavigationIcon(R.drawable.menu);
toolbar.setNavigationOnClickListener(this);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, mDrawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
mDrawerLayout.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.navigation);
navigationView.setNavigationItemSelectedListener(this);
}
private void initUI(){
rideDistance = (TextView)findViewById(R.id.rideDistance) ;
totalFare = (TextView)findViewById(R.id.fareTotal);
rideTotalTime = (TextView)findViewById(R.id.rideTime) ;
mapsTv = (TextView)findViewById(R.id.openMaps);
mapsTv.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.startRide:
startMeterService();
break;
case R.id.drawerLayout:
mDrawerLayout.openDrawer(GravityCompat.START);
break;
case R.id.openMaps:
startActivity(new Intent(this,TukTukMaps.class));
break;
}
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawerLayout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.items, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
startActivity(new Intent(TukTukHomeActivity.this, TukTukSettings.class));
return true;
}
if(id == R.id.navigation){
mDrawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
private void startMeterService() {
Intent startIntent = new Intent(this, LocationManager.class);
startIntent.setAction(AppConstants.ACTION.STARTFOREGROUND_ACTION);
startService(startIntent);
bindService(startIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
displayDistance();
}
#Override
protected void onResume() {
super.onResume();
initUI();
displayDistance();
}
private void displayDistance() {
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
if (mLocationManager != null) {
distance = mLocationManager.getDistanceTraveled();
fareTotal = mLocationManager.getFare_total();
rideTime = mLocationManager.getRideTime();
}
rideDistance.setText(String.valueOf(distance)+"km");
totalFare.setText(getResources().getString(R.string.min_fare_symbol)+String.valueOf(fareTotal));
rideTotalTime.setText(String.valueOf(rideTime));
handler.postDelayed(this, 1000);
}
});
}
#Override
protected void onStop() {
super.onStop();
if (bound) {
unbindService(mServiceConnection);
bound = false;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_ENABLE_GPS:
switch (resultCode) {
case Activity.RESULT_OK:
startMeterService();
break;
case Activity.RESULT_CANCELED:
break;
}
break;
}
}
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.about_us:
startActivity(new Intent(TukTukHomeActivity.this,AboutUs.class));
mDrawerLayout.closeDrawers();
return true;
}
return true;
}
}

To send data from service to activity
Intent i = new Intent();
i.setAction(SOME_ACTION_NAME);
i.setExtra(KEY,VALUE);
context.sendBroadcast(i);
Use a broadcase reciever inside the activity
BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(SOME_ACTION_NAME) {
//read your extra from intent
}
}
}
add your action name to an intent filter and register the broadcast reciever.

Try to use the preference settings and save your values in service class.
Add logs to see whether you're receiving location updates and your values are getting printed or not.
handler.postDelayed(this, 1000); may not be required if your service is updating the values.

Related

How to save state of a progressbar when app is killed?

I am building a simple downloader app, with a pause/resume button. When I click on pause button and kill the app the download progress isn't shown anymore, after I open the app again. I want to save the download progress state even if the app is killed. Can anyone help me with this? I'm building the app using download manager pro library from github.
here's the code:
Activity Class:
public class MainActivity extends AppCompatActivity {
String[] permissions = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
public static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 100;
EditText edt_url;
Button btn_download;
TextView fileNametv, ProgressbarTv;
private MyDownloadService mService;
ProgressBar progressBar;
String filename, url;
/* UrlFileNameListener listener;*/
Integer progress;
MyReceiver receiver;
public static MainActivity instance;
/* RecyclerView recyclerView;
List<Model> downloadList;
LinearLayoutManager manager;
DownloadAdapter adapter;
// ImageView pausebtn;
int position;*/
File myDirectory;
Boolean mBound = false;
Button pause_btn;
int tasktoken;
/* Model model;
Parcelable mListState;
private final String KEY_RECYCLER_STATE = "recycler_state";
private final String KEY_LIST_STATE = "list_state";*/
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mBound = true;
MyDownloadService.LocalBinder localBinder = (MyDownloadService.LocalBinder) iBinder;
mService = localBinder.getService();
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* if(savedInstanceState!=null){
mListState = savedInstanceState.getParcelable(KEY_RECYCLER_STATE);
downloadList =savedInstanceState.getParcelableArrayList(KEY_LIST_STATE);
} */
setContentView(R.layout.activity_main);
edt_url = findViewById(R.id.edt_url);
btn_download = findViewById(R.id.btn_download);
pause_btn = findViewById(R.id.pause_resume);
/*recyclerView = findViewById(R.id.recycler_view);
downloadList = new ArrayList<>();
manager = new LinearLayoutManager(this);
adapter = new DownloadAdapter(downloadList, this);
recyclerView.setLayoutManager(manager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
manager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setAdapter(adapter);*/
fileNametv = findViewById(R.id.download_file_name);
ProgressbarTv = findViewById(R.id.progress_tv);
progressBar = findViewById(R.id.download_progress);
// pausebtn = findViewById(R.id.pause_resume);
instance = this;
/* if (progress!= null && filename != null) {
savedInstanceState.putInt("progress", progress);
savedInstanceState.putString("filename",filename);
// savedInstanceState.putString("filename", model.getFileName());
// savedInstanceState.putParcelable("list",mListState);
}*/
receiver = new MyReceiver();
btn_download.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getDownloadProcess();
}
});
pause_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mService.pauseDownload(tasktoken);
}
});
LocalBroadcastManager.getInstance(this)
.registerReceiver(receiver,
new IntentFilter("download"));
if (checkAndRequestPermissions()) {
myDirectory = new File(Environment.getExternalStorageDirectory() + "/" + "RITSDownloads2");
if (!myDirectory.exists()) {
myDirectory.mkdir();
}
}
}
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this,MyDownloadService.class);
bindService(intent,mServiceConnection,Context.BIND_AUTO_CREATE);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("progress", progress);
outState.putString("filename",filename);
/* mListState = manager.onSaveInstanceState();
outState.putParcelable(KEY_RECYCLER_STATE,mListState);
outState.putParcelableArrayList(KEY_LIST_STATE, (ArrayList<? extends Parcelable>) adapter.getDownloadList());*/
}
#Override
protected void onPause() {
super.onPause();
//mListState = manager.onSaveInstanceState();
}
#Override
protected void onResume() {
super.onResume();
// manager.onRestoreInstanceState(mListState);
}
#Override
public void onBackPressed() {
progress = progressBar.getProgress();
super.onBackPressed();
}
/* #Override
public void onRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onRestoreInstanceState(savedInstanceState, persistentState);
manager.onRestoreInstanceState(mListState);
savedInstanceState.getParcelable(KEY_RECYCLER_STATE);
savedInstanceState.getParcelableArrayList(KEY_LIST_STATE);
}
*/
private void getDownloadProcess() {
url = edt_url.getText().toString();
filename = URLUtil.guessFileName(url, null, null);
//listener.setUrl(url,filename);
edt_url.setText("");
/* model = new Model();
model.setFileName(filename);
downloadList.add(model);
adapter.notifyDataSetChanged();*/
fileNametv.setText(filename);
Intent intent = new Intent(MainActivity.this, MyDownloadService.class);
intent.putExtra("filename", filename);
intent.putExtra("url", url);
intent.setAction(DownloadActions.ACTION.Download_ACTION);
startService(intent);
}
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
progress = intent.getIntExtra("progress", 1);
ReportStructure reportStructure = MyDownloadService.downloadManagerPro.singleDownloadStatus(intent.getIntExtra("tasktoken",1));
tasktoken = intent.getIntExtra("tasktoken",1);
// model.setProgress(progress);
/*int position = downloadList.indexOf(model);
DownloadAdapter.DownloadHolder holder = getDownloadHolder(position);
holder.progressBar.setProgress(progress);*/
progressBar.setProgress(progress);
}
}
/* public DownloadAdapter.DownloadHolder getDownloadHolder(int position) {
return (DownloadAdapter.DownloadHolder) recyclerView.findViewHolderForLayoutPosition(position);
}
*/
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
savedInstanceState.getInt("progress");
savedInstanceState.getString("filename");
/* Log.d("savedInstancestate",savedInstanceState.toString());
//savedInstanceState.getInt("position");
if(savedInstanceState!=null){
List<Model> downloadList = savedInstanceState.getParcelableArrayList(KEY_LIST_STATE);
adapter = new DownloadAdapter(downloadList,this);
}
*/
}
private boolean checkAndRequestPermissions() {
if (ContextCompat.checkSelfPermission(this, permissions[0]) != PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this, permissions[1]) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, permissions, REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
} else {
return true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String permissions[], #NonNull int[] grantResults) {
String TAG = "LOG_PERMISSION";
Log.d(TAG, "Permission callback called-------");
switch (requestCode) {
case REQUEST_ID_MULTIPLE_PERMISSIONS: {
Map<String, Integer> perms = new HashMap<>();
// Initialize the map with both permissions
perms.put(this.permissions[0], PackageManager.PERMISSION_GRANTED);
perms.put(this.permissions[1], PackageManager.PERMISSION_GRANTED);
// Fill with actual results from user
if (grantResults.length > 0) {
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for both permissions
if (perms.get(this.permissions[0]) == PackageManager.PERMISSION_GRANTED
&& perms.get(this.permissions[1]) == PackageManager.PERMISSION_GRANTED
) {
Log.d(TAG, "Phone state and storage permissions granted");
// process the normal flow
//else any one or both the permissions are not granted
//TODO Do your stuff here after permissions granted
} else {
Log.d(TAG, "Some permissions are not granted ask again ");
//permissions is denied (this is the first time, when "never ask again" is not checked) so ask again explaining the usage of permissions
// //shouldShowRequestPermissionRationale will return true
//show the dialog or snackbar saying its necessary and try again otherwise proceed with setup.
if (ActivityCompat.shouldShowRequestPermissionRationale(this, this.permissions[0]) ||
ActivityCompat.shouldShowRequestPermissionRationale(this, this.permissions[1])) {
showDialogOK("Phone state and storage permissions required for this app",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
checkAndRequestPermissions();
break;
case DialogInterface.BUTTON_NEGATIVE:
// proceed with logic by disabling the related features or quit the app.
break;
}
}
});
}
//permissions is denied (and never ask again is checked)
//shouldShowRequestPermissionRationale will return false
else {
Toast.makeText(this, "Go to settings and enable permissions", Toast.LENGTH_LONG)
.show();
//proceed with logic by disabling the related features or quit the app.
}
}
}
}
}
}
private void showDialogOK(String message, DialogInterface.OnClickListener okListener) {
new AlertDialog.Builder(this)
.setMessage(message)
.setPositiveButton("OK", okListener)
.setNegativeButton("Cancel", okListener)
.create()
.show();
}
}
Service Class:
public class MyDownloadService extends Service implements DownloadManagerListener {
private static final String LOG_TAG = "tag";
public static DownloadManagerPro downloadManagerPro;
File myDirectory;
int taskToken;
String name;
Intent notificationIntent;
Notification notification;
PendingIntent pendingIntent;
private IBinder binder = new LocalBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(DownloadActions.ACTION.Download_ACTION)) {
Log.d(LOG_TAG, "Received Start Foreground Intent");
}
name = intent.getStringExtra("filename");
final String url = intent.getStringExtra("url");
Log.d(LOG_TAG, name);
Log.d(LOG_TAG, url);
downloadManagerPro = new DownloadManagerPro(this.getApplicationContext());
downloadManagerPro.init("RITSDownloads2/", 16, this);
myDirectory = new File(Environment.getExternalStorageDirectory() + "/" + "RITSDownloads2");
if (!myDirectory.exists()) {
myDirectory.mkdir();
}
taskToken = downloadManagerPro.addTask(name, url, 16, true, true);
Log.d(LOG_TAG, String.valueOf(taskToken));
try {
downloadManagerPro.startDownload(taskToken);
notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(DownloadActions.ACTION.Download_ACTION);
pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification = new NotificationCompat.Builder(this)
.setContentTitle("Downloading")
.setTicker("Rits Download")
.setContentText(name)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(DownloadActions.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
// stopForeground(true);
// stopSelf();
} catch (IOException e) {
e.printStackTrace();
}
return START_STICKY;
}
#Override
public void OnDownloadStarted(long taskId) {
Log.d(LOG_TAG, "DownloadStarted");
}
#Override
public void OnDownloadPaused(long taskId) {
}
#Override
public void onDownloadProcess(long taskId, double percent, long downloadedLength) {
final int progress = (int) percent;
final int taskToken = (int) taskId;
// int position = positions.get(taskToken);
notification = new NotificationCompat.Builder(this)
.setContentTitle("Downloading")
.setTicker("Rits Download")
.setContentText(name)
.setSmallIcon(android.R.drawable.stat_sys_download)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setColor(ContextCompat.getColor(this, R.color.colorPrimary))
.setProgress(100, progress, false)
.build();
startForeground(DownloadActions.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("progress", progress);
intent.setAction("download");
intent.putExtra("tasktoken",taskToken);
ReportStructure structure = downloadManagerPro.singleDownloadStatus(taskToken);
String name =structure.name;
intent.putExtra("name",name);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
#Override
public void OnDownloadFinished(long taskId) {
}
#Override
public void OnDownloadRebuildStart(long taskId) {
}
#Override
public void OnDownloadRebuildFinished(long taskId) {
}
public void pauseDownload(int taskToken){
ReportStructure reportStructure = downloadManagerPro.singleDownloadStatus(taskToken);
if(reportStructure.state == TaskStates.DOWNLOADING){
downloadManagerPro.pauseDownload(taskToken);
} else if(reportStructure.state == TaskStates.PAUSED){
try {
downloadManagerPro.startDownload(taskToken);
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void OnDownloadCompleted(long taskId) {
Log.d(LOG_TAG, "Download Complete");
/* MainActivity.instance.pausebtn.post(new Runnable() {
#Override
public void run() {
MainActivity.instance.pausebtn.setImageDrawable(getResources().getDrawable(R.drawable.ic_action_done));
}
});*/
notification = new NotificationCompat.Builder(this)
.setContentTitle("Download Complete")
.setTicker("Rits Download")
.setContentText(name)
.setSmallIcon(R.drawable.ic_action_done)
.setContentIntent(pendingIntent)
.setOngoing(true)
.setColor(ContextCompat.getColor(this, R.color.colorPrimary))
.build();
startForeground(DownloadActions.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
}
#Override
public void connectionLost(long taskId) {
}
#Override
public void onTaskRemoved(Intent rootIntent) {
/* Intent restartService = new Intent(getApplicationContext(),this.getClass());
restartService.setPackage(getPackageName());
PendingIntent restartPendingIntent =PendingIntent.getService(getApplicationContext(), 1,restartService, PendingIntent.FLAG_ONE_SHOT);
AlarmManager myAlarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
myAlarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartPendingIntent);*/
}
public class LocalBinder extends Binder{
public MyDownloadService getService(){
return MyDownloadService.this;
}
}
}
I don't know how you want to save the state but I do know that an activity has a onStop() method that you can override.
The onStop() method runs when the app is killed so I would imagine you would want to do your "saving" in this method.
As for saving something I believe you would want to use the SharedPreferences class. You can find more information about that here.
You can find the lifecycle of an activity here
hope this helps
Save the progress on SharedPreferences onDestroy() and retrieve it from there when activity is created.
Cache:
#Override
protected void onDestroy() {
super.onDestroy();
SharedPreferences sharedPreferences = getSharedPreferences("space_name", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt("progress", progress).apply();
}
And retrieve:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences sharedPreferences = getSharedPreferences("space_name", MODE_PRIVATE);
progress = sharedPreferences.getInt("progress", 0); // 0 default value in case is empty
}

Not able to connect to REST API inside a service in some devices

I am using retrofit 1.9 in order to create and use connections with server , its working perfectly in app , but when i am trying to hit api in a service , it is returning me this error
"retrofit.RetrofitError: unexpected end of stream on Connection{, proxy=DIRECT# cipherSuite=none protocol=http/1.1} (recycle count=0)"
and only in some devices like for instance in my Xiaomi Redmi note 3.
Here is my code:-
public class TrackingService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private String latitude = "", longitude = "";
private PrefsManager mPrefs;
int requestID = 42;
private int time = 120000;
private static final long SERVICE_INTERVAL = 60000;
private static final long SERVICE_FASTEST = 30000;
private static final long ONE_MIN = 1000;
private GoogleApiClient googleApiClient;
private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
private boolean canGetLocation = false;
private LocationRequest locationRequest;
private LocationManager locationManager;
private final String TAG = "MyAwesomeApp";
private Runnable runnable = new Runnable() {
#Override
public void run() {
updateLocation();
}
};
private Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
getHandler1().postDelayed(runnable, time);
return true;
}
});
private Handler handler1 = new Handler();
public Handler getHandler1() {
return handler1;
}
private NotificationCompat.Builder mBuilder;
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
canGetLocation = !(!locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER) && !locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER));
}
};
private BroadcastReceiver receiverNetwork = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
time = 5000;
handler.sendMessage(new Message());
}
};
private static API REST_CLIENT;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
registerReceiver(receiverNetwork, new IntentFilter(Constants.NETWORK_BROADCAST));
registerReceiver(receiver, new IntentFilter(Constants.INTENT_LOCATION_SERVICE));
}
private void init() {
mPrefs = new PrefsManager(this);
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
locationRequest.setInterval(SERVICE_INTERVAL);
locationRequest.setFastestInterval(SERVICE_FASTEST);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
canGetLocation = !(!locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER) && !locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER));
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
try {
googleApiClient.connect();
} catch (Exception e) {
e.printStackTrace();
}
updateLocation();
}
#Override
public void onDestroy() {
Log.e(TAG, "GPSTrackerNew destroyed!");
googleApiClient.disconnect();
try {
unregisterReceiver(receiverNetwork);
unregisterReceiver(receiver);
} catch (Exception e) {
e.printStackTrace();
}
this.stopForeground(true);
super.onDestroy();
}
/**
* Update driver location for live tracking
*/
private void updateLocation() {
if (canGetLocation()) {
/*setNotification(this, getResources().getString(R.string.tracking));*/
if (!TextUtils.isEmpty(latitude) && !TextUtils.isEmpty(longitude)) {
get().updateLocation(mPrefs.getAccessToken(), latitude, longitude,
new Callback<PojoBase>() {
#Override
public void success(PojoBase pojoBase, Response response) {
try {
if (pojoBase.status == Constants.SUCCESS) {
time = 120000;
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
handler.sendMessage(new Message());
setNotification(TrackingService.this, getResources().getString(R.string.tracking));
} else if (pojoBase.status == Constants.LOGIN_EXPIRED) {
onDestroy();
}
} catch (Exception e) {
onDestroy();
e.printStackTrace();
}
}
#Override
public void failure(RetrofitError error) {
time = 5000;
setNotification(TrackingService.this, getResources().getString(R.string.network_error));
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
handler.sendMessage(new Message());
}
});
} else {
time = 5000;
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
handler.sendMessage(new Message());
}
} else {
time = 5000;
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
handler.sendMessage(new Message());
setNotification(this, getResources().getString(R.string.not_able_to_fetch_location));
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
init();
return START_STICKY;
}
private void setNotification(Context context, String message) {
Intent intent = null;
intent = new Intent(this, HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, requestID,
intent, 0);
mBuilder = new NotificationCompat.Builder(context)
.setContentTitle(getResources().getString(R.string.app_name))
.setOngoing(true)
.setContentText(message)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent);
this.startForeground(requestID, mBuilder.build());
}
#Override
public void onConnected(#Nullable Bundle bundle) {
fusedLocationProviderApi.requestLocationUpdates(googleApiClient,
locationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "GoogleApiClient connection has been suspend");
}
#Override
public void onLocationChanged(Location location) {
if (location != null) {
Log.i("From service:", "Location received: " + location.toString());
canGetLocation = true;
latitude = String.valueOf(location.getLatitude());
longitude = String.valueOf(location.getLongitude());
} else {
canGetLocation = false;
}
}
public boolean canGetLocation() {
return canGetLocation;
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "GoogleApiClient connection has been failed");
}
public static API get() {
if (REST_CLIENT == null) {
RestAdapter.Builder adapter = new RestAdapter.Builder()
.setClient(new OkClient(getClient()));
adapter.setLogLevel(RestAdapter.LogLevel.BASIC);
adapter.setEndpoint(Constants.ROOT);
RestAdapter mAdapter = adapter.build();
REST_CLIENT = mAdapter.create(API.class);
}
return REST_CLIENT;
}
private static OkHttpClient getClient() {
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(30, TimeUnit.SECONDS);
return client;
}
}
Can anyone tell why is this happening ?
TIA
Try to use execute instead enqueue call.Services is already on different thread. So if you are making a network call on different thread you should run api on same thread.

Location update from a repetitive task not working when mobile screen goes off

I have made a location update foreground service which gets locations directly(requestLocationUpdates) when interval is less than 30 secs and if its more than 30 sec, I use ScheduledExecutorService to get the location result and pool location results to get the best location. Only issue I am facing is I am not getting location updates when screen goes off. This code is working well till mobile screen goes off.
Please take care its a foreground service.
My Code is as below:
private boolean currentlyProcessingLocation = false;
public static int intervalForLocationRequestMethod = 500;
public static int intervalForLocationUpdates = 30000;
public int locationUpdateMethodThreshold = 5000;
public int sameLocationCounter = 0;
boolean locationUpdateMethodChanged = false;
ScheduledExecutorService sch;
Runnable periodicTask = new Runnable() {
#Override
public void run() {
Log.i(TAG, "run: repeat ");
Intent i = new Intent(LocationService.this, LocationService.class);
i.setAction(Constants.ACTION.STARTLOCATIONREPEAT_ACTION);
startService(i);
}
};
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate: ");
buildGoogleApiClient();
if (intervalForLocationUpdates <= locationUpdateMethodThreshold) {
intervalForLocationRequestMethod = intervalForLocationUpdates;
}
showOnGoingLocationServiceNotification();
}
private void showOnGoingLocationServiceNotification() {
Log.i(TAG, "showOnGoingLocationServiceNotification: ");
Intent notificationIntent = new Intent(this, MapsActivity.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MapsActivity.class);
stackBuilder.addNextIntent(notificationIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Forcee")
.setTicker("Forcee Tracking")
.setColor(Color.GREEN)
.setContentText("Forcee is tracking your location....Tap to stop")
.setSmallIcon(R.drawable.cast_ic_notification_small_icon)
.setWhen(System.currentTimeMillis())
.setContentIntent(resultPendingIntent)
.setOngoing(true).build();
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE, notification);}
#Override
public void onConnected(#Nullable Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setFastestInterval(intervalForLocationRequestMethod);
mLocationRequest.setInterval(intervalForLocationRequestMethod);
if (intervalForLocationUpdates <= locationUpdateMethodThreshold || locationUpdateMethodChanged) {
mLocationRequest.setSmallestDisplacement(50);
}
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand: ");
Thread thread = new Thread(new LocationUpdateThread(intent, startId));
thread.start();
return START_STICKY;
}
#Override
public void onLocationChanged(Location location) {
Log.i(TAG, "onLocationChanged: " + location);
if (lastLocation != null) {
if (location.distanceTo(lastLocation) >= 40.0f && locationUpdateMethodChanged && location.getAccuracy() <= 100.0f) {
locationUpdateMethodChanged = false;
currentlyProcessingLocation = false;
sch = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1);
sch.scheduleAtFixedRate(periodicTask, intervalForLocationUpdates, intervalForLocationUpdates, TimeUnit.MILLISECONDS);
}
}
if (location.getAccuracy() <= 100.0f) {
if (firstLocationUpdateCall) {
updatingLocation(location);
firstLocationUpdateCall = false;
} else {
if (location.distanceTo(lastLocation) >= 40.0f) {
updatingLocation(location);
sameLocationCounter = 0;
} else {
if (intervalForLocationUpdates > locationUpdateMethodThreshold && !locationUpdateMethodChanged) {
sameLocationCounter++;
lastLocation = location;
Log.i(TAG, "onLocationChanged: " + sameLocationCounter);
if (sameLocationCounter == 5) {
locationUpdateMethodChanged = true;
intervalForLocationRequestMethod = 1000;
stopLocationUpdates();
sameLocationCounter = 0;
sch.shutdownNow();
sch = null;
Intent i = new Intent(LocationService.this, LocationService.class);
i.setAction(Constants.ACTION.STARTLOCATIONREPEAT_ACTION);
startService(i);
}
Log.i(TAG, "onLocationChanged: " + locationUpdateMethodChanged);
}
}
if (intervalForLocationUpdates> locationUpdateMethodThreshold && !locationUpdateMethodChanged) {
stopLocationUpdates();
Log.i(TAG, "onLocationChanged: stopcheckshift");
}
}
}
}
public void updatingLocation(Location location) {
lastLocation = location;
Log.i(TAG, "onLocationChanged: First " + locationPoints.size());
locationPoints.add(location);
Log.i(TAG, "onLocationChanged: Last " + locationPoints.size());
sendLocationsToActivity(locationPoints);
if (intervalForLocationUpdates > locationUpdateMethodThreshold) {
stopLocationUpdates();
}
}
public void sendLocationsToActivity(ArrayList<Location> locationPoints) {
Log.i(TAG, "sendLocationsToActivity: ");
Intent intent = new Intent("LocationUpdates");
intent.putParcelableArrayListExtra("Locations", locationPoints);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void stopLocationUpdates() {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, LocationService.this);
mGoogleApiClient.disconnect();
currentlyProcessingLocation = false;
}
}
final class LocationUpdateThread implements Runnable {
int service_id;
Intent intent;
LocationUpdateThread(Intent intent, int service_id) {
this.intent = intent;
this.service_id = service_id;
}
#Override
public void run() {
Log.i(TAG, "run: ");
if (intent != null) {
Log.i(TAG, "run: " + intent.getAction());
if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
toastHandler("Tracking Started!");
mGoogleApiClient.connect();
currentlyProcessingLocation = true;
if (intervalForLocationUpdates > locationUpdateMethodThreshold) {
sch = Executors.newScheduledThreadPool(1);
sch.scheduleAtFixedRate(periodicTask, intervalForLocationUpdates, intervalForLocationUpdates, TimeUnit.MILLISECONDS);
}
} else if (intent.getAction().equals(Constants.ACTION.STARTLOCATIONREPEAT_ACTION)) {
if (!currentlyProcessingLocation) {
Log.i(TAG, "run: curt");
checkLocationSettings();
currentlyProcessingLocation = true;
mGoogleApiClient.connect();
}
} else if (intent.getAction().equals(Constants.ACTION.STOPFOREGROUND_ACTION)) {
if (mGoogleApiClient != null && mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, LocationService.this);
mGoogleApiClient.disconnect();
}
if (sch != null) {
sch.shutdownNow();
}
stopForeground(true);
stopSelf();
toastHandler("Tracking Stopped!");
}
}
}
void toastHandler(final String msg) {
Handler h = new Handler(Looper.getMainLooper());
h.post(new Runnable() {
public void run() {
Toast.makeText(LocationService.this, msg, Toast.LENGTH_SHORT).show();
}
});
}
}

Android Geo-fence not working properly

I am using geofence api for proximity but it is not working properly. some times it gives in range and out range at the same location.
i am also using GPS library to improve accuracy of geofence inrange-outrange but still it is not working properly. i am using below code for geofence :
I am using 300 meters radius for considering inrange-outrange (enter-exit)
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.geofencedemo">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".CheckPermission"
android:screenOrientation="portrait"
android:theme="#style/DialogActivity" />
<receiver
android:name="services.GeofenceTransitionsReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="com.geofencedemo.ACTION_RECEIVE_GEOFENCE" />
<category android:name="com.geofencedemo" />
</intent-filter>
</receiver>
<service
android:name="services.GeofenceTransitionsIntentService"
android:exported="false" />
</application>
MainActivity.java (for registering geofence)
public class MainActivity extends Activity implements com.google.android.gms.location.LocationListener {
private LocationManager locationManager;
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private final float GEOFENCE_RADIUS_IN_METERS = 300;//Meter(s)
private final long GEOFENCE_EXPIRATION_IN_MILLISECONDS = Geofence.NEVER_EXPIRE;
private int GEOFENCE_TRANSITION_ENTER = 1;
private int GEOFENCE_TRANSITION_EXIT = 2;
private List<Geofence> mGeofenceList;
private String geofenceID = "testGeofence";
private SharedPreferences preferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
preferences = getSharedPreferences("ISSKEYGEOFENCE-prefs", MODE_PRIVATE);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Button btnSetLocation = (Button) findViewById(R.id.btn_setlocation);
btnSetLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
boolean isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (!isGPSEnabled) {
Toast.makeText(getApplicationContext(), "Please enable Location service to allow set location", Toast.LENGTH_LONG).show();
return;
}
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1){
Log.d("myTag", "check marshmallow permission...");
Intent permissionIntent = new Intent(MainActivity.this, CheckPermission.class);
startActivityForResult(permissionIntent, 1111);
} else {
intGoogleAPI();
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1111:
if (resultCode == RESULT_OK) {
intGoogleAPI();
}
break;
}
}
private void intGoogleAPI() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(3000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setFastestInterval(1000);
mGeofenceList = new ArrayList<Geofence>(1);
mGoogleApiClient = new GoogleApiClient.Builder(MainActivity.this).addApi(LocationServices.API).addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(final Bundle bundle) {
if (isServiceConnected()) {
Log.d("myTag", "request for update current location");
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, MainActivity.this);
}
}
#Override
public void onConnectionSuspended(final int cause) {}
}).addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(final ConnectionResult connectionResult) {}
}).build();
mGoogleApiClient.connect();
}
private boolean isServiceConnected() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(MainActivity.this);
return ConnectionResult.SUCCESS == resultCode;
}
#Override
public void onLocationChanged(Location mLastLocation) {
if (isServiceConnected()) {
Log.d("myTag", "request removed location update");
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
try {
addLocation(mLastLocation.getLatitude(), mLastLocation.getLongitude());
} catch (Exception e) {}
}
public void addLocation(final double latitude, final double longitude) {
Log.v("myTag", "set lcation lat: " + latitude);
Log.v("myTag", "set lcation lag: " + longitude);
mGeofenceList.add(new Geofence.Builder().setRequestId(geofenceID).setTransitionTypes(GEOFENCE_TRANSITION_ENTER | GEOFENCE_TRANSITION_EXIT).setCircularRegion(latitude, longitude, GEOFENCE_RADIUS_IN_METERS).setExpirationDuration(GEOFENCE_EXPIRATION_IN_MILLISECONDS).build());
final List<String> GEO_FENCE_ID_LIST = new ArrayList<String>();
GEO_FENCE_ID_LIST.add(geofenceID);
if (mGoogleApiClient != null) {
LocationServices.GeofencingApi.removeGeofences(mGoogleApiClient, GEO_FENCE_ID_LIST).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(final Status status) {
if (status.isSuccess()) {
// successfully removed geofence...
Log.d("myTag", "removed old geofence successfully ");
} else {
Log.d("myTag", "Not removed old geofence");
}
}
});
}
if (mGoogleApiClient != null) {
LocationServices.GeofencingApi.addGeofences(mGoogleApiClient, getGeofencingRequest(), getGeofencePendingIntent()).setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(final Status status) {
if (status.isSuccess()) {
// successfully Added geofence...
Log.d("myTag", "New geofence successfully added");
Toast.makeText(getApplicationContext(), "Successfully added geofence", Toast.LENGTH_LONG).show();
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isinrange", false);
editor.putString("lat", String.valueOf(latitude));
editor.putString("log", String.valueOf(longitude));
editor.apply();
}
try {
if (isServiceConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, MainActivity.this);
}
mGoogleApiClient.disconnect();
} catch (Exception e) {}
}
});
}
}
private GeofencingRequest getGeofencingRequest() {
GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT);
builder.addGeofences(mGeofenceList);
return builder.build();
}
private PendingIntent getGeofencePendingIntent() {
Intent intent = new Intent("com.geofencedemo.ACTION_RECEIVE_GEOFENCE");
return PendingIntent.getBroadcast(MainActivity.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}
GeofenceTransitionsIntentService (Trigger inrange,outrange by geofence)
public class GeofenceTransitionsIntentService extends IntentService implements com.google.android.gms.location.LocationListener {
public GeofenceTransitionsIntentService() {
super("GeofenceTransitionsIntentService");
}
#Override
public void onCreate() {
super.onCreate();
preferences = getSharedPreferences("ISSKEYGEOFENCE-prefs", MODE_PRIVATE);
}
private LocationRequest mLocationRequest;
private GoogleApiClient mGoogleApiClient;
private boolean isLocationFetched = false;
private String geofenceTransitionIds;
private boolean isInRange = false;
private SharedPreferences preferences;
#Override
protected void onHandleIntent(final Intent intent) {
if (intent.getExtras() != null) {
int geofenceTransitionType = intent.getIntExtra("TransitionType", 4);
geofenceTransitionIds = intent.getStringExtra("TransitionId");
/*final String lat = intent.getStringExtra("TransitionId_lat");
final String log = intent.getStringExtra("TransitionId_log");*/
if (geofenceTransitionIds != null && geofenceTransitionIds.length() > 0) {
switch (geofenceTransitionType) {
case Geofence.GEOFENCE_TRANSITION_ENTER:
geofenceTransitionIds(geofenceTransitionIds, true);
//new IntGoogleApiClient(appStorage, null, true).Intialize();
//processIn(geofenceTransitionIds, lat, log);
break;
case Geofence.GEOFENCE_TRANSITION_EXIT:
geofenceTransitionIds(geofenceTransitionIds, false);
//new IntGoogleApiClient(appStorage, null, true).Intialize();
//processOut(geofenceTransitionIds, lat, log);
break;
}
}
}
}
private void geofenceTransitionIds (String geofenceTransitionIds, boolean isEnteCall) {
if (geofenceTransitionIds != null && geofenceTransitionIds.length() > 0) {
isInRange = isEnteCall;
intGoogleAPI();
}
}
private void intGoogleAPI() {
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(3000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setFastestInterval(1000);
mGoogleApiClient = new GoogleApiClient.Builder(GeofenceTransitionsIntentService.this).addApi(LocationServices.API).addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(final Bundle bundle) {
if (isServiceConnected()) {
// please consider here location permission is already allowed...
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, GeofenceTransitionsIntentService.this);
}
}
#Override
public void onConnectionSuspended(final int cause) {}
}).addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(final ConnectionResult connectionResult) {}
}).build();
mGoogleApiClient.connect();
}
private boolean isServiceConnected() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(GeofenceTransitionsIntentService.this);
return ConnectionResult.SUCCESS == resultCode;
}
#Override
public void onLocationChanged(Location passedLocation) {
if (passedLocation != null && !isLocationFetched) {
if (isServiceConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, GeofenceTransitionsIntentService.this);
}
isLocationFetched = true;
try {
if (geofenceTransitionIds != null && geofenceTransitionIds.length() > 0) {
if (isInRange) {
processIn(geofenceTransitionIds, String.valueOf(passedLocation.getLatitude()), String.valueOf(passedLocation.getLongitude()));
} else {
processOut(geofenceTransitionIds, String.valueOf(passedLocation.getLatitude()), String.valueOf(passedLocation.getLongitude()));
}
}
} catch (Exception e) {}
disconnectGoogleClient();
}
}
private void disconnectGoogleClient() {
try {
if (mGoogleApiClient != null) {
if (isServiceConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, GeofenceTransitionsIntentService.this);
}
mGoogleApiClient.disconnect();
}
} catch (Exception e) {}
}
private void processIn(String passedIds, String lat, String log) {
if (passedIds != null) {
List<String> items = Arrays.asList(passedIds.split("\\s*,\\s*"));
for (String deviceName : items) {
if (deviceName != null) {
boolean isOutRange = preferences.getBoolean("isinrange", false);
if (mappingRadius(true, deviceName, lat, log) && isOutRange) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isinrange", false);
editor.apply();
sendNotification(GeofenceTransitionsIntentService.this, "In range come!", Color.BLACK);
}
}
}
}
}
private void processOut(String passedIds, String lat, String log) {
if (passedIds != null) {
List<String> items = Arrays.asList(passedIds.split("\\s*,\\s*"));
for (String deviceName : items) {
if (deviceName != null) {
boolean isInRange = preferences.getBoolean("isinrange", false);
if (mappingRadius(false, deviceName, lat, log) && !isInRange) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("isinrange", true);
editor.apply();
sendNotification(GeofenceTransitionsIntentService.this, "Out range come!", Color.RED);
}
}
}
}
}
private boolean mappingRadius(boolean isInRange, String deviceName, String currentLat, String currentLog) {
final float cLat = Float.parseFloat(currentLat);
final float cLog = Float.parseFloat(currentLog);
Log.d("myTag", "GeofenceTransitionsReceiver lat " + cLat);
Log.d("myTag", "GeofenceTransitionsReceiver log " + cLog);
float appLat;
float appLog;
appLat = Float.parseFloat(preferences.getString("lat", "0.0"));
appLog = Float.parseFloat(preferences.getString("log", "0.0"));
Log.d("myTag", "GeofenceTransitionsReceiver app lat " + appLat);
Log.d("myTag", "GeofenceTransitionsReceiver app log " + appLog);
Location current_latlog = new Location("crntlocation");
current_latlog.setLatitude(appLat);
current_latlog.setLongitude(appLog);
Location new_latlog = new Location("newlocation");
new_latlog.setLatitude(cLat);
new_latlog.setLongitude(cLog);
final double distance = current_latlog.distanceTo(new_latlog);
Log.v("myTag", "GeofenceTransitionsReceiver calculation distance is: " + distance);
//if (distance < 2000) {
if (isInRange) {
if (distance <= 300) { // with in 300 Meters consider as in range...
return true;
} else {
return false;
}
} else {
if (distance >= 300) { // more than 300 Meters consider as out range...
return true;
} else {
return false;
}
}
/*} else {
return false;
}*/
}
private void sendNotification(final Context context, String notificationMessage, int color) {
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntent(new Intent());
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setSmallIcon(R.mipmap.ic_launcher).setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher)).setContentTitle(context.getResources().getString(R.string.app_name)).setTicker(notificationMessage).setContentText(notificationMessage).setContentIntent(notificationPendingIntent).setColor(color).setVibrate(new long[] { 1000, 1000, 1000, 1000 }).setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify((int) System.currentTimeMillis(), builder.build());
}
}
GeofenceTransitionsReceiver (handling/calculate distance after geofence trigger)
public class GeofenceTransitionsReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent.hasError()) {
String errorMessage = getErrorString(context, geofencingEvent.getErrorCode());
Log.d("myTag", "GeofenceTransitionsReceiver error " +errorMessage);
// sendNotification(context, errorMessage, Color.RED);
return;
}
int geofenceTransition = geofencingEvent.getGeofenceTransition();
Log.d("myTag", "GeofenceTransitionsReceiver " + geofenceTransition);
// for testing....
//sendNotification(context, context.getResources().getString(R.string.geofence_transition_type, geofenceTransition), Color.RED);
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
String geofenceTransitionIds = getGeofenceTransitionIds(triggeringGeofences);
Location triggeringLocation = geofencingEvent.getTriggeringLocation();
Intent serviceIntent = new Intent(context.getApplicationContext(), GeofenceTransitionsIntentService.class);
serviceIntent.putExtra("TransitionType", geofenceTransition);
serviceIntent.putExtra("TransitionId", geofenceTransitionIds);
serviceIntent.putExtra("TransitionId_lat", String.valueOf(triggeringLocation.getLatitude()));
serviceIntent.putExtra("TransitionId_log", String.valueOf(triggeringLocation.getLongitude()));
context.startService(serviceIntent);
} else {
// sendNotification(context,
// context.getResources().getString(R.string.geofence_transition_invalid_type,
// geofenceTransition), Color.RED);
}
}
private String getErrorString(final Context context, int errorCode) {
Resources mResources = context.getResources();
switch (errorCode) {
case GeofenceStatusCodes.GEOFENCE_NOT_AVAILABLE:
return "Geofence service is not available now";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_GEOFENCES:
return "Your app has registered too many geofences";
case GeofenceStatusCodes.GEOFENCE_TOO_MANY_PENDING_INTENTS:
return "You have provided too many PendingIntents to the addGeofences() call";
default:
return "Unknown error: the Geofence service is not available now";
}
}
private String getGeofenceTransitionIds(List<Geofence> triggeringGeofences) {
List<String> triggeringGeofencesIdsList = new ArrayList<String>();
for (Geofence geofence : triggeringGeofences) {
triggeringGeofencesIdsList.add(geofence.getRequestId());
}
return TextUtils.join(",", triggeringGeofencesIdsList);
}
}
Is there anything else we can do to improve accuracy and overcome the problem of inrange outrange at the same location ?

Intent Service getting killed after sometime

I have implemented an intent service in my application, the purpose of which is to monitor the device's shake on a continuous basis.According to the requirement,whenever a shake is detected ,this info should be sent to the app server.
When I started this implementation I had a dilemma on whether to use service or intent service but I chose the latter.Currently,I am able to detect the shake and this info is getting relayed to my app server,but sometimes from 15 min to 2 hour(post starting the app) I notice that this intent service no longer seems to detect any shakes(seems its getting killed on its own).
Here is my code:
public class TheftAlertService1 extends IntentService {
/* The connection to the hardware */
private SensorManager mySensorManager;
/* Here we store the current values of acceleration, one for each axis */
private float xAccel;
private float yAccel;
private float zAccel;
/* And here the previous ones */
private float xPreviousAccel;
private float yPreviousAccel;
private float zPreviousAccel;
private static int SyncRunningFlag = 0;
private double latitude; // latitude
private double longitude; // longitude
/* Used to suppress the first shaking */
private boolean firstUpdate = true;
/* What acceleration difference would we assume as a rapid movement? */
private final float shakeThreshold = .75f;
/* Has a shaking motion been started (one direction) */
private boolean shakeInitiated = false;
public TheftAlertService1() {
super("TheftAlertService1");
Log.d("TheftAlertService1", "inside constr");
// TODO Auto-generated constructor stub
}
#Override
protected void onHandleIntent(Intent arg0) {
mySensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); // (1)
mySensorManager.registerListener(mySensorEventListener,
mySensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL); // (2)
Log.d("TheftAlertService1", "Inside shake onHandleEvent");
}
/* The SensorEventListener lets us wire up to the real hardware events */
private final SensorEventListener mySensorEventListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent se) {
updateAccelParameters(se.values[0], se.values[1], se.values[2]); // (1)
if ((!shakeInitiated) && isAccelerationChanged()) { // (2)
shakeInitiated = true;
} else if ((shakeInitiated) && isAccelerationChanged()) { // (3)
executeShakeAction();
} else if ((shakeInitiated) && (!isAccelerationChanged())) { // (4)
shakeInitiated = false;
}
}
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
};
/* Store the acceleration values given by the sensor */
private void updateAccelParameters(float xNewAccel, float yNewAccel,
float zNewAccel) {
/*
* we have to suppress the first change of acceleration, it results from
* first values being initialized with 0
*/
if (firstUpdate) {
xPreviousAccel = xNewAccel;
yPreviousAccel = yNewAccel;
zPreviousAccel = zNewAccel;
firstUpdate = false;
} else {
xPreviousAccel = xAccel;
yPreviousAccel = yAccel;
zPreviousAccel = zAccel;
}
xAccel = xNewAccel;
yAccel = yNewAccel;
zAccel = zNewAccel;
}
/*
* If the values of acceleration have changed on at least two axises, we are
* probably in a shake motion
*/
private boolean isAccelerationChanged() {
float deltaX = Math.abs(xPreviousAccel - xAccel);
float deltaY = Math.abs(yPreviousAccel - yAccel);
float deltaZ = Math.abs(zPreviousAccel - zAccel);
return (deltaX > shakeThreshold && deltaY > shakeThreshold)
|| (deltaX > shakeThreshold && deltaZ > shakeThreshold)
|| (deltaY > shakeThreshold && deltaZ > shakeThreshold);
}
private void executeShakeAction() {
Log.d("TheftAlertService1", "inside executeShakeAction");
if (SyncRunningFlag == 0)
new SendTheftAlertToBackend().execute();
}
/******************************************************************************************************/
class SendTheftAlertToBackend extends AsyncTask<String, String, String> implements LocationListener{
JSONParser jsonParser = new JSONParser();
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String device_id = tm.getDeviceId();
#Override
protected void onPreExecute() {
super.onPreExecute();
SyncRunningFlag = 1;
LocationManager locationManager;
Location location; // location
locationManager = (LocationManager) getApplicationContext().getSystemService(LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0,0, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
Log.d("TheftAlertService1", "Latitude - " +latitude + "longitude - "+longitude);
}
}
Log.d("TheftAlertService1", "Sending Theft Alert to app server");
}
protected String doInBackground(String... args) {
String theft_alert_time = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance()
.getTime());
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("device_id", device_id));
params.add(new BasicNameValuePair("theft_alert_time",theft_alert_time));
params.add(new BasicNameValuePair("theft_alert_longitude","lon -" + longitude));
params.add(new BasicNameValuePair("theft_alert_latitude","lat -" + latitude));
// getting JSON Object
JSONObject json = jsonParser.makeHttpRequest(
AppConstants.url_theft_alert, "POST", params);
try {
Log.d("TheftAlertService1,Response from server : ",
json.toString());
} catch (Exception e1) {
e1.printStackTrace();
SyncRunningFlag = 0;
}
// check for success tag
try {
int success = json.getInt(AppConstants.TAG_SUCCESS);
String tagDeviceId = json.getString(AppConstants.TAG_DEVICE_ID);
if (success == 1 && tagDeviceId.equals(device_id)) {
Log.d("TheftAlertService1",
"Theft Alert successfully logged in server");
SyncRunningFlag = 0;
} else {
Log.d("TheftAlertService1",
"Failed to log Theft Alert in server");
SyncRunningFlag = 0;
}
} catch (Exception e) {
e.printStackTrace();
SyncRunningFlag = 0;
}
return null;
}
protected void onPostExecute(String file_url) {
Log.d("TheftAlertService1", "inside onPost of async task");
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
}
}
This is what I have tried till now :
1) I have overridden onStartCommand and gave its return as START REDELIVER INTENT
2) I tried to make the intent service in foreground.
But nethier of these two options have 'sustained' the continuous background monitoring of shake on my device.
Following code I tried but in vain:
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
final int myID = 1234;
//The intent to launch when the user clicks the expanded notification
Intent intentService = new Intent(this, Staff.class);
intentService.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendIntent = PendingIntent.getActivity(this, 0, intentService, 0);
//This constructor is deprecated. Use Notification.Builder instead
Notification notice = new Notification(R.drawable.ic_launcher, "Ticker text", System.currentTimeMillis());
//This method is deprecated. Use Notification.Builder instead.
notice.setLatestEventInfo(this, "Title text", "Content text", pendIntent);
notice.flags |= Notification.FLAG_NO_CLEAR;
startForeground(myID, notice);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("TheftAlertService1","Service got killed");
}
What is it that I am doing wrong? What should I do to make my intent service to run continuously in the background(and sense shakes forever).
Any help is appreciated.Thanks !
As Pankaj Kumar suggested I created my shake detection inside a service instead of an IntentService (as I was trying before,which used to fail to detect the shakes after sometime).I tested my service for 48 hours straight on devices(like nexus4,galaxy grand) and was able to detect shakes for the above tested period whenever the device was shaked.
To make the service live indefinitely I made the service foreground and returned START_STICKY as shown below.Following is the full code:
public class ShakeService extends Service {
/* The connection to the hardware */
private SensorManager mySensorManager;
/* Here we store the current values of acceleration, one for each axis */
private float xAccel;
private float yAccel;
private float zAccel;
/* And here the previous ones */
private float xPreviousAccel;
private float yPreviousAccel;
private float zPreviousAccel;
/* Used to suppress the first shaking */
private boolean firstUpdate = true;
/* What acceleration difference would we assume as a rapid movement? */
private final float shakeThreshold = .75f;
/* Has a shaking motion been started (one direction) */
private boolean shakeInitiated = false;
private BackgroundThread backGroundThread = null;
SensorEventListener mySensorEventListener;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
if (backGroundThread == null) {
backGroundThread = new BackgroundThread();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (backGroundThread == null)
backGroundThread = new BackgroundThread();
if ((backGroundThread.getState() == Thread.State.NEW) || (backGroundThread.getState() == Thread.State.TERMINATED)) {
if (backGroundThread.getState() == Thread.State.TERMINATED)
backGroundThread = new BackgroundThread();
backGroundThread.start();
Notification localNotification = new Notification(R.drawable.ic_launcher, "", System.currentTimeMillis());
localNotification.setLatestEventInfo(this,AppConstants.NOTIFICATION_NAME,AppConstants.NOTIFICATION_DESCRIPTION, null);
localNotification.flags = Notification.FLAG_NO_CLEAR;
startForeground(377982, localNotification);
mySensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mySensorManager.registerListener(mySensorEventListener,mySensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL);
Log.d("ShakeService", "Inside shake onStartCommand");
}
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
BackgroundThread.yield();
backGroundThread = null;
}
class BackgroundThread extends Thread {
#Override
public void run() {
/* The SensorEventListener lets us wire up to the real hardware events */
mySensorEventListener = new SensorEventListener() {
public void onSensorChanged(SensorEvent se) {
updateAccelParameters(se.values[0], se.values[1], se.values[2]);
if ((!shakeInitiated) && isAccelerationChanged()) {
shakeInitiated = true;
} else if ((shakeInitiated) && isAccelerationChanged()) {
executeShakeAction();
} else if ((shakeInitiated) && (!isAccelerationChanged())) {
shakeInitiated = false;
}
}
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
/* Store the acceleration values given by the sensor */
private void updateAccelParameters(float xNewAccel, float yNewAccel,float zNewAccel) {
/*
* we have to suppress the first change of acceleration, it results from
* first values being initialized with 0
*/
if (firstUpdate) {
xPreviousAccel = xNewAccel;
yPreviousAccel = yNewAccel;
zPreviousAccel = zNewAccel;
firstUpdate = false;
} else {
xPreviousAccel = xAccel;
yPreviousAccel = yAccel;
zPreviousAccel = zAccel;
}
xAccel = xNewAccel;
yAccel = yNewAccel;
zAccel = zNewAccel;
}
/*
* If the values of acceleration have changed on at least two axises, we are
* probably in a shake motion
*/
private boolean isAccelerationChanged() {
float deltaX = Math.abs(xPreviousAccel - xAccel);
float deltaY = Math.abs(yPreviousAccel - yAccel);
float deltaZ = Math.abs(zPreviousAccel - zAccel);
return (deltaX > shakeThreshold && deltaY > shakeThreshold) || (deltaX > shakeThreshold && deltaZ > shakeThreshold) || (deltaY > shakeThreshold && deltaZ > shakeThreshold);
}
private void executeShakeAction() {
Log.d("ShakeService", "inside executeShakeAction");
// Or do something like post the shake status to app server
}
};
}
}
}
newIntent(GcmIntentService.this,TheftAlertService1.class); startService(theftAlertIntent);
replace this with
newIntent(getApplicationContext(),TheftAlertService1.class); startService(theftAlertIntent);

Categories

Resources