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.
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
interface View {
...
void requestReadPermission();
boolean areReadPermissionGranted();
void showPermissionError();
void hidePermissionError();
...
}
interface Presenter {
...
void setReadPermissions(boolean grantedPermissions);
...
}
interface Model {
...
}
My view implementation. (Fragment in this case but it can be Activity or whatever, the Presenter will only expect the response).
public class MyView extends Fragment implements Contract.View {
...
Contract.Presenter presenter;
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
boolean grantedPermissions = (grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED);
presenter.setReadPermissions(grantedPermissions);
}
@Override
public void showPermissionError() {
// Show not permission message
}
@Override
public void hidePermissionError() {
// Hide not permission message
}
@Override
public void requestReadPermission() {
this.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
@Override
public boolean areReadPermissionGranted() {
return ContextCompat.checkSelfPermission(getContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
...
And the Presenter implementation
public class MyPresenter implements Contract.Presenter {
...
Contract.View view;
public void doSomethingThatRequiresPermissions() {
...
if ( !view.areReadPermissionGranted() ) {
view.requestReadPermission();
view.showPermissionError();
} else {
view.hidePermissionError();
doSomethingWithPermissionsGranted();
}
...
}
@Override
public void setReadPermissions(boolean grantedPermissions) {
if( grantedPermissions ){
view.hidePermissionError();
doSomethingThatRequiresPermissions();
} else {
view.showPermissionError();
}
}
public void doSomethingWithPermissionsGranted(){
...
}
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();
}