Merge remote-tracking branch 'refs/remotes/origin/2.8-release'

This commit is contained in:
misaochan 2018-07-11 00:45:02 +10:00
commit f1f41e59f7
14 changed files with 78 additions and 197 deletions

View file

@ -24,6 +24,7 @@ import static android.content.Intent.EXTRA_STREAM;
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.upload.UploadService.EXTRA_SOURCE;
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
public class ContributionController {
@ -91,6 +92,7 @@ public class ContributionController {
}
public void handleImagePicked(int requestCode, Intent data, boolean isDirectUpload, String wikiDataEntityId) {
Timber.d("Is direct upload %s and the Wikidata entity ID is %s", isDirectUpload, wikiDataEntityId);
FragmentActivity activity = fragment.getActivity();
Timber.d("handleImagePicked() called with onActivityResult()");
Intent shareIntent = new Intent(activity, ShareActivity.class);
@ -119,7 +121,7 @@ public class ContributionController {
try {
shareIntent.putExtra("isDirectUpload", isDirectUpload);
if (wikiDataEntityId != null && !wikiDataEntityId.equals("")) {
shareIntent.putExtra("wikiDataEntityId", wikiDataEntityId);
shareIntent.putExtra(WIKIDATA_ENTITY_ID_PREF, wikiDataEntityId);
}
activity.startActivity(shareIntent);
} catch (SecurityException e) {

View file

@ -35,6 +35,7 @@ import timber.log.Timber;
import static android.app.Activity.RESULT_OK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
public class NearbyListFragment extends DaggerFragment {
private Bundle bundleForUpdates; // Carry information from activity about changed nearby places and current location
@ -146,7 +147,7 @@ public class NearbyListFragment extends DaggerFragment {
if (resultCode == RESULT_OK) {
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data);
controller.handleImagePicked(requestCode, data, true, directPrefs.getString("WikiDataEntityId", null));
controller.handleImagePicked(requestCode, data, true, directPrefs.getString(WIKIDATA_ENTITY_ID_PREF, null));
} else {
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data);

View file

@ -63,6 +63,7 @@ import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView;
import static android.app.Activity.RESULT_OK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
public class NearbyMapFragment extends DaggerFragment {
@ -711,7 +712,7 @@ public class NearbyMapFragment extends DaggerFragment {
fabCamera.setOnClickListener(view -> {
if (fabCamera.isShown()) {
Timber.d("Camera button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
Timber.d("Camera button tapped. Place: %s", place.toString());
storeSharedPrefs();
directUpload.initiateCameraUpload();
}
@ -719,7 +720,7 @@ public class NearbyMapFragment extends DaggerFragment {
fabGallery.setOnClickListener(view -> {
if (fabGallery.isShown()) {
Timber.d("Gallery button tapped. Image title: " + place.getName() + "Image desc: " + place.getLongDescription());
Timber.d("Gallery button tapped. Place: %s", place.toString());
storeSharedPrefs();
directUpload.initiateGalleryUpload();
}
@ -731,7 +732,7 @@ public class NearbyMapFragment extends DaggerFragment {
editor.putString("Title", place.getName());
editor.putString("Desc", place.getLongDescription());
editor.putString("Category", place.getCategory());
editor.putString("WikiDataEntityId", place.getWikiDataEntityId());
editor.putString(WIKIDATA_ENTITY_ID_PREF, place.getWikiDataEntityId());
editor.apply();
}
@ -767,7 +768,7 @@ public class NearbyMapFragment extends DaggerFragment {
if (resultCode == RESULT_OK) {
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data);
controller.handleImagePicked(requestCode, data, true, directPrefs.getString("WikiDataEntityId", null));
controller.handleImagePicked(requestCode, data, true, directPrefs.getString(WIKIDATA_ENTITY_ID_PREF, null));
} else {
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data);

View file

@ -10,6 +10,7 @@ import java.util.Map;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.location.LatLng;
import timber.log.Timber;
public class Place {
@ -58,10 +59,12 @@ public class Place {
@Nullable
public String getWikiDataEntityId() {
if (!hasWikidataLink()) {
Timber.d("Wikidata entity ID is null for place with sitelink %s", siteLinks.toString());
return null;
}
String wikiDataLink = siteLinks.getWikidataLink().toString();
Timber.d("Wikidata entity is %s", wikiDataLink);
return wikiDataLink.replace("http://www.wikidata.org/entity/", "");
}
@ -94,7 +97,18 @@ public class Place {
@Override
public String toString() {
return String.format("Place(%s@%s)", name, location);
return "Place{" +
"name='" + name + '\'' +
", label='" + label + '\'' +
", longDescription='" + longDescription + '\'' +
", secondaryImageUrl='" + secondaryImageUrl + '\'' +
", location='" + location + '\'' +
", category='" + category + '\'' +
", image='" + image + '\'' +
", secondaryImage=" + secondaryImage +
", distance='" + distance + '\'' +
", siteLinks='" + siteLinks.toString() + '\'' +
'}';
}
/**

View file

@ -58,6 +58,15 @@ public class Sitelinks implements Parcelable {
return Uri.parse(sanitisedStringUrl);
}
@Override
public String toString() {
return "Sitelinks{" +
"wikipediaLink='" + wikipediaLink + '\'' +
", commonsLink='" + commonsLink + '\'' +
", wikidataLink='" + wikidataLink + '\'' +
'}';
}
private Sitelinks(Sitelinks.Builder builder) {
this.wikidataLink = builder.wikidataLink;
this.wikipediaLink = builder.wikipediaLink;

View file

@ -106,20 +106,20 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse {
ParcelFileDescriptor descriptor = contentResolver.openFileDescriptor(mediaUri, "r");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (descriptor != null) {
imageObj = new GPSExtractor(descriptor.getFileDescriptor(), context, prefs);
imageObj = new GPSExtractor(descriptor.getFileDescriptor());
}
} else {
String filePath = getPathOfMediaOrCopy();
if (filePath != null) {
imageObj = new GPSExtractor(filePath, context, prefs);
imageObj = new GPSExtractor(filePath);
}
}
decimalCoords = imageObj.getCoords(gpsEnabled);
decimalCoords = imageObj.getCoords();
if (decimalCoords == null || !imageObj.imageCoordsExists) {
//Find other photos taken around the same time which has gps coordinates
if (!haveCheckedForOtherImages)
findOtherImages(gpsEnabled);// Do not do repeat the process
findOtherImages();// Do not do repeat the process
} else {
useImageCoords();
}
@ -137,9 +137,8 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse {
/**
* Find other images around the same location that were taken within the last 20 sec
*
* @param gpsEnabled True if GPS is enabled
*/
private void findOtherImages(boolean gpsEnabled) {
private void findOtherImages() {
Timber.d("filePath" + getPathOfMediaOrCopy());
long timeOfCreation = new File(filePath).lastModified();//Time when the original image was created
@ -161,17 +160,17 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse {
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (descriptor != null) {
tempImageObj = new GPSExtractor(descriptor.getFileDescriptor(), context, prefs);
tempImageObj = new GPSExtractor(descriptor.getFileDescriptor());
}
} else {
if (filePath != null) {
tempImageObj = new GPSExtractor(file.getAbsolutePath(), context, prefs);
tempImageObj = new GPSExtractor(file.getAbsolutePath());
}
}
if (tempImageObj != null) {
Timber.d("not null fild EXIF" + tempImageObj.imageCoordsExists + " coords" + tempImageObj.getCoords(gpsEnabled));
if (tempImageObj.getCoords(gpsEnabled) != null && tempImageObj.imageCoordsExists) {
Timber.d("not null fild EXIF" + tempImageObj.imageCoordsExists + " coords" + tempImageObj.getCoords());
if (tempImageObj.getCoords() != null && tempImageObj.imageCoordsExists) {
// Current image has gps coordinates and it's not current gps locaiton
Timber.d("This file has image coords:" + file.getAbsolutePath());
SimilarImageDialogFragment newFragment = new SimilarImageDialogFragment();
@ -250,7 +249,7 @@ public class FileProcessor implements SimilarImageDialogFragment.onResponse {
@Override
public void onPositiveResponse() {
imageObj = tempImageObj;
decimalCoords = imageObj.getCoords(false);// Not necessary to use gps as image already ha EXIF data
decimalCoords = imageObj.getCoords();// Not necessary to use gps as image already ha EXIF data
Timber.d("EXIF from tempImageObj");
useImageCoords();
}

View file

@ -1,13 +1,6 @@
package fr.free.nrw.commons.upload;
import android.content.Context;
import android.content.SharedPreferences;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.ExifInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
@ -19,31 +12,21 @@ import timber.log.Timber;
/**
* Extracts geolocation to be passed to API for category suggestions. If a picture with geolocation
* is uploaded, extract latitude and longitude from EXIF data of image. If a picture without
* geolocation is uploaded, retrieve user's location (if enabled in Settings).
* is uploaded, extract latitude and longitude from EXIF data of image.
*/
public class GPSExtractor {
private final Context context;
private SharedPreferences prefs;
private ExifInterface exif;
private double decLatitude;
private double decLongitude;
private Double currentLatitude = null;
private Double currentLongitude = null;
public boolean imageCoordsExists;
private MyLocationListener myLocationListener;
private LocationManager locationManager;
/**
* Construct from the file descriptor of the image (only for API 24 or newer).
* @param fileDescriptor the file descriptor of the image
* @param context the context
*/
@RequiresApi(24)
public GPSExtractor(@NonNull FileDescriptor fileDescriptor, Context context, SharedPreferences prefs) {
this.context = context;
this.prefs = prefs;
public GPSExtractor(@NonNull FileDescriptor fileDescriptor) {
try {
exif = new ExifInterface(fileDescriptor);
} catch (IOException | IllegalArgumentException e) {
@ -54,65 +37,22 @@ public class GPSExtractor {
/**
* Construct from the file path of the image.
* @param path file path of the image
* @param context the context
*
*/
public GPSExtractor(@NonNull String path, Context context, SharedPreferences prefs) {
this.prefs = prefs;
public GPSExtractor(@NonNull String path) {
try {
exif = new ExifInterface(path);
} catch (IOException | IllegalArgumentException e) {
Timber.w(e);
}
this.context = context;
}
/**
* Check if user enabled retrieval of their current location in Settings
* @return true if enabled, false if disabled
*/
private boolean gpsPreferenceEnabled() {
boolean gpsPref = prefs.getBoolean("allowGps", false);
Timber.d("Gps pref set to: %b", gpsPref);
return gpsPref;
}
/**
* Registers a LocationManager to listen for current location
*/
protected void registerLocationManager() {
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
String provider = locationManager.getBestProvider(criteria, true);
myLocationListener = new MyLocationListener();
try {
locationManager.requestLocationUpdates(provider, 400, 1, myLocationListener);
Location location = locationManager.getLastKnownLocation(provider);
if (location != null) {
myLocationListener.onLocationChanged(location);
}
} catch (IllegalArgumentException e) {
Timber.e(e, "Illegal argument exception");
} catch (SecurityException e) {
Timber.e(e, "Security exception");
}
}
protected void unregisterLocationManager() {
try {
locationManager.removeUpdates(myLocationListener);
} catch (SecurityException e) {
Timber.e(e, "Security exception");
}
}
/**
* Extracts geolocation (either of image from EXIF data, or of user)
* @param useGPS set to true if location permissions allowed (by API 23), false if disallowed
* @return coordinates as string (needs to be passed as a String in API query)
*/
@Nullable
public String getCoords(boolean useGPS) {
public String getCoords() {
String latitude;
String longitude;
String latitudeRef;
@ -120,30 +60,9 @@ public class GPSExtractor {
String decimalCoords;
//If image has no EXIF data and user has enabled GPS setting, get user's location
//TODO: Always return null as a temporary fix for #1599
if (exif == null || exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE) == null) {
if (useGPS) {
registerLocationManager();
imageCoordsExists = false;
Timber.d("EXIF data has no location info");
//Check what user's preference is for automatic location detection
boolean gpsPrefEnabled = gpsPreferenceEnabled();
//Check that currentLatitude and currentLongitude have been
// explicitly set by MyLocationListener
// and do not default to (0.0,0.0)
if (gpsPrefEnabled && currentLatitude != null && currentLongitude != null) {
Timber.d("Current location values: Lat = %f Long = %f",
currentLatitude, currentLongitude);
return String.valueOf(currentLatitude) + "|" + String.valueOf(currentLongitude);
} else {
// No coords found
return null;
}
} else {
return null;
}
return null;
} else {
//If image has EXIF data, extract image coords
imageCoordsExists = true;
@ -166,33 +85,6 @@ public class GPSExtractor {
}
}
/**
* Listen for user's location when it changes
*/
private class MyLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
currentLatitude = location.getLatitude();
currentLongitude = location.getLongitude();
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Timber.d("%s's status changed to %d", provider, status);
}
@Override
public void onProviderEnabled(String provider) {
Timber.d("Provider %s enabled", provider);
}
@Override
public void onProviderDisabled(String provider) {
Timber.d("Provider %s disabled", provider);
}
}
public double getDecLatitude() {
return decLatitude;
}

View file

@ -329,18 +329,18 @@ public class MultipleShareActivity extends AuthenticatedActivity
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ParcelFileDescriptor fd = getContentResolver().openFileDescriptor(imageUri,"r");
if (fd != null) {
gpsExtractor = new GPSExtractor(fd.getFileDescriptor(),this,prefs);
gpsExtractor = new GPSExtractor(fd.getFileDescriptor());
}
} else {
String filePath = FileUtils.getPath(this,imageUri);
if (filePath != null) {
gpsExtractor = new GPSExtractor(filePath,this,prefs);
gpsExtractor = new GPSExtractor(filePath);
}
}
if (gpsExtractor != null) {
//get image coordinates from exif data or user location
return gpsExtractor.getCoords(locationPermitted);
return gpsExtractor.getCoords();
}
} catch (FileNotFoundException fnfe) {

View file

@ -21,9 +21,7 @@ import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.annotation.RequiresApi;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.view.KeyEvent;
import android.view.MenuItem;
@ -68,6 +66,7 @@ import timber.log.Timber;
import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.DUPLICATE_PROCEED;
import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.NO_DUPLICATE;
import static fr.free.nrw.commons.upload.FileUtils.getSHA1;
import static fr.free.nrw.commons.wikidata.WikidataConstants.WIKIDATA_ENTITY_ID_PREF;
/**
* Activity for the title/desc screen after image is selected. Also starts processing image
@ -77,7 +76,6 @@ public class ShareActivity
extends AuthenticatedActivity
implements SingleUploadFragment.OnUploadActionInitiated,
OnCategoriesSaveHandler {
private static final int REQUEST_PERM_ON_CREATE_LOCATION = 2;
private static final int REQUEST_PERM_ON_SUBMIT_STORAGE = 4;
//Had to make them class variables, to extract out the click listeners, also I see no harm in this
final Rect startBounds = new Rect();
@ -130,7 +128,6 @@ public class ShareActivity
private String title;
private String description;
private String wikiDataEntityId;
private Snackbar snackbar;
private boolean duplicateCheckPassed = false;
private boolean isNearbyUpload = false;
private Animator CurrentAnimator;
@ -277,22 +274,6 @@ public class ShareActivity
Timber.d("Uri: %s", mediaUri.toString());
Timber.d("Ext storage dir: %s", Environment.getExternalStorageDirectory());
useNewPermissions = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
useNewPermissions = true;
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
locationPermitted = true;
}
}
// Check location permissions if M or newer for category suggestions, request via snackbar if not present
if (!locationPermitted) {
requestPermissionUsingSnackBar(
getString(R.string.location_permission_rationale),
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
REQUEST_PERM_ON_CREATE_LOCATION);
}
SingleUploadFragment shareView = (SingleUploadFragment) getSupportFragmentManager().findFragmentByTag("shareView");
categorizationFragment = (CategorizationFragment) getSupportFragmentManager().findFragmentByTag("categorization");
if (shareView == null && categorizationFragment == null) {
@ -327,6 +308,8 @@ public class ShareActivity
if (intent.hasExtra("isDirectUpload")) {
Timber.d("This was initiated by a direct upload from Nearby");
isNearbyUpload = true;
wikiDataEntityId = intent.getStringExtra(WIKIDATA_ENTITY_ID_PREF);
Timber.d("Received wikiDataEntityId from contribution controller %s", wikiDataEntityId);
}
mimeType = intent.getType();
}
@ -391,7 +374,7 @@ public class ShareActivity
}
/**
* Handles BOTH snackbar permission request (for location) and submit button permission request (for storage)
* Handles submit button permission request (for storage)
*
* @param requestCode type of request
* @param permissions permissions requested
@ -400,41 +383,19 @@ public class ShareActivity
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_PERM_ON_CREATE_LOCATION: {
if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
locationPermitted = true;
checkIfFileExists();
}
return;
}
// Storage (from submit button) - this needs to be separate from (1) because only the
// submit button should bring user to next screen
case REQUEST_PERM_ON_SUBMIT_STORAGE: {
if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//It is OK to call this at both (1) and (4) because if perm had been granted at
//snackbar, user should not be prompted at submit button
checkIfFileExists();
//Uploading only begins if storage permission granted from arrow icon
uploadBegins();
snackbar.dismiss();
}
}
}
}
/**
* Displays Snackbar to ask for location permissions
*/
private Snackbar requestPermissionUsingSnackBar(String rationale, final String[] perms, final int code) {
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), rationale,
Snackbar.LENGTH_INDEFINITE).setAction(R.string.ok,
view -> ActivityCompat.requestPermissions(ShareActivity.this, perms, code));
snackbar.show();
return snackbar;
}
/**
* Check if file user wants to upload already exists on Commons
*/
@ -471,12 +432,6 @@ public class ShareActivity
@Override
public void onPause() {
super.onPause();
try {
gpsObj.unregisterLocationManager();
Timber.d("Unregistered locationManager");
} catch (NullPointerException e) {
Timber.d("locationManager does not exist, not unregistered");
}
}
@Override

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.upload;
import android.annotation.SuppressLint;
import android.accounts.Account;
import android.content.ComponentName;
import android.content.ContentResolver;
@ -98,6 +99,7 @@ public class UploadController {
public void startUpload(String title, Uri mediaUri, String description, String mimeType, String source, String decimalCoords, String wikiDataEntityId, ContributionUploadProgress onComplete) {
Contribution contribution;
Timber.d("Wikidata entity ID received from Share activity is %s", wikiDataEntityId);
//TODO: Modify this to include coords
Account currentAccount = sessionManager.getCurrentAccount();
if(currentAccount == null) {
@ -124,6 +126,7 @@ public class UploadController {
* @param contribution the contribution object
* @param onComplete the progress tracker
*/
@SuppressLint("StaticFieldLeak")
public void startUpload(final Contribution contribution, final ContributionUploadProgress onComplete) {
//Set creator, desc, and license
if (TextUtils.isEmpty(contribution.getCreator())) {

View file

@ -251,8 +251,10 @@ public class UploadService extends HandlerService<Contribution> {
String resultStatus = uploadResult.getResultStatus();
if (!resultStatus.equals("Success")) {
Timber.d("Contribution upload failed. Wikidata entity won't be edited");
showFailedNotification(contribution);
} else {
Timber.d("Contribution upload success. Initiating Wikidata edit for entity id %s", contribution.getWikiDataEntityId());
wikidataEditService.createClaimWithLogging(contribution.getWikiDataEntityId(), filename);
contribution.setFilename(uploadResult.getCanonicalFilename());
contribution.setImageUrl(uploadResult.getImageUrl());

View file

@ -0,0 +1,5 @@
package fr.free.nrw.commons.wikidata;
public class WikidataConstants {
public static final String WIKIDATA_ENTITY_ID_PREF = "WikiDataEntityId";
}

View file

@ -48,10 +48,16 @@ public class WikidataEditService {
* @param fileName
*/
public void createClaimWithLogging(String wikidataEntityId, String fileName) {
if(wikidataEntityId == null
|| fileName == null) {
if(wikidataEntityId == null) {
Timber.d("Skipping creation of claim as Wikidata entity ID is null");
return;
}
if(fileName == null) {
Timber.d("Skipping creation of claim as fileName entity ID is null");
return;
}
editWikidataProperty(wikidataEntityId, fileName);
}

View file

@ -38,16 +38,8 @@
</PreferenceCategory>
<PreferenceCategory
android:title="@string/preference_category_location">
<SwitchPreference
android:key="allowGps"
android:title="@string/allow_gps"
android:defaultValue="false"
android:summary="@string/allow_gps_summary" />
</PreferenceCategory>
<!-- The key 'allowGps' was used before and has since been removed based on the discussion at #1599.
Do not reuse this key unless you revive the same feature with the changes mentioned at #1599.-->
<PreferenceCategory
android:title="@string/preference_category_feedback">