Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f117b3f
build.gradle: add ExifInterface support library
ilgazer Jul 13, 2018
827f3e0
FileProcessor: implement methods for EXIF and location anonymization
ilgazer Jul 13, 2018
8c1430e
MultipleShareActivity: upload anonymized photo and coords
ilgazer Jul 13, 2018
ad312b4
preferences: add global options for anonymization
ilgazer Jul 25, 2018
35ce75a
strings.xml:added strings
ilgazer Jul 25, 2018
fe3b4f6
ShareActivity: upload anonymized photo and coords
ilgazer Jul 13, 2018
7c988db
resolved merge conflicts.
ilgazer Jul 14, 2018
daf170f
Revert "strings.xml:added strings" as it had whitespace issues
ilgazer Jul 25, 2018
5f8a2f1
strings.xml:added strings for anonymization prefs
ilgazer Jul 25, 2018
4a39818
Merge branch 'master' into master
ilgazer Jul 25, 2018
8e42038
strings.xml:remove duplicate string
ilgazer Jul 25, 2018
78f5e9f
preferences.xml:fixed merge errors
ilgazer Jul 25, 2018
671782c
Merge branch 'master' into master
ilgazer Jul 28, 2018
40b02a6
strings.xml:fixed merge errors
ilgazer Jul 28, 2018
86e43d7
prefs: Migrate new preferences to LongTitle versions.
ilgazer Jul 31, 2018
fcf368c
Merge branch 'master' into master
ilgazer Sep 4, 2018
eaed89d
Implement wholesale XMP Data removal. Implement better system for mat…
ilgazer Sep 4, 2018
eff6b95
SettingsActivityTest: Implemented support for preferences of type Set
ilgazer Sep 5, 2018
f10cd68
Merge branch 'master' into master
ilgazer Sep 9, 2018
a790ec4
Merge branch 'master' into master
ilgazer Sep 15, 2018
bc0157b
Added default value for location preference.
ilgazer Sep 16, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ dependencies {
implementation 'com.jakewharton.timber:timber:4.6.0'
implementation 'info.debatty:java-string-similarity:0.24'
implementation 'com.borjabravo:readmoretextview:2.1.0'

implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation "com.android.support:exifinterface:27.1.1"
implementation('com.mapbox.mapboxsdk:mapbox-android-sdk:5.5.0@aar') {
transitive = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.junit.runner.RunWith;

import java.util.Map;
import java.util.Set;

import fr.free.nrw.commons.settings.SettingsActivity;

Expand Down Expand Up @@ -51,6 +52,8 @@ protected void afterActivityFinished() {
editor.putBoolean(key, (Boolean)val);
} else if (val instanceof Integer) {
editor.putInt(key, (Integer)val);
} else if (val instanceof Set){
editor.putStringSet(key, (Set<String>)val);
} else {
throw new RuntimeException("type not implemented: " + entry);
}
Expand Down
25 changes: 25 additions & 0 deletions app/src/main/java/fr/free/nrw/commons/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -224,4 +227,26 @@ public static Bitmap getScreenShot(View view) {
return bitmap;
}


public static <T> Set<T> toSet(T... params){
return new HashSet<>(Arrays.asList(params));
}

/**
* Ensures that an object reference passed as a parameter to the calling method is not null.
*
* @param reference an object reference
* @param errorMessage the exception message to use if the check fails; will be converted to a
* string using {@link String#valueOf(Object)}
* @return the non-null reference that was validated
* @throws NullPointerException if {@code reference} is null
*/
public static <T> T checkNotNull(T reference, Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
}
return reference;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package fr.free.nrw.commons.ui.LongTitlePreferences;

import android.content.Context;
import android.preference.MultiSelectListPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;

/**
* Created by Ilgaz Er on 7/31/2018.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove author tags, I know Android Studio automatically adds them, but our code style discourages them. :)

*/
public class LongTitleMultiSelectListPreference extends MultiSelectListPreference {
public LongTitleMultiSelectListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}

public LongTitleMultiSelectListPreference(Context context) {
super(context);
}

@Override
protected void onBindView(View view) {
super.onBindView(view);

TextView title = view.findViewById(android.R.id.title);
if (title != null) {
title.setSingleLine(false);
}
}
}
102 changes: 102 additions & 0 deletions app/src/main/java/fr/free/nrw/commons/upload/FileMetadataUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package fr.free.nrw.commons.upload;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import io.reactivex.Observable;
import timber.log.Timber;

import static android.support.media.ExifInterface.*;
import static fr.free.nrw.commons.Utils.checkNotNull;

public class FileMetadataUtils {


public static Observable<String> getTagsFromPref(String pref) {
Timber.d("Retuning tags for pref:" + pref);
switch (pref) {
case "Author":
return Observable.fromArray(TAG_ARTIST, TAG_CAMARA_OWNER_NAME);
case "Copyright":
return Observable.fromArray(TAG_COPYRIGHT);
case "Camera Model":
return Observable.fromArray(TAG_MAKE, TAG_MODEL);
case "Lens Model":
return Observable.fromArray(TAG_LENS_MAKE, TAG_LENS_MODEL, TAG_LENS_SPECIFICATION);
case "Serial Numbers":
return Observable.fromArray(TAG_BODY_SERIAL_NUMBER, TAG_LENS_SERIAL_NUMBER);
case "Software":
return Observable.fromArray(TAG_SOFTWARE);
default:
return null;
}
}


/**
* Removes all XMP data from the input file and writes the rest of the image to a new file.
*
* This works by black magic. Pleae read the JPEG section of the XMP Spesification Part 3 before making changes.
* https://wwwimages2.adobe.com/content/dam/acom/en/devnet/xmp/pdfs/XMP%20SDK%20Release%20cc-2016-08/XMPSpecificationPart3.pdf
*
* @param inputPath the path of the input file
* @param outputPath the path of the new file
*/
public static void removeXmpAndWriteToFile(String inputPath, String outputPath) {
try (BufferedInputStream is = new BufferedInputStream(new FileInputStream(inputPath));
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outputPath))) {
int next = 0;
while (next != -1) {
next = is.read();
//Detect first byte of FF E1, the code of APP1 marker
if (next == 0xFF) {
next = is.read();
if (next == 0xE1) {
Timber.i("Found FF E1");
//2 bytes that contain the length of the APP1 section.
byte Lp1 = (byte) is.read();
byte Lp2 = (byte) is.read();
Timber.i(Integer.toHexString(Lp1));
Timber.i(Integer.toHexString(Lp2));
//The identifier of the APP1 section, we find out if this section contains XMP data or not.
byte[] namespace = new byte[28];
if (is.read(namespace, 0, 28) != 28)
throw new IOException("Wrong amount of bytes read.");
Timber.i(new String(namespace, "UTF-8"));
if (new String(namespace, "UTF-8").equals("http://ns.adobe.com/xap/1.0/")) {
Timber.i("Found XMP marker");
while (next != 0xFF) {
if (next == -1)
throw new IOException("Unexpected end of file.");
next = is.read();
}
//FF means the start of the next marker.
// This means the XMP section is finished and that we should resume copying.
outputStream.write(0xFF);
} else {
//Write everything back to the output file as we want to leave non-XMP APP1 sections as-is.
Timber.i("Not XMP marker");
outputStream.write(0xFF);
outputStream.write(0xE1);
outputStream.write(Lp1);
outputStream.write(Lp2);
outputStream.write(namespace);
}
} else {
outputStream.write(0xFF);
outputStream.write(next);
}
} else {
outputStream.write(next);
}
}
} catch (IOException e) {
Timber.e(e);
}
}

}
Loading