mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-31 06:43:56 +01:00 
			
		
		
		
	* Use dexter to ask for location permissions * Addressed code review comments
This commit is contained in:
		
							parent
							
								
									6f9d69e63c
								
							
						
					
					
						commit
						8971743479
					
				
					 6 changed files with 95 additions and 375 deletions
				
			
		|  | @ -5,22 +5,10 @@ import android.content.ComponentName; | |||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.database.Cursor; | ||||
| import android.database.DataSetObserver; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import android.os.IBinder; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.fragment.app.FragmentManager; | ||||
| import androidx.fragment.app.FragmentTransaction; | ||||
| import androidx.loader.app.LoaderManager; | ||||
| import androidx.loader.content.CursorLoader; | ||||
| import androidx.loader.content.Loader; | ||||
| import androidx.cursoradapter.widget.CursorAdapter; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
|  | @ -28,6 +16,16 @@ import android.widget.Adapter; | |||
| import android.widget.CheckBox; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.cursoradapter.widget.CursorAdapter; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.fragment.app.FragmentManager; | ||||
| import androidx.fragment.app.FragmentTransaction; | ||||
| import androidx.loader.app.LoaderManager; | ||||
| import androidx.loader.content.CursorLoader; | ||||
| import androidx.loader.content.Loader; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
|  | @ -57,6 +55,7 @@ import fr.free.nrw.commons.settings.Prefs; | |||
| import fr.free.nrw.commons.upload.UploadService; | ||||
| import fr.free.nrw.commons.utils.ConfigUtils; | ||||
| import fr.free.nrw.commons.utils.DialogUtil; | ||||
| import fr.free.nrw.commons.utils.PermissionUtils; | ||||
| import fr.free.nrw.commons.utils.ViewUtil; | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.android.schedulers.AndroidSchedulers; | ||||
|  | @ -66,7 +65,7 @@ import timber.log.Timber; | |||
| 
 | ||||
| import static fr.free.nrw.commons.contributions.ContributionDao.Table.ALL_FIELDS; | ||||
| import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI; | ||||
| import static fr.free.nrw.commons.location.LocationServiceManager.LOCATION_REQUEST; | ||||
| import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION; | ||||
| import static fr.free.nrw.commons.settings.Prefs.UPLOADS_SHOWING; | ||||
| import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween; | ||||
| 
 | ||||
|  | @ -351,35 +350,6 @@ public class ContributionsFragment | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | ||||
|         Timber.d("onRequestPermissionsResult"); | ||||
|         switch (requestCode) { | ||||
|             case LOCATION_REQUEST: { | ||||
|                 if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
|                     Timber.d("Location permission granted, refreshing view"); | ||||
|                     // No need to display permission request button anymore | ||||
|                     locationManager.registerLocationManager(); | ||||
|                 } else { | ||||
|                     if (store.getBoolean("displayLocationPermissionForCardView", true)) { | ||||
|                         // Still ask for permission | ||||
|                         DialogUtil.showAlertDialog(getActivity(), | ||||
|                                 getString(R.string.nearby_card_permission_title), | ||||
|                                 getString(R.string.nearby_card_permission_explanation), | ||||
|                                 this::displayYouWontSeeNearbyMessage, | ||||
|                                 this::enableLocationPermission, | ||||
|                                 checkBoxView, | ||||
|                                 false); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|             default: | ||||
|                 // This is needed to allow the request codes from the Fragments to be routed appropriately | ||||
|                 super.onRequestPermissionsResult(requestCode, permissions, grantResults); | ||||
|         } | ||||
|     } | ||||
|     /** | ||||
|      * Replace whatever is in the current contributionsFragmentContainer view with | ||||
|      * mediaDetailPagerFragment, and preserve previous state in back stack. | ||||
|  | @ -496,7 +466,7 @@ public class ContributionsFragment | |||
| 
 | ||||
| 
 | ||||
|         if (store.getBoolean("displayNearbyCardView", true)) { | ||||
|             checkGPS(); | ||||
|             checkPermissionsAndShowNearbyCardView(); | ||||
|             if (nearbyNotificationCardView.cardViewVisibilityState == NearbyNotificationCardView.CardViewVisibilityState.READY) { | ||||
|                 nearbyNotificationCardView.setVisibility(View.VISIBLE); | ||||
|             } | ||||
|  | @ -509,77 +479,39 @@ public class ContributionsFragment | |||
|         fetchCampaigns(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check GPS to decide displaying request permission button or not. | ||||
|      */ | ||||
|     private void checkGPS() { | ||||
|         if (!locationManager.isProviderEnabled()) { | ||||
|             Timber.d("GPS is not enabled"); | ||||
|             nearbyNotificationCardView.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_GPS; | ||||
|             if (store.getBoolean("displayLocationPermissionForCardView", true)) { | ||||
|                 DialogUtil.showAlertDialog(getActivity(), | ||||
|                         getString(R.string.nearby_card_permission_title), | ||||
|                         getString(R.string.nearby_card_permission_explanation), | ||||
|                         this::displayYouWontSeeNearbyMessage, | ||||
|                         this::enableGPS, | ||||
|                         checkBoxView, | ||||
|                         false); | ||||
|             } | ||||
|         } else { | ||||
|             Timber.d("GPS is enabled"); | ||||
|             checkLocationPermission(); | ||||
|     private void checkPermissionsAndShowNearbyCardView() { | ||||
|         if (PermissionUtils.hasPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)) { | ||||
|             onLocationPermissionGranted(); | ||||
|         } else if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) | ||||
|                 && store.getBoolean("displayLocationPermissionForCardView", true) | ||||
|                 && (((MainActivity) getActivity()).viewPager.getCurrentItem() == CONTRIBUTIONS_TAB_POSITION)) { | ||||
|             nearbyNotificationCardView.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION; | ||||
|             showNearbyCardPermissionRationale(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void checkLocationPermission() { | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||||
|             if (locationManager.isLocationPermissionGranted(requireContext())) { | ||||
|                 nearbyNotificationCardView.permissionType = NearbyNotificationCardView.PermissionType.NO_PERMISSION_NEEDED; | ||||
|                 locationManager.registerLocationManager(); | ||||
|             } else { | ||||
|                 nearbyNotificationCardView.permissionType = NearbyNotificationCardView.PermissionType.ENABLE_LOCATION_PERMISSION; | ||||
|                 // If user didn't selected Don't ask again | ||||
|                 if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) | ||||
|                         && store.getBoolean("displayLocationPermissionForCardView", true)) { | ||||
|                         DialogUtil.showAlertDialog(getActivity(), | ||||
|                                 getString(R.string.nearby_card_permission_title), | ||||
|                                 getString(R.string.nearby_card_permission_explanation), | ||||
|                                 this::displayYouWontSeeNearbyMessage, | ||||
|                                 this::enableLocationPermission, | ||||
|                                 checkBoxView, | ||||
|                                 false); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             // If device is under Marshmallow, we already checked for GPS | ||||
|             nearbyNotificationCardView.permissionType = NearbyNotificationCardView.PermissionType.NO_PERMISSION_NEEDED; | ||||
|             locationManager.registerLocationManager(); | ||||
|         } | ||||
|     private void requestLocationPermission() { | ||||
|         PermissionUtils.checkPermissionsAndPerformAction(getActivity(), | ||||
|                 Manifest.permission.ACCESS_FINE_LOCATION, | ||||
|                 this::onLocationPermissionGranted, | ||||
|                 this::displayYouWontSeeNearbyMessage, | ||||
|                 -1, | ||||
|                 -1); | ||||
|     } | ||||
| 
 | ||||
|     private void enableLocationPermission() { | ||||
|         if (!getActivity().isFinishing()) { | ||||
|             ((MainActivity) getActivity()).locationManager.requestPermissions(getActivity()); | ||||
|         } | ||||
|     private void onLocationPermissionGranted() { | ||||
|         nearbyNotificationCardView.permissionType = NearbyNotificationCardView.PermissionType.NO_PERMISSION_NEEDED; | ||||
|         locationManager.registerLocationManager(); | ||||
|     } | ||||
| 
 | ||||
|     private void enableGPS() { | ||||
|         new AlertDialog.Builder(getActivity()) | ||||
|                 .setMessage(R.string.gps_disabled) | ||||
|                 .setCancelable(false) | ||||
|                 .setPositiveButton(R.string.enable_gps, | ||||
|                         (dialog, id) -> { | ||||
|                             Intent callGPSSettingIntent = new Intent( | ||||
|                                     android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); | ||||
|                             Timber.d("Loaded settings page"); | ||||
|                             ((MainActivity) getActivity()).startActivityForResult(callGPSSettingIntent, 1); | ||||
|                         }) | ||||
|                 .setNegativeButton(R.string.menu_cancel_upload, (dialog, id) -> { | ||||
|                     dialog.cancel(); | ||||
|                     displayYouWontSeeNearbyMessage(); | ||||
|                 }) | ||||
|                 .create() | ||||
|                 .show(); | ||||
|     private void showNearbyCardPermissionRationale() { | ||||
|         DialogUtil.showAlertDialog(getActivity(), | ||||
|                 getString(R.string.nearby_card_permission_title), | ||||
|                 getString(R.string.nearby_card_permission_explanation), | ||||
|                 this::displayYouWontSeeNearbyMessage, | ||||
|                 this::requestLocationPermission, | ||||
|                 checkBoxView, | ||||
|                 false); | ||||
|     } | ||||
| 
 | ||||
|     private void displayYouWontSeeNearbyMessage() { | ||||
|  | @ -589,7 +521,6 @@ public class ContributionsFragment | |||
| 
 | ||||
|     private void updateClosestNearbyCardViewInfo() { | ||||
|         curLatLng = locationManager.getLastLocation(); | ||||
| 
 | ||||
|         compositeDisposable.add(Observable.fromCallable(() -> nearbyController | ||||
|                 .loadAttractionsFromLocation(curLatLng, curLatLng, true, false)) // thanks to boolean, it will only return closest result | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|  |  | |||
|  | @ -45,7 +45,6 @@ import io.reactivex.schedulers.Schedulers; | |||
| import timber.log.Timber; | ||||
| 
 | ||||
| import static android.content.ContentResolver.requestSync; | ||||
| import static fr.free.nrw.commons.location.LocationServiceManager.LOCATION_REQUEST; | ||||
| 
 | ||||
| public class MainActivity extends AuthenticatedActivity implements FragmentManager.OnBackStackChangedListener { | ||||
| 
 | ||||
|  | @ -68,8 +67,8 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag | |||
|     public boolean isAuthCookieAcquired = false; | ||||
| 
 | ||||
|     public ContributionsActivityPagerAdapter contributionsActivityPagerAdapter; | ||||
|     public final int CONTRIBUTIONS_TAB_POSITION = 0; | ||||
|     public final int NEARBY_TAB_POSITION = 1; | ||||
|     public static final int CONTRIBUTIONS_TAB_POSITION = 0; | ||||
|     public static final int NEARBY_TAB_POSITION = 1; | ||||
| 
 | ||||
|     public boolean isContributionsFragmentVisible = true; // False means nearby fragment is visible | ||||
|     private Menu menu; | ||||
|  | @ -361,12 +360,6 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private boolean deviceHasCamera() { | ||||
|         PackageManager pm = getPackageManager(); | ||||
|         return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA) || | ||||
|                 pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT); | ||||
|     } | ||||
| 
 | ||||
|     public class ContributionsActivityPagerAdapter extends FragmentPagerAdapter { | ||||
|         FragmentManager fragmentManager; | ||||
|         private boolean isContributionsListFragment = true; // to know what to put in first tab, Contributions of Media Details | ||||
|  | @ -450,15 +443,6 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag | |||
|             return "android:switcher:" + viewId + ":" + index; | ||||
|         } | ||||
| 
 | ||||
|         /** | ||||
|          * In first tab we can have ContributionsFragment or Media details fragment. This method | ||||
|          * is responsible to update related boolean | ||||
|          * @param isContributionsListFragment true when contribution fragment should be visible, false | ||||
|          *                                means user clicked to MediaDetails | ||||
|          */ | ||||
|         private void updateContributionFragmentTabContent(boolean isContributionsListFragment) { | ||||
|             this.isContributionsListFragment = isContributionsListFragment; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  | @ -468,27 +452,6 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag | |||
|         controller.handleActivityResult(this, requestCode, resultCode, data); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onRequestPermissionsResult(int requestCode, | ||||
|                                            String[] permissions, int[] grantResults) { | ||||
|         if (requestCode == LOCATION_REQUEST) { | ||||
|             // If request is cancelled, the result arrays are empty. | ||||
|             if (grantResults.length > 0 | ||||
|                     && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
|                 Timber.d("Location permission given"); | ||||
|                 ((ContributionsFragment)contributionsActivityPagerAdapter | ||||
|                         .getItem(0)).locationManager.registerLocationManager(); | ||||
|             } else { | ||||
|                 // If nearby fragment is visible and location permission is not given, send user back to contrib fragment | ||||
|                 if (!isContributionsFragmentVisible) { | ||||
|                     viewPager.setCurrentItem(CONTRIBUTIONS_TAB_POSITION); | ||||
| 
 | ||||
|                     // TODO: If contrib fragment is visible and location permission is not given, display permission request button | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|  |  | |||
|  | @ -1,19 +1,12 @@ | |||
| package fr.free.nrw.commons.location; | ||||
| 
 | ||||
| import android.Manifest; | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.Activity; | ||||
| import android.content.Context; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.location.Location; | ||||
| import android.location.LocationListener; | ||||
| import android.location.LocationManager; | ||||
| import android.os.Bundle; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.core.app.ActivityCompat; | ||||
| import androidx.core.content.ContextCompat; | ||||
| 
 | ||||
| import java.util.HashSet; | ||||
| import java.util.List; | ||||
| import java.util.Set; | ||||
|  | @ -44,78 +37,6 @@ public class LocationServiceManager implements LocationListener { | |||
|         this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the current status of the location provider. | ||||
|      * | ||||
|      * @return true if the location provider is enabled | ||||
|      */ | ||||
|     public boolean isProviderEnabled() { | ||||
|         return (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns whether the location permission is granted. | ||||
|      * @return true if the location permission is granted | ||||
|      */ | ||||
|     public boolean isLocationPermissionGranted(@NonNull Context context) { | ||||
|         return ContextCompat.checkSelfPermission(context, | ||||
|                 Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Requests the location permission to be granted. | ||||
|      * | ||||
|      * @param activity the activity | ||||
|      */ | ||||
|     public void requestPermissions(Activity activity) { | ||||
|         if (activity.isFinishing()) { | ||||
|             return; | ||||
|         } | ||||
|         ActivityCompat.requestPermissions(activity, | ||||
|                 new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, | ||||
|                 LOCATION_REQUEST); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * The permission explanation dialog box is now displayed just once for a particular activity. We are subscribing | ||||
|      * to updates from multiple providers so its important to show the dialog just once. Otherwise it will be displayed | ||||
|      * once for every provider, which in our case currently is 2. | ||||
|      * @param activity | ||||
|      * @return | ||||
|      */ | ||||
|     public boolean isPermissionExplanationRequired(Activity activity) { | ||||
|         if (activity.isFinishing()) { | ||||
|             return false; | ||||
|         } | ||||
|         boolean showRequestPermissionRationale = ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_FINE_LOCATION); | ||||
|         if (showRequestPermissionRationale && !locationExplanationDisplayed.contains(activity)) { | ||||
|             locationExplanationDisplayed.add(activity); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Gets the last known location in cases where there wasn't time to register a listener | ||||
|      * (e.g. when Location permission just granted) | ||||
|      * @return last known LatLng | ||||
|      */ | ||||
|     @SuppressLint("MissingPermission") | ||||
|     public LatLng getLKL(@NonNull Context context) { | ||||
|         if (isLocationPermissionGranted(context)) { | ||||
|             Location lastKL = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); | ||||
|             if (lastKL == null) { | ||||
|                 lastKL = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); | ||||
|             } | ||||
|             if (lastKL == null) { | ||||
|                 return null; | ||||
|             } | ||||
|             return LatLng.from(lastKL); | ||||
|         } else { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public LatLng getLastLocation() { | ||||
|         if (lastLocation == null) { | ||||
|             return null; | ||||
|  |  | |||
|  | @ -1,20 +1,11 @@ | |||
| package fr.free.nrw.commons.nearby; | ||||
| 
 | ||||
| import android.Manifest; | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.IntentFilter; | ||||
| import android.os.Build; | ||||
| import android.os.Bundle; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.constraintlayout.widget.ConstraintLayout; | ||||
| import com.google.android.material.bottomsheet.BottomSheetBehavior; | ||||
| import com.google.android.material.snackbar.Snackbar; | ||||
| 
 | ||||
| import androidx.fragment.app.FragmentManager; | ||||
| import androidx.fragment.app.FragmentTransaction; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
|  | @ -22,12 +13,19 @@ import android.widget.FrameLayout; | |||
| import android.widget.LinearLayout; | ||||
| import android.widget.ProgressBar; | ||||
| 
 | ||||
| import com.google.android.material.bottomsheet.BottomSheetBehavior; | ||||
| import com.google.android.material.snackbar.Snackbar; | ||||
| import com.google.gson.Gson; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import javax.inject.Inject; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.constraintlayout.widget.ConstraintLayout; | ||||
| import androidx.fragment.app.FragmentManager; | ||||
| import androidx.fragment.app.FragmentTransaction; | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| import fr.free.nrw.commons.R; | ||||
|  | @ -38,6 +36,7 @@ import fr.free.nrw.commons.location.LocationServiceManager; | |||
| import fr.free.nrw.commons.location.LocationUpdateListener; | ||||
| import fr.free.nrw.commons.utils.FragmentUtils; | ||||
| import fr.free.nrw.commons.utils.NetworkUtils; | ||||
| import fr.free.nrw.commons.utils.PermissionUtils; | ||||
| import fr.free.nrw.commons.utils.ViewUtil; | ||||
| import fr.free.nrw.commons.wikidata.WikidataEditListener; | ||||
| import io.reactivex.Observable; | ||||
|  | @ -45,6 +44,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers; | |||
| import io.reactivex.schedulers.Schedulers; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| import static fr.free.nrw.commons.contributions.MainActivity.CONTRIBUTIONS_TAB_POSITION; | ||||
| import static fr.free.nrw.commons.contributions.MainActivity.NEARBY_TAB_POSITION; | ||||
| import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED; | ||||
| import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED; | ||||
| import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED; | ||||
|  | @ -193,8 +194,8 @@ public class NearbyFragment extends CommonsDaggerSupportFragment | |||
|         bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { | ||||
| 
 | ||||
|             @Override | ||||
|             public void onStateChanged(View bottomSheet, int newState) { | ||||
|                 prepareViewsForSheetPosition(newState); | ||||
|             public void onStateChanged(View bottomSheet, int unusedNewState) { | ||||
|                 prepareViewsForSheetPosition(); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|  | @ -210,9 +211,8 @@ public class NearbyFragment extends CommonsDaggerSupportFragment | |||
| 
 | ||||
|     /** | ||||
|      * Sets camera position, zoom level according to sheet positions | ||||
|      * @param bottomSheetState expanded, collapsed or hidden | ||||
|      */ | ||||
|     public void prepareViewsForSheetPosition(int bottomSheetState) { | ||||
|     private void prepareViewsForSheetPosition() { | ||||
|         // TODO | ||||
|     } | ||||
| 
 | ||||
|  | @ -246,7 +246,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment | |||
|      * | ||||
|      * @param locationChangeType defines if location changed significantly or slightly | ||||
|      */ | ||||
|     public void refreshView(LocationServiceManager.LocationChangeType locationChangeType) { | ||||
|     private void refreshView(LocationServiceManager.LocationChangeType locationChangeType) { | ||||
|         Timber.d("Refreshing nearby places"); | ||||
|         if (lockNearbyView) { | ||||
|             return; | ||||
|  | @ -324,7 +324,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment | |||
|      * button. It populates places for custom location. | ||||
|      * @param customLatLng Custom area which we will search around | ||||
|      */ | ||||
|     public void refreshViewForCustomLocation(LatLng customLatLng, boolean refreshForCurrentLocation) { | ||||
|     void refreshViewForCustomLocation(LatLng customLatLng, boolean refreshForCurrentLocation) { | ||||
|         if (customLatLng == null) { | ||||
|             // If null, return | ||||
|             return; | ||||
|  | @ -568,130 +568,7 @@ public class NearbyFragment extends CommonsDaggerSupportFragment | |||
|      * This method first checks if the location permissions has been granted and then register the location manager for updates. | ||||
|      */ | ||||
|     private void registerLocationUpdates() { | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||||
|             if (locationManager.isLocationPermissionGranted(requireContext())) { | ||||
|                 locationManager.registerLocationManager(); | ||||
|             } else { | ||||
|                 // Should we show an explanation? | ||||
|                 if (locationManager.isPermissionExplanationRequired(getActivity())) { | ||||
|                     new AlertDialog.Builder(getActivity()) | ||||
|                             .setMessage(getString(R.string.location_permission_rationale_nearby)) | ||||
|                             .setPositiveButton(android.R.string.ok, (dialog, which) -> { | ||||
|                                 requestLocationPermissions(); | ||||
|                                 dialog.dismiss(); | ||||
|                             }) | ||||
|                             .setNegativeButton(android.R.string.cancel, (dialog, id) -> { | ||||
|                                 showLocationPermissionDeniedErrorDialog(); | ||||
|                                 dialog.cancel(); | ||||
|                             }) | ||||
|                             .create() | ||||
|                             .show(); | ||||
| 
 | ||||
|                 } else { | ||||
|                     // No explanation needed, we can request the permission. | ||||
|                     requestLocationPermissions(); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             locationManager.registerLocationManager(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Requests location permission if activity is not null | ||||
|      */ | ||||
|     private void requestLocationPermissions() { | ||||
|         if (!getActivity().isFinishing()) { | ||||
|             locationManager.requestPermissions(getActivity()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Will warn user if location is denied | ||||
|      */ | ||||
|     private void showLocationPermissionDeniedErrorDialog() { | ||||
|         new AlertDialog.Builder(getActivity()) | ||||
|                 .setMessage(R.string.nearby_needs_permissions) | ||||
|                 .setCancelable(false) | ||||
|                 .setPositiveButton(R.string.give_permission, (dialog, which) -> { | ||||
|                     //will ask for the location permission again | ||||
|                     checkGps(); | ||||
|                 }) | ||||
|                 .setNegativeButton(R.string.cancel, (dialog, which) -> { | ||||
|                     //dismiss dialog and send user to contributions tab instead | ||||
|                     dialog.cancel(); | ||||
|                     ((MainActivity)getActivity()).viewPager.setCurrentItem(((MainActivity)getActivity()).CONTRIBUTIONS_TAB_POSITION); | ||||
|                 }) | ||||
|                 .create() | ||||
|                 .show(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Checks device GPS permission first for all API levels | ||||
|      */ | ||||
|     private void checkGps() { | ||||
|         Timber.d("checking GPS"); | ||||
|         if (!locationManager.isProviderEnabled()) { | ||||
|             Timber.d("GPS is not enabled"); | ||||
|             new AlertDialog.Builder(getActivity()) | ||||
|                     .setMessage(R.string.gps_disabled) | ||||
|                     .setCancelable(false) | ||||
|                     .setPositiveButton(R.string.enable_gps, | ||||
|                             (dialog, id) -> { | ||||
|                                 Intent callGPSSettingIntent = new Intent( | ||||
|                                         android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS); | ||||
|                                 Timber.d("Loaded settings page"); | ||||
|                                 startActivityForResult(callGPSSettingIntent, 1); | ||||
|                             }) | ||||
|                     .setNegativeButton(R.string.menu_cancel_upload, (dialog, id) -> { | ||||
|                         showLocationPermissionDeniedErrorDialog(); | ||||
|                         dialog.cancel(); | ||||
|                     }) | ||||
|                     .create() | ||||
|                     .show(); | ||||
|         } else { | ||||
|             Timber.d("GPS is enabled"); | ||||
|             checkLocationPermission(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * This method ideally should be called from inside of CheckGPS method. If device GPS is enabled | ||||
|      * then we need to control app specific permissions for >=M devices. For other devices, enabled | ||||
|      * GPS is enough for nearby, so directly call refresh view. | ||||
|      */ | ||||
|     private void checkLocationPermission() { | ||||
|         Timber.d("Checking location permission"); | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | ||||
|             if (locationManager.isLocationPermissionGranted(requireContext())) { | ||||
|                 refreshView(LOCATION_SIGNIFICANTLY_CHANGED); | ||||
|             } else { | ||||
|                 // Should we show an explanation? | ||||
|                 if (locationManager.isPermissionExplanationRequired(getActivity())) { | ||||
|                     // 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(getActivity()) | ||||
|                             .setMessage(getString(R.string.location_permission_rationale_nearby)) | ||||
|                             .setPositiveButton(android.R.string.ok, (dialog, which) -> { | ||||
|                                 requestLocationPermissions(); | ||||
|                                 dialog.dismiss(); | ||||
|                             }) | ||||
|                             .setNegativeButton(android.R.string.cancel, (dialog, id) -> { | ||||
|                                 showLocationPermissionDeniedErrorDialog(); | ||||
|                                 dialog.cancel(); | ||||
|                             }) | ||||
|                             .create() | ||||
|                             .show(); | ||||
| 
 | ||||
|                 } else { | ||||
|                     // No explanation needed, we can request the permission. | ||||
|                     requestLocationPermissions(); | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             refreshView(LOCATION_SIGNIFICANTLY_CHANGED); | ||||
|         } | ||||
|         locationManager.registerLocationManager(); | ||||
|     } | ||||
| 
 | ||||
|     private void showErrorMessage(String message) { | ||||
|  | @ -748,8 +625,12 @@ public class NearbyFragment extends CommonsDaggerSupportFragment | |||
|     public void onResume() { | ||||
|         super.onResume(); | ||||
|         // Resume the fragment if exist | ||||
|         resumeFragment(); | ||||
|         if (((MainActivity) getActivity()).viewPager.getCurrentItem() == NEARBY_TAB_POSITION) { | ||||
|             checkPermissionsAndPerformAction(this::resumeFragment); | ||||
|         } else { | ||||
|             resumeFragment(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Perform nearby operations on nearby tab selected | ||||
|  | @ -758,8 +639,16 @@ public class NearbyFragment extends CommonsDaggerSupportFragment | |||
|     public void onTabSelected(boolean onOrientationChanged) { | ||||
|         Timber.d("On nearby tab selected"); | ||||
|         this.onOrientationChanged = onOrientationChanged; | ||||
|         performNearbyOperations(); | ||||
|         checkPermissionsAndPerformAction(this::performNearbyOperations); | ||||
|     } | ||||
| 
 | ||||
|     private void checkPermissionsAndPerformAction(Runnable runnable) { | ||||
|         PermissionUtils.checkPermissionsAndPerformAction(getActivity(), | ||||
|                 Manifest.permission.ACCESS_FINE_LOCATION, | ||||
|                 runnable, | ||||
|                 () -> ((MainActivity) getActivity()).viewPager.setCurrentItem(CONTRIBUTIONS_TAB_POSITION), | ||||
|                 R.string.location_permission_title, | ||||
|                 R.string.location_permission_rationale_nearby); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -769,8 +658,8 @@ public class NearbyFragment extends CommonsDaggerSupportFragment | |||
|         locationManager.addLocationListener(this); | ||||
|         registerLocationUpdates(); | ||||
|         lockNearbyView = false; | ||||
|         checkGps(); | ||||
|         addNetworkBroadcastReceiver(); | ||||
|         refreshView(LOCATION_SIGNIFICANTLY_CHANGED); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  |  | |||
|  | @ -5,17 +5,17 @@ import android.content.Intent; | |||
| import android.content.pm.PackageManager; | ||||
| import android.net.Uri; | ||||
| import android.provider.Settings; | ||||
| import androidx.annotation.StringRes; | ||||
| import androidx.core.content.ContextCompat; | ||||
| 
 | ||||
| import androidx.annotation.StringRes; | ||||
| import androidx.core.content.ContextCompat; | ||||
| 
 | ||||
| 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 fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.R; | ||||
| 
 | ||||
|  | @ -27,7 +27,7 @@ public class PermissionUtils { | |||
|      It open the app settings from where the user can manually give us the required permission. | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void askUserToManuallyEnablePermissionFromSettings(Activity activity) { | ||||
|     private static void askUserToManuallyEnablePermissionFromSettings(Activity activity) { | ||||
|         Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); | ||||
|         Uri uri = Uri.fromParts("package", activity.getPackageName(), null); | ||||
|         intent.setData(uri); | ||||
|  | @ -50,6 +50,9 @@ public class PermissionUtils { | |||
|      * Checks for a particular permission and runs the runnable to perform an action when the permission is granted | ||||
|      * Also, it shows a rationale if needed | ||||
|      * | ||||
|      * rationaleTitle and rationaleMessage can be invalid @StringRes. If the value is -1 then no permission rationale | ||||
|      * will be displayed and permission would be requested | ||||
|      * | ||||
|      * Sample usage: | ||||
|      * | ||||
|      * PermissionUtils.checkPermissionsAndPerformAction(activity, | ||||
|  | @ -58,12 +61,20 @@ public class PermissionUtils { | |||
|      *                 R.string.storage_permission_title, | ||||
|      *                 R.string.write_storage_permission_rationale); | ||||
|      * | ||||
|      * If you don't want the permission rationale to be shown then use: | ||||
|      * | ||||
|      * PermissionUtils.checkPermissionsAndPerformAction(activity, | ||||
|      *                 Manifest.permission.WRITE_EXTERNAL_STORAGE, | ||||
|      *                 () -> initiateCameraUpload(activity), | ||||
|      *                 - 1, -1); | ||||
|      * | ||||
|      * | ||||
|      * | ||||
|      * @param activity activity requesting permissions | ||||
|      * @param permission the permission being requests | ||||
|      * @param onPermissionGranted the runnable to be executed when the permission is granted | ||||
|      * @param rationaleTitle rationale title to be displayed when permission was denied | ||||
|      * @param rationaleMessage rationale message to be displayed when permission was denied | ||||
|      * @param rationaleTitle rationale title to be displayed when permission was denied. It can be an invalid @StringRes | ||||
|      * @param rationaleMessage rationale message to be displayed when permission was denied. It can be an invalid @StringRes | ||||
|      */ | ||||
|     public static void checkPermissionsAndPerformAction(Activity activity, String permission, | ||||
|         Runnable onPermissionGranted, @StringRes int rationaleTitle, | ||||
|  | @ -93,7 +104,6 @@ public class PermissionUtils { | |||
|      * @param rationaleTitle rationale title to be displayed when permission was denied | ||||
|      * @param rationaleMessage rationale message to be displayed when permission was denied | ||||
|      */ | ||||
| 
 | ||||
|     public static void checkPermissionsAndPerformAction(Activity activity, String permission, | ||||
|         Runnable onPermissionGranted, Runnable onPermissionDenied, @StringRes int rationaleTitle, | ||||
|         @StringRes int rationaleMessage) { | ||||
|  | @ -120,6 +130,10 @@ public class PermissionUtils { | |||
|                 @Override | ||||
|                 public void onPermissionRationaleShouldBeShown(PermissionRequest permission, | ||||
|                     PermissionToken token) { | ||||
|                     if (rationaleTitle == -1 && rationaleMessage == -1) { | ||||
|                         token.continuePermissionRequest(); | ||||
|                         return; | ||||
|                     } | ||||
|                     DialogUtil.showAlertDialog(activity, activity.getString(rationaleTitle), | ||||
|                         activity.getString(rationaleMessage), | ||||
|                         activity.getString(android.R.string.ok), | ||||
|  | @ -129,4 +143,5 @@ public class PermissionUtils { | |||
|             }) | ||||
|             .check(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vivek Maskara
						Vivek Maskara