Skip to content

Commit 4bd7a5b

Browse files
authored
#3493 App freezes for 15 seconds when you press Next in UploadMediaDetailsFragment (#3499)
* #3493 App freezes for 15 seconds when you press Next in UploadMediaDetailsFragment - add apropriate schedulers and convert justs to fromCallable * #3493 App freezes for 15 seconds when you press Next in UploadMediaDetailsFragment - remove test for removed functionality * #3493 App freezes for 15 seconds when you press Next in UploadMediaDetailsFragment - replace kotlin with java
1 parent ed5f8ef commit 4bd7a5b

12 files changed

+118
-135
lines changed

app/src/main/java/fr/free/nrw/commons/repository/UploadRemoteDataSource.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,10 @@ public Observable<UploadItem> preProcessImage(UploadableFile uploadableFile, Pla
179179
* ask the UplaodModel for the image quality of the UploadItem
180180
*
181181
* @param uploadItem
182-
* @param shouldValidateTitle
183182
* @return
184183
*/
185-
public Single<Integer> getImageQuality(UploadItem uploadItem, boolean shouldValidateTitle) {
186-
return uploadModel.getImageQuality(uploadItem, shouldValidateTitle);
184+
public Single<Integer> getImageQuality(UploadItem uploadItem) {
185+
return uploadModel.getImageQuality(uploadItem);
187186
}
188187

189188
/**

app/src/main/java/fr/free/nrw/commons/repository/UploadRepository.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,10 @@ public Observable<UploadItem> preProcessImage(UploadableFile uploadableFile, Pla
187187
* query the RemoteDataSource for image quality
188188
*
189189
* @param uploadItem
190-
* @param shouldValidateTitle
191190
* @return
192191
*/
193-
public Single<Integer> getImageQuality(UploadItem uploadItem, boolean shouldValidateTitle) {
194-
return remoteDataSource.getImageQuality(uploadItem, shouldValidateTitle);
192+
public Single<Integer> getImageQuality(UploadItem uploadItem) {
193+
return remoteDataSource.getImageQuality(uploadItem);
195194
}
196195

197196
/**

app/src/main/java/fr/free/nrw/commons/upload/ImageProcessingService.java

+41-46
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
11
package fr.free.nrw.commons.upload;
22

3-
import android.content.Context;
4-
5-
import org.apache.commons.lang3.StringUtils;
6-
7-
import javax.inject.Inject;
8-
import javax.inject.Singleton;
3+
import static fr.free.nrw.commons.utils.ImageUtils.EMPTY_TITLE;
4+
import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS;
5+
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
96

7+
import android.content.Context;
108
import fr.free.nrw.commons.media.MediaClient;
119
import fr.free.nrw.commons.nearby.Place;
1210
import fr.free.nrw.commons.utils.ImageUtils;
1311
import fr.free.nrw.commons.utils.ImageUtilsWrapper;
1412
import io.reactivex.Single;
13+
import io.reactivex.schedulers.Schedulers;
14+
import javax.inject.Inject;
15+
import javax.inject.Singleton;
16+
import org.apache.commons.lang3.StringUtils;
1517
import timber.log.Timber;
1618

17-
import static fr.free.nrw.commons.utils.ImageUtils.EMPTY_TITLE;
18-
import static fr.free.nrw.commons.utils.ImageUtils.FILE_NAME_EXISTS;
19-
import static fr.free.nrw.commons.utils.ImageUtils.IMAGE_OK;
20-
2119
/**
2220
* Methods for pre-processing images to be uploaded
2321
*/
@@ -41,38 +39,33 @@ public ImageProcessingService(FileUtilsWrapper fileUtilsWrapper,
4139
this.mediaClient = mediaClient;
4240
}
4341

44-
/**
45-
* Check image quality before upload
46-
* - checks duplicate image
47-
* - checks dark image
48-
* - checks geolocation for image
49-
* - check for valid title
50-
*/
51-
Single<Integer> validateImage(UploadModel.UploadItem uploadItem, boolean checkTitle) {
52-
int currentImageQuality = uploadItem.getImageQuality();
53-
Timber.d("Current image quality is %d", currentImageQuality);
54-
if (currentImageQuality == ImageUtils.IMAGE_KEEP) {
55-
return Single.just(ImageUtils.IMAGE_OK);
56-
}
57-
Timber.d("Checking the validity of image");
58-
String filePath = uploadItem.getMediaUri().getPath();
59-
Single<Integer> duplicateImage = checkDuplicateImage(filePath);
60-
Single<Integer> wrongGeoLocation = checkImageGeoLocation(uploadItem.getPlace(), filePath);
61-
Single<Integer> darkImage = checkDarkImage(filePath);
62-
Single<Integer> itemTitle = checkTitle ? validateItemTitle(uploadItem) : Single.just(ImageUtils.IMAGE_OK);
63-
Single<Integer> checkFBMD = checkFBMD(filePath);
64-
Single<Integer> checkEXIF = checkEXIF(filePath);
65-
66-
Single<Integer> zipResult = Single.zip(duplicateImage, wrongGeoLocation, darkImage, itemTitle,
67-
(duplicate, wrongGeo, dark, title) -> {
68-
Timber.d("Result for duplicate: %d, geo: %d, dark: %d, title: %d", duplicate, wrongGeo, dark, title);
69-
return duplicate | wrongGeo | dark | title;
70-
});
71-
return Single.zip(zipResult, checkFBMD , checkEXIF , (zip , fbmd , exif)->{
72-
Timber.d("zip:" + zip + "fbmd:" + fbmd + "exif:" + exif);
73-
return zip | fbmd | exif;
74-
});
42+
/**
43+
* Check image quality before upload - checks duplicate image - checks dark image - checks
44+
* geolocation for image - check for valid title
45+
*/
46+
Single<Integer> validateImage(UploadModel.UploadItem uploadItem) {
47+
int currentImageQuality = uploadItem.getImageQuality();
48+
Timber.d("Current image quality is %d", currentImageQuality);
49+
if (currentImageQuality == ImageUtils.IMAGE_KEEP) {
50+
return Single.just(ImageUtils.IMAGE_OK);
7551
}
52+
Timber.d("Checking the validity of image");
53+
String filePath = uploadItem.getMediaUri().getPath();
54+
55+
return Single.zip(
56+
checkDuplicateImage(filePath),
57+
checkImageGeoLocation(uploadItem.getPlace(), filePath),
58+
checkDarkImage(filePath),
59+
validateItemTitle(uploadItem),
60+
checkFBMD(filePath),
61+
checkEXIF(filePath),
62+
(duplicateImage, wrongGeoLocation, darkImage, itemTitle, fbmd, exif) -> {
63+
Timber.d("duplicate: %d, geo: %d, dark: %d, title: %d" + "fbmd:" + fbmd + "exif:" + exif,
64+
duplicateImage, wrongGeoLocation, darkImage, itemTitle);
65+
return duplicateImage | wrongGeoLocation | darkImage | itemTitle | fbmd | exif;
66+
}
67+
);
68+
}
7669

7770
/**
7871
* We want to discourage users from uploading images to Commons that were taken from Facebook.
@@ -113,7 +106,8 @@ private Single<Integer> validateItemTitle(UploadModel.UploadItem uploadItem) {
113106
.map(doesFileExist -> {
114107
Timber.d("Result for valid title is %s", doesFileExist);
115108
return doesFileExist ? FILE_NAME_EXISTS : IMAGE_OK;
116-
});
109+
})
110+
.subscribeOn(Schedulers.io());
117111
}
118112

119113
/**
@@ -124,14 +118,14 @@ private Single<Integer> validateItemTitle(UploadModel.UploadItem uploadItem) {
124118
*/
125119
private Single<Integer> checkDuplicateImage(String filePath) {
126120
Timber.d("Checking for duplicate image %s", filePath);
127-
return Single.fromCallable(() ->
128-
fileUtilsWrapper.getFileInputStream(filePath))
121+
return Single.fromCallable(() -> fileUtilsWrapper.getFileInputStream(filePath))
129122
.map(fileUtilsWrapper::getSHA1)
130123
.flatMap(mediaClient::checkFileExistsUsingSha)
131124
.map(b -> {
132125
Timber.d("Result for duplicate image %s", b);
133126
return b ? ImageUtils.IMAGE_DUPLICATE : ImageUtils.IMAGE_OK;
134-
});
127+
})
128+
.subscribeOn(Schedulers.io());
135129
}
136130

137131
/**
@@ -164,7 +158,8 @@ private Single<Integer> checkImageGeoLocation(Place place, String filePath) {
164158
return Single.just(ImageUtils.IMAGE_OK);
165159
}
166160
return imageUtilsWrapper.checkImageGeolocationIsDifferent(geoLocation, place.getLocation());
167-
});
161+
})
162+
.subscribeOn(Schedulers.io());
168163
}
169164
}
170165

Original file line numberDiff line numberDiff line change
@@ -1,48 +1,48 @@
11
package fr.free.nrw.commons.upload;
22

3+
import fr.free.nrw.commons.utils.ImageUtils;
4+
import io.reactivex.Single;
35
import java.io.FileInputStream;
46
import java.io.IOException;
5-
67
import javax.inject.Inject;
78
import javax.inject.Singleton;
89

9-
import fr.free.nrw.commons.utils.ImageUtils;
10-
import io.reactivex.Single;
11-
1210
/**
13-
* We want to discourage users from uploading images to Commons that were taken from Facebook.
14-
* This attempts to detect whether an image was downloaded from Facebook by heuristically
15-
* searching for metadata that is specific to images that come from Facebook.
11+
* We want to discourage users from uploading images to Commons that were taken from Facebook. This
12+
* attempts to detect whether an image was downloaded from Facebook by heuristically searching for
13+
* metadata that is specific to images that come from Facebook.
1614
*/
1715
@Singleton
1816
public class ReadFBMD {
1917

20-
@Inject
21-
public ReadFBMD() {
22-
}
23-
24-
public Single<Integer> processMetadata(String path) {
25-
try {
26-
int psBlockOffset;
27-
int fbmdOffset;
28-
29-
try (FileInputStream fs = new FileInputStream(path)) {
30-
byte[] bytes = new byte[4096];
31-
fs.read(bytes);
32-
fs.close();
33-
String fileStr = new String(bytes);
34-
psBlockOffset = fileStr.indexOf("8BIM");
35-
fbmdOffset = fileStr.indexOf("FBMD");
36-
}
18+
@Inject
19+
public ReadFBMD() {
20+
}
21+
22+
public Single<Integer> processMetadata(String path) {
23+
return Single.fromCallable(() -> {
24+
try {
25+
int psBlockOffset;
26+
int fbmdOffset;
27+
28+
try (FileInputStream fs = new FileInputStream(path)) {
29+
byte[] bytes = new byte[4096];
30+
fs.read(bytes);
31+
fs.close();
32+
String fileStr = new String(bytes);
33+
psBlockOffset = fileStr.indexOf("8BIM");
34+
fbmdOffset = fileStr.indexOf("FBMD");
35+
}
3736

38-
if (psBlockOffset > 0 && fbmdOffset > 0
39-
&& fbmdOffset > psBlockOffset && fbmdOffset - psBlockOffset < 0x80) {
40-
return Single.just(ImageUtils.FILE_FBMD);
41-
}
42-
} catch (IOException e) {
43-
e.printStackTrace();
37+
if (psBlockOffset > 0 && fbmdOffset > 0
38+
&& fbmdOffset > psBlockOffset && fbmdOffset - psBlockOffset < 0x80) {
39+
return ImageUtils.FILE_FBMD;
4440
}
45-
return Single.just(ImageUtils.IMAGE_OK);
46-
}
41+
} catch (IOException e) {
42+
e.printStackTrace();
43+
}
44+
return ImageUtils.IMAGE_OK;
45+
});
46+
}
4747
}
4848

app/src/main/java/fr/free/nrw/commons/upload/UploadModel.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ public Observable<UploadItem> preProcessImage(UploadableFile uploadableFile,
119119
return Observable.just(getUploadItem(uploadableFile, place, source, similarImageInterface));
120120
}
121121

122-
public Single<Integer> getImageQuality(UploadItem uploadItem, boolean checkTitle) {
123-
return imageProcessingService.validateImage(uploadItem, checkTitle);
122+
public Single<Integer> getImageQuality(UploadItem uploadItem) {
123+
return imageProcessingService.validateImage(uploadItem);
124124
}
125125

126126
private UploadItem getUploadItem(UploadableFile uploadableFile,
@@ -378,4 +378,4 @@ public int hashCode() {
378378
}
379379
}
380380

381-
}
381+
}

app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailFragment.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ private void showInfoAlert(int titleStringID, int messageStringId) {
251251
@OnClick(R.id.btn_next)
252252
public void onNextButtonClicked() {
253253
uploadItem.setDescriptions(descriptionsAdapter.getDescriptions());
254-
presenter.verifyImageQuality(uploadItem, true);
254+
presenter.verifyImageQuality(uploadItem);
255255
}
256256

257257
@OnClick(R.id.btn_previous)

app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaDetailsContract.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ interface UserActionListener extends BasePresenter<View> {
4343
void receiveImage(UploadableFile uploadableFile, @Contribution.FileSource String source,
4444
Place place);
4545

46-
void verifyImageQuality(UploadItem uploadItem, boolean validateTitle);
46+
void verifyImageQuality(UploadItem uploadItem);
4747

4848
void setUploadItem(int index, UploadItem uploadItem);
4949

app/src/main/java/fr/free/nrw/commons/upload/mediaDetails/UploadMediaPresenter.java

+7-8
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,14 @@ private void checkNearbyPlaces(UploadItem uploadItem) {
111111
* asks the repository to verify image quality
112112
*
113113
* @param uploadItem
114-
* @param validateTitle
115114
*/
116115
@Override
117-
public void verifyImageQuality(UploadItem uploadItem, boolean validateTitle) {
116+
public void verifyImageQuality(UploadItem uploadItem) {
118117
view.showProgress(true);
119-
Disposable imageQualityDisposable = repository
120-
.getImageQuality(uploadItem, true)
121-
.subscribeOn(ioScheduler)
118+
119+
compositeDisposable.add(
120+
repository
121+
.getImageQuality(uploadItem)
122122
.observeOn(mainThreadScheduler)
123123
.subscribe(imageResult -> {
124124
view.showProgress(false);
@@ -129,9 +129,8 @@ public void verifyImageQuality(UploadItem uploadItem, boolean validateTitle) {
129129
view.showMessage("" + throwable.getLocalizedMessage(),
130130
R.color.color_error);
131131
Timber.e(throwable, "Error occurred while handling image");
132-
});
133-
134-
compositeDisposable.add(imageQualityDisposable);
132+
})
133+
);
135134
}
136135

137136
/**
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
package fr.free.nrw.commons.utils;
22

3-
import javax.inject.Inject;
4-
import javax.inject.Singleton;
5-
63
import fr.free.nrw.commons.location.LatLng;
74
import io.reactivex.Single;
85
import io.reactivex.schedulers.Schedulers;
6+
import javax.inject.Inject;
7+
import javax.inject.Singleton;
98

109
@Singleton
1110
public class ImageUtilsWrapper {
1211

13-
@Inject
14-
public ImageUtilsWrapper() {
12+
@Inject
13+
public ImageUtilsWrapper() {
1514

16-
}
15+
}
1716

18-
public Single<Integer> checkIfImageIsTooDark(String bitmapPath) {
19-
return Single.just(ImageUtils.checkIfImageIsTooDark(bitmapPath))
20-
.subscribeOn(Schedulers.computation())
21-
.observeOn(Schedulers.computation());
22-
}
17+
public Single<Integer> checkIfImageIsTooDark(String bitmapPath) {
18+
return Single.fromCallable(() -> ImageUtils.checkIfImageIsTooDark(bitmapPath))
19+
.subscribeOn(Schedulers.computation());
20+
}
2321

24-
public Single<Integer> checkImageGeolocationIsDifferent(String geolocationOfFileString, LatLng latLng) {
25-
boolean isImageGeoLocationDifferent = ImageUtils.checkImageGeolocationIsDifferent(geolocationOfFileString, latLng);
26-
return Single.just(isImageGeoLocationDifferent)
27-
.subscribeOn(Schedulers.computation())
28-
.observeOn(Schedulers.computation())
29-
.map(isDifferent -> isDifferent ? ImageUtils.IMAGE_GEOLOCATION_DIFFERENT : ImageUtils.IMAGE_OK);
30-
}
22+
public Single<Integer> checkImageGeolocationIsDifferent(String geolocationOfFileString,
23+
LatLng latLng) {
24+
return Single.fromCallable(
25+
() -> ImageUtils.checkImageGeolocationIsDifferent(geolocationOfFileString, latLng))
26+
.subscribeOn(Schedulers.computation())
27+
.map(isDifferent -> isDifferent ? ImageUtils.IMAGE_GEOLOCATION_DIFFERENT
28+
: ImageUtils.IMAGE_OK);
29+
}
3130
}

0 commit comments

Comments
 (0)