Skip to content Skip to sidebar Skip to footer

What's The Best Way To Check For Permissions At Runtime Using Mvp Architecture?

I'm developing an android app in which I have to ask for permissions at runtime. I'm wondering about the best way to implement that using Model-View-Presenter architecture. My init

Solution 1:

What I would do is:

The view will implement:

public Activity getViewActivity();

The presenter will implement:

publicvoidrequestPermissions();
publicvoidonPermissionsResult();

Inside requestPermissions, the presenter will do: getViewActivity().checkSelfPermission; getViewActivity.requestPermissions(); etc.

The view will call inside the onRequestPermissionsResult callback to presenter.onPermissionsResult();

With this all the logic will be implemented inside the presenter.

In my opinion, your presenter is decoupled: it won't depend on any view implementation (it will only depend on the view interface).

"I've heard that keeping your presenter free from Android code is good for testing." I don't understand this part. If the code is good, it can be tested without any problem.

Solution 2:

If you still want to be able to mock permission access/requests, you still create something like a PermissionHandler, but only reference it inside your view class. For example -

Interface:

publicinterfacePermissionsHandler {
    booleancheckHasPermission(AppCompatActivity activity, String permission);
    voidrequestPermission(AppCompatActivity activity, String[] permissions, int requestCode);
}

Production implementation:

publicclassPermissionsHandlerAndroidimplementsPermissionsHandler {
    @OverridepublicbooleancheckHasPermission(AppCompatActivity activity, String permission) {
        returnContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED;
    }

    @OverridepublicvoidrequestPermission(AppCompatActivity activity, String[] permissions, int requestCode){
        ActivityCompat.requestPermissions(activity, permissions, requestCode);
    }
}

Mocked class (for example, to test and make sure your activity correctly handles onRequestPermissionsResult)

publicclassPermissionsHandlerMockedimplementsPermissionsHandler {
    @OverridepublicbooleancheckHasPermission(AppCompatActivity activity, String permission) {
        returnfalse;
    }

    @OverridepublicvoidrequestPermission(AppCompatActivity activity, String[] permissions, int requestCode){
        int[] grantResults = new int[permissions.length];
        for (int i = 0; i < permissions.length; i++) {
            grantResults[i] = PackageManager.PERMISSION_GRANTED
        }
        activity.onRequestPermissionResult(requestCode, permissions, grantResults);
    }
}

Then in your activity:

PermissionsHandler permissionsHandler;

@OverrideprotectedvoidonCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    permissionsHandler = Injection.providePermissionsHandler();
    //or however you choose to inject your production vs mocked handler. 
}

//method from your view interface, to be called by your presenter@OverridevoidrequestLocationPermission() {
    permissionsHandler.requestPermision((AppCompatActivity) this, newString[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE_LOCATION};
}

fobo66, you can always make the view implement much more generic methods like checkLocationPermissionGranted() and requestLocationPermission(). Then your view implementation can reference the activity as needed, and your presenter never has to touch the activity reference.

Solution 3:

Permissions requests and status are View(Fragment or Activity) responsibility due to depend of the user actions to make a request or grant permissions. I manage permissions with MVP as follows(Read external storage example):

My Contract

interfaceView {
    ...
    voidrequestReadPermission();
    boolean areReadPermissionGranted();
    voidshowPermissionError();
    voidhidePermissionError();
    ...
}

interfacePresenter {
    ...
    voidsetReadPermissions(boolean grantedPermissions);
    ...
}

interfaceModel {
    ...
}

My view implementation. (Fragment in this case but it can be Activity or whatever, the Presenter will only expect the response).

publicclassMyViewextendsFragmentimplementsContract.View {

...
Contract.Presenter presenter;

@OverridepublicvoidonRequestPermissionsResult(int requestCode, @NonNullString[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    boolean grantedPermissions =  (grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED);
    presenter.setReadPermissions(grantedPermissions);
}



@OverridepublicvoidshowPermissionError() {
    // Show not permission message
}

@OverridepublicvoidhidePermissionError() {
    // Hide not permission message
}

@OverridepublicvoidrequestReadPermission() {
    this.requestPermissions(newString[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
@OverridepublicbooleanareReadPermissionGranted() {
    returnContextCompat.checkSelfPermission(getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
...

And the Presenter implementation

publicclassMyPresenterimplementsContract.Presenter {

...
Contract.View view;

publicvoiddoSomethingThatRequiresPermissions() {

    ...
        if ( !view.areReadPermissionGranted() ) {
            view.requestReadPermission();
            view.showPermissionError();
        } else {
            view.hidePermissionError();
            doSomethingWithPermissionsGranted();
        }
    ...
}

@OverridepublicvoidsetReadPermissions(boolean grantedPermissions) {
    if( grantedPermissions ){
        view.hidePermissionError();
        doSomethingThatRequiresPermissions();

    } else {
        view.showPermissionError();
    }
}

publicvoiddoSomethingWithPermissionsGranted(){
    ...
}

Then you can make unit test like

Contract.View mockedView;
@Test
public void requestAlbumListWithoutPermissions() {
    when(mockedView.areReadPermissionGranted()).thenReturn(false);
    presenter.doSomethingWithPermissionsGranted();
    verify(mockedView).showPermissionError();
    verify(mockedView).requestReadPermission();
}

Post a Comment for "What's The Best Way To Check For Permissions At Runtime Using Mvp Architecture?"