diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java index eea4e25d5..50666e65a 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsFragment.java @@ -1,5 +1,6 @@ package fr.free.nrw.commons.contributions; +import android.Manifest; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -20,12 +21,14 @@ import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.app.LoaderManager; import android.support.v4.widget.CursorAdapter; -import android.util.Log; +import android.support.v7.app.AlertDialog; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Adapter; import android.widget.AdapterView; +import android.widget.CheckBox; +import android.widget.CompoundButton; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; @@ -50,6 +53,8 @@ import fr.free.nrw.commons.notification.NotificationController; import fr.free.nrw.commons.notification.UnreadNotificationsCheckAsync; import fr.free.nrw.commons.settings.Prefs; import fr.free.nrw.commons.upload.UploadService; +import fr.free.nrw.commons.utils.DialogUtil; +import fr.free.nrw.commons.utils.ViewUtil; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; @@ -102,10 +107,11 @@ public class ContributionsFragment private LatLng curLatLng; private boolean firstLocationUpdate = true; - private LocationServiceManager locationManager; + public LocationServiceManager locationManager; private boolean isFragmentAttachedBefore = false; - + private View checkBoxView; + private CheckBox checkBox; /** * Since we will need to use parent activity on onAuthCookieAcquired, we have to wait @@ -137,6 +143,18 @@ public class ContributionsFragment public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_contributions, container, false); nearbyNoificationCardView = view.findViewById(R.id.card_view_nearby); + checkBoxView = View.inflate(getActivity(), R.layout.nearby_permission_dialog, null); + checkBox = (CheckBox) checkBoxView.findViewById(R.id.never_ask_again); + checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (isChecked) { + // Do not ask for permission on activity start again + prefs.edit().putBoolean("displayLocationPermissionForCardView",false).apply(); + } + } + }); if (savedInstanceState != null) { mediaDetailPagerFragment = (MediaDetailPagerFragment)getChildFragmentManager().findFragmentByTag(MEDIA_DETAIL_PAGER_FRAGMENT_TAG); @@ -186,7 +204,9 @@ public class ContributionsFragment // show nearby card view on contributions list is visible if (nearbyNoificationCardView != null) { if (prefs.getBoolean("displayNearbyCardView", true)) { - nearbyNoificationCardView.setVisibility(View.VISIBLE); + if (nearbyNoificationCardView.cardViewVisibilityState == NearbyNoificationCardView.CardViewVisibilityState.READY) { + nearbyNoificationCardView.setVisibility(View.VISIBLE); + } } else { nearbyNoificationCardView.setVisibility(View.GONE); } @@ -312,16 +332,24 @@ 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 - nearbyNoificationCardView.displayPermissionRequestButton(false); locationManager.registerLocationManager(); } else { - // Still ask for permission - nearbyNoificationCardView.displayPermissionRequestButton(true); + if (prefs.getBoolean("displayLocationPermissionForCardView", true)) { + // Still ask for permission + DialogUtil.showAlertDialog(getActivity(), + getString(R.string.nearby_card_permission_title), + getString(R.string.nearby_card_permission_explanation), + () -> displayYouWontSeeNearbyMessage(), + () -> enableLocationPermission(), + checkBoxView, + false); + } } } break; @@ -499,9 +527,10 @@ public class ContributionsFragment if (prefs.getBoolean("displayNearbyCardView", true)) { - nearbyNoificationCardView.cardViewVisibilityState = NearbyNoificationCardView.CardViewVisibilityState.LOADING; - nearbyNoificationCardView.setVisibility(View.VISIBLE); checkGPS(); + if (nearbyNoificationCardView.cardViewVisibilityState == NearbyNoificationCardView.CardViewVisibilityState.READY) { + nearbyNoificationCardView.setVisibility(View.VISIBLE); + } } else { // Hide nearby notification card view if related shared preferences is false @@ -511,7 +540,6 @@ public class ContributionsFragment } - /** * Check GPS to decide displaying request permission button or not. */ @@ -519,7 +547,15 @@ public class ContributionsFragment if (!locationManager.isProviderEnabled()) { Timber.d("GPS is not enabled"); nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.ENABLE_GPS; - nearbyNoificationCardView.displayPermissionRequestButton(true); + if (prefs.getBoolean("displayLocationPermissionForCardView", true)) { + DialogUtil.showAlertDialog(getActivity(), + getString(R.string.nearby_card_permission_title), + getString(R.string.nearby_card_permission_explanation), + () -> displayYouWontSeeNearbyMessage(), + () -> enableGPS(), + checkBoxView, + false); + } } else { Timber.d("GPS is enabled"); checkLocationPermission(); @@ -530,20 +566,57 @@ public class ContributionsFragment if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (locationManager.isLocationPermissionGranted()) { nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.NO_PERMISSION_NEEDED; - nearbyNoificationCardView.displayPermissionRequestButton(false); locationManager.registerLocationManager(); } else { nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.ENABLE_LOCATION_PERMISSON; - nearbyNoificationCardView.displayPermissionRequestButton(true); + // If user didn't selected Don't ask again + if (shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION) + && prefs.getBoolean("displayLocationPermissionForCardView", true)) { + DialogUtil.showAlertDialog(getActivity(), + getString(R.string.nearby_card_permission_title), + getString(R.string.nearby_card_permission_explanation), + () -> displayYouWontSeeNearbyMessage(), + () -> enableLocationPermission(), + checkBoxView, + false); + } } } else { // If device is under Marshmallow, we already checked for GPS nearbyNoificationCardView.permissionType = NearbyNoificationCardView.PermissionType.NO_PERMISSION_NEEDED; - nearbyNoificationCardView.displayPermissionRequestButton(false); locationManager.registerLocationManager(); } } + private void enableLocationPermission() { + if (!getActivity().isFinishing()) { + ((MainActivity) getActivity()).locationManager.requestPermissions(getActivity()); + } + } + + 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 displayYouWontSeeNearbyMessage() { + ViewUtil.showLongToast(getActivity(), getResources().getString(R.string.unable_to_display_nearest_place)); + } + private void updateClosestNearbyCardViewInfo() { curLatLng = locationManager.getLastLocation(); diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java index e3ed7f18e..9b8035e5d 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java @@ -31,6 +31,7 @@ import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.nearby.NearbyFragment; import fr.free.nrw.commons.nearby.NearbyMapFragment; +import fr.free.nrw.commons.nearby.NearbyNoificationCardView; import fr.free.nrw.commons.notification.NotificationActivity; import fr.free.nrw.commons.theme.NavigationBaseActivity; import fr.free.nrw.commons.upload.UploadService; @@ -253,7 +254,9 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag showTabs(); // Nearby Notification Card View was invisible when Media Details Fragment is active, make it visible again on Contrib List Fragment active, according to preferences if (prefs.getBoolean("displayNearbyCardView", true)) { - contributionsFragment.nearbyNoificationCardView.setVisibility(View.VISIBLE); + if (contributionsFragment.nearbyNoificationCardView.cardViewVisibilityState == NearbyNoificationCardView.CardViewVisibilityState.READY) { + contributionsFragment.nearbyNoificationCardView.setVisibility(View.VISIBLE); + } } else { contributionsFragment.nearbyNoificationCardView.setVisibility(View.GONE); } @@ -468,6 +471,8 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag 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) { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java index c44fbf763..61798a95a 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyNoificationCardView.java @@ -3,6 +3,7 @@ package fr.free.nrw.commons.nearby; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.design.widget.CoordinatorLayout; @@ -10,6 +11,7 @@ import android.support.design.widget.SwipeDismissBehavior; import android.support.v7.app.AlertDialog; import android.support.v7.widget.CardView; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button; @@ -19,6 +21,7 @@ import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; + import fr.free.nrw.commons.R; import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.utils.ViewUtil; @@ -86,7 +89,7 @@ public class NearbyNoificationCardView extends CardView{ protected void onAttachedToWindow() { super.onAttachedToWindow(); // If you don't setVisibility after getting layout params, then you will se an empty space in place of nerabyNotificationCardView - if (((MainActivity)context).prefs.getBoolean("displayNearbyCardView", true)) { + if (((MainActivity)context).prefs.getBoolean("displayNearbyCardView", true) && this.cardViewVisibilityState == NearbyNoificationCardView.CardViewVisibilityState.READY) { this.setVisibility(VISIBLE); } else { this.setVisibility(GONE); @@ -183,7 +186,7 @@ public class NearbyNoificationCardView extends CardView{ } else { cardViewVisibilityState = CardViewVisibilityState.LOADING; - permissionRequestButton.setVisibility(GONE); + /*permissionRequestButton.setVisibility(GONE); contentLayout.setVisibility(VISIBLE); // Set visibility of elements in content layout once it become visible progressBar.setVisibility(VISIBLE); @@ -191,10 +194,35 @@ public class NearbyNoificationCardView extends CardView{ notificationDistance.setVisibility(GONE); notificationIcon.setVisibility(GONE); - permissionRequestButton.setVisibility(GONE); + permissionRequestButton.setVisibility(GONE);*/ + + this.setVisibility(GONE); + Handler nearbyNotificationHandler = new Handler(); + Runnable nearbyNotificationRunnable = new Runnable() { + @Override + public void run() { + if (cardViewVisibilityState != NearbyNoificationCardView.CardViewVisibilityState.READY + && cardViewVisibilityState != NearbyNoificationCardView.CardViewVisibilityState.ASK_PERMISSION + && cardViewVisibilityState != NearbyNoificationCardView.CardViewVisibilityState.INVISIBLE) { + // If after 30 seconds, card view is not ready + errorOcured(); + } else { + suceeded(); + } + } + }; + nearbyNotificationHandler.postDelayed(nearbyNotificationRunnable, 30000); } } + private void errorOcured() { + this.setVisibility(GONE); + } + + private void suceeded() { + this.setVisibility(VISIBLE); + } + /** * Pass place information to views. * @param isClosestNearbyPlaceFound false if there are no close place @@ -202,6 +230,7 @@ public class NearbyNoificationCardView extends CardView{ */ public void updateContent(boolean isClosestNearbyPlaceFound, Place place) { Timber.d("Update nearby card notification content"); + this.setVisibility(VISIBLE); cardViewVisibilityState = CardViewVisibilityState.READY; permissionRequestButton.setVisibility(GONE); contentLayout.setVisibility(VISIBLE); @@ -269,6 +298,7 @@ public class NearbyNoificationCardView extends CardView{ READY, INVISIBLE, ASK_PERMISSION, + ERROR_OCURED } /** diff --git a/app/src/main/java/fr/free/nrw/commons/utils/DialogUtil.java b/app/src/main/java/fr/free/nrw/commons/utils/DialogUtil.java index f68037488..21cc69b14 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/DialogUtil.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/DialogUtil.java @@ -10,6 +10,7 @@ import android.os.Build; import android.support.annotation.Nullable; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; +import android.view.View; import fr.free.nrw.commons.R; import timber.log.Timber; @@ -160,6 +161,63 @@ public class DialogUtil { showSafely(activity, dialog); } + /* + Shows alert dialog with custom view + */ + public static void showAlertDialog(Activity activity, + String title, + String message, + final Runnable onPositiveBtnClick, + final Runnable onNegativeBtnClick, + View customView, + boolean cancelable) { + showAlertDialog(activity, + title, + message, + activity.getString(R.string.no), + activity.getString(R.string.yes), + onPositiveBtnClick, + onNegativeBtnClick, + customView, + false); + } + + /* + Shows alert dialog with custom view + */ + private static void showAlertDialog(Activity activity, + String title, + String message, + String positiveButtonText, + String negativeButtonText, + final Runnable onPositiveBtnClick, + final Runnable onNegativeBtnClick, + View customView, + boolean cancelable) { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(title); + builder.setMessage(message); + builder.setView(customView); + builder.setCancelable(cancelable); + + builder.setPositiveButton(positiveButtonText, (dialogInterface, i) -> { + dialogInterface.dismiss(); + if (onPositiveBtnClick != null) { + onPositiveBtnClick.run(); + } + }); + + builder.setNegativeButton(negativeButtonText, (DialogInterface dialogInterface, int i) -> { + dialogInterface.dismiss(); + if (onNegativeBtnClick != null) { + onNegativeBtnClick.run(); + } + }); + + AlertDialog dialog = builder.create(); + showSafely(activity, dialog); + } + public interface Callback { void onPositiveButtonClicked(); diff --git a/app/src/main/res/layout/nearby_permission_dialog.xml b/app/src/main/res/layout/nearby_permission_dialog.xml new file mode 100644 index 000000000..feb19a4cf --- /dev/null +++ b/app/src/main/res/layout/nearby_permission_dialog.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5104f0c75..4224f231f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -414,5 +414,11 @@ Upload your first media by touching the camera or gallery icon above. No, Go Back (For all images in set) + Permission Request + Would you like us to use your current location to display the nearest place that needs pictures? + Unable to display nearest place that needs pictures without location permissions + Never ask this again + Display location permission + Ask for location permission when needed for nearby notification card view feature. diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 0af4d50c6..e272e02af 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -42,6 +42,12 @@ android:defaultValue="true" android:summary="@string/display_nearby_notification_summary" /> + +