34

I have an application which needs to find the user location, and location is fetched in various classes, so i have written a separate class(Not an Activity class) that fetches user location using location services, it works fine under Android M but requires run time permissions in Android M, i want to check permissions in my Location class and i know how to check them but i cannot use onRequestPermissionsResult method in my Location class, because my Location class do not extends from any activity.

So What i should do for achieving this? any help/clue is appreciated Thanks in advance

Muhammad Husnain Tahir
  • 1,009
  • 1
  • 15
  • 28
  • 1
    You just need to get the permission before you need it. It doesn't necessarily have to be right when you need it. Just ask the user for it from one of your Activities, wherever that might be appropriate. – Mike M. Jul 20 '16 at 12:02
  • @MikeM. do i need to check permission in some Activity/Fragment? basically i am checking permission in my Location class – Muhammad Husnain Tahir Jul 20 '16 at 12:04
  • You can _check_ for a permission wherever you have access to a `Context`, which you presumably would in your `Location` class, so that's fine, and also exactly what you should be doing there. – Mike M. Jul 20 '16 at 12:07
  • @MikeM. Yes i do have context my Location class but how do i override onRequestPermissionsResult – Muhammad Husnain Tahir Jul 20 '16 at 12:11
  • requestPermission() can only be called from an Activity and not a Service (unlike checkPermission() that only requires PackageManager). check this answer for more details http://stackoverflow.com/questions/32292675/how-to-request-permissions-from-a-service-in-android-marshmallow – Piyush k Jul 20 '16 at 12:15
  • 1
    You wouldn't. `onRequestPermissionsResult()` follows from a `requestPermissions()` call, which, as we said, you should be doing in your `Activity`, not in the `Location` class. There is no callback for `checkSelfPermission()`. – Mike M. Jul 20 '16 at 12:17
  • @MikeM. thanks for clearing things up – Muhammad Husnain Tahir Jul 20 '16 at 12:19
  • No problem. Yeah, you should listen to CommonsWare. You probably wanna check for the permission before you even create your `Location` class instance, so there's really no need to even just check from there. – Mike M. Jul 20 '16 at 12:33
  • I Just found two Solutions: 1-you must override the onRequestPermissionsResult in your Activity where you calling that non activity class 2-you can repeat call function of request permission and call your get location function inside it after request permission. – HusseinKamal Aug 05 '19 at 07:22
  • I Just found two Solutions: 1-you must override the onRequestPermissionsResult in your Activity where you calling that non activity class 2-you can repeat call function of request permission and call your get location function inside it after request permission. – HusseinKamal Aug 05 '19 at 07:23

6 Answers6

21

Since public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) is an abstract method of ActivityCompat.OnRequestPermissionsResultCallback interface. See the documentation

Just implement this interface in the required class and it's done. For example

class location implements  ActivityCompat.OnRequestPermissionsResultCallback{ }

Now just override onRequestPermissionsResult()

 @Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
     // case Statements
    }
}
AkshayK
  • 309
  • 2
  • 5
  • 14
    In theory yes, but android doesn't seems to call onRequestPermissionsResult on non activity class. – mauron85 Nov 28 '17 at 14:36
  • @mauron85 when you implement OnRequestPermissionsResultCallback interface in any non-activity class, you will surly get onRequestPermissionsResult method. – AkshayK Dec 06 '17 at 05:52
  • 3
    well, that can't be true since `requestPermissions()` needs `Activity` as a parameter, not just a class implementing `OnRequestPermissionsResultCallback` – Alexey Andronov Feb 27 '18 at 05:23
  • 3
    I did this but it dosen't work so this answer is useless – mmdreza baqalpour May 13 '18 at 10:54
  • It's not about adding the method to service and overriding, it's about getting the method called from the system. – Ravinder Payal May 20 '18 at 15:12
  • 1
    Come on, you are creating a new object implementing a similar interface implemented by the Activity and expect it to call the callback? The OS only knows about the Activity implementing the interface and nothing else. – Ali Nem Nov 20 '18 at 09:36
  • 1
    when a method (A) calls an interface (B) callback (C) if A have a parametre referring to B then the callback C will be called otherwise C couldn't be called. for the method requestPermissions() it uses activity as a parametre not ActivityCompat.OnRequestPermissionsResultCallback so it's not possible to use this at all – Farido mastr Nov 05 '19 at 09:39
11

You are welcome to call checkSelfPermission() from a non-UI class, as that merely needs some Context.

However, you must call requestPermissions() on some activity or fragment. You override onRequestPermissionsResult() on that same activity or fragment. This is no different than calling startActivityForResult() and implementing onActivityResult().

The idea is that you request the permission before you do anything that involves your non-UI classes that are dealing with locations.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    Thanks for the answer, i know this approach, but i basically wanted to override onRequestPermissionsResult() in non-activity class. and now i guess it is not possible – Muhammad Husnain Tahir Jul 20 '16 at 12:18
  • @Tahir: Correct. You are welcome to have the activity or fragment call into your non-UI class to provide the results of the permission request. Preferably, the non-activity class instance does not even exist, though -- you request and confirm the permission before creating that `Location` instance and trying to do things with the location data. – CommonsWare Jul 20 '16 at 12:19
  • @CommonsWare, In that case, is there any way that I can get the context in onRequestPermissionsResult() in non UI-class ? – Noor Hossain Feb 14 '21 at 02:26
  • 1
    @NoorHossain: As I wrote in the answer, "You override `onRequestPermissionsResult()` on that *same* activity or fragment." I am going to interpret "non UI-class" as meaning something other than an activity or fragment. If you decide to implement a method named `onRequestPermissionsResult()` on a "non UI-class", you are responsible for calling that method yourself. And, therefore, you can pass whatever parameters you like, such as a `Context`. – CommonsWare Feb 14 '21 at 12:09
  • @CommonsWare, thanks for quick and great reply, - regards. – Noor Hossain Feb 14 '21 at 16:23
5

1- create a transparent activity

<activity android:name=".activity.activity.CheckStoragePermissionsActivity" android:theme="@style/Theme.Transparent">

<style name="Theme.Transparent" parent="Theme.AppCompat">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:backgroundDimEnabled">false</item>
    </style>

2- customize your activity

public class CheckStoragePermissionsActivity extends AppCompatActivity {

    private String[] permissions;
    private int pCode = 12321;
    public static PermissionListener permissionListener;

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

        checkPermissions();
    }

    private void checkPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            permissions = new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};

            boolean flag = false;
            for (String s : permissions)
                if (checkSelfPermission(s) != PackageManager.PERMISSION_GRANTED)
                    flag = true;

            if (flag) {
                requestPermissions(permissions, pCode);
            } else {
                permissionListener.permissionResult(true);
                finish();
            }
        }else
            finish();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == pCode) {
            boolean flag = true;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
                for (int i = 0, len = permissions.length; i < len; i++)
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED)
                        flag = false;
            if (flag) {
                if (permissionListener != null)
                    permissionListener.permissionResult(true);
            } else if (permissionListener != null)
                permissionListener.permissionResult(false);
            finish();
        }
    }
}

3- permissionListener is an static interface and can be set directly before context.startActivity(...), or use your plan to found permission result.

public interface PermissionListener extends Serializable {
    void permissionResult(boolean hasPermission);
}

4- finally call context.startActivity(new Intent(context, CheckStoragePermissionsActivity.class));

CheckStoragePermissionsActivity do all of needed and finish after user Allow or Deny action.

Misagh
  • 3,403
  • 1
  • 20
  • 17
  • 1
    Just FYI, Its not mandatory to check for permission in Activity. You can still do it with just context instance from anywhere using ContextCompat class. You can even avoid lot of version checks if you use ContextCompat class. – Ayyappa Sep 23 '17 at 11:35
  • 1
    @Ayyappa onRequestPermissionsResult is not called if we dont do it in Activity – Amit Hooda Jan 24 '22 at 19:41
4

You can not override it. This method is only available for Activity and Fragments. But you can create a static method inside your Location class and call it from your activity/fragment's overridden onRequestPermissionResult method.

I have made a custom implementation for Location combined with permission. You can also use a library called Let for permissions.

Embydextrous
  • 1,611
  • 1
  • 12
  • 20
0

probably you can create a class that extends Activity (AppCompactActivity is better), implement all needed location code and extends with this class all activities where you need to use it.

user3132789
  • 151
  • 1
  • 5
-1

use this class :

public class permissionModule {

final public static int STORAGE_PERMISSION_CODE = 23;
private Activity activity;

public permissionModule(Activity activity) {
    this.activity = activity;
}

public void startGetPermission(){
    if (isStorageReadable()){
        Toast.makeText(activity,"you Already have the permission to access storage",Toast.LENGTH_SHORT).show();
    }else {
        requestStoragePermission();
    }
}

private void requestStoragePermission() {
    ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
}

private boolean isStorageReadable() {
    int result = ContextCompat.checkSelfPermission(activity, 

Manifest.permission.READ_EXTERNAL_STORAGE);
        return result == PackageManager.PERMISSION_GRANTED;
    }
}

and in your activity call :

new permissionModule(MainActivity.this).startGetPermission();

finally for result , override this in your activity :

@TargetApi(Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == permissionModule.STORAGE_PERMISSION_CODE) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Snackbar permissionWarning = Snackbar.make(rootLayout, "tnk", Snackbar.LENGTH_INDEFINITE);
            permissionWarning.setAction("ok", new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //...
                }
            });
            permissionWarning.show();
        } else {
            boolean showRationale = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);
            if (showRationale) {
                Snackbar permissionWarning = Snackbar.make(rootLayout, "Permission Required to access storage", Snackbar.LENGTH_INDEFINITE);
                permissionWarning.setAction("ok", new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        //requestStoragePermission();
                    }
                });
                permissionWarning.show();
            } else {
                Snackbar snackbar = Snackbar.make(rootLayout, "you denied the permission for ever pleas fix it in setting", Snackbar.LENGTH_INDEFINITE);
                snackbar.setAction("setting", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Intent intent = new Intent();
                        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        Uri uri = Uri.fromParts("package", MainActivity.this.getPackageName(), null);
                        intent.setData(uri);
                        MainActivity.this.startActivity(intent);
                    }
                });
                snackbar.show();
            }
        }
    }
}
Iwo Kucharski
  • 3,735
  • 3
  • 50
  • 66
m.sajjad.s
  • 711
  • 7
  • 19