0

i've an app that plots the route between the current user's position and that of a postcode from another activity. It all works well apart from one feature. I've implemented a timer via a handler/runnable mechanism. If the display is not touched for a predetermined time eg 2 mins, then i go back to the menu screen where the usewr has to log in again. It's a security feature of my app.

I've overridden the dispatchTouchEvent method so that when the user touches the screen the timer is reset. This part is not working correctly. The app goes to the menu screen regardless whether the user has touched the screen or not.

I thought that if i set the handler and runnable to null and remove all callbacks to the runnable before starting the timer again would work.

Can anyone tell me how to cancel the current runnable and restart it again.

Here's the full code, thank in advance. matt.

public class GetClientDirections extends MapActivity implements LocationListener{

    private MapController mapController;
    private MapView mapView;

    private List<Overlay> mapOverlays;
    private StringBuffer response = null;
    private static final String TAG = GetClientDirections.class.getSimpleName();
    private double lon;
    private double lat;
    private JSONArray routes = null;
    private JSONObject bounds = null;
    private JSONObject northeast = null;
    private JSONObject anonObject;
    private JSONObject overViewPolyline;
    private String stringUrl;
    private String polyPoints;
    Context context;
    private String endAddr;
    private GeoPoint startAddr;
    BroadcastReceiver locationChangereceiver;
    double lati;
    double lngi;
    boolean isTrafficOn;
    SharedPreferences  appSharedPrefs;
    Handler handler;
    Runnable runnable;
    String rotaAutoLogout;
    int rotaAutoLogoutAsInt;
    final String               QRCODE_ACTION = "com.carefreegroup.QRCODE_ACTION";
    NfcScannerApplication      nfcscannerapplication;
    private LocationManager locationManager;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.mapview);

        Intent intent = this.getIntent();
        String postcode = intent.getStringExtra("postcode");
        Log.e(TAG, "postcode = " + postcode);
        appSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        nfcscannerapplication = (NfcScannerApplication) getApplication();


                context = this;
                endAddr = postcode;

                isTrafficOn = false;

                rotaAutoLogout = appSharedPrefs.getString("120", null);    
                rotaAutoLogoutAsInt = Integer.parseInt(rotaAutoLogout);

                if(rotaAutoLogoutAsInt > 0){
                    initHandler();
                    handler.postDelayed(runnable, rotaAutoLogoutAsInt * 1000);
                    }   





    }// end of onCreate


    public void initHandler(){

          handler = new Handler();
          runnable = new Runnable() {
                public void run() {
                    returnToMenu();

                }

                private void returnToMenu() {
                    Intent intent2 = new Intent(GetClientDirections.this,
                            NfcscannerActivity.class);
                    intent2.setAction(QRCODE_ACTION);
                    intent2.putExtra("carerid", nfcscannerapplication.getCarerID());
                    startActivity(intent2);
                }
            };

        }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        Log.e(TAG, "screen touched");
           if(rotaAutoLogoutAsInt > 0){

            handler.removeCallbacks(runnable);
            handler = null;
            runnable = null;
            initHandler();
            handler.postDelayed(runnable, rotaAutoLogoutAsInt * 1000);
            Log.e(TAG, " reset timer");
           }
            return super.dispatchTouchEvent(ev);

    }




    @Override
    protected void onPause() {
        locationManager.removeUpdates(this);
         handler.removeCallbacks(runnable);
        super.onPause();
    }




    @Override
    protected void onResume() {
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);

            handler.removeCallbacks(runnable);
            initHandler();
            handler.postDelayed(runnable, rotaAutoLogoutAsInt * 1000);

        super.onResume();
    }





    @Override
    protected void onStop() {
        handler.removeCallbacks(runnable);

        super.onStop();
    }





    private class AsyncGetRoute extends AsyncTask<Void, Void, Void> {


        @Override
        protected Void doInBackground(Void... params) {

            getRoute();
            return null;
        }


        @Override
        protected void onPostExecute(Void result) {

            String jsonOutput = response.toString();
            Log.e(TAG, "jsonOutput = " + jsonOutput);

            JSONObject results = null;
            try {

                results = new JSONObject(jsonOutput);

                routes = results.getJSONArray("routes");

                anonObject = routes.getJSONObject(0);
                bounds = anonObject.getJSONObject("bounds");
                overViewPolyline = anonObject.getJSONObject("overview_polyline");
                polyPoints = overViewPolyline.getString("points");
                Log.e(TAG, "overview_polyline  = " + overViewPolyline);
                Log.e(TAG, "points  = " + polyPoints);

                northeast = bounds.getJSONObject("northeast");

                lat = (Double) northeast.get("lat");

                lon = (Double) northeast.get("lng");

                Log.e(TAG, "lon/lat = " + lon + " " + lat);

            } catch (NumberFormatException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }



            List<GeoPoint> list = decodePoly(polyPoints);



            mapView = (MapView) findViewById(R.id.cfmapview);
            mapView.setBuiltInZoomControls(true);
            mapView.setEnabled(true);
            mapView.setSatellite(true);

            mapController = mapView.getController();
            mapController.setZoom(10);
            mapOverlays = mapView.getOverlays();
            mapOverlays.clear();
            mapOverlays.add(new RoutePathOverlay(list, getApplicationContext()));
            mapController.animateTo(new GeoPoint(list.get(0).getLatitudeE6(), list
                    .get(0).getLongitudeE6()));

            mapView.invalidate();

            super.onPostExecute(result);
        }


    }





    public void getRoute() {

        response = new StringBuffer();
        URL url = null;
        try {
            url = new URL(stringUrl);
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        HttpURLConnection httpconn = null;
        try {
            httpconn = (HttpURLConnection) url.openConnection();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            if (httpconn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                // Log.e(TAG,"response code OK ");
                BufferedReader input = new BufferedReader(
                        new InputStreamReader(httpconn.getInputStream()), 8192);
                String strLine = null;

                while ((strLine = input.readLine()) != null) {
                    // Log.e(TAG,""+strLine);
                    response.append(strLine);
                }
                input.close();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }// end of getRoute




    private List<GeoPoint> decodePoly(String encoded) {

        List<GeoPoint> poly = new ArrayList<GeoPoint>();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;

        while (index < len) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lat += dlat;

            shift = 0;
            result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;

            GeoPoint p = new GeoPoint((int) (((double) lat / 1E5) * 1E6),
                    (int) (((double) lng / 1E5) * 1E6));
            poly.add(p);
        }

        return poly;
    }

    @Override
    protected boolean isRouteDisplayed() {
        // TODO Auto-generated method stub
        return false;
    }




    @Override
    public void onLocationChanged(Location location) {
         lati =  (location.getLatitude());
         lngi =  (location.getLongitude());
         startAddr = new GeoPoint((int)(lati*1000000.0), (int)(lngi*1000000.0));
        Log.e(TAG, "lat = " + lati);
        Log.e(TAG, "lon = " + lngi);
        Log.e(TAG, "lat after cast  = " + (int)(lati * 1000000));
        Log.e(TAG, "lon after cast = " + (int)(lngi * 1000000));
        locationManager.removeUpdates(this);
        StringBuilder sb = new StringBuilder();
        sb.append("http://maps.google.com/maps/api/directions/json?origin=");
        //sb.append(startAddr);
        sb.append(lati);
        sb.append(",");
        sb.append(lngi);
        sb.append("&destination=");
        sb.append(endAddr);
        sb.append("&sensor=false");

        stringUrl = sb.toString();
        Log.e(TAG, "url = " + stringUrl);
        AsyncGetRoute agr = new AsyncGetRoute();
        agr.execute();

    }




    @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

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.layout.menutogglemapview, menu);
        return true;

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {


        switch (item.getItemId()) {

    case R.id.satellite:

        mapView.setSatellite(true);

        return true;

    case R.id.terrain:

        mapView.setSatellite(false);

        return true;

    case R.id.traffic:



        if(isTrafficOn == false){
        mapView.setTraffic(true);
        isTrafficOn = true;
        }else{
            mapView.setTraffic(false);
            isTrafficOn = false;
        }

        return true;



    default:

        return super.onOptionsItemSelected(item);

        }
    }

}
turtleboy
  • 8,210
  • 27
  • 100
  • 199
  • And you're sure that you call `removeCallbacks()`, right? BTW, you don't need to create `Handler` again and again, do it once in `onCreate`. – Code Painters Nov 16 '12 at 13:34
  • @Code Painters Hi yes it is called, i've logged it out. – turtleboy Nov 16 '12 at 13:38
  • 1
    Please only create one `Handler` and one `Runnable`. Right now, you are creating one of each on every touch event. You might also consider dumping the cancel-and-reschedule logic. Just set up a `Runnable` to run every couple of seconds, and check to see if the last time the user touched the screen (timestamp maintained by your `dispatchTouchEvent()`) has exceeded your desired timeout period. – CommonsWare Nov 16 '12 at 13:42
  • 1
    It's a bit hard to see what's going on without debugging, I'd expect it to work, at first sight. As @CommonsWare said, there's no point recreating either `Runnable` or `Handler` instances - but still, it should work this way. BTW, you should trim away unrelated pieces of code before asking for help. – Code Painters Nov 16 '12 at 13:47

1 Answers1

1

You can simplify all your code related to starting/stoping this timer using the following approach:

//Generic Task Start/Stop 

private Handler mHandler = new Handler();

private void startTimer(Runnable Task, long delay) {  
    mHandler.removeCallbacks(Task);       
    mHandler.postDelayed(Task, delay);    
}

private void stopTimer(Runnable Task) {  
    mHandler.removeCallbacks(Task);       
}

//Now your specific code

private Runnable tReturnToMenu = new Runnable() {
    public void run() {
         returnToMenu();
    }
};

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {

    Log.e(TAG, "screen touched");
       if(rotaAutoLogoutAsInt > 0){
             stopTimer(tButtonFadeOut);
             startTimer(tButtonFadeOut);
             Log.e(TAG, " reset timer");
       }
        return super.dispatchTouchEvent(ev);

}

Regards.

Luis
  • 11,978
  • 3
  • 27
  • 35
  • I suggest making `Task` parameter lowercase :) – Code Painters Nov 16 '12 at 14:13
  • @Luis Hi Luis, No it still calls the returnToMenu method 2 mins after the activity starts regardless if the user touches the screen. The time is not being reset. The orginal code does actually work in the 2 activities prior to the activity that is in the opening post. It just doesn't seem to work with this activity. The difference with this activity is that it has a google mapview and it implements location listener the other 2 prior don't – turtleboy Nov 16 '12 at 14:26
  • @Luis actually i've just tested it again and the original code in the 2 activities prior to this one calls the returnToMenu method after 2 mins regardless of any touch events. So none of it works. For some reason the timer is not being reset – turtleboy Nov 16 '12 at 15:17