mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-31 14:53:59 +01:00 
			
		
		
		
	Use dexter for requesting storage permissions (#2258)
* Use dexter for requesting storage permissions * minor changes * Fix minor issue
This commit is contained in:
		
							parent
							
								
									2ea6bd7f65
								
							
						
					
					
						commit
						a48a09a785
					
				
					 13 changed files with 149 additions and 408 deletions
				
			
		|  | @ -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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vivek Maskara
						Vivek Maskara