Skip to content

Commit b5a4b58

Browse files
author
Vivek Maskara
authored
Merge pull request #1552 from misaochan/upload-overhaul-fork
Refactor ShareActivity
2 parents 862318c + a9ae072 commit b5a4b58

11 files changed

+698
-655
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
android:theme="@style/LightAppTheme"
2828
android:supportsRtl="true" >
2929
<activity android:name="org.acra.CrashReportDialog"
30-
android:theme="@android:style/Theme.Dialog"
31-
android:launchMode="singleInstance"
32-
android:excludeFromRecents="true"
33-
android:finishOnTaskLaunch="true" />
30+
android:theme="@android:style/Theme.Dialog"
31+
android:launchMode="singleInstance"
32+
android:excludeFromRecents="true"
33+
android:finishOnTaskLaunch="true" />
3434

3535
<activity android:name=".auth.LoginActivity">
3636
<intent-filter>

app/src/main/java/fr/free/nrw/commons/CommonsApplication.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package fr.free.nrw.commons;
22

3-
import android.app.Application;
43
import android.content.Context;
54
import android.content.SharedPreferences;
65
import android.database.sqlite.SQLiteDatabase;
@@ -28,7 +27,7 @@
2827
import fr.free.nrw.commons.data.DBOpenHelper;
2928
import fr.free.nrw.commons.di.ApplicationlessInjection;
3029
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
31-
import fr.free.nrw.commons.utils.FileUtils;
30+
import fr.free.nrw.commons.upload.FileUtils;
3231
import io.reactivex.android.schedulers.AndroidSchedulers;
3332
import io.reactivex.schedulers.Schedulers;
3433
import timber.log.Timber;

app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
import fr.free.nrw.commons.delete.DeleteTask;
1414
import fr.free.nrw.commons.modifications.ModificationsSyncAdapter;
1515
import fr.free.nrw.commons.nearby.PlaceRenderer;
16+
import fr.free.nrw.commons.upload.FileProcessor;
1617
import fr.free.nrw.commons.settings.SettingsFragment;
1718

19+
1820
@Singleton
1921
@Component(modules = {
2022
CommonsApplicationModule.class,
@@ -46,6 +48,8 @@ public interface CommonsApplicationComponent extends AndroidInjector<Application
4648

4749
void inject(PlaceRenderer placeRenderer);
4850

51+
void inject(FileProcessor fileProcessor);
52+
4953
@Component.Builder
5054
@SuppressWarnings({"WeakerAccess", "unused"})
5155
interface Builder {

app/src/main/java/fr/free/nrw/commons/nearby/NearbyPlaces.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import fr.free.nrw.commons.Utils;
1919
import fr.free.nrw.commons.location.LatLng;
20-
import fr.free.nrw.commons.utils.FileUtils;
20+
import fr.free.nrw.commons.upload.FileUtils;
2121
import timber.log.Timber;
2222

2323
public class NearbyPlaces {

app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33
import android.Manifest;
44
import android.app.AlertDialog;
55
import android.content.ActivityNotFoundException;
6-
import android.content.ComponentName;
76
import android.content.Context;
8-
import android.content.DialogInterface;
97
import android.content.Intent;
108
import android.content.SharedPreferences;
119
import android.content.pm.PackageManager;
12-
import android.content.pm.ResolveInfo;
1310
import android.net.Uri;
1411
import android.os.Build;
1512
import android.os.Bundle;
@@ -24,8 +21,6 @@
2421
import android.widget.Toast;
2522

2623
import java.io.File;
27-
import java.util.ArrayList;
28-
import java.util.List;
2924

3025
import javax.inject.Inject;
3126
import javax.inject.Named;
@@ -35,7 +30,7 @@
3530
import fr.free.nrw.commons.R;
3631
import fr.free.nrw.commons.Utils;
3732
import fr.free.nrw.commons.di.ApplicationlessInjection;
38-
import fr.free.nrw.commons.utils.FileUtils;
33+
import fr.free.nrw.commons.upload.FileUtils;
3934

4035
public class SettingsFragment extends PreferenceFragment {
4136

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
package fr.free.nrw.commons.upload;
2+
3+
import android.annotation.SuppressLint;
4+
import android.app.Activity;
5+
import android.content.ContentResolver;
6+
import android.content.Context;
7+
import android.content.SharedPreferences;
8+
import android.net.Uri;
9+
import android.os.Build;
10+
import android.os.Bundle;
11+
import android.os.ParcelFileDescriptor;
12+
import android.support.annotation.Nullable;
13+
import android.support.v7.app.AppCompatActivity;
14+
15+
import java.io.File;
16+
import java.io.FileNotFoundException;
17+
import java.io.IOException;
18+
import java.lang.ref.WeakReference;
19+
import java.util.Date;
20+
import java.util.List;
21+
22+
import javax.inject.Inject;
23+
import javax.inject.Named;
24+
25+
import fr.free.nrw.commons.caching.CacheController;
26+
import fr.free.nrw.commons.di.ApplicationlessInjection;
27+
import fr.free.nrw.commons.mwapi.CategoryApi;
28+
import io.reactivex.schedulers.Schedulers;
29+
import timber.log.Timber;
30+
31+
import static com.mapbox.mapboxsdk.Mapbox.getApplicationContext;
32+
33+
/**
34+
* Processing of the image file that is about to be uploaded via ShareActivity is done here
35+
*/
36+
public class FileProcessor implements SimilarImageDialogFragment.onResponse {
37+
38+
@Inject
39+
CacheController cacheController;
40+
@Inject
41+
GpsCategoryModel gpsCategoryModel;
42+
@Inject
43+
CategoryApi apiCall;
44+
@Inject
45+
@Named("default_preferences")
46+
SharedPreferences prefs;
47+
private Uri mediaUri;
48+
private ContentResolver contentResolver;
49+
private GPSExtractor imageObj;
50+
private Context context;
51+
private String decimalCoords;
52+
private boolean haveCheckedForOtherImages = false;
53+
private String filePath;
54+
private boolean useExtStorage;
55+
private boolean cacheFound;
56+
private GPSExtractor tempImageObj;
57+
58+
FileProcessor(Uri mediaUri, ContentResolver contentResolver, Context context) {
59+
this.mediaUri = mediaUri;
60+
this.contentResolver = contentResolver;
61+
this.context = context;
62+
ApplicationlessInjection.getInstance(context.getApplicationContext()).getCommonsApplicationComponent().inject(this);
63+
useExtStorage = prefs.getBoolean("useExternalStorage", true);
64+
}
65+
66+
/**
67+
* Gets file path from media URI.
68+
* In older devices getPath() may fail depending on the source URI, creating and using a copy of the file seems to work instead.
69+
*
70+
* @return file path of media
71+
*/
72+
@Nullable
73+
private String getPathOfMediaOrCopy() {
74+
filePath = FileUtils.getPath(context, mediaUri);
75+
Timber.d("Filepath: " + filePath);
76+
if (filePath == null) {
77+
String copyPath = null;
78+
try {
79+
ParcelFileDescriptor descriptor = contentResolver.openFileDescriptor(mediaUri, "r");
80+
if (descriptor != null) {
81+
if (useExtStorage) {
82+
copyPath = FileUtils.createCopyPath(descriptor);
83+
return copyPath;
84+
}
85+
copyPath = getApplicationContext().getCacheDir().getAbsolutePath() + "/" + new Date().getTime() + ".jpg";
86+
FileUtils.copy(descriptor.getFileDescriptor(), copyPath);
87+
Timber.d("Filepath (copied): %s", copyPath);
88+
return copyPath;
89+
}
90+
} catch (IOException e) {
91+
Timber.w(e, "Error in file " + copyPath);
92+
return null;
93+
}
94+
}
95+
return filePath;
96+
}
97+
98+
/**
99+
* Processes file coordinates, either from EXIF data or user location
100+
*
101+
* @param gpsEnabled if true use GPS
102+
*/
103+
GPSExtractor processFileCoordinates(boolean gpsEnabled) {
104+
Timber.d("Calling GPSExtractor");
105+
try {
106+
ParcelFileDescriptor descriptor = contentResolver.openFileDescriptor(mediaUri, "r");
107+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
108+
if (descriptor != null) {
109+
imageObj = new GPSExtractor(descriptor.getFileDescriptor(), context, prefs);
110+
}
111+
} else {
112+
String filePath = getPathOfMediaOrCopy();
113+
if (filePath != null) {
114+
imageObj = new GPSExtractor(filePath, context, prefs);
115+
}
116+
}
117+
118+
decimalCoords = imageObj.getCoords(gpsEnabled);
119+
if (decimalCoords == null || !imageObj.imageCoordsExists) {
120+
//Find other photos taken around the same time which has gps coordinates
121+
if (!haveCheckedForOtherImages)
122+
findOtherImages(gpsEnabled);// Do not do repeat the process
123+
} else {
124+
useImageCoords();
125+
}
126+
127+
} catch (FileNotFoundException e) {
128+
Timber.w("File not found: " + mediaUri, e);
129+
}
130+
return imageObj;
131+
}
132+
133+
String getDecimalCoords() {
134+
return decimalCoords;
135+
}
136+
137+
/**
138+
* Find other images around the same location that were taken within the last 20 sec
139+
*
140+
* @param gpsEnabled True if GPS is enabled
141+
*/
142+
private void findOtherImages(boolean gpsEnabled) {
143+
Timber.d("filePath" + getPathOfMediaOrCopy());
144+
145+
long timeOfCreation = new File(filePath).lastModified();//Time when the original image was created
146+
File folder = new File(filePath.substring(0, filePath.lastIndexOf('/')));
147+
File[] files = folder.listFiles();
148+
Timber.d("folderTime Number:" + files.length);
149+
150+
151+
for (File file : files) {
152+
if (file.lastModified() - timeOfCreation <= (120 * 1000) && file.lastModified() - timeOfCreation >= -(120 * 1000)) {
153+
//Make sure the photos were taken within 20seconds
154+
Timber.d("fild date:" + file.lastModified() + " time of creation" + timeOfCreation);
155+
tempImageObj = null;//Temporary GPSExtractor to extract coords from these photos
156+
ParcelFileDescriptor descriptor = null;
157+
try {
158+
descriptor = contentResolver.openFileDescriptor(Uri.parse(file.getAbsolutePath()), "r");
159+
} catch (FileNotFoundException e) {
160+
e.printStackTrace();
161+
}
162+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
163+
if (descriptor != null) {
164+
tempImageObj = new GPSExtractor(descriptor.getFileDescriptor(), context, prefs);
165+
}
166+
} else {
167+
if (filePath != null) {
168+
tempImageObj = new GPSExtractor(file.getAbsolutePath(), context, prefs);
169+
}
170+
}
171+
172+
if (tempImageObj != null) {
173+
Timber.d("not null fild EXIF" + tempImageObj.imageCoordsExists + " coords" + tempImageObj.getCoords(gpsEnabled));
174+
if (tempImageObj.getCoords(gpsEnabled) != null && tempImageObj.imageCoordsExists) {
175+
// Current image has gps coordinates and it's not current gps locaiton
176+
Timber.d("This file has image coords:" + file.getAbsolutePath());
177+
SimilarImageDialogFragment newFragment = new SimilarImageDialogFragment();
178+
Bundle args = new Bundle();
179+
args.putString("originalImagePath", filePath);
180+
args.putString("possibleImagePath", file.getAbsolutePath());
181+
newFragment.setArguments(args);
182+
newFragment.show(((AppCompatActivity) context).getSupportFragmentManager(), "dialog");
183+
break;
184+
}
185+
}
186+
}
187+
}
188+
haveCheckedForOtherImages = true; //Finished checking for other images
189+
}
190+
191+
/**
192+
* Initiates retrieval of image coordinates or user coordinates, and caching of coordinates.
193+
* Then initiates the calls to MediaWiki API through an instance of CategoryApi.
194+
*/
195+
@SuppressLint("CheckResult")
196+
public void useImageCoords() {
197+
if (decimalCoords != null) {
198+
Timber.d("Decimal coords of image: %s", decimalCoords);
199+
Timber.d("is EXIF data present:" + imageObj.imageCoordsExists + " from findOther image");
200+
201+
// Only set cache for this point if image has coords
202+
if (imageObj.imageCoordsExists) {
203+
double decLongitude = imageObj.getDecLongitude();
204+
double decLatitude = imageObj.getDecLatitude();
205+
cacheController.setQtPoint(decLongitude, decLatitude);
206+
}
207+
208+
List<String> displayCatList = cacheController.findCategory();
209+
boolean catListEmpty = displayCatList.isEmpty();
210+
211+
212+
// If no categories found in cache, call MediaWiki API to match image coords with nearby Commons categories
213+
if (catListEmpty) {
214+
cacheFound = false;
215+
apiCall.request(decimalCoords)
216+
.subscribeOn(Schedulers.io())
217+
.observeOn(Schedulers.io())
218+
.subscribe(
219+
gpsCategoryModel::setCategoryList,
220+
throwable -> {
221+
Timber.e(throwable);
222+
gpsCategoryModel.clear();
223+
}
224+
);
225+
Timber.d("displayCatList size 0, calling MWAPI %s", displayCatList);
226+
} else {
227+
cacheFound = true;
228+
Timber.d("Cache found, setting categoryList in model to %s", displayCatList);
229+
gpsCategoryModel.setCategoryList(displayCatList);
230+
}
231+
} else {
232+
Timber.d("EXIF: no coords");
233+
}
234+
}
235+
236+
boolean isCacheFound() {
237+
return cacheFound;
238+
}
239+
240+
/**
241+
* Calls the async task that detects if image is fuzzy, too dark, etc
242+
*/
243+
void detectUnwantedPictures() {
244+
String imageMediaFilePath = FileUtils.getPath(context, mediaUri);
245+
DetectUnwantedPicturesAsync detectUnwantedPicturesAsync
246+
= new DetectUnwantedPicturesAsync(new WeakReference<Activity>((Activity) context), imageMediaFilePath);
247+
detectUnwantedPicturesAsync.execute();
248+
}
249+
250+
@Override
251+
public void onPositiveResponse() {
252+
imageObj = tempImageObj;
253+
decimalCoords = imageObj.getCoords(false);// Not necessary to use gps as image already ha EXIF data
254+
Timber.d("EXIF from tempImageObj");
255+
useImageCoords();
256+
}
257+
258+
@Override
259+
public void onNegativeResponse() {
260+
Timber.d("EXIF from imageObj");
261+
useImageCoords();
262+
}
263+
}

0 commit comments

Comments
 (0)