diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..d8ef17752 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,35 @@ +_Before creating an issue, please search the existing issues to see if a similar one has already been created. You can search issues by specific labels (e.g. `label:nearby `) or just by typing keywords into the search filter._ + +**Summary:** + +Summarize your issue in one sentence (what goes wrong, what did you expect to happen) + +**Steps to reproduce:** + +How can we reproduce the issue? + +**Add System logs:** + +Add logcat files here (if possible). + +**Expected behavior:** + +What did you expect the App to do? + +**Observed behavior:** + +What did you see instead? Describe your issue in detail here. + +**Device and Android version:** + +What make and model device (e.g., Samsung J7) did you encounter this on? What Android +version (e.g., Android 4.0 Ice Cream Sandwich or Android 6.0 Marshmallow) are you running? Is it + the stock version from the manufacturer or a custom ROM ? + + **Commons app version:** + +You can find this information by going to the navigation drawer in the app and tapping 'About' + +**Screen-shots:** + +Can be created by pressing the Volume Down and Power Button at the same time on Android 4.0 and higher. diff --git a/app/src/main/java/fr/free/nrw/commons/AboutActivity.java b/app/src/main/java/fr/free/nrw/commons/AboutActivity.java index 7fd96d9bb..46e1441d6 100644 --- a/app/src/main/java/fr/free/nrw/commons/AboutActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/AboutActivity.java @@ -34,7 +34,7 @@ public class AboutActivity extends NavigationBaseActivity { setContentView(R.layout.activity_about); ButterKnife.bind(this); - String aboutText = getString(R.string.about_license, getString(R.string.trademarked_name)); + String aboutText = getString(R.string.about_license); aboutLicenseText.setHtmlText(aboutText); versionText.setText(BuildConfig.VERSION_NAME); diff --git a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java index a6cf2d65d..ab156bab7 100644 --- a/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java +++ b/app/src/main/java/fr/free/nrw/commons/CommonsApplication.java @@ -57,7 +57,6 @@ public class CommonsApplication extends Application { public static final String FEEDBACK_EMAIL_SUBJECT = "Commons Android App (%s) Feedback"; - private CommonsApplicationComponent component; private RefWatcher refWatcher; @@ -136,9 +135,10 @@ public class CommonsApplication extends Application { .subscribe(() -> { Timber.d("All accounts have been removed"); //TODO: fix preference manager - defaultPrefs.edit().clear().commit(); - applicationPrefs.edit().clear().commit(); - applicationPrefs.edit().putBoolean("firstrun", false).apply();otherPrefs.edit().clear().commit(); + defaultPrefs.edit().clear().apply(); + applicationPrefs.edit().clear().apply(); + applicationPrefs.edit().putBoolean("firstrun", false).apply(); + otherPrefs.edit().clear().apply(); updateAllDatabases(); logoutListener.onLogoutComplete(); diff --git a/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java b/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java index 0927f0338..25e778b74 100644 --- a/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java +++ b/app/src/main/java/fr/free/nrw/commons/MediaDataExtractor.java @@ -283,7 +283,7 @@ public class MediaDataExtractor { /** * Take our metadata and inject it into a live Media object. * Media object might contain stale or cached data, or emptiness. - * @param media + * @param media Media object to inject into */ public void fill(Media media) { if (!fetched) { diff --git a/app/src/main/java/fr/free/nrw/commons/Utils.java b/app/src/main/java/fr/free/nrw/commons/Utils.java index 967f2cf8e..817c39f24 100644 --- a/app/src/main/java/fr/free/nrw/commons/Utils.java +++ b/app/src/main/java/fr/free/nrw/commons/Utils.java @@ -65,7 +65,7 @@ public class Utils { /** * Capitalizes the first character of a string. * - * @param string + * @param string String to alter * @return string with capitalized first character */ public static String capitalize(String string) { diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index c5707b970..3e90fbf5e 100644 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -32,7 +32,6 @@ import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; -import dagger.android.AndroidInjection; import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.PageTitle; import fr.free.nrw.commons.R; diff --git a/app/src/main/java/fr/free/nrw/commons/auth/LoginTask.java b/app/src/main/java/fr/free/nrw/commons/auth/LoginTask.java deleted file mode 100644 index b751dfe93..000000000 --- a/app/src/main/java/fr/free/nrw/commons/auth/LoginTask.java +++ /dev/null @@ -1,128 +0,0 @@ -package fr.free.nrw.commons.auth; - -import android.accounts.AccountAuthenticatorResponse; -import android.app.ProgressDialog; -import android.content.SharedPreferences; -import android.os.AsyncTask; -import android.os.Bundle; - -import java.io.IOException; - -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.mwapi.MediaWikiApi; -import timber.log.Timber; - -import static android.accounts.AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE; -import static android.accounts.AccountManager.KEY_ACCOUNT_NAME; -import static android.accounts.AccountManager.KEY_ACCOUNT_TYPE; -import static fr.free.nrw.commons.auth.AccountUtil.ACCOUNT_TYPE; - -class LoginTask extends AsyncTask { - - private LoginActivity loginActivity; - private String username; - private String password; - private String twoFactorCode = ""; - private AccountUtil accountUtil; - private MediaWikiApi mwApi; - - public LoginTask(LoginActivity loginActivity, String username, String password, - String twoFactorCode, AccountUtil accountUtil, - MediaWikiApi mwApi, SharedPreferences prefs) { - this.loginActivity = loginActivity; - this.username = username; - this.password = password; - this.twoFactorCode = twoFactorCode; - this.accountUtil = accountUtil; - this.mwApi = mwApi; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - loginActivity.progressDialog = new ProgressDialog(loginActivity); - loginActivity.progressDialog.setIndeterminate(true); - loginActivity.progressDialog.setTitle(loginActivity.getString(R.string.logging_in_title)); - loginActivity.progressDialog.setMessage(loginActivity.getString(R.string.logging_in_message)); - loginActivity.progressDialog.setCanceledOnTouchOutside(false); - loginActivity.progressDialog.show(); - } - - @Override - protected String doInBackground(String... params) { - try { - if (twoFactorCode.isEmpty()) { - return mwApi.login(username, password); - } else { - return mwApi.login(username, password, twoFactorCode); - } - } catch (IOException e) { - // Do something better! - return "NetworkFailure"; - } - } - - @Override - protected void onPostExecute(String result) { - super.onPostExecute(result); - Timber.d("Login done!"); - - if (result.equals("PASS")) { - handlePassResult(); - } else { - handleOtherResults(result); - } - } - - private void handlePassResult() { - loginActivity.showSuccessAndDismissDialog(); - - AccountAuthenticatorResponse response = null; - - Bundle extras = loginActivity.getIntent().getExtras(); - if (extras != null) { - Timber.d("Bundle of extras: %s", extras); - response = extras.getParcelable(KEY_ACCOUNT_AUTHENTICATOR_RESPONSE); - if (response != null) { - Bundle authResult = new Bundle(); - authResult.putString(KEY_ACCOUNT_NAME, username); - authResult.putString(KEY_ACCOUNT_TYPE, ACCOUNT_TYPE); - response.onResult(authResult); - } - } - - accountUtil.createAccount(response, username, password); - loginActivity.startMainActivity(); - } - - /** - * Match known failure message codes and provide messages. - * @param result String - */ - private void handleOtherResults(String result) { - if (result.equals("NetworkFailure")) { - // Matches NetworkFailure which is created by the doInBackground method - loginActivity.showMessageAndCancelDialog(R.string.login_failed_network); - } else if (result.toLowerCase().contains("nosuchuser".toLowerCase()) || result.toLowerCase().contains("noname".toLowerCase())) { - // Matches nosuchuser, nosuchusershort, noname - loginActivity.showMessageAndCancelDialog(R.string.login_failed_username); - loginActivity.emptySensitiveEditFields(); - } else if (result.toLowerCase().contains("wrongpassword".toLowerCase())) { - // Matches wrongpassword, wrongpasswordempty - loginActivity.showMessageAndCancelDialog(R.string.login_failed_password); - loginActivity.emptySensitiveEditFields(); - } else if (result.toLowerCase().contains("throttle".toLowerCase())) { - // Matches unknown throttle error codes - loginActivity.showMessageAndCancelDialog(R.string.login_failed_throttled); - } else if (result.toLowerCase().contains("userblocked".toLowerCase())) { - // Matches login-userblocked - loginActivity.showMessageAndCancelDialog(R.string.login_failed_blocked); - } else if (result.equals("2FA")) { - loginActivity.askUserForTwoFactorAuth(); - } else { - // Occurs with unhandled login failure codes - Timber.d("Login failed with reason: %s", result); - loginActivity.showMessageAndCancelDialog(R.string.login_failed_generic); - } - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java index 76a70c0b3..7c2e910c4 100644 --- a/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/category/CategorizationFragment.java @@ -1,6 +1,5 @@ package fr.free.nrw.commons.category; -import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.app.AlertDialog; @@ -298,8 +297,10 @@ public class CategorizationFragment extends CommonsDaggerSupportFragment { //Check if item contains a 4-digit word anywhere within the string (.* is wildcard) //And that item does not equal the current year or previous year //And if it is an irrelevant category such as Media_needing_categories_as_of_16_June_2017(Issue #750) + //Check if the year in the form of XX(X)0s is relevant, i.e. in the 2000s or 2010s as stated in Issue #1029 return ((item.matches(".*(19|20)\\d{2}.*") && !item.contains(yearInString) && !item.contains(prevYearInString)) - || item.matches("(.*)needing(.*)") || item.matches("(.*)taken on(.*)")); + || item.matches("(.*)needing(.*)") || item.matches("(.*)taken on(.*)") + || (item.matches(".*0s.*") && !item.matches(".*(200|201)0s.*"))); } private void updateCategoryCount(CategoryItem item) { diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java index a243330c3..db20963e7 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionController.java @@ -93,10 +93,15 @@ class ContributionController { shareIntent.putExtra(EXTRA_SOURCE, SOURCE_GALLERY); break; case SELECT_FROM_CAMERA: - shareIntent.setType("image/jpeg"); //FIXME: Find out appropriate mime type + //FIXME: Find out appropriate mime type + // AFAIK this is the right type for a JPEG image + // https://developer.android.com/training/sharing/send.html#send-binary-content + shareIntent.setType("image/jpeg"); shareIntent.putExtra(EXTRA_STREAM, lastGeneratedCaptureUri); shareIntent.putExtra(EXTRA_SOURCE, SOURCE_CAMERA); break; + default: + break; } Timber.i("Image selected"); try { diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContentProvider.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContentProvider.java index 7dc750732..0a68ac626 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContentProvider.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsContentProvider.java @@ -86,7 +86,7 @@ public class ContributionsContentProvider extends CommonsDaggerContentProvider { public Uri insert(@NonNull Uri uri, ContentValues contentValues) { int uriType = uriMatcher.match(uri); SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); - long id = 0; + long id; switch (uriType) { case CONTRIBUTIONS: id = sqlDB.insert(TABLE_NAME, null, contentValues); @@ -158,7 +158,7 @@ public class ContributionsContentProvider extends CommonsDaggerContentProvider { */ int uriType = uriMatcher.match(uri); SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); - int rowsUpdated = 0; + int rowsUpdated; switch (uriType) { case CONTRIBUTIONS: rowsUpdated = sqlDB.update(TABLE_NAME, contentValues, selection, selectionArgs); diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java index 3a391b293..25bf6eb93 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsListFragment.java @@ -20,6 +20,8 @@ import android.widget.ListAdapter; import android.widget.ProgressBar; import android.widget.TextView; +import java.util.Arrays; + import javax.inject.Inject; import javax.inject.Named; @@ -45,8 +47,12 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment { @BindView(R.id.loadingContributionsProgressBar) ProgressBar progressBar; - @Inject @Named("prefs") SharedPreferences prefs; - @Inject @Named("default_preferences") SharedPreferences defaultPrefs; + @Inject + @Named("prefs") + SharedPreferences prefs; + @Inject + @Named("default_preferences") + SharedPreferences defaultPrefs; private ContributionController controller; @@ -208,7 +214,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { Timber.d("onRequestPermissionsResult: req code = " + " perm = " - + permissions + " grant =" + grantResults); + + Arrays.toString(permissions) + " grant =" + Arrays.toString(grantResults)); switch (requestCode) { // 1 = Storage allowed when gallery selected diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java index 5be634a2e..aedc3f789 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/ContributionsSyncAdapter.java @@ -23,7 +23,6 @@ import java.util.TimeZone; import javax.inject.Inject; import javax.inject.Named; -import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.mwapi.LogEventResult; diff --git a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java index 14985c6b6..f5974d519 100644 --- a/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java +++ b/app/src/main/java/fr/free/nrw/commons/di/CommonsApplicationComponent.java @@ -1,7 +1,5 @@ package fr.free.nrw.commons.di; -import android.content.Context; - import javax.inject.Singleton; import dagger.Component; @@ -11,10 +9,7 @@ import dagger.android.support.AndroidSupportInjectionModule; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.MediaWikiImageView; import fr.free.nrw.commons.auth.LoginActivity; -import fr.free.nrw.commons.category.CategoryContentProvider; -import fr.free.nrw.commons.contributions.ContributionsContentProvider; import fr.free.nrw.commons.contributions.ContributionsSyncAdapter; -import fr.free.nrw.commons.modifications.ModificationsContentProvider; import fr.free.nrw.commons.modifications.ModificationsSyncAdapter; import fr.free.nrw.commons.settings.SettingsFragment; diff --git a/app/src/main/java/fr/free/nrw/commons/location/LatLng.java b/app/src/main/java/fr/free/nrw/commons/location/LatLng.java index d587b88e3..494cce077 100644 --- a/app/src/main/java/fr/free/nrw/commons/location/LatLng.java +++ b/app/src/main/java/fr/free/nrw/commons/location/LatLng.java @@ -38,7 +38,7 @@ public class LatLng { /** * gets the latitude and longitude of a given non-null location * @param location the non-null location of the user - * @return + * @return LatLng the Latitude and Longitude of a given location */ public static LatLng from(@NonNull Location location) { return new LatLng(location.getLatitude(), location.getLongitude(), location.getAccuracy()); @@ -48,13 +48,12 @@ public class LatLng { * creates a hash code for the longitude and longitude */ public int hashCode() { - boolean var1 = true; - byte var2 = 1; - long var3 = Double.doubleToLongBits(this.latitude); - int var5 = 31 * var2 + (int)(var3 ^ var3 >>> 32); - var3 = Double.doubleToLongBits(this.longitude); - var5 = 31 * var5 + (int)(var3 ^ var3 >>> 32); - return var5; + byte var1 = 1; + long var2 = Double.doubleToLongBits(this.latitude); + int var3 = 31 * var1 + (int)(var2 ^ var2 >>> 32); + var2 = Double.doubleToLongBits(this.longitude); + var3 = 31 * var3 + (int)(var2 ^ var2 >>> 32); + return var3; } /** diff --git a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java index d949189ed..851114ef9 100644 --- a/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java +++ b/app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java @@ -14,9 +14,6 @@ import android.support.v4.content.ContextCompat; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import javax.inject.Inject; -import javax.inject.Singleton; - import timber.log.Timber; public class LocationServiceManager implements LocationListener { @@ -33,6 +30,7 @@ public class LocationServiceManager implements LocationListener { /** * Constructs a new instance of LocationServiceManager. + * * @param context the context */ public LocationServiceManager(Context context) { @@ -42,6 +40,7 @@ public class LocationServiceManager implements LocationListener { /** * Returns the current status of the GPS provider. + * * @return true if the GPS provider is enabled */ public boolean isProviderEnabled() { @@ -50,6 +49,7 @@ public class LocationServiceManager implements LocationListener { /** * Returns whether the location permission is granted. + * * @return true if the location permission is granted */ public boolean isLocationPermissionGranted() { @@ -59,6 +59,7 @@ public class LocationServiceManager implements LocationListener { /** * Requests the location permission to be granted. + * * @param activity the activity */ public void requestPermissions(Activity activity) { @@ -71,11 +72,9 @@ public class LocationServiceManager implements LocationListener { } public boolean isPermissionExplanationRequired(Activity activity) { - if (activity.isFinishing()) { - return false; - } - return ActivityCompat.shouldShowRequestPermissionRationale(activity, - Manifest.permission.ACCESS_FINE_LOCATION); + return !activity.isFinishing() && + ActivityCompat.shouldShowRequestPermissionRationale(activity, + Manifest.permission.ACCESS_FINE_LOCATION); } public LatLng getLastLocation() { @@ -85,7 +84,8 @@ public class LocationServiceManager implements LocationListener { return LatLng.from(lastLocation); } - /** Registers a LocationManager to listen for current location. + /** + * Registers a LocationManager to listen for current location. */ public void registerLocationManager() { if (!isLocationManagerRegistered) @@ -95,6 +95,7 @@ public class LocationServiceManager implements LocationListener { /** * Requests location updates from the specified provider. + * * @param locationProvider the location provider * @return true if successful */ @@ -116,7 +117,8 @@ public class LocationServiceManager implements LocationListener { /** * Returns whether a given location is better than the current best location. - * @param location the location to be tested + * + * @param location the location to be tested * @param currentBestLocation the current best location * @return true if the given location is better */ @@ -172,7 +174,8 @@ public class LocationServiceManager implements LocationListener { return provider1.equals(provider2); } - /** Unregisters location manager. + /** + * Unregisters location manager. */ public void unregisterLocationManager() { isLocationManagerRegistered = false; @@ -185,6 +188,7 @@ public class LocationServiceManager implements LocationListener { /** * Adds a new listener to the list of location listeners. + * * @param listener the new listener */ public void addLocationListener(LocationUpdateListener listener) { @@ -195,6 +199,7 @@ public class LocationServiceManager implements LocationListener { /** * Removes a listener from the list of location listeners. + * * @param listener the listener to be removed */ public void removeLocationListener(LocationUpdateListener listener) { diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java index 96ce8da29..5f41007ff 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailFragment.java @@ -77,7 +77,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private ViewTreeObserver.OnGlobalLayoutListener layoutListener; // for layout stuff, only used once! private ViewTreeObserver.OnScrollChangedListener scrollListener; private DataSetObserver dataObserver; - private AsyncTask detailFetchTask; + private AsyncTask detailFetchTask; private LicenseList licenseList; @Override @@ -96,7 +96,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - detailProvider = (MediaDetailPagerFragment.MediaDetailProvider)getActivity(); + detailProvider = (MediaDetailPagerFragment.MediaDetailProvider) getActivity(); if (savedInstanceState != null) { editable = savedInstanceState.getBoolean("editable"); @@ -157,7 +157,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { return view; } - @Override public void onResume() { + @Override + public void onResume() { super.onResume(); Media media = detailProvider.getMediaAtPosition(index); if (media == null) { @@ -239,13 +240,13 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { detailFetchTask.cancel(true); detailFetchTask = null; } - if (layoutListener != null) { + if (layoutListener != null && getView() != null) { getView().getViewTreeObserver().removeGlobalOnLayoutListener(layoutListener); // old Android was on crack. CRACK IS WHACK layoutListener = null; } - if (scrollListener != null) { + if (scrollListener != null && getView() != null) { getView().getViewTreeObserver().removeOnScrollChangedListener(scrollListener); - scrollListener = null; + scrollListener = null; } if (dataObserver != null) { detailProvider.unregisterDataSetObserver(dataObserver); @@ -290,7 +291,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { private View buildCatLabel(final String catName, ViewGroup categoryContainer) { final View item = LayoutInflater.from(getContext()).inflate(R.layout.detail_category_item, categoryContainer, false); - final CompatTextView textView = (CompatTextView)item.findViewById(R.id.mediaDetailCategoryItemText); + final CompatTextView textView = (CompatTextView) item.findViewById(R.id.mediaDetailCategoryItemText); textView.setText(catName); if (categoriesLoaded && categoriesPresent) { @@ -317,7 +318,7 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { // You must face the darkness alone int scrollY = scrollView.getScrollY(); int scrollMax = getView().getHeight(); - float scrollPercentage = (float)scrollY / (float)scrollMax; + float scrollPercentage = (float) scrollY / (float) scrollMax; final float transparencyMax = 0.75f; if (scrollPercentage > transparencyMax) { scrollPercentage = transparencyMax; @@ -371,7 +372,8 @@ public class MediaDetailFragment extends CommonsDaggerSupportFragment { } - private @Nullable String licenseLink(Media media) { + private @Nullable + String licenseLink(Media media) { String licenseKey = media.getLicense(); if (licenseKey == null || licenseKey.equals("")) { return null; diff --git a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java index f0e0c635b..d1f4ffd97 100644 --- a/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/media/MediaDetailPagerFragment.java @@ -44,9 +44,13 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment implements ViewPager.OnPageChangeListener { - @Inject MediaWikiApi mwApi; - @Inject SessionManager sessionManager; - @Inject @Named("default_preferences") SharedPreferences prefs; + @Inject + MediaWikiApi mwApi; + @Inject + SessionManager sessionManager; + @Inject + @Named("default_preferences") + SharedPreferences prefs; private ViewPager pager; private Boolean editable; @@ -175,13 +179,19 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple req.allowScanningByMediaScanner(); req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !(ContextCompat.checkSelfPermission(getContext(), READ_EXTERNAL_STORAGE) == PERMISSION_GRANTED)) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && + ContextCompat.checkSelfPermission(getContext(), READ_EXTERNAL_STORAGE) + != PERMISSION_GRANTED + && getView() != null) { Snackbar.make(getView(), R.string.read_storage_permission_rationale, Snackbar.LENGTH_INDEFINITE).setAction(R.string.ok, view -> ActivityCompat.requestPermissions(getActivity(), new String[]{READ_EXTERNAL_STORAGE}, 1)).show(); } else { - ((DownloadManager) getActivity().getSystemService(DOWNLOAD_SERVICE)).enqueue(req); + DownloadManager systemService = (DownloadManager) getActivity().getSystemService(DOWNLOAD_SERVICE); + if (systemService != null) { + systemService.enqueue(req); + } } } diff --git a/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java b/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java index c7b92a3ec..0d4468d84 100644 --- a/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java +++ b/app/src/main/java/fr/free/nrw/commons/modifications/ModificationsContentProvider.java @@ -70,7 +70,7 @@ public class ModificationsContentProvider extends CommonsDaggerContentProvider { public Uri insert(@NonNull Uri uri, ContentValues contentValues) { int uriType = uriMatcher.match(uri); SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); - long id = 0; + long id; switch (uriType) { case MODIFICATIONS: id = sqlDB.insert(TABLE_NAME, null, contentValues); @@ -132,7 +132,7 @@ public class ModificationsContentProvider extends CommonsDaggerContentProvider { */ int uriType = uriMatcher.match(uri); SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); - int rowsUpdated = 0; + int rowsUpdated; switch (uriType) { case MODIFICATIONS: rowsUpdated = sqlDB.update(TABLE_NAME, diff --git a/app/src/main/java/fr/free/nrw/commons/modifications/ModifierSequenceDao.java b/app/src/main/java/fr/free/nrw/commons/modifications/ModifierSequenceDao.java index e6b741d7a..a23079b5e 100644 --- a/app/src/main/java/fr/free/nrw/commons/modifications/ModifierSequenceDao.java +++ b/app/src/main/java/fr/free/nrw/commons/modifications/ModifierSequenceDao.java @@ -52,7 +52,7 @@ public class ModifierSequenceDao { ModifierSequence fromCursor(Cursor cursor) { // Hardcoding column positions! - ModifierSequence ms = null; + ModifierSequence ms; try { ms = new ModifierSequence(Uri.parse(cursor.getString(1)), new JSONObject(cursor.getString(2))); diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java index 57d21dd95..0e67afc2f 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyActivity.java @@ -1,6 +1,5 @@ package fr.free.nrw.commons.nearby; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; @@ -41,8 +40,6 @@ import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; import timber.log.Timber; -import static fr.free.nrw.commons.location.LocationServiceManager.LOCATION_REQUEST; - public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener { @@ -259,7 +256,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp /** * This method should be the single point to load/refresh nearby places * - * @param isHardRefresh + * @param isHardRefresh Should display a toast if the location hasn't changed */ private void refreshView(boolean isHardRefresh) { if (lockNearbyView) { diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java index 624a0de0f..035532c11 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyController.java @@ -39,8 +39,9 @@ public class NearbyController { /** * Prepares Place list to make their distance information update later. + * * @param curLatLng current location for user - * @param context context + * @param context context * @return Place list without distance information */ public List loadAttractionsFromLocation(LatLng curLatLng, Context context) { @@ -51,25 +52,24 @@ public class NearbyController { List places = prefs.getBoolean("useWikidata", true) ? nearbyPlaces.getFromWikidataQuery(curLatLng, Locale.getDefault().getLanguage()) : nearbyPlaces.getFromWikiNeedsPictures(); - if (curLatLng != null) { - Timber.d("Sorting places by distance..."); - final Map distances = new HashMap<>(); - for (Place place: places) { - distances.put(place, computeDistanceBetween(place.location, curLatLng)); - } - Collections.sort(places, - (lhs, rhs) -> { - double lhsDistance = distances.get(lhs); - double rhsDistance = distances.get(rhs); - return (int) (lhsDistance - rhsDistance); - } - ); + Timber.d("Sorting places by distance..."); + final Map distances = new HashMap<>(); + for (Place place : places) { + distances.put(place, computeDistanceBetween(place.location, curLatLng)); } + Collections.sort(places, + (lhs, rhs) -> { + double lhsDistance = distances.get(lhs); + double rhsDistance = distances.get(rhs); + return (int) (lhsDistance - rhsDistance); + } + ); return places; } /** * Loads attractions from location for list view, we need to return Place data type. + * * @param curLatLng users current location * @param placeList list of nearby places in Place data type * @return Place list that holds nearby places @@ -78,7 +78,7 @@ public class NearbyController { LatLng curLatLng, List placeList) { placeList = placeList.subList(0, Math.min(placeList.size(), MAX_RESULTS)); - for (Place place: placeList) { + for (Place place : placeList) { String distance = formatDistanceBetween(curLatLng, place.location); place.setDistance(distance); } @@ -86,7 +86,8 @@ public class NearbyController { } /** - *Loads attractions from location for map view, we need to return BaseMarkerOption data type. + * Loads attractions from location for map view, we need to return BaseMarkerOption data type. + * * @param curLatLng users current location * @param placeList list of nearby places in Place data type * @return BaseMarkerOptions list that holds nearby places @@ -103,26 +104,28 @@ public class NearbyController { placeList = placeList.subList(0, Math.min(placeList.size(), MAX_RESULTS)); - Bitmap icon = UiUtils.getBitmap( - VectorDrawableCompat.create( - context.getResources(), R.drawable.ic_custom_map_marker, context.getTheme() - )); + VectorDrawableCompat vectorDrawable = VectorDrawableCompat.create( + context.getResources(), R.drawable.ic_custom_map_marker, context.getTheme() + ); + if (vectorDrawable != null) { + Bitmap icon = UiUtils.getBitmap(vectorDrawable); - for (Place place: placeList) { - String distance = formatDistanceBetween(curLatLng, place.location); - place.setDistance(distance); + for (Place place : placeList) { + String distance = formatDistanceBetween(curLatLng, place.location); + place.setDistance(distance); - NearbyBaseMarker nearbyBaseMarker = new NearbyBaseMarker(); - nearbyBaseMarker.title(place.name); - nearbyBaseMarker.position( - new com.mapbox.mapboxsdk.geometry.LatLng( - place.location.getLatitude(), - place.location.getLongitude())); - nearbyBaseMarker.place(place); - nearbyBaseMarker.icon(IconFactory.getInstance(context) - .fromBitmap(icon)); + NearbyBaseMarker nearbyBaseMarker = new NearbyBaseMarker(); + nearbyBaseMarker.title(place.name); + nearbyBaseMarker.position( + new com.mapbox.mapboxsdk.geometry.LatLng( + place.location.getLatitude(), + place.location.getLongitude())); + nearbyBaseMarker.place(place); + nearbyBaseMarker.icon(IconFactory.getInstance(context) + .fromBitmap(icon)); - baseMarkerOptions.add(nearbyBaseMarker); + baseMarkerOptions.add(nearbyBaseMarker); + } } return baseMarkerOptions; } diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java index 3cfb4840f..d57a23137 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NearbyListFragment.java @@ -19,7 +19,6 @@ import java.util.Collections; import java.util.List; import dagger.android.support.AndroidSupportInjection; -import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.R; import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.utils.UriDeserializer; diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/NoPermissionsFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/NoPermissionsFragment.java index 7a907a1e4..f08fa6acd 100644 --- a/app/src/main/java/fr/free/nrw/commons/nearby/NoPermissionsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/nearby/NoPermissionsFragment.java @@ -9,7 +9,6 @@ import android.view.ViewGroup; import butterknife.ButterKnife; import dagger.android.support.AndroidSupportInjection; -import dagger.android.support.DaggerFragment; import fr.free.nrw.commons.R; import timber.log.Timber; diff --git a/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java b/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java index 20efa40e1..43e880ba2 100644 --- a/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/notification/NotificationActivity.java @@ -61,9 +61,7 @@ public class NotificationActivity extends NavigationBaseActivity { .subscribe(notificationList -> { Timber.d("Number of notifications is %d", notificationList.size()); setAdapter(notificationList); - }, throwable -> { - Timber.e(throwable, "Error occurred while loading notifications"); - }); + }, throwable -> Timber.e(throwable, "Error occurred while loading notifications")); } private void handleUrl(String url) { diff --git a/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java b/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java index 9bf3cec93..a5aac0508 100644 --- a/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java +++ b/app/src/main/java/fr/free/nrw/commons/notification/NotificationRenderer.java @@ -8,13 +8,9 @@ import android.widget.TextView; import com.pedrogomez.renderers.Renderer; -import java.util.Calendar; -import java.util.Date; - import butterknife.BindView; import butterknife.ButterKnife; import fr.free.nrw.commons.R; -import fr.free.nrw.commons.utils.DateUtils; /** * Created by root on 19.12.2017. diff --git a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java index 2a017c854..66be88e3f 100644 --- a/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java +++ b/app/src/main/java/fr/free/nrw/commons/settings/SettingsFragment.java @@ -25,7 +25,6 @@ import java.io.File; import javax.inject.Inject; import javax.inject.Named; -import dagger.android.AndroidInjection; import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.R; @@ -71,7 +70,12 @@ public class SettingsFragment extends PreferenceFragment { uploadLimit.setText(uploads + ""); uploadLimit.setSummary(uploads + ""); uploadLimit.setOnPreferenceChangeListener((preference, newValue) -> { - int value = Integer.parseInt(newValue.toString()); + int value; + try { + value = Integer.parseInt(newValue.toString()); + } catch(Exception e) { + value = 100; //Default number + } final SharedPreferences.Editor editor = prefs.edit(); if (value > 500) { new AlertDialog.Builder(getActivity()) @@ -85,9 +89,9 @@ public class SettingsFragment extends PreferenceFragment { uploadLimit.setSummary(500 + ""); uploadLimit.setText(500 + ""); } else { - editor.putInt(Prefs.UPLOADS_SHOWING, Integer.parseInt(newValue.toString())); + editor.putInt(Prefs.UPLOADS_SHOWING, value); editor.putBoolean(Prefs.IS_CONTRIBUTION_COUNT_CHANGED,true); - uploadLimit.setSummary(newValue.toString()); + uploadLimit.setSummary(String.valueOf(value)); } editor.apply(); return true; diff --git a/app/src/main/java/fr/free/nrw/commons/ui/widget/CompatTextView.java b/app/src/main/java/fr/free/nrw/commons/ui/widget/CompatTextView.java index a04f7f8c8..abe2e2554 100644 --- a/app/src/main/java/fr/free/nrw/commons/ui/widget/CompatTextView.java +++ b/app/src/main/java/fr/free/nrw/commons/ui/widget/CompatTextView.java @@ -1,7 +1,7 @@ package fr.free.nrw.commons.ui.widget; -/** - * Created by mikel on 07/08/2017. +/* + *Created by mikel on 07/08/2017. */ import android.content.Context; @@ -20,20 +20,22 @@ import fr.free.nrw.commons.utils.UiUtils; * a text view compatible with older versions of the platform */ public class CompatTextView extends AppCompatTextView { - + /** * Constructs a new instance of CompatTextView + * * @param context the view context */ public CompatTextView(Context context) { super(context); init(null); } - + /** * Constructs a new instance of CompatTextView + * * @param context the view context - * @param attrs the set of attributes for the view + * @param attrs the set of attributes for the view */ public CompatTextView(Context context, AttributeSet attrs) { super(context, attrs); @@ -42,6 +44,7 @@ public class CompatTextView extends AppCompatTextView { /** * Constructs a new instance of CompatTextView + * * @param context * @param attrs * @param defStyleAttr @@ -53,6 +56,7 @@ public class CompatTextView extends AppCompatTextView { /** * initializes the view + * * @param attrs the attribute set of the view, which can be null */ private void init(@Nullable AttributeSet attrs) { diff --git a/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.java b/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.java index bf7742843..58fccf4d7 100644 --- a/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.java +++ b/app/src/main/java/fr/free/nrw/commons/ui/widget/OverlayDialog.java @@ -19,7 +19,7 @@ public abstract class OverlayDialog extends DialogFragment { /** * creates a DialogFragment with the correct style and theme - * @param savedInstanceState + * @param savedInstanceState bundle re-constructed from a previous saved state */ @Override public void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java b/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java index 2cf18e7d7..f069cfec9 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/FileUtils.java @@ -28,7 +28,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 @@ -49,29 +49,31 @@ public class FileUtils { if ("primary".equalsIgnoreCase(type)) { return 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)) { + } 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=?"; @@ -163,7 +165,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 +179,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 */ diff --git a/app/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java b/app/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java index 404177032..b9750e350 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/GPSExtractor.java @@ -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; diff --git a/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java index a41938cf7..00a1b958f 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/MultipleShareActivity.java @@ -51,11 +51,17 @@ public class MultipleShareActivity extends AuthenticatedActivity MultipleUploadListFragment.OnMultipleUploadInitiatedHandler, OnCategoriesSaveHandler { - @Inject MediaWikiApi mwApi; - @Inject SessionManager sessionManager; - @Inject UploadController uploadController; - @Inject ModifierSequenceDao modifierSequenceDao; - @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 photosList = null; @@ -240,7 +246,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 urisList = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); @@ -278,7 +284,7 @@ public class MultipleShareActivity extends AuthenticatedActivity @Override public void onBackStackChanged() { - getSupportActionBar().setDisplayHomeAsUpEnabled(mediaDetails != null && mediaDetails.isVisible()) ; + getSupportActionBar().setDisplayHomeAsUpEnabled(mediaDetails != null && mediaDetails.isVisible()); } } \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index 2f0a4977e..a0b9102b6 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -16,6 +16,7 @@ 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.view.MenuItem; import android.view.View; @@ -61,10 +62,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,12 +73,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 ModifierSequenceDao modifierSequenceDao; - @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; @@ -89,6 +97,7 @@ public class ShareActivity private boolean cacheFound; private GPSExtractor imageObj; + private GPSExtractor tempImageObj; private String decimalCoords; private boolean useNewPermissions = false; @@ -99,7 +108,7 @@ public class ShareActivity private String description; private Snackbar snackbar; private boolean duplicateCheckPassed = false; - + private boolean haveCheckedForOtherImages = false; /** * Called when user taps the submit button. */ @@ -216,7 +225,7 @@ 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); @@ -452,13 +461,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 +555,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 +579,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 diff --git a/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java b/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java new file mode 100644 index 000000000..a8f336927 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/upload/SimilarImageDialogFragment.java @@ -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 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); + } +} diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadController.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadController.java index ade22ece6..32554da0f 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadController.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadController.java @@ -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 diff --git a/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java b/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java index 1c8f9ac58..94c005256 100644 --- a/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java +++ b/app/src/main/java/fr/free/nrw/commons/upload/UploadService.java @@ -161,7 +161,7 @@ public class UploadService extends HandlerService { @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); diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ExecutorUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/ExecutorUtils.java index 15f18ee5e..57ed86eeb 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ExecutorUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/ExecutorUtils.java @@ -15,6 +15,8 @@ public class ExecutorUtils { } }; - public static Executor uiExecutor() { return uiExecutor; } + public static Executor uiExecutor() { + return uiExecutor; + } } diff --git a/app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java b/app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java index 6912d0ceb..d56a7b608 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/FileUtils.java @@ -11,7 +11,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; -import fr.free.nrw.commons.CommonsApplication; import timber.log.Timber; public class FileUtils { @@ -32,7 +31,7 @@ public class FileUtils { reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); String line; while ((line = reader.readLine()) != null) { - buffer.append(line + "\n"); + buffer.append(line).append("\n"); } } finally { if (reader != null) { diff --git a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java index 947c70eb6..f2a02398f 100644 --- a/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java +++ b/app/src/main/java/fr/free/nrw/commons/utils/ViewUtil.java @@ -7,11 +7,6 @@ import android.widget.Toast; public class ViewUtil { public static void showLongToast(final Context context, @StringRes final int stringResId) { - ExecutorUtils.uiExecutor().execute(new Runnable() { - @Override - public void run() { - Toast.makeText(context, context.getString(stringResId), Toast.LENGTH_LONG).show(); - } - }); + ExecutorUtils.uiExecutor().execute(() -> Toast.makeText(context, context.getString(stringResId), Toast.LENGTH_LONG).show()); } } diff --git a/app/src/main/res/layout/activity_contributions.xml b/app/src/main/res/layout/activity_contributions.xml index 9065618f2..51a48f0a5 100644 --- a/app/src/main/res/layout/activity_contributions.xml +++ b/app/src/main/res/layout/activity_contributions.xml @@ -15,9 +15,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> - - diff --git a/app/src/main/res/layout/fragment_similar_image_dialog.xml b/app/src/main/res/layout/fragment_similar_image_dialog.xml new file mode 100644 index 000000000..90fec6bcf --- /dev/null +++ b/app/src/main/res/layout/fragment_similar_image_dialog.xml @@ -0,0 +1,57 @@ + + + + + + + + + +