Merge branch 'master' into featuredImages

This commit is contained in:
Vivek Maskara 2018-03-24 12:46:38 +05:30 committed by GitHub
commit 463673f942
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
343 changed files with 11434 additions and 3062 deletions

View file

@ -0,0 +1,59 @@
package fr.free.nrw.commons.upload;
import android.content.Context;
import android.graphics.BitmapRegionDecoder;
import android.net.Uri;
import android.os.AsyncTask;
import java.io.IOException;
import fr.free.nrw.commons.utils.ImageUtils;
import timber.log.Timber;
/**
* Created by bluesir9 on 16/9/17.
*
* <p>Responsible for checking if the picture that the user is trying to upload is useful or not. Will attempt to filter
* away completely black,fuzzy/blurry pictures(for now).
*
* <p>todo: Detect selfies?
*/
public class DetectUnwantedPicturesAsync extends AsyncTask<Void, Void, ImageUtils.Result> {
interface Callback {
void onResult(ImageUtils.Result result);
}
private final Callback callback;
private final String imageMediaFilePath;
DetectUnwantedPicturesAsync(String imageMediaFilePath, Callback callback) {
this.callback = callback;
this.imageMediaFilePath = imageMediaFilePath;
}
@Override
protected ImageUtils.Result doInBackground(Void... voids) {
try {
Timber.d("FilePath: " + imageMediaFilePath);
if (imageMediaFilePath == null) {
return ImageUtils.Result.IMAGE_OK;
}
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(imageMediaFilePath,false);
return ImageUtils.checkIfImageIsTooDark(decoder);
} catch (IOException ioe) {
Timber.e(ioe, "IO Exception");
return ImageUtils.Result.IMAGE_OK;
}
}
@Override
protected void onPostExecute(ImageUtils.Result result) {
super.onPostExecute(result);
//callback to UI so that it can take necessary decision based on the result obtained
callback.onResult(result);
}
}

View file

@ -1,11 +1,13 @@
package fr.free.nrw.commons.upload;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v7.app.AlertDialog;
import java.io.IOException;
import java.lang.ref.WeakReference;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.contributions.ContributionsActivity;
@ -28,12 +30,14 @@ public class ExistingFileAsync extends AsyncTask<Void, Void, Boolean> {
DUPLICATE_CANCELLED
}
private final WeakReference<Activity> activity;
private final MediaWikiApi api;
private final String fileSha1;
private final Context context;
private final WeakReference<Context> context;
private final Callback callback;
public ExistingFileAsync(String fileSha1, Context context, Callback callback, MediaWikiApi mwApi) {
public ExistingFileAsync(WeakReference<Activity> activity, String fileSha1, WeakReference<Context> context, Callback callback, MediaWikiApi mwApi) {
this.activity = activity;
this.fileSha1 = fileSha1;
this.context = context;
this.callback = callback;
@ -69,19 +73,21 @@ public class ExistingFileAsync extends AsyncTask<Void, Void, Boolean> {
// If file exists, display warning to user.
// Use soft warning for now (user able to choose to proceed) until have determined that implementation works without bugs
if (fileExists) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
AlertDialog.Builder builder = new AlertDialog.Builder(context.get());
builder.setMessage(R.string.file_exists)
.setTitle(R.string.warning);
builder.setPositiveButton(R.string.no, (dialog, id) -> {
//Go back to ContributionsActivity
Intent intent = new Intent(context, ContributionsActivity.class);
context.startActivity(intent);
Intent intent = new Intent(context.get(), ContributionsActivity.class);
context.get().startActivity(intent);
callback.onResult(Result.DUPLICATE_CANCELLED);
});
builder.setNegativeButton(R.string.yes, (dialog, id) -> callback.onResult(Result.DUPLICATE_PROCEED));
AlertDialog dialog = builder.create();
dialog.show();
if (!activity.get().isFinishing()) {
dialog.show();
}
} else {
callback.onResult(Result.NO_DUPLICATE);
}

View file

@ -3,20 +3,25 @@ package fr.free.nrw.commons.upload;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.preference.PreferenceManager;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.Date;
import timber.log.Timber;
@ -28,7 +33,7 @@ public class FileUtils {
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param uri The Uri to query.
* @author paulburke
*/
// Can be safely suppressed, checks for isKitKat before running isDocumentUri
@ -36,6 +41,7 @@ public class FileUtils {
@Nullable
public static String getPath(Context context, Uri uri) {
String returnPath = null;
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
@ -47,31 +53,34 @@ public class FileUtils {
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
returnPath = Environment.getExternalStorageDirectory() + "/" + split[1];
}
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
} else if (isDownloadsDocument(uri)) { // DownloadsProvider
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
returnPath = getDataColumn(context, contentUri, null, null);
} else if (isMediaDocument(uri)) { // MediaProvider
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
switch (type) {
case "image":
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
break;
case "video":
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
break;
case "audio":
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
break;
default:
break;
}
final String selection = "_id=?";
@ -79,16 +88,55 @@ public class FileUtils {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
returnPath = getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
returnPath = getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
returnPath = uri.getPath();
}
if(returnPath == null) {
//fetching path may fail depending on the source URI and all hope is lost
//so we will create and use a copy of the file, which seems to work
String copyPath = null;
try {
ParcelFileDescriptor descriptor
= context.getContentResolver().openFileDescriptor(uri, "r");
if (descriptor != null) {
SharedPreferences sharedPref = PreferenceManager
.getDefaultSharedPreferences(context);
boolean useExtStorage = sharedPref.getBoolean("useExternalStorage", true);
if (useExtStorage) {
copyPath = Environment.getExternalStorageDirectory().toString()
+ "/CommonsApp/" + new Date().getTime() + ".jpg";
File newFile = new File(Environment.getExternalStorageDirectory().toString() + "/CommonsApp");
newFile.mkdir();
FileUtils.copy(
descriptor.getFileDescriptor(),
copyPath);
Timber.d("Filepath (copied): %s", copyPath);
return copyPath;
}
copyPath = context.getCacheDir().getAbsolutePath()
+ "/" + new Date().getTime() + ".jpg";
FileUtils.copy(
descriptor.getFileDescriptor(),
copyPath);
Timber.d("Filepath (copied): %s", copyPath);
return copyPath;
}
} catch (IOException e) {
Timber.w(e, "Error in file " + copyPath);
return null;
}
} else {
return returnPath;
}
return null;
@ -109,7 +157,7 @@ public class FileUtils {
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String column = MediaStore.Images.ImageColumns.DATA;
final String[] projection = {
column
};
@ -163,7 +211,8 @@ public class FileUtils {
/**
* Copy content from source file to destination file.
* @param source stream copied from
*
* @param source stream copied from
* @param destination stream copied to
* @throws IOException thrown when failing to read source or opening destination file
*/
@ -176,7 +225,8 @@ public class FileUtils {
/**
* Copy content from source file to destination file.
* @param source file descriptor copied from
*
* @param source file descriptor copied from
* @param destination file path copied to
* @throws IOException thrown when failing to read source or opening destination file
*/

View file

@ -113,11 +113,11 @@ public class GPSExtractor {
*/
@Nullable
public String getCoords(boolean useGPS) {
String latitude = "";
String longitude = "";
String latitude_ref = "";
String longitude_ref = "";
String decimalCoords = "";
String latitude;
String longitude;
String latitudeRef;
String longitudeRef;
String decimalCoords;
//If image has no EXIF data and user has enabled GPS setting, get user's location
if (exif == null || exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE) == null) {
@ -150,15 +150,15 @@ public class GPSExtractor {
Timber.d("EXIF data has location info");
latitude = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
latitude_ref = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
latitudeRef = exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
longitude = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
longitude_ref = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
longitudeRef = exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
if (latitude!=null && latitude_ref!=null && longitude!=null && longitude_ref!=null) {
Timber.d("Latitude: %s %s", latitude, latitude_ref);
Timber.d("Longitude: %s %s", longitude, longitude_ref);
if (latitude!=null && latitudeRef!=null && longitude!=null && longitudeRef!=null) {
Timber.d("Latitude: %s %s", latitude, latitudeRef);
Timber.d("Longitude: %s %s", longitude, longitudeRef);
decimalCoords = getDecimalCoords(latitude, latitude_ref, longitude, longitude_ref);
decimalCoords = getDecimalCoords(latitude, latitudeRef, longitude, longitudeRef);
return decimalCoords;
} else {
return null;

View file

@ -2,7 +2,6 @@ package fr.free.nrw.commons.upload;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@ -12,7 +11,9 @@ import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
@ -22,6 +23,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Toast;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
@ -52,10 +54,17 @@ public class MultipleShareActivity extends AuthenticatedActivity
MultipleUploadListFragment.OnMultipleUploadInitiatedHandler,
OnCategoriesSaveHandler {
@Inject MediaWikiApi mwApi;
@Inject SessionManager sessionManager;
@Inject UploadController uploadController;
@Inject @Named("default_preferences") SharedPreferences prefs;
@Inject
MediaWikiApi mwApi;
@Inject
SessionManager sessionManager;
@Inject
UploadController uploadController;
@Inject
ModifierSequenceDao modifierSequenceDao;
@Inject
@Named("default_preferences")
SharedPreferences prefs;
private ArrayList<Contribution> photosList = null;
@ -63,6 +72,8 @@ public class MultipleShareActivity extends AuthenticatedActivity
private MediaDetailPagerFragment mediaDetails;
private CategorizationFragment categorizationFragment;
private boolean locationPermitted = false;
@Override
public Media getMediaAtPosition(int i) {
return photosList.get(i);
@ -166,19 +177,18 @@ public class MultipleShareActivity extends AuthenticatedActivity
@Override
public void onCategoriesSave(List<String> categories) {
if (categories.size() > 0) {
ModifierSequenceDao dao = new ModifierSequenceDao(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY));
for (Contribution contribution : photosList) {
ModifierSequence categoriesSequence = new ModifierSequence(contribution.getContentUri());
categoriesSequence.queueModifier(new CategoryModifier(categories.toArray(new String[]{})));
categoriesSequence.queueModifier(new TemplateRemoveModifier("Uncategorized"));
dao.save(categoriesSequence);
modifierSequenceDao.save(categoriesSequence);
}
}
// FIXME: Make sure that the content provider is up
// This is the wrong place for it, but bleh - better than not having it turned on by default for people who don't go throughl ogin
ContentResolver.setSyncAutomatically(sessionManager.getCurrentAccount(), ModificationsContentProvider.AUTHORITY, true); // Enable sync by default!
ContentResolver.setSyncAutomatically(sessionManager.getCurrentAccount(), ModificationsContentProvider.MODIFICATIONS_AUTHORITY, true); // Enable sync by default!
finish();
}
@ -208,6 +218,14 @@ public class MultipleShareActivity extends AuthenticatedActivity
getSupportFragmentManager().addOnBackStackChangedListener(this);
requestAuthToken();
//TODO: 15/10/17 should location permission be explicitly requested if not provided?
//check if location permission is enabled
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
locationPermitted = true;
}
}
}
@Override
@ -241,7 +259,7 @@ public class MultipleShareActivity extends AuthenticatedActivity
mwApi.setAuthCookie(authCookie);
Intent intent = getIntent();
if (intent.getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
if (Intent.ACTION_SEND_MULTIPLE.equals(intent.getAction())) {
if (photosList == null) {
photosList = new ArrayList<>();
ArrayList<Uri> urisList = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
@ -253,6 +271,11 @@ public class MultipleShareActivity extends AuthenticatedActivity
up.setTag("sequence", i);
up.setSource(Contribution.SOURCE_EXTERNAL);
up.setMultiple(true);
String imageGpsCoordinates = extractImageGpsData(uri);
if (imageGpsCoordinates != null) {
Timber.d("GPS data for image found!");
up.setDecimalCoords(imageGpsCoordinates);
}
photosList.add(up);
}
}
@ -279,7 +302,49 @@ public class MultipleShareActivity extends AuthenticatedActivity
@Override
public void onBackStackChanged() {
getSupportActionBar().setDisplayHomeAsUpEnabled(mediaDetails != null && mediaDetails.isVisible()) ;
getSupportActionBar().setDisplayHomeAsUpEnabled(mediaDetails != null && mediaDetails.isVisible());
}
/**
* Will attempt to extract the gps coordinates using exif data or by using the current
* location if available for the image who's imageUri has been provided.
* @param imageUri The uri of the image who's GPS coordinates data we wish to extract
* @return GPS coordinates as a String as is returned by {@link GPSExtractor}
*/
@Nullable
private String extractImageGpsData(Uri imageUri) {
Timber.d("Entering extractImagesGpsData");
if (imageUri == null) {
//now why would you do that???
return null;
}
GPSExtractor gpsExtractor = null;
try {
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);
}
} else {
String filePath = FileUtils.getPath(this,imageUri);
if (filePath != null) {
gpsExtractor = new GPSExtractor(filePath,this,prefs);
}
}
if (gpsExtractor != null) {
//get image coordinates from exif data or user location
return gpsExtractor.getCoords(locationPermitted);
}
} catch (FileNotFoundException fnfe) {
Timber.w(fnfe);
return null;
}
return null;
}
}

View file

@ -1,14 +1,17 @@
package fr.free.nrw.commons.upload;
import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -27,12 +30,12 @@ import android.widget.TextView;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.view.SimpleDraweeView;
import dagger.android.support.DaggerFragment;
import dagger.android.support.AndroidSupportInjection;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
public class MultipleUploadListFragment extends DaggerFragment {
public class MultipleUploadListFragment extends Fragment {
public interface OnMultipleUploadInitiatedHandler {
void OnMultipleUploadInitiated();
@ -56,6 +59,12 @@ public class MultipleUploadListFragment extends DaggerFragment {
private RelativeLayout overlay;
}
@Override
public void onAttach(Context context) {
AndroidSupportInjection.inject(this);
super.onAttach(context);
}
private class PhotoDisplayAdapter extends BaseAdapter {
@Override
@ -170,9 +179,21 @@ public class MultipleUploadListFragment extends DaggerFragment {
photosGrid.setColumnWidth(photoSize.x);
baseTitle.addTextChangedListener(textWatcher);
baseTitle.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
hideKeyboard(v);
}
});
return view;
}
public void hideKeyboard(View view) {
InputMethodManager inputMethodManager =(InputMethodManager)getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
@Override
public void onDestroyView() {
baseTitle.removeTextChangedListener(textWatcher);

View file

@ -1,7 +1,10 @@
package fr.free.nrw.commons.upload;
import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
@ -16,7 +19,9 @@ import android.support.annotation.RequiresApi;
import android.support.design.widget.Snackbar;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
@ -29,6 +34,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@ -46,11 +52,14 @@ import fr.free.nrw.commons.caching.CacheController;
import fr.free.nrw.commons.category.CategorizationFragment;
import fr.free.nrw.commons.category.OnCategoriesSaveHandler;
import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.contributions.ContributionsActivity;
import fr.free.nrw.commons.modifications.CategoryModifier;
import fr.free.nrw.commons.modifications.ModificationsContentProvider;
import fr.free.nrw.commons.modifications.ModifierSequence;
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
import fr.free.nrw.commons.modifications.TemplateRemoveModifier;
import fr.free.nrw.commons.utils.ImageUtils;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import timber.log.Timber;
@ -61,10 +70,10 @@ import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.NO_DUPLICATE;
* Activity for the title/desc screen after image is selected. Also starts processing image
* GPS coordinates or user location (if enabled in Settings) for category suggestions.
*/
public class ShareActivity
extends AuthenticatedActivity
public class ShareActivity
extends AuthenticatedActivity
implements SingleUploadFragment.OnUploadActionInitiated,
OnCategoriesSaveHandler {
OnCategoriesSaveHandler,SimilarImageDialogFragment.onResponse {
private static final int REQUEST_PERM_ON_CREATE_STORAGE = 1;
private static final int REQUEST_PERM_ON_CREATE_LOCATION = 2;
@ -72,11 +81,19 @@ public class ShareActivity
private static final int REQUEST_PERM_ON_SUBMIT_STORAGE = 4;
private CategorizationFragment categorizationFragment;
@Inject MediaWikiApi mwApi;
@Inject CacheController cacheController;
@Inject SessionManager sessionManager;
@Inject UploadController uploadController;
@Inject @Named("default_preferences") SharedPreferences prefs;
@Inject
MediaWikiApi mwApi;
@Inject
CacheController cacheController;
@Inject
SessionManager sessionManager;
@Inject
UploadController uploadController;
@Inject
ModifierSequenceDao modifierSequenceDao;
@Inject
@Named("default_preferences")
SharedPreferences prefs;
private String source;
private String mimeType;
@ -88,6 +105,7 @@ public class ShareActivity
private boolean cacheFound;
private GPSExtractor imageObj;
private GPSExtractor tempImageObj;
private String decimalCoords;
private boolean useNewPermissions = false;
@ -99,6 +117,9 @@ public class ShareActivity
private Snackbar snackbar;
private boolean duplicateCheckPassed = false;
private boolean haveCheckedForOtherImages = false;
private boolean isNearbyUpload = false;
/**
* Called when user taps the submit button.
*/
@ -166,13 +187,12 @@ public class ShareActivity
categoriesSequence.queueModifier(new CategoryModifier(categories.toArray(new String[]{})));
categoriesSequence.queueModifier(new TemplateRemoveModifier("Uncategorized"));
ModifierSequenceDao dao = new ModifierSequenceDao(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY));
dao.save(categoriesSequence);
modifierSequenceDao.save(categoriesSequence);
}
// FIXME: Make sure that the content provider is up
// This is the wrong place for it, but bleh - better than not having it turned on by default for people who don't go throughl ogin
ContentResolver.setSyncAutomatically(sessionManager.getCurrentAccount(), ModificationsContentProvider.AUTHORITY, true); // Enable sync by default!
ContentResolver.setSyncAutomatically(sessionManager.getCurrentAccount(), ModificationsContentProvider.MODIFICATIONS_AUTHORITY, true); // Enable sync by default!
finish();
}
@ -197,6 +217,10 @@ public class ShareActivity
finish();
}
protected boolean isNearbyUpload() {
return isNearbyUpload;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -216,13 +240,17 @@ public class ShareActivity
//Receive intent from ContributionController.java when user selects picture to upload
Intent intent = getIntent();
if (intent.getAction().equals(Intent.ACTION_SEND)) {
if (Intent.ACTION_SEND.equals(intent.getAction())) {
mediaUri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (intent.hasExtra(UploadService.EXTRA_SOURCE)) {
source = intent.getStringExtra(UploadService.EXTRA_SOURCE);
} else {
source = Contribution.SOURCE_EXTERNAL;
}
if (intent.hasExtra("isDirectUpload")) {
Timber.d("This was initiated by a direct upload from Nearby");
isNearbyUpload = true;
}
mimeType = intent.getType();
}
@ -278,7 +306,7 @@ public class ShareActivity
REQUEST_PERM_ON_CREATE_LOCATION);
}
}
performPreuploadProcessingOfFile();
performPreUploadProcessingOfFile();
SingleUploadFragment shareView = (SingleUploadFragment) getSupportFragmentManager().findFragmentByTag("shareView");
@ -302,7 +330,7 @@ public class ShareActivity
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
backgroundImageView.setImageURI(mediaUri);
storagePermitted = true;
performPreuploadProcessingOfFile();
performPreUploadProcessingOfFile();
}
return;
}
@ -310,7 +338,7 @@ public class ShareActivity
if (grantResults.length >= 1
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
locationPermitted = true;
performPreuploadProcessingOfFile();
performPreUploadProcessingOfFile();
}
return;
}
@ -319,12 +347,12 @@ public class ShareActivity
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
backgroundImageView.setImageURI(mediaUri);
storagePermitted = true;
performPreuploadProcessingOfFile();
performPreUploadProcessingOfFile();
}
if (grantResults.length >= 2
&& grantResults[1] == PackageManager.PERMISSION_GRANTED) {
locationPermitted = true;
performPreuploadProcessingOfFile();
performPreUploadProcessingOfFile();
}
return;
}
@ -335,7 +363,7 @@ public class ShareActivity
&& 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
performPreuploadProcessingOfFile();
performPreUploadProcessingOfFile();
//Uploading only begins if storage permission granted from arrow icon
uploadBegins();
@ -346,7 +374,7 @@ public class ShareActivity
}
}
private void performPreuploadProcessingOfFile() {
private void performPreUploadProcessingOfFile() {
if (!useNewPermissions || storagePermitted) {
if (!duplicateCheckPassed) {
//Test SHA1 of image to see if it matches SHA1 of a file on Commons
@ -357,11 +385,21 @@ public class ShareActivity
Timber.d("File SHA1 is: %s", fileSHA1);
ExistingFileAsync fileAsyncTask =
new ExistingFileAsync(fileSHA1, this, result -> {
new ExistingFileAsync(new WeakReference<Activity>(this), fileSHA1, new WeakReference<Context>(this), result -> {
Timber.d("%s duplicate check: %s", mediaUri.toString(), result);
duplicateCheckPassed = (result == DUPLICATE_PROCEED
|| result == NO_DUPLICATE);
}, mwApi);
/*
TODO: 16/9/17 should we run DetectUnwantedPicturesAsync if DUPLICATE_PROCEED is returned? Since that means
we are processing images that are already on server???...
*/
if (duplicateCheckPassed) {
//image can be uploaded, so now check if its a useless picture or not
performUnwantedPictureDetectionProcess();
}
},mwApi);
fileAsyncTask.execute();
} catch (IOException e) {
Timber.d(e, "IO Exception: ");
@ -375,6 +413,37 @@ public class ShareActivity
}
}
private void performUnwantedPictureDetectionProcess() {
String imageMediaFilePath = FileUtils.getPath(this,mediaUri);
DetectUnwantedPicturesAsync detectUnwantedPicturesAsync = new DetectUnwantedPicturesAsync(imageMediaFilePath, result -> {
if (result != ImageUtils.Result.IMAGE_OK) {
//show appropriate error message
String errorMessage = result == ImageUtils.Result.IMAGE_DARK ? getString(R.string.upload_image_too_dark) : getString(R.string.upload_image_blurry);
AlertDialog.Builder errorDialogBuilder = new AlertDialog.Builder(this);
errorDialogBuilder.setMessage(errorMessage);
errorDialogBuilder.setTitle(getString(R.string.warning));
errorDialogBuilder.setPositiveButton(getString(R.string.no), (dialogInterface, i) -> {
//user does not wish to upload the picture, take them back to ContributionsActivity
Intent intent = new Intent(ShareActivity.this, ContributionsActivity.class);
dialogInterface.dismiss();
startActivity(intent);
});
errorDialogBuilder.setNegativeButton(getString(R.string.yes), (dialogInterface, i) -> {
//user wishes to go ahead with the upload of this picture, just dismiss this dialog
dialogInterface.dismiss();
});
AlertDialog errorDialog = errorDialogBuilder.create();
if (!isFinishing()) {
errorDialog.show();
}
}
});
detectUnwantedPicturesAsync.execute();
}
private Snackbar requestPermissionUsingSnackBar(String rationale,
final String[] perms,
final int code) {
@ -452,13 +521,93 @@ public class ShareActivity
if (imageObj != null) {
// Gets image coords from exif data or user location
decimalCoords = imageObj.getCoords(gpsEnabled);
useImageCoords();
if(decimalCoords==null || !imageObj.imageCoordsExists){
// Check if the location is from GPS or EXIF
// Find other photos taken around the same time which has gps coordinates
Timber.d("EXIF:false");
Timber.d("EXIF call"+(imageObj==tempImageObj));
if(!haveCheckedForOtherImages)
findOtherImages(gpsEnabled);// Do not do repeat the process
}
else {
// As the selected image has GPS data in EXIF go ahead with the same.
useImageCoords();
}
}
} catch (FileNotFoundException e) {
Timber.w("File not found: " + mediaUri, e);
}
}
private void findOtherImages(boolean gpsEnabled) {
Timber.d("filePath"+getPathOfMediaOrCopy());
String filePath = getPathOfMediaOrCopy();
long timeOfCreation = new File(filePath).lastModified();//Time when the original image was created
File folder = new File(filePath.substring(0,filePath.lastIndexOf('/')));
File[] files = folder.listFiles();
Timber.d("folderTime Number:"+files.length);
for(File file : files){
if(file.lastModified()-timeOfCreation<=(120*1000) && file.lastModified()-timeOfCreation>=-(120*1000)){
//Make sure the photos were taken within 20seconds
Timber.d("fild date:"+file.lastModified()+ " time of creation"+timeOfCreation);
tempImageObj = null;//Temporary GPSExtractor to extract coords from these photos
ParcelFileDescriptor descriptor
= null;
try {
descriptor = getContentResolver().openFileDescriptor(Uri.parse(file.getAbsolutePath()), "r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
if (descriptor != null) {
tempImageObj = new GPSExtractor(descriptor.getFileDescriptor(),this, prefs);
}
} else {
if (filePath != null) {
tempImageObj = new GPSExtractor(file.getAbsolutePath(), this, prefs);
}
}
if(tempImageObj!=null){
Timber.d("not null fild EXIF"+tempImageObj.imageCoordsExists +" coords"+tempImageObj.getCoords(gpsEnabled));
if(tempImageObj.getCoords(gpsEnabled)!=null && tempImageObj.imageCoordsExists){
// Current image has gps coordinates and it's not current gps locaiton
Timber.d("This fild has image coords:"+ file.getAbsolutePath());
// Create a dialog fragment for the suggestion
FragmentManager fragmentManager = getSupportFragmentManager();
SimilarImageDialogFragment newFragment = new SimilarImageDialogFragment();
Bundle args = new Bundle();
args.putString("originalImagePath",filePath);
args.putString("possibleImagePath",file.getAbsolutePath());
newFragment.setArguments(args);
newFragment.show(fragmentManager, "dialog");
break;
}
}
}
}
haveCheckedForOtherImages = true; //Finished checking for other images
return;
}
@Override
public void onPostiveResponse() {
imageObj = tempImageObj;
decimalCoords = imageObj.getCoords(false);// Not necessary to use gps as image already ha EXIF data
Timber.d("EXIF from tempImageObj");
useImageCoords();
}
@Override
public void onNegativeResponse() {
Timber.d("EXIF from imageObj");
useImageCoords();
}
/**
* Initiates retrieval of image coordinates or user coordinates, and caching of coordinates.
* Then initiates the calls to MediaWiki API through an instance of MwVolleyApi.
@ -466,6 +615,7 @@ public class ShareActivity
public void useImageCoords() {
if (decimalCoords != null) {
Timber.d("Decimal coords of image: %s", decimalCoords);
Timber.d("is EXIF data present:"+imageObj.imageCoordsExists+" from findOther image:"+(imageObj==tempImageObj));
// Only set cache for this point if image has coords
if (imageObj.imageCoordsExists) {
@ -489,7 +639,10 @@ public class ShareActivity
Timber.d("Cache found, setting categoryList in MwVolleyApi to %s", displayCatList);
MwVolleyApi.setGpsCat(displayCatList);
}
}else{
Timber.d("EXIF: no coords");
}
}
@Override

View file

@ -0,0 +1,112 @@
package fr.free.nrw.commons.upload;
import android.app.Dialog;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.listener.RequestListener;
import com.facebook.imagepipeline.listener.RequestLoggingListener;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import fr.free.nrw.commons.R;
/**
* Created by harisanker on 14/2/18.
*/
public class SimilarImageDialogFragment extends DialogFragment {
SimpleDraweeView originalImage;
SimpleDraweeView possibleImage;
Button positiveButton;
Button negativeButton;
onResponse mOnResponse;//Implemented interface from shareActivity
Boolean gotResponse = false;
public SimilarImageDialogFragment() {
}
public interface onResponse{
public void onPostiveResponse();
public void onNegativeResponse();
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_similar_image_dialog, container, false);
Set<RequestListener> requestListeners = new HashSet<>();
requestListeners.add(new RequestLoggingListener());
originalImage =(SimpleDraweeView) view.findViewById(R.id.orginalImage);
possibleImage =(SimpleDraweeView) view.findViewById(R.id.possibleImage);
positiveButton = (Button) view.findViewById(R.id.postive_button);
negativeButton = (Button) view.findViewById(R.id.negative_button);
originalImage.setHierarchy(GenericDraweeHierarchyBuilder
.newInstance(getResources())
.setPlaceholderImage(VectorDrawableCompat.create(getResources(),
R.drawable.ic_image_black_24dp,getContext().getTheme()))
.setFailureImage(VectorDrawableCompat.create(getResources(),
R.drawable.ic_error_outline_black_24dp, getContext().getTheme()))
.build());
possibleImage.setHierarchy(GenericDraweeHierarchyBuilder
.newInstance(getResources())
.setPlaceholderImage(VectorDrawableCompat.create(getResources(),
R.drawable.ic_image_black_24dp,getContext().getTheme()))
.setFailureImage(VectorDrawableCompat.create(getResources(),
R.drawable.ic_error_outline_black_24dp, getContext().getTheme()))
.build());
originalImage.setImageURI(Uri.fromFile(new File(getArguments().getString("originalImagePath"))));
possibleImage.setImageURI(Uri.fromFile(new File(getArguments().getString("possibleImagePath"))));
negativeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnResponse.onNegativeResponse();
gotResponse = true;
dismiss();
}
});
positiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnResponse.onPostiveResponse();
gotResponse = true;
dismiss();
}
});
return view;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mOnResponse = (onResponse) getActivity();//Interface Implementation
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
return dialog;
}
@Override
public void onDismiss(DialogInterface dialog) {
// I user dismisses dialog by pressing outside the dialog.
if(!gotResponse)
mOnResponse.onNegativeResponse();
super.onDismiss(dialog);
}
}

View file

@ -1,5 +1,8 @@
package fr.free.nrw.commons.upload;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -8,9 +11,11 @@ import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -25,6 +30,7 @@ import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
@ -36,16 +42,16 @@ import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnItemSelected;
import butterknife.OnTouch;
import dagger.android.support.DaggerFragment;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.settings.Prefs;
import timber.log.Timber;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_UP;
public class SingleUploadFragment extends DaggerFragment {
public class SingleUploadFragment extends CommonsDaggerSupportFragment {
@BindView(R.id.titleEdit) EditText titleEdit;
@BindView(R.id.descEdit) EditText descEdit;
@ -54,6 +60,7 @@ public class SingleUploadFragment extends DaggerFragment {
@BindView(R.id.licenseSpinner) Spinner licenseSpinner;
@Inject @Named("default_preferences") SharedPreferences prefs;
@Inject @Named("direct_nearby_upload_prefs") SharedPreferences directPrefs;
private String license;
private OnUploadActionInitiated uploadActionInitiatedHandler;
@ -62,9 +69,6 @@ public class SingleUploadFragment extends DaggerFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.activity_share, menu);
if (titleEdit != null) {
menu.findItem(R.id.menu_upload_single).setEnabled(titleEdit.getText().length() != 0);
}
}
@Override
@ -73,6 +77,11 @@ public class SingleUploadFragment extends DaggerFragment {
//What happens when the 'submit' icon is tapped
case R.id.menu_upload_single:
if (titleEdit.getText().toString().isEmpty()) {
Toast.makeText(getContext(), R.string.add_title_toast, Toast.LENGTH_LONG).show();
return false;
}
String title = titleEdit.getText().toString();
String desc = descEdit.getText().toString();
@ -84,7 +93,6 @@ public class SingleUploadFragment extends DaggerFragment {
uploadActionInitiatedHandler.uploadActionInitiated(title, desc);
return true;
}
return super.onOptionsItemSelected(item);
}
@ -95,6 +103,14 @@ public class SingleUploadFragment extends DaggerFragment {
View rootView = inflater.inflate(R.layout.fragment_single_upload, container, false);
ButterKnife.bind(this, rootView);
Intent activityIntent = getActivity().getIntent();
if (activityIntent.hasExtra("title")) {
titleEdit.setText(activityIntent.getStringExtra("title"));
}
if (activityIntent.hasExtra("description")) {
descEdit.setText(activityIntent.getStringExtra("description"));
}
ArrayList<String> licenseItems = new ArrayList<>();
licenseItems.add(getString(R.string.license_name_cc0));
licenseItems.add(getString(R.string.license_name_cc_by));
@ -104,6 +120,18 @@ public class SingleUploadFragment extends DaggerFragment {
license = prefs.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
// If this is a direct upload from Nearby, autofill title and desc fields with the Place's values
boolean isNearbyUpload = ((ShareActivity) getActivity()).isNearbyUpload();
if (isNearbyUpload) {
String imageTitle = directPrefs.getString("Title", "");
String imageDesc = directPrefs.getString("Desc", "");
String imageCats = directPrefs.getString("Category", "");
Timber.d("Image title: " + imageTitle + ", image desc: " + imageDesc + ", image categories: " + imageCats);
titleEdit.setText(imageTitle);
descEdit.setText(imageDesc);
}
// check if this is the first time we have uploaded
if (prefs.getString("Title", "").trim().length() == 0
&& prefs.getString("Desc", "").trim().length() == 0) {
@ -136,11 +164,29 @@ public class SingleUploadFragment extends DaggerFragment {
titleEdit.addTextChangedListener(textWatcher);
titleEdit.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
hideKeyboard(v);
}
});
descEdit.setOnFocusChangeListener((v, hasFocus) -> {
if(!hasFocus){
hideKeyboard(v);
}
});
setLicenseSummary(license);
return rootView;
}
public void hideKeyboard(View view) {
Log.i("hide", "hideKeyboard: ");
InputMethodManager inputMethodManager =(InputMethodManager)getActivity().getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
@Override
public void onDestroyView() {
titleEdit.removeTextChangedListener(textWatcher);
@ -208,39 +254,45 @@ public class SingleUploadFragment extends DaggerFragment {
*/
@OnTouch(R.id.titleEdit)
boolean titleInfo(View view, MotionEvent motionEvent) {
//Should replace right with end to support different right-to-left languages as well
final int value = titleEdit.getRight() - titleEdit.getCompoundDrawables()[2].getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() >= value) {
new AlertDialog.Builder(getContext())
.setTitle(R.string.media_detail_title)
.setMessage(R.string.title_info)
.setCancelable(true)
.setNeutralButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
.create()
.show();
return true;
final int value;
if (ViewCompat.getLayoutDirection(getView()) == ViewCompat.LAYOUT_DIRECTION_LTR) {
value = titleEdit.getRight() - titleEdit.getCompoundDrawables()[2].getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() >= value) {
showInfoAlert(R.string.media_detail_title, R.string.title_info);
return true;
}
}
else {
value = titleEdit.getLeft() + titleEdit.getCompoundDrawables()[0].getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() <= value) {
showInfoAlert(R.string.media_detail_title, R.string.title_info);
return true;
}
}
return false;
}
@OnTouch(R.id.descEdit)
boolean descriptionInfo(View view, MotionEvent motionEvent) {
final int value = descEdit.getRight() - descEdit.getCompoundDrawables()[2].getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() >= value) {
new AlertDialog.Builder(getContext())
.setTitle(R.string.media_detail_description)
.setMessage(R.string.description_info)
.setCancelable(true)
.setNeutralButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
.create()
.show();
return true;
final int value;
if (ViewCompat.getLayoutDirection(getView()) == ViewCompat.LAYOUT_DIRECTION_LTR) {
value = descEdit.getRight() - descEdit.getCompoundDrawables()[2].getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() >= value) {
showInfoAlert(R.string.media_detail_description,R.string.description_info);
return true;
}
}
else{
value = descEdit.getLeft() + descEdit.getCompoundDrawables()[0].getBounds().width();
if (motionEvent.getAction() == ACTION_UP && motionEvent.getRawX() <= value) {
showInfoAlert(R.string.media_detail_description,R.string.description_info);
return true;
}
}
return false;
}
@SuppressLint("StringFormatInvalid")
private void setLicenseSummary(String license) {
licenseSummaryView.setText(getString(R.string.share_license_summary, getString(Utils.licenseNameFor(license))));
}
@ -301,4 +353,14 @@ public class SingleUploadFragment extends DaggerFragment {
}
}
}
private void showInfoAlert (int titleStringID, int messageStringID){
new AlertDialog.Builder(getContext())
.setTitle(titleStringID)
.setMessage(messageStringID)
.setCancelable(true)
.setNeutralButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
.create()
.show();
}
}

View file

@ -6,6 +6,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
@ -49,7 +50,7 @@ public class UploadController {
private ServiceConnection uploadServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
uploadService = (UploadService) ((HandlerService.HandlerServiceLocalBinder)binder).getService();
uploadService = (UploadService) ((HandlerService.HandlerServiceLocalBinder) binder).getService();
isUploadServiceConnected = true;
}
@ -81,13 +82,14 @@ public class UploadController {
/**
* Starts a new upload task.
* @param title the title of the contribution
* @param mediaUri the media URI of the contribution
* @param description the description of the contribution
* @param mimeType the MIME type of the contribution
* @param source the source of the contribution
*
* @param title the title of the contribution
* @param mediaUri the media URI of the contribution
* @param description the description of the contribution
* @param mimeType the MIME type of the contribution
* @param source the source of the contribution
* @param decimalCoords the coordinates in decimal. (e.g. "37.51136|-77.602615")
* @param onComplete the progress tracker
* @param onComplete the progress tracker
*/
public void startUpload(String title, Uri mediaUri, String description, String mimeType, String source, String decimalCoords, ContributionUploadProgress onComplete) {
Contribution contribution;
@ -106,8 +108,9 @@ public class UploadController {
/**
* Starts a new upload task.
*
* @param contribution the contribution object
* @param onComplete the progress tracker
* @param onComplete the progress tracker
*/
public void startUpload(final Contribution contribution, final ContributionUploadProgress onComplete) {
//Set creator, desc, and license
@ -134,15 +137,17 @@ public class UploadController {
ContentResolver contentResolver = context.getContentResolver();
try {
if (contribution.getDataLength() <= 0) {
length = contentResolver
.openAssetFileDescriptor(contribution.getLocalUri(), "r")
.getLength();
if (length == -1) {
// Let us find out the long way!
length = countBytes(contentResolver
.openInputStream(contribution.getLocalUri()));
AssetFileDescriptor assetFileDescriptor = contentResolver
.openAssetFileDescriptor(contribution.getLocalUri(), "r");
if (assetFileDescriptor != null) {
length = assetFileDescriptor.getLength();
if (length == -1) {
// Let us find out the long way!
length = countBytes(contentResolver
.openInputStream(contribution.getLocalUri()));
}
contribution.setDataLength(length);
}
contribution.setDataLength(length);
}
} catch (IOException e) {
Timber.e(e, "IO Exception: ");
@ -152,7 +157,7 @@ public class UploadController {
Timber.e(e, "Security Exception: ");
}
String mimeType = (String)contribution.getTag("mimeType");
String mimeType = (String) contribution.getTag("mimeType");
Boolean imagePrefix = false;
if (mimeType == null || TextUtils.isEmpty(mimeType) || mimeType.endsWith("*")) {
@ -199,6 +204,7 @@ public class UploadController {
/**
* Counts the number of bytes in {@code stream}.
*
* @param stream the stream
* @return the number of bytes in {@code stream}
* @throws IOException if an I/O error occurs

View file

@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
@ -52,9 +51,9 @@ public class UploadService extends HandlerService<Contribution> {
@Inject MediaWikiApi mwApi;
@Inject SessionManager sessionManager;
@Inject @Named("default_preferences") SharedPreferences prefs;
@Inject ContributionDao contributionDao;
private NotificationManager notificationManager;
private ContentProviderClient contributionsProviderClient;
private NotificationCompat.Builder curProgressNotification;
private int toUpload;
@ -67,7 +66,6 @@ public class UploadService extends HandlerService<Contribution> {
public static final int NOTIFICATION_UPLOAD_IN_PROGRESS = 1;
public static final int NOTIFICATION_UPLOAD_COMPLETE = 2;
public static final int NOTIFICATION_UPLOAD_FAILED = 3;
private ContributionDao dao;
public UploadService() {
super("UploadService");
@ -107,7 +105,7 @@ public class UploadService extends HandlerService<Contribution> {
startForeground(NOTIFICATION_UPLOAD_IN_PROGRESS, curProgressNotification.build());
contribution.setTransferred(transferred);
dao.save(contribution);
contributionDao.save(contribution);
}
}
@ -115,7 +113,6 @@ public class UploadService extends HandlerService<Contribution> {
@Override
public void onDestroy() {
super.onDestroy();
contributionsProviderClient.release();
Timber.d("UploadService.onDestroy; %s are yet to be uploaded", unfinishedUploads);
}
@ -124,8 +121,6 @@ public class UploadService extends HandlerService<Contribution> {
super.onCreate();
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
contributionsProviderClient = this.getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY);
dao = new ContributionDao(contributionsProviderClient);
}
@Override
@ -147,7 +142,7 @@ public class UploadService extends HandlerService<Contribution> {
contribution.setState(Contribution.STATE_QUEUED);
contribution.setTransferred(0);
dao.save(contribution);
contributionDao.save(contribution);
toUpload++;
if (curProgressNotification != null && toUpload != 1) {
curProgressNotification.setContentText(getResources().getQuantityString(R.plurals.uploads_pending_notification_indicator, toUpload, toUpload));
@ -166,7 +161,7 @@ public class UploadService extends HandlerService<Contribution> {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(ACTION_START_SERVICE) && freshStart) {
if (ACTION_START_SERVICE.equals(intent.getAction()) && freshStart) {
ContentValues failedValues = new ContentValues();
failedValues.put(ContributionDao.Table.COLUMN_STATE, Contribution.STATE_FAILED);
@ -262,7 +257,7 @@ public class UploadService extends HandlerService<Contribution> {
contribution.setImageUrl(uploadResult.getImageUrl());
contribution.setState(Contribution.STATE_COMPLETED);
contribution.setDateUploaded(uploadResult.getDateUploaded());
dao.save(contribution);
contributionDao.save(contribution);
}
} catch (IOException e) {
Timber.d("I have a network fuckup");
@ -274,7 +269,7 @@ public class UploadService extends HandlerService<Contribution> {
toUpload--;
if (toUpload == 0) {
// Sync modifications right after all uplaods are processed
ContentResolver.requestSync(sessionManager.getCurrentAccount(), ModificationsContentProvider.AUTHORITY, new Bundle());
ContentResolver.requestSync(sessionManager.getCurrentAccount(), ModificationsContentProvider.MODIFICATIONS_AUTHORITY, new Bundle());
stopForeground(true);
}
}
@ -293,7 +288,7 @@ public class UploadService extends HandlerService<Contribution> {
notificationManager.notify(NOTIFICATION_UPLOAD_FAILED, failureNotification);
contribution.setState(Contribution.STATE_FAILED);
dao.save(contribution);
contributionDao.save(contribution);
}
private String findUniqueFilename(String fileName) throws IOException {