Ashutosh Chapagain
Ashutosh Chapagain

Reputation: 926

Client must have ACCESS_FINE_LOCATION permission to request PRIORITY_HIGH_ACCURACY locations runtime error

There are plenty of similar questions asked but none seem to solve my problem.

I have applied run time permissions as mentioned on the documentation, still I am getting a run time error on the line

LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);

Here is my complete code.

public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks,
    GoogleApiClient.OnConnectionFailedListener,LocationListener {

private static final String TAG ="hello" ;
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;


public Location mLastLocation=null;


public final int MY_PERMISSIONS_REQUEST_COARSE_LOCATION=0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (mGoogleApiClient==null){
        mGoogleApiClient= new GoogleApiClient.Builder(this)

                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .addApi(LocationServices.API)
                .build();
    }

    mLocationRequest = LocationRequest.create()
            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
            .setInterval(10 * 100)        // 10 seconds, in milliseconds
            .setFastestInterval( 1* 100); // 1 second, in milliseconds

    }









@Override
public void onConnected(@Nullable Bundle bundle) {


    int permissionCheck = ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_FINE_LOCATION);
    int permissionCheck1 = ContextCompat.checkSelfPermission(this,
            Manifest.permission.ACCESS_COARSE_LOCATION);
    if (permissionCheck != PackageManager
            .PERMISSION_GRANTED && permissionCheck1 != PackageManager.PERMISSION_GRANTED) {

        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_FINE_LOCATION)) {

            // Show an explanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.

        } else {

            // No explanation needed, we can request the permission.

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


        }
    }


    mLastLocation=LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
    if (mLastLocation != null) {
        TextView mLatitudeText =(TextView)findViewById(R.id.textView);
        TextView mLongitudeText =(TextView)findViewById(R.id.textView2);

        mLatitudeText.setText(String.valueOf(mLastLocation.getLatitude()));
        mLongitudeText.setText(String.valueOf(mLastLocation.getLongitude()));

        Log.i("Location Info", "Location achieved!");

    } else {



        Log.i("Location Info", "No location :(");

    }


    LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);//error here!!






}



@Override
public void onConnectionSuspended(int i) {

}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {

}

@Override
protected void onResume() {
    mGoogleApiClient.connect();
    super.onResume();

}

@Override
protected void onPause() {
    mGoogleApiClient.disconnect();
    super.onPause();
}



@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode) {
        case  MY_PERMISSIONS_REQUEST_COARSE_LOCATION :{
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                Log.i("Message","Got full permission");



            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }



}


@Override
public void onLocationChanged(Location location)
{
    Log.i("Location Info", "Location is changed Bitchh :(");
    handleNewLocation(location);
}

private void handleNewLocation(Location location) {
    Log.d(TAG, location.toString());
}

}

Also I have given permission in the manifest file.

So, this is the error stack trace on run time

10-24 17:13:02.857 2224-2379/com.example.ashutosh.location E/AbstractTracker: Can't create handler inside thread that has not called Looper.prepare() 0-24 17:13:03.184 2224-2224/com.example.ashutosh.location E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.ashutosh.location, PID: 2224 java.lang.SecurityException: Client must have ACCESS_FINE_LOCATION permission to request PRIORITY_HIGH_ACCURACY locations. at android.os.Parcel.readException(Parcel.java:1620) at android.os.Parcel.readException(Parcel.java:1573) at com.google.android.gms.internal.zzed.zzb(Unknown Source) at com.google.android.gms.internal.zzcda.zza(Unknown Source) at com.google.android.gms.internal.zzcdd.zza(Unknown Source) at com.google.android.gms.internal.zzcdj.zza(Unknown Source) at com.google.android.gms.internal.zzccc.zza(Unknown Source) at com.google.android.gms.internal.zzbay.zzb(Unknown Source) at com.google.android.gms.internal.zzbca.zze(Unknown Source) at com.google.android.gms.internal.zzbcx.zze(Unknown Source) at com.google.android.gms.internal.zzbcp.zze(Unknown Source) at com.google.android.gms.internal.zzccb.requestLocationUpdates(Unknown Source) at com.example.ashutosh.location.MainActivity.onConnected(MainActivity.java:122) at com.google.android.gms.common.internal.zzac.zzn(Unknown Source) at com.google.android.gms.internal.zzbcp.zzm(Unknown Source) at com.google.android.gms.internal.zzbcd.zzpY(Unknown Source) at com.google.android.gms.internal.zzbcd.onConnected(Unknown Source) at com.google.android.gms.internal.zzbcx.onConnected(Unknown Source) at com.google.android.gms.internal.zzbbi.onConnected(Unknown Source) at com.google.android.gms.common.internal.zzaa.onConnected(Unknown Source) at com.google.android.gms.common.internal.zzn.zzrj(Unknown Source) at com.google.android.gms.common.internal.zze.zzs(Unknown Source) at com.google.android.gms.common.internal.zzi.zzrk(Unknown Source) at com.google.android.gms.common.internal.zzh.handleMessage(Unknown Source) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:152) at android.app.ActivityThread.main(ActivityThread.java:5497) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

Upvotes: 2

Views: 4325

Answers (3)

Maneki Neko
Maneki Neko

Reputation: 1257

I hate the following solution but I did not find any better. If you request location API from Google API's and you do: .addApi(LocationServices.API), you need to have location permitted before connecting GoogleAPI's.

Thus,

fun checkPermission(context:Context, permission:Name) : Boolean =
    ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED

fun isLocationPermissionGranted() = checkPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)

if (isLocationPermissionGranted()) {
     googleApiBuilder.connect()
} else {
     MyPermissionChangeRegistrar().instance.register { 
          if (isLocationPermissionGranted()) {
               googleApiBuilder.connect()
          }
     } 
}

When the Permission registrar is a class that calls a callback when a permission changed

class SomeActivity: Activity() {
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        MyPermissionChangeRegistrar.callCallbacks()
    }
}

IMMHO, Google ought to protect against such cases internally. But they don't.

Upvotes: 0

rushi
rushi

Reputation: 277

Try this sequence,

@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


int permissionCheck = ContextCompat.checkSelfPermission(this,
        Manifest.permission.ACCESS_FINE_LOCATION);
int permissionCheck1 = ContextCompat.checkSelfPermission(this,
        Manifest.permission.ACCESS_COARSE_LOCATION);
if (permissionCheck != PackageManager
        .PERMISSION_GRANTED && permissionCheck1 != PackageManager.PERMISSION_GRANTED) {

    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.ACCESS_FINE_LOCATION)) {

        // Show an explanation to the user *asynchronously* -- don't block
        // this thread waiting for the user's response! After the user
        // sees the explanation, try again to request the permission.

    } else {

        // No explanation needed, we can request the permission.

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


    }
} else {

if (mGoogleApiClient==null){
    mGoogleApiClient= new GoogleApiClient.Builder(this)

            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
}

mLocationRequest = LocationRequest.create()
        .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
        .setInterval(10 * 100)        // 10 seconds, in milliseconds
        .setFastestInterval( 1* 100); // 1 second, in milliseconds
        }
}



@Override public void onConnected(@Nullable Bundle bundle) {
mLastLocation=LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation != null) {
    TextView mLatitudeText =(TextView)findViewById(R.id.textView);
    TextView mLongitudeText =(TextView)findViewById(R.id.textView2);
    mLatitudeText.setText(String.valueOf(mLastLocation.getLatitude()));
    mLongitudeText.setText(String.valueOf(mLastLocation.getLongitude()));
    Log.i("Location Info", "Location achieved!");
} else {
    Log.i("Location Info", "No location :(");
}

LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);//error here!!
}


@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
    case  MY_PERMISSIONS_REQUEST_COARSE_LOCATION :{
        // If request is cancelled, the result arrays are empty.
        if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Log.i("Message","Got full permission");
        if (mGoogleApiClient==null){
         mGoogleApiClient= new GoogleApiClient.Builder(this)
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();
        }
        mLocationRequest = LocationRequest.create()
        .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
        .setInterval(10 * 100)        // 10 seconds, in milliseconds
        .setFastestInterval( 1* 100); // 1 second, in milliseconds
        } else {

            // permission denied, boo! Disable the
            // functionality that depends on this permission.
        }
        return;
    }
    // other 'case' lines to check for other
    // permissions this app might request
}

}

Upvotes: 0

CommonsWare
CommonsWare

Reputation: 1007321

requestPermissions() is asynchronous. When it returns, you do not yet have permission. The user has not even been asked about the permission.

You need to do your location logic in two places:

  • Up front, if you have permission already

  • In onRequestPermissionResult(), if you requested permissions and the user granted them

This sample app and this sample app illustrate how to request runtime permissions and use them with LocationClient.

Upvotes: 2

Related Questions