Question

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 !

Was it helpful?

Solution

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
                            }
                        };
                    }
                }   
            }

OTHER TIPS

newIntent(GcmIntentService.this,TheftAlertService1.class); startService(theftAlertIntent);

replace this with

newIntent(getApplicationContext(),TheftAlertService1.class); startService(theftAlertIntent);

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top