Search code examples
androidgoogle-maps-markersandroid-permissionsfusedlocationproviderclient

Location Permission Not Switching on With Device


I have implemented location using FusedLocationProviderClient. The problem in my app is that the permission dialog does not switch on the location in settings. I have to manually turn it on before I start getting updates.

I have checked and requested permission using ContextCompat and ActivityCompat classes but nothing happens until I manually press the button. Is this a bug with FusedLocationProviderClient or bad programming on my side? I have worked with location manager and Fused Location Provider APIs and never faced this before.

Here's my code:

public class HomeFragment extends BaseFragment implements OnMapReadyCallback {

private static final String TAG = HomeFragment.class.getSimpleName();

private Toolbar toolbar;
private TextView driverStatusTV;

public static MaterialAnimatedSwitch statusSwitch;

private FusedLocationProviderClient providerClient;
public static Location mLastLocation;
public static LocationRequest locationRequest;
public GoogleMap mGmap;

public static Marker currentMarker;
public static double latitude = 0f, longitude = 0f;
private static boolean isLocationGranted = false;

public static final int UPDATE_INTERVAL = 15000;
public static final int FASTEST_INTERVAL = 8000;
public static final int DISPLACEMENT = 10;

public static final int PLAY_SERVICES_REQ_CODE = 9009;
public static final int PLAY_SERVICES_RESOLUTION_REQ_CODE = 9090;

private SupportMapFragment mapFragment;

public HomeFragment() {
    // Required empty public constructor
}

private void initViews(View view) {
    toolbar = view.findViewById(R.id.toolbar);
    driverStatusTV = view.findViewById(R.id.driverStatusTV);
    statusSwitch = view.findViewById(R.id.statusSwitch);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_home, container, false);
    initViews(view);
    ((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);

    checkPerms();
    providerClient = LocationServices.getFusedLocationProviderClient(getActivity());
    mapFragment = (SupportMapFragment) this.getChildFragmentManager().findFragmentById(R.id.mapFragment);
    mapFragment.getMapAsync(this);

    driverStatusTV.setText("OFFLINE");
    statusSwitch.setOnCheckedChangeListener(new MaterialAnimatedSwitch.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(boolean b) {
            if (b) {
                Snackbar.make(getActivity().findViewById(android.R.id.content), "You are Now Online", Snackbar.LENGTH_LONG).show();
                if (checkPerms()) {
                    startLocationListener();
                    driverStatusTV.setText("ONLINE");
                }
            } else {
                Snackbar.make(getActivity().findViewById(android.R.id.content), "You are Now Offline", Snackbar.LENGTH_LONG).show();
                mGmap.setIndoorEnabled(false);
                if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    return;
                }
                mGmap.setMyLocationEnabled(false);
                stopLocationListener();
                driverStatusTV.setText("OFFLINE");
                if (currentMarker != null){
                    currentMarker.remove();
                }
            }
        }
    });

    return view;
}

private void stopLocationListener() {
    if (providerClient != null){
        providerClient.removeLocationUpdates(locationCallback);
    }
}

@Override
public void onPause() {
    super.onPause();
    stopLocationListener();
}

private void startLocationListener() {
    locationRequest = LocationRequest.create();
    locationRequest.setSmallestDisplacement(DISPLACEMENT);
    locationRequest.setFastestInterval(FASTEST_INTERVAL);
    locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    locationRequest.setInterval(UPDATE_INTERVAL);

    LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
    builder.addLocationRequest(locationRequest);

    LocationSettingsRequest settingsRequest = builder.build();

    SettingsClient client = LocationServices.getSettingsClient(getActivity());
    client.checkLocationSettings(settingsRequest);

    displayLocation();

}

private boolean checkPerms() {
    if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        reqPerms();
        isLocationGranted = false;
        Log.d(TAG, "Permission Value:\t" + isLocationGranted);
    } else {
        isLocationGranted = true;
        Log.d(TAG, "Permission Value:\t" + isLocationGranted);
    }
    return isLocationGranted;
}

private void reqPerms() {
    ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, AppConstants.LOC_PERM_CODE);
}

private void displayLocation() {
    if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        reqPerms();
    } else {
        if (statusSwitch.isChecked()) {
            providerClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper());
            mGmap.setIndoorEnabled(true);
            mGmap.setMyLocationEnabled(true);
        } else {
            mGmap.setIndoorEnabled(false);
            mGmap.setMyLocationEnabled(false);
        }
    }
}

private LocationCallback locationCallback = new LocationCallback() {
    @Override
    public void onLocationResult(LocationResult locationResult) {

        Location location = locationResult.getLastLocation();
        mLastLocation = location;
        if (currentMarker != null) {
            currentMarker.remove();
        }
        latitude = mLastLocation.getLatitude();
        Log.d(TAG, "Lat:\t" + latitude);
        longitude = mLastLocation.getLongitude();
        Log.d(TAG, "Long:\t" + longitude);

        MarkerOptions options = new MarkerOptions();
        options.position(new LatLng(latitude, longitude));
        options.title("Driver");
        //options.icon(BitmapDescriptorFactory.fromResource(R.drawable.car)); // throws error

        currentMarker = mGmap.addMarker(options);
        rotateMarker(currentMarker, 360, mGmap);
        mGmap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latitude,longitude), 18.0f));

    }
};

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case AppConstants.LOC_PERM_CODE:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                isLocationGranted = true;
                if (checkPlayServices() && statusSwitch.isChecked()) {
                    startLocationListener();
                } else {
                    Snackbar.make(getActivity().findViewById(android.R.id.content), "Google Play Services Not Supported on Your Device", Snackbar.LENGTH_LONG).show();
                }
            }
            break;
    }
}

public boolean checkPlayServices() {
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity());
    if (resultCode != ConnectionResult.SUCCESS) {
        if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
            GooglePlayServicesUtil.getErrorDialog(resultCode, getActivity(), AppConstants.PLAY_SERVICES_RESOLUTION_REQUEST).show();
        } else {
            Snackbar.make(getActivity().findViewById(android.R.id.content), "Play Services NOT Supported on Your Device", Snackbar.LENGTH_LONG).show();
            getActivity().finish();
            getActivity().moveTaskToBack(true);
        }
        return false;
    }
    return true;
}

private void rotateMarker(final Marker currentMarker, final float i, GoogleMap mGmap) {
    final Handler handler = new Handler();
    final long start = SystemClock.uptimeMillis();
    final float startRotation = currentMarker.getRotation();
    final int duration = 1500;

    final Interpolator interpolator = new LinearInterpolator();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            long elapsed = SystemClock.elapsedRealtime() - start;
            float t = interpolator.getInterpolation(elapsed / duration);
            float rot = t * i + (1 - t) * startRotation;
            currentMarker.setRotation(-rot > 180 ? rot / 2 : rot);

            if (t < 1.0) {
                handler.postDelayed(this, 16);
            }

        }
    }, duration);
}

@Override
public void onMapReady(GoogleMap googleMap) {
    mGmap = googleMap;

    startLocationListener();

}

}

Alos, the set icon on marker throws this error com.google.maps.api.android.lib6.common.apiexception.b: Failed to decode image. The provided image must be a Bitmap.

Can anyone help me solve these two problems? Thank you


Solution

  • your onRequestPermissionsResult will never be called, you are requesting permissions from your activity and your activity's onRequestPermissionsResult would be getting invoked. If you want permission callback in your fragment just remove Activity when you request permssions

    private void reqPerms() {
       requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, AppConstants.LOC_PERM_CODE);
    }
    

    Your fragment has to be a supportFragment if you want to access this method