2

This is my first post in stackoverflow so please dont hate me if I say something wrong!

I am trying to adapt this tutorial https://developers.google.com/maps/documentation/android-api/current-place-tutorial to work on my fragment and with PermisionDispatcher. However, I am getting checkPermision error and I dont understand why.

I have checked this answer trying to add marshmallow permissions using "Permissions Dispatcher" however, I still cant get that right.. This is my fragment code:

import android.Manifest;
import android.app.FragmentManager;
import android.content.Context;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;

import permissions.dispatcher.NeedsPermission;
import permissions.dispatcher.OnNeverAskAgain;
import permissions.dispatcher.OnPermissionDenied;
import permissions.dispatcher.OnShowRationale;
import permissions.dispatcher.PermissionRequest;
import permissions.dispatcher.RuntimePermissions;

import static android.content.ContentValues.TAG;

/**
 * Created by Daumantas on 2017-05-25.
 */
@RuntimePermissions
public class AddPlacesFragment extends Fragment implements OnMapReadyCallback, GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
Context mContext;
private GoogleApiClient mGoogleApiClient;
private GoogleMap mMap;
private boolean mLocationPermissionGranted = false;
private Location mLastKnownLocation = null;
private CameraPosition mCameraPosition = null;
private LatLng mDefaultLocation = new LatLng(40.76793169992044,
        -73.98180484771729);
private float DEFAULT_ZOOM = 10;
@Nullable
@Override

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {


    mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
            .enableAutoManage(getActivity(),
                    this)
            .addConnectionCallbacks(this)
            .addApi(LocationServices.API)
            //.addApi(Places.GEO_DATA_API)
            //.addApi(Places.PLACE_DETECTION_API)
            .build();
    mGoogleApiClient.connect();


    return inflater.inflate(R.layout.add_places_fragment, container, false);
}

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);


    mContext = getContext();

    FragmentManager fragment = getActivity().getFragmentManager();
    MapFragment mf = (MapFragment) fragment.findFragmentById(R.id.map);
    mf.getMapAsync(this);


}


@Override
public void onMapReady(final GoogleMap map) {

    mMap = map;

    // Do other setup activities here too, as described elsewhere in this tutorial.

    AddPlacesFragmentPermissionsDispatcher.updateLocationUIWithCheck(this); //UpdateLocationUI

    // Turn on the My Location layer and the related control on the map.

    // Get the current location of the device and set the position of the map.
    //getDeviceLocation();
    AddPlacesFragmentPermissionsDispatcher.getDeviceLocationWithCheck(this);
}


@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    Log.d("CONNECTION CALLBACK","failed");
}

@Override
public void onConnected(@Nullable Bundle bundle) {
    Log.d("CONNECTION CALLBACK","connected");
}

@Override
public void onConnectionSuspended(int i) {
    Log.d("CONNECTION CALLBACK","suspended");
}

@NeedsPermission({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})
void updateLocationUI() {

    if (mMap == null) {
        Log.d("LOCATION","MAPS ARE NULL");
    }else{
        Log.d("LOCATION","updateLocationUI");
        //noinspection MissingPermission

        mMap.setMyLocationEnabled(true);
        mLocationPermissionGranted = true;
        mMap.getUiSettings().setMyLocationButtonEnabled(true);

    }
}




@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    AddPlacesFragmentPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}

@OnShowRationale({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})
void updateLocationUIOnShowRationale(final PermissionRequest request) {
}

@OnPermissionDenied({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})
void updateLocationUIOnPermissionDenied() {

    mMap.setMyLocationEnabled(false);
    mMap.getUiSettings().setMyLocationButtonEnabled(false);

}

@OnNeverAskAgain({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})
void updateLocationUIOnNeverAskAgain() {
}

@NeedsPermission({Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION})
void getDeviceLocation() {

    mLastKnownLocation = LocationServices.FusedLocationApi
                .getLastLocation(mGoogleApiClient);

    // Set the map's camera position to the current location of the device.
    if (mCameraPosition != null) {
        mMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPosition));
    } else if (mLastKnownLocation != null) {
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
                new LatLng(mLastKnownLocation.getLatitude(),
                        mLastKnownLocation.getLongitude()), DEFAULT_ZOOM));
    } else {
        Log.d(TAG, "Current location is null. Using defaults.");
        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mDefaultLocation, DEFAULT_ZOOM));
        mMap.getUiSettings().setMyLocationButtonEnabled(false);
    }

}
}

EDIT So I have made some changes as you have suggested and I don't longer get the error in

SetMyLocationEnabled(true)

(even though I sometimes get it if I move it around in the method)

now I have advanced a bit in the tutorial and I have same problems.. Now I get an error in

mLastKnownLocation = LocationServices.FusedLocationApi
            .getLastLocation(mGoogleApiClient);

and dont really know what do to. The code compiles, but running it on emulator just zooms in on default location and running it on my phone the app crashes

EDIT Runned it on my phone and found an exception in stacktrace (the app didn't crash this time but showed only world map, without any sign of my location or zooming onto the default location)

06-19 23:10:33.990 3728-6926/? D/LocationManagerService: request 3ab885c 

fused Request[ACCURACY_BLOCK fused requested=+30m0s0ms fastest=+30m0s0ms] from com.samsung.voiceserviceplatform(10039)
06-19 23:10:34.083 3728-6926/? D/LocationManagerService: provider request: fused ProviderRequest[ON interval=+30m0s0ms]
06-19 23:10:34.084 4511-4511/? D/FusedRequestManager_FLP: manageLocationRequest, new fused request from com.samsung.voiceserviceplatform with 3ab885c , interval = 1800000 through LocationManagerService
06-19 23:10:34.126 4707-4936/? E/LocationClientHelper: exception when setting module id
                                                       java.lang.IllegalStateException: Unable to get current module info in ModuleManager created with non-module Context
                                                       at com.google.android.chimera.config.ModuleManager.getCurrentModule(:com.google.android.gms:1)
                                                       at tpn.a(:com.google.android.gms:17)
                                                       at tpr.b(:com.google.android.gms:13)
                                                       at too.a(:com.google.android.gms:4)
                                                       at kit.b(:com.google.android.gms:3)
                                                       at kjv.b(:com.google.android.gms:14)
                                                       at kks.b(:com.google.android.gms:7)
                                                       at kkk.b(:com.google.android.gms:25)
                                                       at txt.a(:com.google.android.gms:6)
                                                       at txs.b(:com.google.android.gms:1)
                                                       at txs.a(:com.google.android.gms:1)
                                                       at txs.a(:com.google.android.gms:15)
                                                       at tyc.a(:com.google.android.gms:8)
                                                       at ajuo.handleMessage(:com.google.android.gms:21)
                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                       at akwg.dispatchMessage(:com.google.android.gms:7)
                                                       at android.os.Looper.loop(Looper.java:154)
                                                       at android.os.HandlerThread.run(HandlerThread.java:61)
06-19 23:10:37.578 4707-27455/? W/ctxmgr: [AclManager]No 2 for (accnt=account#1348010355#, com.google.android.gms(10018):UserLocationProducer, vrsn=11055000, 0, 3pPkg = null ,  3pMdlId = null ,  pid = 4707). Was: 2 for 1, account#1348010355#
06-19 23:10:37.580 4707-27455/? W/ctxmgr: [AclManager]No 2 for (accnt=account#-1563429706#, com.google.android.gms(10018):UserLocationProducer, vrsn=11055000, 0, 3pPkg = null ,  3pMdlId = null ,  pid = 4707). Was: 2 for 1, account#-1563429706#
06-19 23:10:43.903 3728-4583/? D/LocationManagerService: getLastLocation: Request[POWER_NONE passive fastest=0 num=1]
06-19 23:10:43.968 3728-6921/? D/LocationManagerService: getLastLocation: Request[POWER_NONE passive fastest=0 num=1]

Thank you or helping me..

Maikido
  • 23
  • 1
  • 5

1 Answers1

1

The app is getting the map asynchronously, so even though it is asking permission right after calling mf.getMapAsync(this), the app could load the map and can call onMapReady, which calls mMap.setMyLocationEnabled(true) through your method, before the user has a chance to allow the permission. I would suggest the following:

@Override
public void onMapReady(final GoogleMap map) {

    mMap = map;

    //Now that you have the map, request permission here.
    getPermisions();
}

This is how you should handle this, since you only request the location once the map is loaded.

Pablo Baxter
  • 2,144
  • 1
  • 17
  • 36
  • Thank you for your speedy response. It kinda helped me to get rid of that error, however, after advancing in tutorial I have same error just in a different place know.. I have updated the post and if you could look into it I would greatly appreciate your help – Maikido Jun 17 '17 at 23:28
  • Seems like something else is going wrong. Post your stacktrace please. – Pablo Baxter Jun 19 '17 at 16:20
  • Edited: posted the exception from stacktrace – Maikido Jun 19 '17 at 22:19
  • Looks like it's an issue with `setMyLocationEnabled` method being called before you do this. Try calling `AddPlacesFragmentPermissionsDispatcher.getDeviceLocationWithCheck(this)` before `AddPlacesFragmentPermissionsDispatcher.updateLocationUIWithCheck(this)`. – Pablo Baxter Jun 19 '17 at 22:26
  • well it worked! however I don't understand why and there is one problem: when launching map fragment it zooms in to the default location (log says that the location is null at that time) but after clicking button that calls AddPlacesFragmentPermissionsDispatcher.getDeviceLocationWith‌​Check(this) it works like a charm so I think I need to delay the request a bit. Any suggestions how can I achieve that? thank you – Maikido Jun 20 '17 at 07:55
  • Honestly, not sure why it works either, just seems to be an issue with `setMyLocationEnabled` being active while trying to use FusedLocationProvider. In regards to the second part, I would avoid using `setMyLocationEnabled` and look into implementing FusedLocationProvider with this https://developers.google.com/android/reference/com/google/android/gms/maps/LocationSource – Pablo Baxter Jun 20 '17 at 17:35
  • I am kinda new in real-world programing and don't yet understand how to read that documentation.. tried implementing something but I had no idea what I am doing and I believe that was crap. Maybe you could explain how can I implement so I could figure out how to understand the docs you have sent afterwards. I greatly appreciate what you've done for me. thank you – Maikido Jun 20 '17 at 20:04
  • 1
    Everyone has no idea what they are doing when they first program. When you look back on it, maybe it is all crap code to everyone else, but it is what taught you, and I wouldn't call it crap. My advice to really learn: Practice! Don't just follow the tutorials blindly, but question how the code works, and try to understand why it was done in the specific way it was shown. If you truly do get stuck somewhere and need another helping hand, post your (well researched) question here on StackOverflow. For now, I leave it to you to find a tutorial on LocationSource. Might learn something new! :-) – Pablo Baxter Jun 20 '17 at 20:50