Venkata
Venkata

Reputation: 51

How to display duration using Google Maps?

I am trying to display to the user just the duration between two locations using latitude and longitude. I am having trouble with permissions which I am not sure how to handle it.

Here is my doInBackground code:

protected String[] doInBackground(String... params) {


            try {
                LocationManager locationManager = (LocationManager) MyCustomHomeActivity.this
                        .getSystemService(LOCATION_SERVICE);

                // getting GPS status
                boolean isGPSEnabled = locationManager
                        .isProviderEnabled(LocationManager.GPS_PROVIDER);

                // getting network status
                boolean isNetworkEnabled = locationManager
                        .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

                if (!isGPSEnabled && !isNetworkEnabled) {
                    // no network provider is enabled
                } else {

                    // if GPS Enabled get lat/long using GPS Services
                    if (isGPSEnabled) {

                            if (locationManager != null) {
                                location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

                                if (location != null) {
                                    latitude = location.getLatitude();
                                    longitude = location.getLongitude();
                                }
                            }
                        }
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }


            String shuLat = "41.2207188";
            String shuLong = "-73.24168179999999";
            String forecastJsonStr = null;

            String myUrlSetup = "https://maps.googleapis.com/maps/api/directions/json?origin="+latitude + "," + longitude +"&destination="+shuLat +"," + shuLong + "&departure_time=now&traffic_model=best_guess&key=AIzaSyB6l8vrnspw2-1Q_cnzO03JlAsIOMl-7bs";
            HttpURLConnection urlConnection = null;
            BufferedReader reader = null;

            try {

                URL url;
                url = new URL(myUrlSetup);


                // Create the request to GoogleMapAPI, and open the connection
                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("GET");
                urlConnection.connect();

                // Read the input stream into a String
                InputStream inputStream = urlConnection.getInputStream();
                StringBuffer buffer = new StringBuffer();
                if (inputStream == null) {
                    // Nothing to do.
                    return null;
                }
                System.out.println("I am in doInBackground step3");
                reader = new BufferedReader(new InputStreamReader(inputStream));

                String line;
                while ((line = reader.readLine()) != null) {
                    // Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
                    // But it does make debugging a *lot* easier if you print out the completed
                    // buffer for debugging.
                    buffer.append(line + "\n");
                }

                if (buffer.length() == 0) {
                    // Stream was empty.  No point in parsing.
                    return null;
                }
                forecastJsonStr = buffer.toString();

                Log.v(LOG_TAG, "Forecast string: " + forecastJsonStr);
            } catch (IOException e) {
                Log.e(LOG_TAG, "Error ", e);
                // If the code didn't successfully get the weather data, there's no point in attemping
                // to parse it.
                return null;
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (final IOException e) {
                        Log.e(LOG_TAG, "Error closing stream", e);
                    }
                }
            }

            try {
                System.out.println("I am just in front of calling getDurationDataFromJson");
                return getDurationDataFromJson(forecastJsonStr);
            } catch (JSONException e) {
                Log.e(LOG_TAG, e.getMessage(), e);
                e.printStackTrace();
            }
            return new String[0];
        }//end doInBackground

Here is my getDurationDataFromJSON code:

private String[] getDurationDataFromJson(String forecastJsonStr)
        throws JSONException {

    // These are the names of the JSON objects that need to be extracted.
    final String OWM_ROUTES = "routes";
    final String OWM_LEGS = "legs";
    final String OWM_DURATION = "duration";
    final String OWM_TEXT = "text";


    String[] resultStrs = new String[0];
    String duration;

    JSONObject durationJson = new JSONObject(forecastJsonStr);

    JSONArray routeArray = durationJson.getJSONArray(OWM_ROUTES);

    JSONArray legArray = routeArray.getJSONObject(0).getJSONArray(OWM_LEGS);

    //Duration
    JSONObject durationObj = legArray.getJSONObject(0).getJSONObject(OWM_DURATION);

    duration = durationObj.getString(OWM_TEXT);

    resultStrs[0] = duration;

    System.out.println("Duration is: " + duration);
    for (String s : resultStrs) {
        System.out.println("Duration entry: " + s);
        Log.v(LOG_TAG, "Duration entry: " + s);
    }
    return resultStrs;

}

Trouble I am facing is the following part in doInBackGround code:

location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);

Error is:

Call requires permission which may be rejected by user: code should explicitly check to see if permission is available(with `check permission`) or explicitly handle a potential `SecurityException`.

I am not sure if I am going in the right direction. Please guide me through this.

Upvotes: 1

Views: 56

Answers (2)

Barno
Barno

Reputation: 786

I will suggest you to use FusedLocationProviderApi to get last known location.

But before doing anything with location you need make sure that you have provided

  • android.permission.ACCESS_COARSE_LOCATION
  • android.permission.ACCESS_FINE_LOCATION

in your manifest.xml.

Now I came to your point. From API Level-23 android indrouces explicit permission seeking feature. To provide this you need to follow some steps.

I hereby attach some code blocks for your help-

  1. Checker of required permission states and device location service

    public boolean isLocationEnabled() {
        int locationMode = 0;
        String locationProviders;
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            try {
                locationMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE);
            } catch (Settings.SettingNotFoundException e) {
                e.printStackTrace();
            }
    
            return locationMode != Settings.Secure.LOCATION_MODE_OFF;
    
        } else {
            locationProviders = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
            return !TextUtils.isEmpty(locationProviders);
        }
    
    }
    
    public boolean hasCoarseLocationPermission() {
        return ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
    }
    
    public boolean hasFineLocationPermission() {
        return ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
    }

  2. Now launch your activity/fragment after checking and providing expicit permission

private void initiateYourActivityCallAfterCheckingPermission() {
           if (hasCoarseLocationPermission() && hasFineLocationPermission()) {
               if (locationUtil.isLocationEnabled()) {
                   startYourLocationActivity();
               } 
           } else if (!hasFineLocationPermission() && hasCoarseLocationPermission()) {
               requestBothLocationPermission();
           } else if (hasFineLocationPermission() && hasCoarseLocationPermission()) {
               requestFineLocationPermission();
           } else if (hasFineLocationPermission() && !hasCoarseLocationPermission()) {
               requestCoarseLocationPermission();
           }
}

private void requestBothLocationPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(SplashActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION)
                && ActivityCompat.shouldShowRequestPermissionRationale(SplashActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)) {

        } else {
            ActivityCompat.requestPermissions(SplashActivity.this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION},
                    REQUEST_BOTH_LOCATION);
        }
    }

    private void requestCoarseLocationPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(SplashActivity.this,
                Manifest.permission.ACCESS_COARSE_LOCATION)) {

        } else {
            ActivityCompat.requestPermissions(SplashActivity.this,
                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_COARSE_LOCATION);
        }
    }

    private void requestFineLocationPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(SplashActivity.this,
                Manifest.permission.ACCESS_FINE_LOCATION)) {

        } else {
            ActivityCompat.requestPermissions(SplashActivity.this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_FINE_LOCATION);
        }
    }

/**
     * to process permission result
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case General.REQUEST_BOTH_LOCATION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                    startYourLocationActivity();
                } 
                break;
            case General.REQUEST_COARSE_LOCATION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    startYourLocationActivity();
                } 
                break;
            case General.REQUEST_FINE_LOCATION:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    startYourLocationActivity();
                }
                break;
        }
    }

Hope this will help.

Upvotes: 0

kelmi92
kelmi92

Reputation: 394

With Android API level (23), permissions are requested at running time, here you have de official documentation:

https://developer.android.com/training/permissions/requesting.html

Basically, you need to check if the device Android API level is >= 23, and if so, request the required permissions. Try something like this:

if ( Build.VERSION.SDK_INT >= 23)
        //Ask for needed permissions following the docs mentioned above
}

I hope this helps!

Upvotes: 1

Related Questions