Use dexter for requesting storage permissions (#2258)

* Use dexter for requesting storage permissions

* minor changes

* Fix minor issue
This commit is contained in:
Vivek Maskara 2019-01-02 21:41:19 +05:30 committed by neslihanturan
parent 2ea6bd7f65
commit a48a09a785
13 changed files with 149 additions and 408 deletions

View file

@ -1,7 +1,10 @@
package fr.free.nrw.commons.contributions;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
@ -14,12 +17,24 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.FileProvider;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.PermissionToken;
import com.karumi.dexter.listener.PermissionDeniedResponse;
import com.karumi.dexter.listener.PermissionGrantedResponse;
import com.karumi.dexter.listener.PermissionRequest;
import com.karumi.dexter.listener.single.BasePermissionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.upload.UploadActivity;
import fr.free.nrw.commons.utils.DialogUtil;
import fr.free.nrw.commons.utils.PermissionUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import timber.log.Timber;
import static android.content.Intent.ACTION_GET_CONTENT;
@ -34,14 +49,16 @@ import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ITEM_LOCAT
public class ContributionController {
public static final int SELECT_FROM_GALLERY = 1;
static final int SELECT_FROM_GALLERY = 1;
public static final int SELECT_FROM_CAMERA = 2;
public static final int PICK_IMAGE_MULTIPLE = 3;
static final int PICK_IMAGE_MULTIPLE = 3;
private Fragment fragment;
private SharedPreferences defaultPrefs;
public ContributionController(Fragment fragment) {
public ContributionController(Fragment fragment, SharedPreferences defaultSharedPrefs) {
this.fragment = fragment;
this.defaultPrefs = defaultSharedPrefs;
}
// See http://stackoverflow.com/a/5054673/17865 for why this is done
@ -58,6 +75,85 @@ public class ContributionController {
photoFile);
}
public void initiateCameraPick(Activity activity) {
boolean useExtStorage = defaultPrefs.getBoolean("useExternalStorage", true);
if (!useExtStorage) {
startCameraCapture();
return;
}
Dexter.withActivity(activity)
.withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withListener(new BasePermissionListener() {
@Override
public void onPermissionGranted(PermissionGrantedResponse response) {
startCameraCapture();
}
@Override
public void onPermissionDenied(PermissionDeniedResponse response) {
if (response.isPermanentlyDenied()) {
DialogUtil.showAlertDialog(activity,
activity.getString(R.string.storage_permission_title),
activity.getString(R.string.write_storage_permission_rationale),
activity.getString(R.string.navigation_item_settings),
null,
() -> PermissionUtils.askUserToManuallyEnablePermissionFromSettings(activity),
null);
}
}
@Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
DialogUtil.showAlertDialog(activity,
activity.getString(R.string.storage_permission_title),
activity.getString(R.string.write_storage_permission_rationale),
activity.getString(android.R.string.ok),
activity.getString(android.R.string.cancel),
token::continuePermissionRequest,
token::cancelPermissionRequest);
}
}).check();
}
public void initiateGalleryPick(Activity activity) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
startGalleryPick();
} else {
Dexter.withActivity(activity)
.withPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new BasePermissionListener() {
@Override
public void onPermissionGranted(PermissionGrantedResponse response) {
startCameraCapture();
}
@Override
public void onPermissionDenied(PermissionDeniedResponse response) {
if (response.isPermanentlyDenied()) {
DialogUtil.showAlertDialog(activity,
activity.getString(R.string.storage_permission_title),
activity.getString(R.string.read_storage_permission_rationale),
activity.getString(R.string.navigation_item_settings),
null,
() -> PermissionUtils.askUserToManuallyEnablePermissionFromSettings(activity),
null);
}
}
@Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
DialogUtil.showAlertDialog(activity,
activity.getString(R.string.storage_permission_title),
activity.getString(R.string.read_storage_permission_rationale),
activity.getString(android.R.string.ok),
activity.getString(android.R.string.cancel),
token::continuePermissionRequest,
token::cancelPermissionRequest);
}
}).check();
}
}
private static void requestWritePermission(Context context, Intent intent, Uri uri) {
List<ResolveInfo> resInfoList = context.getPackageManager().queryIntentActivities(intent,
@ -69,7 +165,7 @@ public class ContributionController {
}
}
public void startCameraCapture() {
private void startCameraCapture() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
lastGeneratedCaptureUri = reGenerateImageCaptureUriInCache();
@ -84,7 +180,7 @@ public class ContributionController {
fragment.startActivityForResult(takePictureIntent, SELECT_FROM_CAMERA);
}
public void startGalleryPick() {
private void startGalleryPick() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
startMultipleGalleryPick();
} else {
@ -92,7 +188,7 @@ public class ContributionController {
}
}
public void startSingleGalleryPick() {
private void startSingleGalleryPick() {
//FIXME: Starts gallery (opens Google Photos)
Intent pickImageIntent = new Intent(ACTION_GET_CONTENT);
pickImageIntent.setType("image/*");
@ -107,7 +203,7 @@ public class ContributionController {
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public void startMultipleGalleryPick() {
private void startMultipleGalleryPick() {
Intent pickImageIntent = new Intent(ACTION_GET_CONTENT);
pickImageIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
pickImageIntent.setType("image/*");
@ -120,7 +216,7 @@ public class ContributionController {
fragment.startActivityForResult(pickImageIntent, PICK_IMAGE_MULTIPLE);
}
public void handleImagesPicked(int requestCode, @Nullable ArrayList<Uri> uri) {
void handleImagesPicked(int requestCode, @Nullable ArrayList<Uri> uri) {
FragmentActivity activity = fragment.getActivity();
Intent shareIntent = new Intent(activity, UploadActivity.class);
shareIntent.setAction(ACTION_SEND_MULTIPLE);

View file

@ -4,15 +4,12 @@ import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -26,7 +23,6 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Arrays;
import javax.inject.Inject;
import javax.inject.Named;
@ -36,11 +32,8 @@ import butterknife.ButterKnife;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.utils.PermissionUtils;
import timber.log.Timber;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.Activity.RESULT_OK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.View.*;
@ -96,7 +89,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (controller == null) {
controller = new ContributionController(this);
controller = new ContributionController(this, defaultPrefs);
}
controller.loadState(savedInstanceState);
}
@ -107,7 +100,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
if (controller != null) {
controller.saveState(outState);
} else {
controller = new ContributionController(this);
controller = new ContributionController(this, defaultPrefs);
}
}
@ -130,88 +123,11 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
}
private void setListeners() {
fabPlus.setOnClickListener(view -> animateFAB(isFabOpen));
fabCamera.setOnClickListener(view -> {
boolean useExtStorage = defaultPrefs.getBoolean("useExternalStorage", true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && useExtStorage) {
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(getActivity(), WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if (shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE)) {
// 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.
new AlertDialog.Builder(getParentFragment().getActivity())
.setMessage(getString(R.string.write_storage_permission_rationale))
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
getActivity().requestPermissions
(new String[]{WRITE_EXTERNAL_STORAGE}, PermissionUtils.CAMERA_PERMISSION_FROM_CONTRIBUTION_LIST);
dialog.dismiss();
})
.setNegativeButton(android.R.string.cancel, null)
.create()
.show();
} else {
// No explanation needed, we can request the permission.
requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
3);
// MY_PERMISSIONS_WRITE_EXTERNAL_STORAGE is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
controller.startCameraCapture();
}
} else {
controller.startCameraCapture();
}
});
fabGallery.setOnClickListener(view -> {
// Gallery crashes before reach ShareActivity screen so must implement permissions check here
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(getActivity(), READ_EXTERNAL_STORAGE)
!= PERMISSION_GRANTED) {
// Should we show an explanation?
if (shouldShowRequestPermissionRationale(READ_EXTERNAL_STORAGE)) {
// 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.
new AlertDialog.Builder(getParentFragment().getActivity())
.setMessage(getString(R.string.read_storage_permission_rationale))
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
getActivity().requestPermissions
(new String[]{READ_EXTERNAL_STORAGE}, PermissionUtils.GALLERY_PERMISSION_FROM_CONTRIBUTION_LIST);
dialog.dismiss();
})
.setNegativeButton(android.R.string.cancel, null)
.create()
.show();
} else {
// No explanation needed, we can request the permission.
requestPermissions(new String[]{READ_EXTERNAL_STORAGE}, 1);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
controller.startGalleryPick();
}
} else {
controller.startGalleryPick();
}
controller.initiateCameraPick(getActivity());
});
fabGallery.setOnClickListener(view -> controller.initiateGalleryPick(getActivity()));
}
private void animateFAB(boolean isFabOpen) {
@ -260,40 +176,6 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Timber.d("onRequestPermissionsResult: req code = " + " perm = "
+ Arrays.toString(permissions) + " grant =" + Arrays.toString(grantResults));
switch (requestCode) {
// 1 = Storage allowed when gallery selected
case 1: {
if (grantResults.length > 0 && grantResults[0] == PERMISSION_GRANTED) {
Timber.d("Call controller.startGalleryPick()");
controller.startGalleryPick();
}
}
break;
// 2 = Location allowed when 'nearby places' selected
case 2: {
// TODO: understand and fix
/*if (grantResults.length > 0 && grantResults[0] == PERMISSION_GRANTED) {
Timber.d("Location permission granted");
Intent nearbyIntent = new Intent(getActivity(), MainActivity.class);
startActivity(nearbyIntent);
}*/
}
break;
case 3: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Timber.d("Call controller.startCameraCapture()");
controller.startCameraCapture();
}
}
}
}
private void handleMultipleImages(int requestCode, Intent data) {
if (getContext() == null) {
return;

View file

@ -477,60 +477,6 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
}
return;
}
// Storage permission for gallery
case PermissionUtils.GALLERY_PERMISSION_FROM_CONTRIBUTION_LIST: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Storage permission given
ContributionsListFragment contributionsListFragment =
(ContributionsListFragment) contributionsActivityPagerAdapter
.getItem(0).getChildFragmentManager()
.findFragmentByTag(ContributionsFragment.CONTRIBUTION_LIST_FRAGMENT_TAG);
contributionsListFragment.controller.startGalleryPick();
}
return;
}
case PermissionUtils.CAMERA_PERMISSION_FROM_CONTRIBUTION_LIST: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Storage permission given
ContributionsListFragment contributionsListFragment =
(ContributionsListFragment) contributionsActivityPagerAdapter
.getItem(0).getChildFragmentManager()
.findFragmentByTag(ContributionsFragment.CONTRIBUTION_LIST_FRAGMENT_TAG);
contributionsListFragment.controller.startCameraCapture();
}
return;
}
case PermissionUtils.CAMERA_PERMISSION_FROM_NEARBY_MAP: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Storage permission given
NearbyMapFragment nearbyMapFragment =
((NearbyFragment) contributionsActivityPagerAdapter
.getItem(1)).nearbyMapFragment;
nearbyMapFragment.controller.startCameraCapture();
}
return;
}
case PermissionUtils.GALLERY_PERMISSION_FROM_NEARBY_MAP: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Storage permission given
NearbyMapFragment nearbyMapFragment =
((NearbyFragment) contributionsActivityPagerAdapter
.getItem(1)).nearbyMapFragment;
nearbyMapFragment.controller.startGalleryPick();
}
return;
}
default:
return;