diff --git a/CHANGELOG.md b/CHANGELOG.md index 6255cd920..526c48bab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Wikimedia Commons for Android ## v1.5 +- Caches area and associated categories +- Increased search radius for nearby categories + +## v1.4 - New feature: Suggests nearby Commons categories ## v1.3 diff --git a/commons/AndroidManifest.xml b/commons/AndroidManifest.xml index 7fed5543f..de1e407dc 100644 --- a/commons/AndroidManifest.xml +++ b/commons/AndroidManifest.xml @@ -1,7 +1,7 @@ + android:versionCode="21" + android:versionName="1.5" > categories + cacheData = new CacheController(); + DiskBasedCache cache = new DiskBasedCache(getCacheDir(), 16 * 1024 * 1024); volleyQueue = new RequestQueue(cache, new BasicNetwork(new HurlStack())); volleyQueue.start(); diff --git a/commons/src/main/java/fr/free/nrw/commons/caching/CacheController.java b/commons/src/main/java/fr/free/nrw/commons/caching/CacheController.java new file mode 100644 index 000000000..2681fb606 --- /dev/null +++ b/commons/src/main/java/fr/free/nrw/commons/caching/CacheController.java @@ -0,0 +1,88 @@ +package fr.free.nrw.commons.caching; + +import android.util.Log; + +import com.github.varunpant.quadtree.Point; +import com.github.varunpant.quadtree.QuadTree; + +import java.util.ArrayList; +import java.util.List; + +import fr.free.nrw.commons.upload.MwVolleyApi; + +public class CacheController { + + private double x, y; + private QuadTree quadTree; + private Point[] pointsFound; + private double xMinus, xPlus, yMinus, yPlus; + + private static final String TAG = CacheController.class.getName(); + private static final int EARTH_RADIUS = 6378137; + + public CacheController() { + quadTree = new QuadTree(-180, -90, +180, +90); + } + + public void setQtPoint(double decLongitude, double decLatitude) { + x = decLongitude; + y = decLatitude; + Log.d(TAG, "New QuadTree created"); + Log.d(TAG, "X (longitude) value: " + x + ", Y (latitude) value: " + y); + } + + public void cacheCategory() { + List pointCatList = new ArrayList(); + if (MwVolleyApi.GpsCatExists.getGpsCatExists() == true) { + pointCatList.addAll(MwVolleyApi.getGpsCat()); + Log.d(TAG, "Categories being cached: " + pointCatList); + } else { + Log.d(TAG, "No categories found, so no categories cached"); + } + quadTree.set(x, y, pointCatList); + } + + public List findCategory() { + //Convert decLatitude and decLongitude to a coordinate offset range + convertCoordRange(); + pointsFound = quadTree.searchWithin(xMinus, yMinus, xPlus, yPlus); + List displayCatList = new ArrayList(); + Log.d(TAG, "Points found in quadtree: " + pointsFound); + + if (pointsFound.length != 0) { + Log.d(TAG, "Entering for loop"); + + for (Point point : pointsFound) { + Log.d(TAG, "Nearby point: " + point.toString()); + displayCatList = (List)point.getValue(); + Log.d(TAG, "Nearby cat: " + point.getValue()); + } + + Log.d(TAG, "Categories found in cache: " + displayCatList.toString()); + } else { + Log.d(TAG, "No categories found in cache"); + } + return displayCatList; + } + + //Based on algorithm at http://gis.stackexchange.com/questions/2951/algorithm-for-offsetting-a-latitude-longitude-by-some-amount-of-meters + public void convertCoordRange() { + //Position, decimal degrees + double lat = y; + double lon = x; + + //offsets in meters + double offset = 100; + + //Coordinate offsets in radians + double dLat = offset/EARTH_RADIUS; + double dLon = offset/(EARTH_RADIUS*Math.cos(Math.PI*lat/180)); + + //OffsetPosition, decimal degrees + yPlus = lat + dLat * 180/Math.PI; + yMinus = lat - dLat * 180/Math.PI; + xPlus = lon + dLon * 180/Math.PI; + xMinus = lon - dLon * 180/Math.PI; + Log.d(TAG, "Search within: xMinus=" + xMinus + ", yMinus=" + yMinus + ", xPlus=" + xPlus + ", yPlus=" + yPlus); + } +} diff --git a/commons/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java b/commons/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java index e5491c27f..3a6d1d329 100644 --- a/commons/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java +++ b/commons/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java @@ -51,6 +51,7 @@ public class CategorizationFragment extends SherlockFragment{ private ContentProviderClient client; private final int SEARCH_CATS_LIMIT = 25; + private static final String TAG = CategorizationFragment.class.getName(); public static class CategoryItem implements Parcelable { public String name; @@ -152,9 +153,9 @@ public class CategorizationFragment extends SherlockFragment{ } if (MwVolleyApi.GpsCatExists.getGpsCatExists() == true){ - Log.d("Cat", "GPS cats found in CategorizationFragment.java" + MwVolleyApi.getGpsCat().toString()); + Log.d(TAG, "GPS cats found in CategorizationFragment.java" + MwVolleyApi.getGpsCat().toString()); List gpsItems = new ArrayList(MwVolleyApi.getGpsCat()); - Log.d("Cat", "GPS items: " + gpsItems.toString()); + Log.d(TAG, "GPS items: " + gpsItems.toString()); mergedItems.addAll(gpsItems); } @@ -165,7 +166,7 @@ public class CategorizationFragment extends SherlockFragment{ // faaaail throw new RuntimeException(e); } - Log.d("Cat", "Merged items: " + mergedItems.toString()); + Log.d(TAG, "Merged items: " + mergedItems.toString()); return mergedItems; } diff --git a/commons/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java b/commons/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java index 88191b894..4de87d42a 100644 --- a/commons/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java +++ b/commons/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java @@ -9,6 +9,7 @@ import java.io.IOException; public class GPSExtractor { private String filePath; + private double decLatitude, decLongitude; public GPSExtractor(String filePath){ this.filePath = filePath; @@ -41,18 +42,27 @@ public class GPSExtractor { longitude = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE); longitude_ref = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF); + Log.d("Image", "Latitude: " + latitude + " " + latitude_ref); Log.d("Image", "Longitude: " + longitude + " " + longitude_ref); - decimalCoords = getDecimalCoords(latitude, latitude_ref, longitude, longitude_ref); return decimalCoords; + } } - //Converts format of coords into decimal coords as required by API for next step + public double getDecLatitude() { + return decLatitude; + } + + public double getDecLongitude() { + return decLongitude; + } + + //Converts format of coords into decimal coords as required by MediaWiki API private String getDecimalCoords(String latitude, String latitude_ref, String longitude, String longitude_ref) { - double decLatitude, decLongitude; + if(latitude_ref.equals("N")){ decLatitude = convertToDegree(latitude); @@ -68,9 +78,12 @@ public class GPSExtractor { decLongitude = 0 - convertToDegree(longitude); } - return (String.valueOf(decLatitude) + "|" + String.valueOf(decLongitude)); + String decimalCoords = String.valueOf(decLatitude) + "|" + String.valueOf(decLongitude); + Log.d("Coords", "Latitude and Longitude are " + decimalCoords); + return decimalCoords; } + private double convertToDegree(String stringDMS){ double result; String[] DMS = stringDMS.split(",", 3); diff --git a/commons/src/main/java/fr/free/nrw/commons/upload/MwVolleyApi.java b/commons/src/main/java/fr/free/nrw/commons/upload/MwVolleyApi.java index e3c69d2b4..fe55f3f7f 100644 --- a/commons/src/main/java/fr/free/nrw/commons/upload/MwVolleyApi.java +++ b/commons/src/main/java/fr/free/nrw/commons/upload/MwVolleyApi.java @@ -24,6 +24,8 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import fr.free.nrw.commons.caching.CacheController; + public class MwVolleyApi { private static RequestQueue REQUEST_QUEUE; @@ -32,23 +34,27 @@ public class MwVolleyApi { private String coordsLog; protected static Set categorySet; + private static List categoryList; private static final String MWURL = "https://commons.wikimedia.org/"; + private static final String TAG = MwVolleyApi.class.getName(); public MwVolleyApi(Context context) { this.context = context; categorySet = new HashSet(); } - //To get the list of categories for display public static List getGpsCat() { - List list = new ArrayList(categorySet); - return list; + return categoryList; } + public static void setGpsCat(List cachedList) { + categoryList = new ArrayList(); + categoryList.addAll(cachedList); + Log.d(TAG, "Setting GPS cats from cache: " + categoryList.toString()); + } public void request(String coords) { - coordsLog = coords; String apiUrl = buildUrl(coords); Log.d("Image", "URL: " + apiUrl); @@ -77,7 +83,7 @@ public class MwVolleyApi { .appendQueryParameter("codistancefrompoint", coords) .appendQueryParameter("generator", "geosearch") .appendQueryParameter("ggscoord", coords) - .appendQueryParameter("ggsradius", "100") + .appendQueryParameter("ggsradius", "10000") .appendQueryParameter("ggslimit", "10") .appendQueryParameter("ggsnamespace", "6") .appendQueryParameter("ggsprop", "type|name|dim|country|region|globe") @@ -164,13 +170,14 @@ public class MwVolleyApi { private String printSet() { if (categorySet == null || categorySet.isEmpty()) { GpsCatExists.setGpsCatExists(false); - Log.d("Cat", "gpsCatExists=" + GpsCatExists.getGpsCatExists()); + Log.d(TAG, "gpsCatExists=" + GpsCatExists.getGpsCatExists()); return "No collection of categories"; } else { GpsCatExists.setGpsCatExists(true); - Log.d("Cat", "gpsCatExists=" + GpsCatExists.getGpsCatExists()); + Log.d(TAG, "gpsCatExists=" + GpsCatExists.getGpsCatExists()); return "CATEGORIES FOUND" + categorySet.toString(); } + } @Override @@ -225,6 +232,7 @@ public class MwVolleyApi { } } + categoryList = new ArrayList(categorySet); builder.replace(builder.length() - 1, builder.length(), ""); return builder.toString(); } diff --git a/commons/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/commons/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 369d9b990..c6eb6698b 100644 --- a/commons/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/commons/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -11,6 +11,7 @@ import android.util.Log; import android.widget.*; import fr.free.nrw.commons.*; +import fr.free.nrw.commons.caching.CacheController; import fr.free.nrw.commons.modifications.CategoryModifier; import fr.free.nrw.commons.modifications.TemplateRemoveModifier; import fr.free.nrw.commons.CommonsApplication; @@ -22,6 +23,8 @@ import fr.free.nrw.commons.modifications.ModificationsContentProvider; import fr.free.nrw.commons.modifications.ModifierSequence; import java.util.ArrayList; +import java.util.List; + public class ShareActivity @@ -46,6 +49,11 @@ public class ShareActivity private UploadController uploadController; + private CommonsApplication cacheObj; + private boolean cacheFound; + + private static final String TAG = ShareActivity.class.getName(); + public ShareActivity() { super(WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE); } @@ -53,6 +61,13 @@ public class ShareActivity public void uploadActionInitiated(String title, String description) { Toast startingToast = Toast.makeText(getApplicationContext(), R.string.uploading_started, Toast.LENGTH_LONG); startingToast.show(); + + if (cacheFound == false) { + //Has to be called after apiCall.request() + app.cacheData.cacheCategory(); + Log.d(TAG, "Cache the categories found"); + } + uploadController.startUpload(title, mediaUri, description, mimeType, source, new UploadController.ContributionUploadProgress() { public void onUploadStarted(Contribution contribution) { ShareActivity.this.contribution = contribution; @@ -168,29 +183,47 @@ public class ShareActivity } else { source = Contribution.SOURCE_EXTERNAL; } - mimeType = intent.getType(); } mediaUriString = mediaUri.toString(); - Log.d("Image", "Uri: " + mediaUriString); - + Log.d(TAG, "Uri: " + mediaUriString); //convert image Uri to file path FilePathConverter uriObj = new FilePathConverter(this, mediaUri); String filePath = uriObj.getFilePath(); + if (filePath != null) { //extract the coordinates of image in decimal degrees - Log.d("Image", "Calling GPSExtractor"); + Log.d(TAG, "Calling GPSExtractor"); GPSExtractor imageObj = new GPSExtractor(filePath); - String coords = imageObj.getCoords(); + String decimalCoords = imageObj.getCoords(); + + + if (decimalCoords != null) { + double decLongitude = imageObj.getDecLongitude(); + double decLatitude = imageObj.getDecLatitude(); + + Log.d(TAG, "Decimal coords of image: " + decimalCoords); + app.cacheData.setQtPoint(decLongitude, decLatitude); - if (coords != null) { - Log.d("Image", "Coords of image: " + coords); MwVolleyApi apiCall = new MwVolleyApi(this); - //asynchronous calls to MediaWiki Commons API to match image coords with nearby Commons categories - apiCall.request(coords); + List displayCatList = app.cacheData.findCategory(); + boolean catListEmpty = displayCatList.isEmpty(); + + //if no categories found in cache, call MW API to match image coords with nearby Commons categories + if (catListEmpty) { + cacheFound = false; + apiCall.request(decimalCoords); + Log.d(TAG, "displayCatList size 0, calling MWAPI" + displayCatList.toString()); + + } else { + cacheFound = true; + Log.d(TAG, "Cache found, setting categoryList in MwVolleyApi to " + displayCatList.toString()); + MwVolleyApi.setGpsCat(displayCatList); + } + } }