mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Fixes #945 Check image coordinates for direct Nearby uploads in locations that the user is not currently in (#2099)
* Add getGeolocation method to geolocation from file path * Add geolocation check to receiveDirect method checks, means it will be checked durimg nearby direct uploads * Create method body for geolocation and nearby place coordinate comparaison, this method will be filled on consequent commits * Add a method to find location missmatch * app/src/main/java/fr/free/nrw/commons/utils/ImageUtils.java * Add if check to upload activity to detect pictures with wrong location, and save it to shared prefs * Do not edit wikidata item if picture has wrong location info * Add one more bitwise operand to possible warning reasons for wrong location case * Add a bitwise variable for wrong locatio case * Share nearby place location just like wikidataEntityId, so that we can compare * Implement check image geolocation is different method by comparing nearby location and file EXIF geolocation * Add Javadocs * Remove logs * Fix all taken on wrong phrases as taken at * Fix typo on logs * Simplify if logic * Fix string issues
This commit is contained in:
parent
6754ce121c
commit
718ad3a12c
15 changed files with 161 additions and 54 deletions
|
|
@ -34,6 +34,8 @@ import timber.log.Timber;
|
||||||
|
|
||||||
import static android.app.Activity.RESULT_OK;
|
import static android.app.Activity.RESULT_OK;
|
||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
||||||
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ITEM_LOCATION;
|
||||||
|
|
||||||
public class BookmarkLocationsFragment extends DaggerFragment {
|
public class BookmarkLocationsFragment extends DaggerFragment {
|
||||||
|
|
||||||
|
|
@ -136,13 +138,14 @@ public class BookmarkLocationsFragment extends DaggerFragment {
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
requestCode, resultCode, data);
|
requestCode, resultCode, data);
|
||||||
String wikidataEntityId = directPrefs.getString("WikiDataEntityId", null);
|
String wikidataEntityId = directPrefs.getString(WIKIDATA_ENTITY_ID_PREF, null);
|
||||||
|
String wikidataItemLocation = directPrefs.getString(WIKIDATA_ITEM_LOCATION, null);
|
||||||
if (requestCode == ContributionController.SELECT_FROM_CAMERA) {
|
if (requestCode == ContributionController.SELECT_FROM_CAMERA) {
|
||||||
// If coming from camera, pass null as uri. Because camera photos get saved to a
|
// If coming from camera, pass null as uri. Because camera photos get saved to a
|
||||||
// fixed directory
|
// fixed directory
|
||||||
contributionController.handleImagePicked(requestCode, null, true, wikidataEntityId);
|
contributionController.handleImagePicked(requestCode, null, true, wikidataEntityId, wikidataItemLocation);
|
||||||
} else {
|
} else {
|
||||||
contributionController.handleImagePicked(requestCode, data.getData(), true, wikidataEntityId);
|
contributionController.handleImagePicked(requestCode, data.getData(), true, wikidataEntityId, wikidataItemLocation);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import static fr.free.nrw.commons.contributions.Contribution.SOURCE_CAMERA;
|
||||||
import static fr.free.nrw.commons.contributions.Contribution.SOURCE_GALLERY;
|
import static fr.free.nrw.commons.contributions.Contribution.SOURCE_GALLERY;
|
||||||
import static fr.free.nrw.commons.upload.UploadService.EXTRA_SOURCE;
|
import static fr.free.nrw.commons.upload.UploadService.EXTRA_SOURCE;
|
||||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
||||||
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ITEM_LOCATION;
|
||||||
|
|
||||||
public class ContributionController {
|
public class ContributionController {
|
||||||
|
|
||||||
|
|
@ -131,7 +132,7 @@ public class ContributionController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleImagePicked(int requestCode, @Nullable Uri uri, boolean isDirectUpload, String wikiDataEntityId) {
|
public void handleImagePicked(int requestCode, @Nullable Uri uri, boolean isDirectUpload, String wikiDataEntityId, String wikidateItemLocation) {
|
||||||
FragmentActivity activity = fragment.getActivity();
|
FragmentActivity activity = fragment.getActivity();
|
||||||
Timber.d("handleImagePicked() called with onActivityResult(). Boolean isDirectUpload: " + isDirectUpload + "String wikiDataEntityId: " + wikiDataEntityId);
|
Timber.d("handleImagePicked() called with onActivityResult(). Boolean isDirectUpload: " + isDirectUpload + "String wikiDataEntityId: " + wikiDataEntityId);
|
||||||
Intent shareIntent = new Intent(activity, UploadActivity.class);
|
Intent shareIntent = new Intent(activity, UploadActivity.class);
|
||||||
|
|
@ -163,6 +164,7 @@ public class ContributionController {
|
||||||
try {
|
try {
|
||||||
if (wikiDataEntityId != null && !wikiDataEntityId.equals("")) {
|
if (wikiDataEntityId != null && !wikiDataEntityId.equals("")) {
|
||||||
shareIntent.putExtra(WIKIDATA_ENTITY_ID_PREF, wikiDataEntityId);
|
shareIntent.putExtra(WIKIDATA_ENTITY_ID_PREF, wikiDataEntityId);
|
||||||
|
shareIntent.putExtra(WIKIDATA_ITEM_LOCATION, wikidateItemLocation);
|
||||||
}
|
}
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
Timber.e(e, "Security Exception");
|
Timber.e(e, "Security Exception");
|
||||||
|
|
|
||||||
|
|
@ -255,11 +255,11 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
|
||||||
if (requestCode == ContributionController.SELECT_FROM_CAMERA) {
|
if (requestCode == ContributionController.SELECT_FROM_CAMERA) {
|
||||||
// If coming from camera, pass null as uri. Because camera photos get saved to a
|
// If coming from camera, pass null as uri. Because camera photos get saved to a
|
||||||
// fixed directory
|
// fixed directory
|
||||||
controller.handleImagePicked(requestCode, null, false, null);
|
controller.handleImagePicked(requestCode, null, false, null, null);
|
||||||
} else if (requestCode == ContributionController.PICK_IMAGE_MULTIPLE) {
|
} else if (requestCode == ContributionController.PICK_IMAGE_MULTIPLE) {
|
||||||
handleMultipleImages(requestCode, data);
|
handleMultipleImages(requestCode, data);
|
||||||
} else if (requestCode == ContributionController.SELECT_FROM_GALLERY){
|
} else if (requestCode == ContributionController.SELECT_FROM_GALLERY){
|
||||||
controller.handleImagePicked(requestCode, data.getData(), false, null);
|
controller.handleImagePicked(requestCode, data.getData(), false, null, null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
|
|
@ -319,7 +319,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
|
||||||
Log.v("LOG_TAG", "Selected Images" + mArrayUri.size());
|
Log.v("LOG_TAG", "Selected Images" + mArrayUri.size());
|
||||||
controller.handleImagesPicked(requestCode, mArrayUri);
|
controller.handleImagesPicked(requestCode, mArrayUri);
|
||||||
} else if(data.getData() != null) {
|
} else if(data.getData() != null) {
|
||||||
controller.handleImagePicked(SELECT_FROM_GALLERY, data.getData(), false, null);
|
controller.handleImagePicked(SELECT_FROM_GALLERY, data.getData(), false, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ import timber.log.Timber;
|
||||||
|
|
||||||
import static android.app.Activity.RESULT_OK;
|
import static android.app.Activity.RESULT_OK;
|
||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
||||||
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ITEM_LOCATION;
|
||||||
|
|
||||||
public class NearbyListFragment extends DaggerFragment {
|
public class NearbyListFragment extends DaggerFragment {
|
||||||
private Bundle bundleForUpdates; // Carry information from activity about changed nearby places and current location
|
private Bundle bundleForUpdates; // Carry information from activity about changed nearby places and current location
|
||||||
|
|
@ -159,13 +161,14 @@ public class NearbyListFragment extends DaggerFragment {
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
requestCode, resultCode, data);
|
requestCode, resultCode, data);
|
||||||
String wikidataEntityId = directPrefs.getString("WikiDataEntityId", null);
|
String wikidataEntityId = directPrefs.getString(WIKIDATA_ENTITY_ID_PREF, null);
|
||||||
|
String wikidataItemLocation = directPrefs.getString(WIKIDATA_ITEM_LOCATION, null);
|
||||||
if (requestCode == ContributionController.SELECT_FROM_CAMERA) {
|
if (requestCode == ContributionController.SELECT_FROM_CAMERA) {
|
||||||
// If coming from camera, pass null as uri. Because camera photos get saved to a
|
// If coming from camera, pass null as uri. Because camera photos get saved to a
|
||||||
// fixed directory
|
// fixed directory
|
||||||
controller.handleImagePicked(requestCode, null, true, wikidataEntityId);
|
controller.handleImagePicked(requestCode, null, true, wikidataEntityId, wikidataItemLocation);
|
||||||
} else {
|
} else {
|
||||||
controller.handleImagePicked(requestCode, data.getData(), true, wikidataEntityId);
|
controller.handleImagePicked(requestCode, data.getData(), true, wikidataEntityId, wikidataItemLocation);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
||||||
import fr.free.nrw.commons.contributions.ContributionController;
|
import fr.free.nrw.commons.contributions.ContributionController;
|
||||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
import fr.free.nrw.commons.location.LocationServiceManager;
|
||||||
import fr.free.nrw.commons.utils.LocationUtils;
|
import fr.free.nrw.commons.utils.LocationUtils;
|
||||||
|
import fr.free.nrw.commons.utils.PlaceUtils;
|
||||||
import fr.free.nrw.commons.utils.UriDeserializer;
|
import fr.free.nrw.commons.utils.UriDeserializer;
|
||||||
import fr.free.nrw.commons.utils.ViewUtil;
|
import fr.free.nrw.commons.utils.ViewUtil;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
@ -71,6 +72,7 @@ import timber.log.Timber;
|
||||||
import static android.app.Activity.RESULT_OK;
|
import static android.app.Activity.RESULT_OK;
|
||||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
||||||
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ITEM_LOCATION;
|
||||||
|
|
||||||
public class NearbyMapFragment extends DaggerFragment {
|
public class NearbyMapFragment extends DaggerFragment {
|
||||||
|
|
||||||
|
|
@ -888,6 +890,7 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
editor.putString("Desc", place.getLongDescription());
|
editor.putString("Desc", place.getLongDescription());
|
||||||
editor.putString("Category", place.getCategory());
|
editor.putString("Category", place.getCategory());
|
||||||
editor.putString(WIKIDATA_ENTITY_ID_PREF, place.getWikiDataEntityId());
|
editor.putString(WIKIDATA_ENTITY_ID_PREF, place.getWikiDataEntityId());
|
||||||
|
editor.putString(WIKIDATA_ITEM_LOCATION, PlaceUtils.latLangToString(place.location));
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -924,13 +927,14 @@ public class NearbyMapFragment extends DaggerFragment {
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
requestCode, resultCode, data);
|
requestCode, resultCode, data);
|
||||||
String wikidataEntityId = directPrefs.getString("WikiDataEntityId", null);
|
String wikidataEntityId = directPrefs.getString(WIKIDATA_ENTITY_ID_PREF, null);
|
||||||
|
String wikidataItemLocation = directPrefs.getString(WIKIDATA_ITEM_LOCATION, null);
|
||||||
if (requestCode == ContributionController.SELECT_FROM_CAMERA) {
|
if (requestCode == ContributionController.SELECT_FROM_CAMERA) {
|
||||||
// If coming from camera, pass null as uri. Because camera photos get saved to a
|
// If coming from camera, pass null as uri. Because camera photos get saved to a
|
||||||
// fixed directory
|
// fixed directory
|
||||||
controller.handleImagePicked(requestCode, null, true, wikidataEntityId);
|
controller.handleImagePicked(requestCode, null, true, wikidataEntityId, wikidataItemLocation);
|
||||||
} else {
|
} else {
|
||||||
controller.handleImagePicked(requestCode, data.getData(), true, wikidataEntityId);
|
controller.handleImagePicked(requestCode, data.getData(), true, wikidataEntityId, wikidataItemLocation);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,12 @@ import fr.free.nrw.commons.auth.LoginActivity;
|
||||||
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
|
||||||
import fr.free.nrw.commons.contributions.ContributionController;
|
import fr.free.nrw.commons.contributions.ContributionController;
|
||||||
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
import fr.free.nrw.commons.di.ApplicationlessInjection;
|
||||||
|
import fr.free.nrw.commons.utils.PlaceUtils;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
import static fr.free.nrw.commons.theme.NavigationBaseActivity.startActivityWithFlags;
|
import static fr.free.nrw.commons.theme.NavigationBaseActivity.startActivityWithFlags;
|
||||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
||||||
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ITEM_LOCATION;
|
||||||
|
|
||||||
public class PlaceRenderer extends Renderer<Place> {
|
public class PlaceRenderer extends Renderer<Place> {
|
||||||
|
|
||||||
|
|
@ -193,6 +195,7 @@ public class PlaceRenderer extends Renderer<Place> {
|
||||||
editor.putString("Desc", place.getLongDescription());
|
editor.putString("Desc", place.getLongDescription());
|
||||||
editor.putString("Category", place.getCategory());
|
editor.putString("Category", place.getCategory());
|
||||||
editor.putString(WIKIDATA_ENTITY_ID_PREF, place.getWikiDataEntityId());
|
editor.putString(WIKIDATA_ENTITY_ID_PREF, place.getWikiDataEntityId());
|
||||||
|
editor.putString(WIKIDATA_ITEM_LOCATION, PlaceUtils.latLangToString(place.location));
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import android.content.ContentUris;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.media.ExifInterface;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
|
@ -78,6 +79,25 @@ public class FileUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Geolocation of file from input file path
|
||||||
|
*/
|
||||||
|
static String getGeolocationOfFile(String filePath) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
ExifInterface exifInterface=new ExifInterface(filePath);
|
||||||
|
GPSExtractor imageObj = new GPSExtractor(exifInterface);
|
||||||
|
if (imageObj.imageCoordsExists) { // If image has geolocation information in its EXIF
|
||||||
|
return imageObj.getCoords();
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In older devices getPath() may fail depending on the source URI. Creating and using a copy of the file seems to work instead.
|
* In older devices getPath() may fail depending on the source URI. Creating and using a copy of the file seems to work instead.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ import timber.log.Timber;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.Result;
|
import static fr.free.nrw.commons.utils.ImageUtils.Result;
|
||||||
import static fr.free.nrw.commons.utils.ImageUtils.getErrorMessageForResult;
|
import static fr.free.nrw.commons.utils.ImageUtils.getErrorMessageForResult;
|
||||||
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
|
||||||
|
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ITEM_LOCATION;
|
||||||
|
|
||||||
public class UploadActivity extends AuthenticatedActivity implements UploadView, SimilarImageInterface {
|
public class UploadActivity extends AuthenticatedActivity implements UploadView, SimilarImageInterface {
|
||||||
@Inject InputMethodManager inputMethodManager;
|
@Inject InputMethodManager inputMethodManager;
|
||||||
|
|
@ -350,6 +351,9 @@ public class UploadActivity extends AuthenticatedActivity implements UploadView,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showBadPicturePopup(@Result int result) {
|
public void showBadPicturePopup(@Result int result) {
|
||||||
|
if (result >= 8 ) { // If location of image and nearby does not match, then set shared preferences to disable wikidata edits
|
||||||
|
directPrefs.edit().putBoolean("Picture_Has_Correct_Location",false);
|
||||||
|
}
|
||||||
String errorMessageForResult = getErrorMessageForResult(this, result);
|
String errorMessageForResult = getErrorMessageForResult(this, result);
|
||||||
if (StringUtils.isNullOrWhiteSpace(errorMessageForResult)) {
|
if (StringUtils.isNullOrWhiteSpace(errorMessageForResult)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -553,7 +557,8 @@ public class UploadActivity extends AuthenticatedActivity implements UploadView,
|
||||||
String imageDesc = directPrefs.getString("Desc", "");
|
String imageDesc = directPrefs.getString("Desc", "");
|
||||||
Timber.i("Received direct upload with title %s and description %s", imageTitle, imageDesc);
|
Timber.i("Received direct upload with title %s and description %s", imageTitle, imageDesc);
|
||||||
String wikidataEntityIdPref = intent.getStringExtra(WIKIDATA_ENTITY_ID_PREF);
|
String wikidataEntityIdPref = intent.getStringExtra(WIKIDATA_ENTITY_ID_PREF);
|
||||||
presenter.receiveDirect(mediaUri, mimeType, source, wikidataEntityIdPref, imageTitle, imageDesc);
|
String wikidataItemLocation = intent.getStringExtra(WIKIDATA_ITEM_LOCATION);
|
||||||
|
presenter.receiveDirect(mediaUri, mimeType, source, wikidataEntityIdPref, imageTitle, imageDesc, wikidataItemLocation);
|
||||||
} else {
|
} else {
|
||||||
Timber.i("Received single upload");
|
Timber.i("Received single upload");
|
||||||
presenter.receive(mediaUri, mimeType, source);
|
presenter.receive(mediaUri, mimeType, source);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import android.database.Cursor;
|
||||||
import android.graphics.BitmapRegionDecoder;
|
import android.graphics.BitmapRegionDecoder;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
|
@ -115,7 +116,7 @@ public class UploadModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
void receiveDirect(Uri media, String mimeType, String source, String wikidataEntityIdPref, String title, String desc, SimilarImageInterface similarImageInterface) {
|
void receiveDirect(Uri media, String mimeType, String source, String wikidataEntityIdPref, String title, String desc, SimilarImageInterface similarImageInterface, String wikidataItemLocation) {
|
||||||
initDefaultValues();
|
initDefaultValues();
|
||||||
long fileCreatedDate = getFileCreatedDate(media);
|
long fileCreatedDate = getFileCreatedDate(media);
|
||||||
String filePath = this.cacheFileUpload(media);
|
String filePath = this.cacheFileUpload(media);
|
||||||
|
|
@ -133,11 +134,16 @@ public class UploadModel {
|
||||||
.map(fileUtilsWrapper::getSHA1)
|
.map(fileUtilsWrapper::getSHA1)
|
||||||
.map(mwApi::existingFile)
|
.map(mwApi::existingFile)
|
||||||
.map(b -> b ? ImageUtils.IMAGE_DUPLICATE : ImageUtils.IMAGE_OK),
|
.map(b -> b ? ImageUtils.IMAGE_DUPLICATE : ImageUtils.IMAGE_OK),
|
||||||
|
Single.fromCallable(() ->
|
||||||
|
filePath)
|
||||||
|
.map(FileUtils::getGeolocationOfFile)
|
||||||
|
.map(geoLocation -> ImageUtils.checkImageGeolocationIsDifferent(geoLocation,wikidataItemLocation))
|
||||||
|
.map(r -> r ? ImageUtils.IMAGE_GEOLOCATION_DIFFERENT : ImageUtils.IMAGE_OK),
|
||||||
Single.fromCallable(() ->
|
Single.fromCallable(() ->
|
||||||
fileUtilsWrapper.getFileInputStream(filePath))
|
fileUtilsWrapper.getFileInputStream(filePath))
|
||||||
.map(file -> BitmapRegionDecoder.newInstance(file, false))
|
.map(file -> BitmapRegionDecoder.newInstance(file, false))
|
||||||
.map(ImageUtils::checkIfImageIsTooDark), //Returns IMAGE_DARK or IMAGE_OK
|
.map(ImageUtils::checkIfImageIsTooDark), //Returns IMAGE_DARK or IMAGE_OK
|
||||||
(dupe, dark) -> dupe | dark).subscribe(item.imageQuality::onNext, Timber::e);
|
(dupe, wrongGeo, dark) -> dupe | wrongGeo | dark).subscribe(item.imageQuality::onNext);
|
||||||
items.add(item);
|
items.add(item);
|
||||||
items.get(0).selected = true;
|
items.get(0).selected = true;
|
||||||
items.get(0).first = true;
|
items.get(0).first = true;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.upload;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -92,8 +93,8 @@ public class UploadPresenter {
|
||||||
* @param source File source from {@link Contribution.FileSource}
|
* @param source File source from {@link Contribution.FileSource}
|
||||||
*/
|
*/
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
void receiveDirect(Uri media, String mimeType, @Contribution.FileSource String source, String wikidataEntityIdPref, String title, String desc) {
|
void receiveDirect(Uri media, String mimeType, @Contribution.FileSource String source, String wikidataEntityIdPref, String title, String desc, String wikidataItemLocation) {
|
||||||
Completable.fromRunnable(() -> uploadModel.receiveDirect(media, mimeType, source, wikidataEntityIdPref, title, desc, similarImageInterface))
|
Completable.fromRunnable(() -> uploadModel.receiveDirect(media, mimeType, source, wikidataEntityIdPref, title, desc, similarImageInterface, wikidataItemLocation))
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(() -> {
|
.subscribe(() -> {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import android.graphics.Rect;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.facebook.common.executors.CallerThreadExecutor;
|
import com.facebook.common.executors.CallerThreadExecutor;
|
||||||
import com.facebook.common.references.CloseableReference;
|
import com.facebook.common.references.CloseableReference;
|
||||||
|
|
@ -25,6 +26,7 @@ import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -36,6 +38,7 @@ public class ImageUtils {
|
||||||
public static final int IMAGE_DARK = 1;
|
public static final int IMAGE_DARK = 1;
|
||||||
public static final int IMAGE_BLURRY = 1 << 1;
|
public static final int IMAGE_BLURRY = 1 << 1;
|
||||||
public static final int IMAGE_DUPLICATE = 1 << 2;
|
public static final int IMAGE_DUPLICATE = 1 << 2;
|
||||||
|
public static final int IMAGE_GEOLOCATION_DIFFERENT = 1 << 3;
|
||||||
public static final int IMAGE_OK = 0;
|
public static final int IMAGE_OK = 0;
|
||||||
public static final int IMAGE_KEEP = -1;
|
public static final int IMAGE_KEEP = -1;
|
||||||
public static final int IMAGE_WAIT = -2;
|
public static final int IMAGE_WAIT = -2;
|
||||||
|
|
@ -54,7 +57,8 @@ public class ImageUtils {
|
||||||
IMAGE_WAIT,
|
IMAGE_WAIT,
|
||||||
EMPTY_TITLE,
|
EMPTY_TITLE,
|
||||||
FILE_NAME_EXISTS,
|
FILE_NAME_EXISTS,
|
||||||
NO_CATEGORY_SELECTED
|
NO_CATEGORY_SELECTED,
|
||||||
|
IMAGE_GEOLOCATION_DIFFERENT
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
|
@ -93,17 +97,30 @@ public class ImageUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pulls the pixels into an array and then runs through it while checking the brightness of each pixel.
|
* @param geolocationOfFileString Geolocation of image. If geotag doesn't exists, then this will be an empty string
|
||||||
* The calculation of brightness of each pixel is done by extracting the RGB constituents of the pixel
|
* @param wikidataItemLocationString Location of wikidata item will be edited after upload
|
||||||
* and then applying the formula to calculate its "Luminance".
|
* @return false if image is neither dark nor blurry or if the input bitmapRegionDecoder provided is null
|
||||||
* Pixels with luminance greater than 40% are considered to be bright pixels while the ones with luminance
|
* true if geolocation of the image and wikidata item are different
|
||||||
* greater than 26% but less than 40% are considered to be pixels with medium brightness. The rest are
|
|
||||||
* dark pixels.
|
|
||||||
* If the number of bright pixels is more than 2.5% or the number of pixels with medium brightness is
|
|
||||||
* more than 30% of the total number of pixels then the image is considered to be OK else dark.
|
|
||||||
* @param bitmap The bitmap that needs to be checked.
|
|
||||||
* @return true if bitmap is dark or null, false if bitmap is bright
|
|
||||||
*/
|
*/
|
||||||
|
public static boolean checkImageGeolocationIsDifferent(String geolocationOfFileString, String wikidataItemLocationString) {
|
||||||
|
Timber.d("Comparing geolocation of file with nearby place location");
|
||||||
|
if (geolocationOfFileString == null || geolocationOfFileString == "") { // Means that geolocation for this image is not given
|
||||||
|
return false; // Since we don't know geolocation of file, we choose letting upload
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] geolocationOfFile = geolocationOfFileString.split("\\|");
|
||||||
|
String[] wikidataItemLocation = wikidataItemLocationString.split("/");
|
||||||
|
|
||||||
|
Double distance = LengthUtils.computeDistanceBetween(
|
||||||
|
new LatLng(Double.parseDouble(geolocationOfFile[0]),Double.parseDouble(geolocationOfFile[1]),0)
|
||||||
|
, new LatLng(Double.parseDouble(wikidataItemLocation[0]), Double.parseDouble(wikidataItemLocation[1]),0));
|
||||||
|
if ( distance >= 1000 ) {// Distance is more than 1 km, means that geolocation is wrong
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean checkIfImageIsDark(Bitmap bitmap) {
|
private static boolean checkIfImageIsDark(Bitmap bitmap) {
|
||||||
if (bitmap == null) {
|
if (bitmap == null) {
|
||||||
Timber.e("Expected bitmap was null");
|
Timber.e("Expected bitmap was null");
|
||||||
|
|
@ -206,24 +223,37 @@ public class ImageUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getErrorMessageForResult(Context context, @Result int result) {
|
public static String getErrorMessageForResult(Context context, @Result int result) {
|
||||||
String errorMessage;
|
/**
|
||||||
if (result == ImageUtils.IMAGE_DARK)
|
* Result variable is a result of an or operation of all possbile problems. Ie. if result
|
||||||
errorMessage = context.getString(R.string.upload_image_problem_dark);
|
* is 0001 means IMAGE_DARK, if result is 1100 IMAGE_DUPLICATE and IMAGE_GEOLOCATION_DIFFERENT
|
||||||
else if (result == ImageUtils.IMAGE_BLURRY)
|
*/
|
||||||
errorMessage = context.getString(R.string.upload_image_problem_blurry);
|
StringBuilder errorMessage = new StringBuilder();
|
||||||
else if (result == ImageUtils.IMAGE_DUPLICATE)
|
if (((IMAGE_DARK | IMAGE_GEOLOCATION_DIFFERENT | IMAGE_BLURRY | IMAGE_DUPLICATE) & result) == 0 ) {
|
||||||
errorMessage = context.getString(R.string.upload_image_problem_duplicate);
|
Timber.d("No issues to warn user is found");
|
||||||
else if (result == (ImageUtils.IMAGE_DARK|ImageUtils.IMAGE_BLURRY))
|
} else {
|
||||||
errorMessage = context.getString(R.string.upload_image_problem_dark_blurry);
|
Timber.d("Issues found to warn user");
|
||||||
else if (result == (ImageUtils.IMAGE_DARK|ImageUtils.IMAGE_DUPLICATE))
|
|
||||||
errorMessage = context.getString(R.string.upload_image_problem_dark_duplicate);
|
|
||||||
else if (result == (ImageUtils.IMAGE_BLURRY|ImageUtils.IMAGE_DUPLICATE))
|
|
||||||
errorMessage = context.getString(R.string.upload_image_problem_blurry_duplicate);
|
|
||||||
else if (result == (ImageUtils.IMAGE_DARK|ImageUtils.IMAGE_BLURRY|ImageUtils.IMAGE_DUPLICATE))
|
|
||||||
errorMessage = context.getString(R.string.upload_image_problem_dark_blurry_duplicate);
|
|
||||||
else
|
|
||||||
return "";
|
|
||||||
|
|
||||||
return errorMessage;
|
errorMessage.append(context.getResources().getString(R.string.upload_problem_exist));
|
||||||
|
|
||||||
|
if ((IMAGE_DARK & result) != 0 ) { // We are checking image dark bit to see if that bit is set or not
|
||||||
|
errorMessage.append(context.getResources().getString(R.string.upload_problem_image_dark));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((IMAGE_BLURRY & result) != 0 ) {
|
||||||
|
errorMessage.append(context.getResources().getString(R.string.upload_image_problem_blurry));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((IMAGE_DUPLICATE & result) != 0 ) {
|
||||||
|
errorMessage.append(context.getResources().getString(R.string.upload_problem_image_duplicate));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((IMAGE_GEOLOCATION_DIFFERENT & result) != 0 ) {
|
||||||
|
errorMessage.append(context.getResources().getString(R.string.upload_problem_different_geolocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
errorMessage.append(context.getResources().getString(R.string.upload_problem_do_you_continue));
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorMessage.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
app/src/main/java/fr/free/nrw/commons/utils/PlaceUtils.java
Normal file
25
app/src/main/java/fr/free/nrw/commons/utils/PlaceUtils.java
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
package fr.free.nrw.commons.utils;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.location.LatLng;
|
||||||
|
|
||||||
|
public class PlaceUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts our defined LatLng to string, to put as String
|
||||||
|
* @param latLng latlang will be converted to string
|
||||||
|
* @return latitude + "/" + longitude
|
||||||
|
*/
|
||||||
|
public static String latLangToString(LatLng latLng) {
|
||||||
|
return latLng.getLatitude()+"/"+latLng.getLongitude();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts latitude + "/" + longitude string to commons LatLng
|
||||||
|
* @param latLngString latitude + "/" + longitude string
|
||||||
|
* @return commons LatLng
|
||||||
|
*/
|
||||||
|
public static LatLng stringToLatLng(String latLngString) {
|
||||||
|
String[] parts = latLngString.split("/");
|
||||||
|
return new LatLng(Double.parseDouble(parts[0]), Double.parseDouble(parts[1]), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,4 +2,5 @@ package fr.free.nrw.commons.wikidata;
|
||||||
|
|
||||||
public class WikidataConstants {
|
public class WikidataConstants {
|
||||||
public static final String WIKIDATA_ENTITY_ID_PREF = "WikiDataEntityId";
|
public static final String WIKIDATA_ENTITY_ID_PREF = "WikiDataEntityId";
|
||||||
|
public static final String WIKIDATA_ITEM_LOCATION = "WikiDataItemLocation";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,11 @@ public class WikidataEditService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(directPrefs.getBoolean("Picture_Has_Correct_Location",true))) {
|
||||||
|
Timber.d("Image location and nearby place location mismatched, so Wikidata item won't be edited");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
editWikidataProperty(wikidataEntityId, fileName);
|
editWikidataProperty(wikidataEntityId, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -236,13 +236,12 @@
|
||||||
<string name="upload_image_too_dark">This picture is too dark, are you sure you want to upload it? Wikimedia Commons is only for pictures with encyclopedic value.</string>
|
<string name="upload_image_too_dark">This picture is too dark, are you sure you want to upload it? Wikimedia Commons is only for pictures with encyclopedic value.</string>
|
||||||
<string name="upload_image_blurry">This picture is blurry, are you sure you want to upload it? Wikimedia Commons is only for pictures with encyclopedic value.</string>
|
<string name="upload_image_blurry">This picture is blurry, are you sure you want to upload it? Wikimedia Commons is only for pictures with encyclopedic value.</string>
|
||||||
|
|
||||||
<string name="upload_image_problem_duplicate">This file already exists on Commons. Are you sure you want to proceed?</string>
|
<string name="upload_problem_exist">Potential problems with this image:</string>
|
||||||
<string name="upload_image_problem_dark">This picture is too dark, are you sure you want to upload it? Wikimedia Commons is only for pictures with encyclopedic value.</string>
|
<string name="upload_problem_image_dark">\n - Image is too dark.</string>
|
||||||
<string name="upload_image_problem_blurry">This picture is blurry, are you sure you want to upload it? Wikimedia Commons is only for pictures with encyclopedic value.</string>
|
<string name="upload_problem_image_blurry">\n - Image is blurry.</string>
|
||||||
<string name="upload_image_problem_dark_duplicate">This picture is too dark and already exists on Commons, are you sure you want to upload it? Please only upload pictures with encyclopedic value.</string>
|
<string name="upload_problem_image_duplicate">\n - Image is already on Commons.</string>
|
||||||
<string name="upload_image_problem_blurry_duplicate">This picture is blurry and already exists on Commons, are you sure you want to upload it? Please only upload pictures with encyclopedic value.</string>
|
<string name="upload_problem_different_geolocation">\n - This picture was taken at a different location.</string>
|
||||||
<string name="upload_image_problem_dark_blurry">This picture is too dark and is blurry, are you sure you want to upload it? Please only upload pictures with encyclopedic value.</string>
|
<string name="upload_problem_do_you_continue">\n\nDo you still want to upload this picture?</string>
|
||||||
<string name="upload_image_problem_dark_blurry_duplicate">This picture is too dark, is blurry and already exists on Commons, are you sure you want to upload it? Please only upload pictures with encyclopedic value.</string>
|
|
||||||
|
|
||||||
<string name="give_permission">Give permission</string>
|
<string name="give_permission">Give permission</string>
|
||||||
<string name="use_external_storage">Use external storage</string>
|
<string name="use_external_storage">Use external storage</string>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue