简体   繁体   中英

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 Sou rce) 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)

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 .

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
}

}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM