Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION [duplicate]

I use a module in a another app. Before I implement the module, I set it on API Level 23 (compile and target) like my Main Project This works fine, except this Error. The Pproblem is, that Google has changed the permissions management since marshmellow. Finaly now, i dont know how and where I should set the permissions.

This error I get when starting the application:

java.lang.SecurityException: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to perform any operations location.

Could you please help me and explain briefly (what kind of code i need and where to insert) to avoid this error?

Manifest from the Modul:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cs.android.weminder">

<!--

android:versionCode="3"
android:versionName="1.2.0" >


<uses-sdk
    android:minSdkVersion="9"
    android:targetSdkVersion="19" />

    -->

<!-- Grant the network access permission -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"           />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- Grant the location access permission -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Permission required to use Alarm Manager -->
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.GET_TASKS" />

<application
    android:allowBackup="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

    <!--    android:name="com.cs.android.weminder.MyApplication"
            android:label="@string/app_name">-->

    <!-- This meta-data tag is required to use Google Play Services. -->
    <meta-data
        android:name="com.google.android.gms.version"
        android:value="@integer/google_play_services_version" />
    <!-- Required for creating dialog of the ACRA report -->
    <activity
        android:name="org.acra.CrashReportDialog"
        android:excludeFromRecents="true"
        android:finishOnTaskLaunch="true"
        android:launchMode="singleInstance"
        android:theme="@style/AcraDialog" />
    <activity
        android:name="com.cs.android.weminder.MainActivity"
        android:launchMode="singleTop"
        android:screenOrientation="portrait" >

        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />

    </activity>
    <activity android:name="com.cs.android.weminder.BaseScreen" />
    <activity android:name="com.cs.android.weminder.LocationBaseScreen" />
    <activity android:name="com.cs.android.weminder.SettingsActivity" />
    <activity android:name="com.cs.android.weminder.WeminderApplication" />


    <!-- Required by the AdMob Ads SDK -->



    <activity
        android:name="com.google.ads.AdActivity"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
    <!-- Include the AdActivity configChanges and theme. -->
    <activity
        android:name="com.google.android.gms.ads.AdActivity"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
        android:theme="@android:style/Theme.Translucent" />


    <receiver
        android:name="com.cs.android.weminder.AlarmReceiver"
        android:process=":remote" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>

    <service android:name="com.cs.android.weminder.AlarmService" >
    </service>
</application>

Main Activity from the Modul:

public class MainActivity extends SettingsActivity implements ActionTypes,
    ResultType {




private TextView tvLocation, tvHTemp, tvLTemp, tvCurrentTemp, tvTimestamp,
        tvDate, tvWindSpeed, tvPressure;
private ImageView ivCurrentWeather, ivRefresh, ivUnit, ivSearch, ivRemind,
        ivMyLocation;
private HorizontalViewGallery forecastGallery;
// Search field
private MyCustomEditText etSearch;

// holding different weather icons presenting weather condition
// alternatively.
private IconFinder mIconFinder;

private ApiCallQueue requestsQueue = new ApiCallQueue();

// Ads View
private AdView adView;





private void setupUI(View view) {
    // Set up touch listener for non-text box views to hide keyboard.
    if (!(view instanceof EditText)) {
        view.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // Hide the search field if the user is touching anywhere
                // except the search field
                if (etSearch.isShown()) {
                    etSearch.startDeflation();
                    return true;
                }
                return false;
            }
        });
    }

    // If a layout container, iterate over children and seed recursion.
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            View innerView = ((ViewGroup) view).getChildAt(i);
            setupUI(innerView);
        }
    }
}

/**
 * Initial the UI of current screen Initial variables;
 */
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void initialActivity() {
    setupUI(findViewById(R.id.parent));
    // display the name of location
    tvLocation = (TextView) findViewById(R.id.tvLocation);
    // Set the location icon
    tvLocation.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_marker), null, null, null);
    // display today highest temperature
    tvHTemp = (TextView) findViewById(R.id.tvHTemp);
    // Set the highest temperature icon
    tvHTemp.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_highest), null, null, null);
    // display today lowest temperature
    tvLTemp = (TextView) findViewById(R.id.tvLTemp);
    // Set the lowest temperature icon
    tvLTemp.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_lowest), null, null, null);
    // display the current temperature
    tvCurrentTemp = (TextView) findViewById(R.id.tvCurrentTemp);
    // display the update time stamp
    tvTimestamp = (TextView) findViewById(R.id.tvTimestamp);
    // display the date of today
    tvDate = (TextView) findViewById(R.id.tvDate);
    // display the wind speed
    tvWindSpeed = (TextView) findViewById(R.id.tvWindSpeed);
    // Set wind speed icon
    tvWindSpeed.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_wind), null, null, null);
    // display the pressure
    tvPressure = (TextView) findViewById(R.id.tvPressure);
    // Set wind speed icon
    tvPressure.setCompoundDrawablesWithIntrinsicBounds(getResources()
            .getDrawable(R.drawable.icon_pressure), null, null, null);
    // visualize the current weather condition
    ivCurrentWeather = (ImageView) findViewById(R.id.ivCurrentWeather);
    // Scrollable forecast
    forecastGallery = (HorizontalViewGallery) findViewById(R.id.gForcast);
    // Search city button
    ivSearch = (ImageView) findViewById(R.id.ivSearch);
    // Setting button
    ivRemind = (ImageView) findViewById(R.id.ivRemind);
    // My location button
    ivMyLocation = (ImageView) findViewById(R.id.ivMyLocation);
    // Temp unit setting Button
    ivUnit = (ImageView) findViewById(R.id.ivUnit);
    if (getTempUnit().equals(PARAM_TEMP_UNIT_C))
        ivUnit.setImageDrawable(getResources().getDrawable(
                R.drawable.button_unit_f));
    else if (getTempUnit().equals(PARAM_TEMP_UNIT_F))
        ivUnit.setImageDrawable(getResources().getDrawable(
                R.drawable.button_unit_c));
    // Refresh button
    ivRefresh = (ImageView) findViewById(R.id.ivRefresh);
    // Search field
    etSearch = (MyCustomEditText) findViewById(R.id.etSearch);
    // set the animation of search field
    // Animation Duration in milliseconds;
    int duration = 500;
    // Inflate animation
    final AnimationSet inflate = new AnimationSet(true);
    ScaleAnimation scaleIn = new ScaleAnimation(0f, 1.0f, 1.0f, 1.0f,
            Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
            0.5f);
    scaleIn.setDuration(duration);
    inflate.addAnimation(scaleIn);
    inflate.setAnimationListener(new AnimationListener() {

        @Override
        public void onAnimationEnd(Animation animation) {
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }

        @Override
        public void onAnimationStart(Animation animation) {
            etSearch.setVisibility(View.VISIBLE);
            etSearch.requestFocus();
            showSoftKeyboard(etSearch);
        }
    });
    // Deflate animation
    final AnimationSet deflate = new AnimationSet(true);
    ScaleAnimation scaleDe = new ScaleAnimation(1.0f, 0f, 1.0f, 1.0f,
            Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
            0.5f);
    scaleDe.setDuration(duration);
    deflate.addAnimation(scaleDe);
    deflate.setAnimationListener(new AnimationListener() {

        @Override
        public void onAnimationEnd(Animation animation) {
            etSearch.setVisibility(View.INVISIBLE);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }

        @Override
        public void onAnimationStart(Animation animation) {
            hideSoftKeyboard(etSearch);
        }
    });

    etSearch.setInflation(inflate);
    etSearch.setDeflation(deflate);

    // Running the change of digital clock on separate UI thread
    // to avoid any delay of other action on UI.
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (!Utils.androidMinimum(API_JELLY_BEAN_MR1)) {
                // Using the widget class {@code DigitalClock} if the
                // android api is less than 17
                DigitalClock dcClock = (DigitalClock) findViewById(R.id.dcClock);
                dcClock.addTextChangedListener(new TextWatcher() {

                    @Override
                    public void onTextChanged(CharSequence s, int start,
                            int before, int count) {
                    }

                    @Override
                    public void beforeTextChanged(CharSequence s,
                            int start, int count, int after) {
                    }

                    @Override
                    public void afterTextChanged(Editable s) {
                        // Removed seconds
                        if (s.length() >= 5) {
                            if (s.charAt(4) == ':') {
                                s.delete(4, s.length());
                            } else if (s.length() >= 6
                                    && s.charAt(5) == ':') {
                                s.delete(5, s.length());
                            }
                        }
                    }
                });
            } else {
                // Using the widget class {@code TextClock} if the android
                // api is greater than or equal to 17
                TextClock dcClock = (TextClock) findViewById(R.id.dcClock);
                dcClock.addTextChangedListener(new TextWatcher() {

                    @Override
                    public void onTextChanged(CharSequence s, int start,
                            int before, int count) {
                    }

                    @Override
                    public void beforeTextChanged(CharSequence s,
                            int start, int count, int after) {
                    }

                    @Override
                    public void afterTextChanged(Editable s) {
                        // Removed seconds
                        if (s.length() >= 5) {
                            if (s.charAt(4) == ':') {
                                s.delete(4, s.length());
                            } else if (s.length() >= 6
                                    && s.charAt(5) == ':') {
                                s.delete(5, s.length());
                            }
                        }
                    }
                });
            }
        }
    });

    mIconFinder = new IconFinder(this);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);




    /*
     * Create a new location client, using the enclosing class to handle
     * callbacks.
     */
    mLocationClient = new LocationClient(this, this, this);

    // Create the LocationRequest object
    mLocationRequest = LocationRequest.create();
    // Use high accuracy
    mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
    // Set the update interval to 5 seconds
    mLocationRequest.setInterval(UPDATE_INTERVAL);
    // Set the fastest update interval to 1 second
    mLocationRequest.setFastestInterval(FASTEST_INTERVAL);

    setContentView(R.layout.activity_main);
    .
    .
    .

Could you please explain, what is the best way to manage the new Permission-System. Please explain to me in a simple way

like image 468
BakteriusD Avatar asked Dec 11 '22 15:12

BakteriusD


1 Answers

The coarse and fine location are considered dangerous permissions. These permissions have to be explicitly requested on Android 6 and up. Here's one way to go about it:

public void checkPermission(){
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
                       ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                    ){//Can add more as per requirement

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

And for calling:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    checkPermission();
}

You can implement it anywhere. You can request it on the first launch, or whenever they're needed.

Nonetheless, always remember to check whether you have the permission before using it. The permission can be revoked at runtime as well, which would bypass any checks you have on startup.

Here's one way to do it:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /*
    This is called before initializing the map because the map needs permissions(the cause of the crash)
    */
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M ) {
        checkPermission();
    }
    // Re-check before enabling. You can add an else statement to warn the user about the lack of functionality if it's disabled. 
    // "or" is used instead of "and" as per the error. If it requires both, flip it over to &&. (I'm not sure, I haven't used GPS stuff before)
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
                   ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
        /*
         * Create a new location client, using the enclosing class to handle
         * callbacks.
         */
        mLocationClient = new LocationClient(this, this, this);

        // Create the LocationRequest object
        mLocationRequest = LocationRequest.create();
        // Use high accuracy
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        // Set the update interval to 5 seconds
        mLocationRequest.setInterval(UPDATE_INTERVAL);
        // Set the fastest update interval to 1 second
        mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
    }
    setContentView(R.layout.activity_main);
    .
    .
    .

This is the way I recommend doing it. There are other ways to deal with permissions, but no matter what you pick, do make sure you check whether you have the permission before accessing an API dependent on dangerous permissions. The permissions can be withdrawn at runtime without triggering the destroy lifecycle events, and therefore bypass any checks you have on startup to make sure you have the permissions. Because of that, checking before you use APIs is extremely important.

There's also other ways to implement permission requesting. If you're looking for alternatives to this super basic startup check, here's some ideas:

  • If you have a setup activity, add permission requesting to it.
  • Don't request permissions at startup, but rather whenever they're needed
  • Add a permission requesting activity to your startup flow, if the permission checks fail on startup

There's also more ways to go about this than I know if. I haven't touched Android in a couple years, and I'm far from familiar with all the ways to request permissions. See also the documentation for potentially more up to date advice.

like image 174
Zoe stands with Ukraine Avatar answered May 08 '23 16:05

Zoe stands with Ukraine