diff --git a/commons/app/build.gradle b/commons/app/build.gradle index 5a6428a72..adf1229fe 100644 --- a/commons/app/build.gradle +++ b/commons/app/build.gradle @@ -8,12 +8,12 @@ dependencies { compile 'com.nostra13.universalimageloader:universal-image-loader:1.8.4' compile 'ch.acra:acra:4.5.0' compile 'org.mediawiki:api:1.3' - compile 'de.keyboardsurfer.android.widget:crouton:1.8.5@aar' compile 'commons-codec:commons-codec:1.10' compile 'com.android.support:support-v4:23.4.0' compile 'com.android.support:appcompat-v7:23.4.0' compile 'com.android.support:design:23.4.0' - //noinspectio GradleDependency - old version has required feature + + //noinspection GradleDependency - old version has required feature compile 'com.google.code.gson:gson:1.4' } diff --git a/commons/app/src/main/AndroidManifest.xml b/commons/app/src/main/AndroidManifest.xml index 50be5c2b1..ccf0998ed 100644 --- a/commons/app/src/main/AndroidManifest.xml +++ b/commons/app/src/main/AndroidManifest.xml @@ -8,10 +8,6 @@ android:targetSdkVersion="23" /> - - - - diff --git a/commons/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java b/commons/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java index 78f06012f..48ef8236e 100644 --- a/commons/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java +++ b/commons/app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java @@ -1,26 +1,39 @@ package fr.free.nrw.commons.auth; +import android.accounts.Account; +import android.accounts.AccountAuthenticatorActivity; +import android.accounts.AccountAuthenticatorResponse; +import android.accounts.AccountManager; +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.ContentResolver; +import android.content.Intent; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.design.widget.Snackbar; +import android.support.v4.app.NavUtils; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.EditorInfo; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + import java.io.IOException; -import android.content.*; -import android.net.Uri; -import android.text.*; -import android.view.inputmethod.EditorInfo; -import de.keyboardsurfer.android.widget.crouton.*; -import android.os.*; -import android.accounts.*; -import android.app.*; -import android.util.*; -import android.view.*; -import android.widget.*; -import android.support.v4.app.NavUtils; - -import fr.free.nrw.commons.*; -import fr.free.nrw.commons.WelcomeActivity; -import fr.free.nrw.commons.modifications.ModificationsContentProvider; import fr.free.nrw.commons.CommonsApplication; import fr.free.nrw.commons.EventLog; -import fr.free.nrw.commons.contributions.*; +import fr.free.nrw.commons.R; +import fr.free.nrw.commons.WelcomeActivity; +import fr.free.nrw.commons.contributions.ContributionsContentProvider; +import fr.free.nrw.commons.modifications.ModificationsContentProvider; public class LoginActivity extends AccountAuthenticatorActivity { @@ -79,7 +92,7 @@ public class LoginActivity extends AccountAuthenticatorActivity { } else if(result.equals("NotExists") || result.equals("Illegal") || result.equals("NotExists")) { response = R.string.login_failed_username; passwordEdit.setText(""); - } else if(result.equals("EmptyPass") || result.equals("WrongPass")) { + } else if(result.equals("EmptyPass") || result.equals("WrongPass") || result.equals("WrongPluginPass")) { response = R.string.login_failed_password; passwordEdit.setText(""); } else if(result.equals("Throttled")) { @@ -88,10 +101,11 @@ public class LoginActivity extends AccountAuthenticatorActivity { response = R.string.login_failed_blocked; } else { // Should never really happen + Log.d("Commons", "Login failed with reason: " + result); response = R.string.login_failed_generic; } - Crouton.makeText(context, response, Style.ALERT, R.id.loginErrors).show(); - dialog.dismiss(); + Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG).show(); + dialog.cancel(); } } diff --git a/commons/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java b/commons/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java index c92c90f6c..4fae74a9f 100644 --- a/commons/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java +++ b/commons/app/src/main/java/fr/free/nrw/commons/upload/ShareActivity.java @@ -5,16 +5,18 @@ import android.content.ContentResolver; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Environment; +import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.app.NavUtils; -import android.support.design.widget.Snackbar; import android.support.v4.content.ContextCompat; import android.util.Log; import android.view.MenuItem; import android.view.View; import android.widget.ImageView; +import android.widget.TextView; import android.widget.Toast; import com.nostra13.universalimageloader.core.ImageLoader; @@ -28,6 +30,7 @@ import fr.free.nrw.commons.R; import fr.free.nrw.commons.auth.AuthenticatedActivity; import fr.free.nrw.commons.auth.WikiAccountAuthenticator; import fr.free.nrw.commons.category.CategorizationFragment; +import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.modifications.CategoryModifier; import fr.free.nrw.commons.modifications.ModificationsContentProvider; import fr.free.nrw.commons.modifications.ModifierSequence; @@ -39,12 +42,12 @@ import fr.free.nrw.commons.modifications.TemplateRemoveModifier; */ public class ShareActivity extends AuthenticatedActivity - implements fr.free.nrw.commons.upload.SingleUploadFragment.OnUploadActionInitiated, + implements SingleUploadFragment.OnUploadActionInitiated, CategorizationFragment.OnCategoriesSaveHandler { private static final String TAG = ShareActivity.class.getName(); - private fr.free.nrw.commons.upload.SingleUploadFragment shareView; + private SingleUploadFragment shareView; private CategorizationFragment categorizationFragment; private CommonsApplication app; @@ -54,14 +57,14 @@ public class ShareActivity private String mediaUriString; private Uri mediaUri; - private fr.free.nrw.commons.contributions.Contribution contribution; + private Contribution contribution; private ImageView backgroundImageView; - private fr.free.nrw.commons.upload.UploadController uploadController; + private UploadController uploadController; private CommonsApplication cacheObj; private boolean cacheFound; - private fr.free.nrw.commons.upload.GPSExtractor imageObj; + private GPSExtractor imageObj; public ShareActivity() { super(WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE); @@ -77,8 +80,8 @@ public class ShareActivity Log.d(TAG, "Cache the categories found"); } - uploadController.startUpload(title, mediaUri, description, mimeType, source, new fr.free.nrw.commons.upload.UploadController.ContributionUploadProgress() { - public void onUploadStarted(fr.free.nrw.commons.contributions.Contribution contribution) { + uploadController.startUpload(title, mediaUri, description, mimeType, source, new UploadController.ContributionUploadProgress() { + public void onUploadStarted(Contribution contribution) { ShareActivity.this.contribution = contribution; showPostUpload(); } @@ -140,7 +143,7 @@ public class ShareActivity } else { EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT) .param("username", app.getCurrentAccount().name) - .param("source", getIntent().getStringExtra(fr.free.nrw.commons.upload.UploadService.EXTRA_SOURCE)) + .param("source", getIntent().getStringExtra(UploadService.EXTRA_SOURCE)) .param("multiple", true) .param("result", "cancelled") .log(); @@ -153,10 +156,10 @@ public class ShareActivity app.getApi().setAuthCookie(authCookie); - shareView = (fr.free.nrw.commons.upload.SingleUploadFragment) getSupportFragmentManager().findFragmentByTag("shareView"); + shareView = (SingleUploadFragment) getSupportFragmentManager().findFragmentByTag("shareView"); categorizationFragment = (CategorizationFragment) getSupportFragmentManager().findFragmentByTag("categorization"); if(shareView == null && categorizationFragment == null) { - shareView = new fr.free.nrw.commons.upload.SingleUploadFragment(); + shareView = new SingleUploadFragment(); this.getSupportFragmentManager() .beginTransaction() .add(R.id.single_upload_fragment_container, shareView, "shareView") @@ -173,10 +176,15 @@ public class ShareActivity finish(); } + /** + * Initiates retrieval of image coordinates or user coordinates, and caching of coordinates. + * Then initiates the calls to MediaWiki API through an instance of MwVolleyApi. + */ + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - uploadController = new fr.free.nrw.commons.upload.UploadController(this); + uploadController = new UploadController(this); setContentView(R.layout.activity_share); app = (CommonsApplication)this.getApplicationContext(); @@ -186,10 +194,10 @@ public class ShareActivity if(intent.getAction().equals(Intent.ACTION_SEND)) { mediaUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM); - if(intent.hasExtra(fr.free.nrw.commons.upload.UploadService.EXTRA_SOURCE)) { - source = intent.getStringExtra(fr.free.nrw.commons.upload.UploadService.EXTRA_SOURCE); + if(intent.hasExtra(UploadService.EXTRA_SOURCE)) { + source = intent.getStringExtra(UploadService.EXTRA_SOURCE); } else { - source = fr.free.nrw.commons.contributions.Contribution.SOURCE_EXTERNAL; + source = Contribution.SOURCE_EXTERNAL; } mimeType = intent.getType(); } @@ -203,80 +211,94 @@ public class ShareActivity contribution = savedInstanceState.getParcelable("contribution"); } requestAuthToken(); - } - /** - * Initiates retrieval of image coordinates or user coordinates, and caching of coordinates. - * Then initiates the calls to MediaWiki API through an instance of MwVolleyApi. - */ - @Override - public void onResume() { - super.onResume(); Log.d(TAG, "Uri: " + mediaUriString); Log.d(TAG, "Ext storage dir: " + Environment.getExternalStorageDirectory()); - - - // Check permissions - if (ContextCompat.checkSelfPermission(this.getApplicationContext(), - Manifest.permission.READ_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { - - if (ActivityCompat.shouldShowRequestPermissionRationale(this, - Manifest.permission.READ_EXTERNAL_STORAGE)) { - - Log.i(TAG, - "Displaying camera permission rationale to provide additional context."); - Snackbar.make(this.findViewById(android.R.id.content), R.string.storage_permission_rationale, Snackbar.LENGTH_INDEFINITE).setAction(R.string.ok, new View.OnClickListener() { + // Check storage permissions if marshmallow or newer + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && + (ContextCompat.checkSelfPermission(this, + Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || + ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) { + if (!(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE) && (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)))) { + String permissionRationales = getResources().getString(R.string.storage_permission_rationale) + "\n" + getResources().getString(R.string.location_permission_rationale); + Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), permissionRationales, + Snackbar.LENGTH_INDEFINITE) + .setAction(R.string.ok, new View.OnClickListener() { @Override public void onClick(View view) { - ActivityCompat.requestPermissions(ShareActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1); + ActivityCompat.requestPermissions(ShareActivity.this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION}, 1); + } + }); + snackbar.show(); + View snackbarView = snackbar.getView(); + TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text); + textView.setMaxLines(3); + } else if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) { + Snackbar.make(findViewById(android.R.id.content), R.string.storage_permission_rationale, + Snackbar.LENGTH_INDEFINITE) + .setAction(R.string.ok, new View.OnClickListener() { + @Override + public void onClick(View view) { + ActivityCompat.requestPermissions(ShareActivity.this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1); + } + }).show(); + } else if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { + Snackbar.make(findViewById(android.R.id.content), R.string.location_permission_rationale, + Snackbar.LENGTH_INDEFINITE) + .setAction(R.string.ok, new View.OnClickListener() { + @Override + public void onClick(View view) { + ActivityCompat.requestPermissions(ShareActivity.this, + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1); } }).show(); - - } else { - ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1); } - } + } else { + // Convert image Uri to file path + String filePath = FileUtils.getPath(this, mediaUri); + Log.d(TAG, "Filepath: " + filePath); - //convert image Uri to file path - String filePath = fr.free.nrw.commons.upload.FileUtils.getPath(this, mediaUri); - Log.d(TAG, "Filepath: " + filePath); + // Check location permissions if marshmallow or newer + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(this, + Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + Log.d(TAG, "Calling GPSExtractor"); + imageObj = new GPSExtractor(filePath, this); + imageObj.registerLocationManager(); - Log.d(TAG, "Calling GPSExtractor"); - imageObj = new fr.free.nrw.commons.upload.GPSExtractor(filePath, this); - imageObj.registerLocationManager(); + if (filePath != null && !filePath.equals("")) { + // Gets image coords if exist, otherwise gets last known coords + String decimalCoords = imageObj.getCoords(); - if (filePath != null && !filePath.equals("")) { - //Gets image coords if exist, otherwise gets last known coords - String decimalCoords = imageObj.getCoords(); + if (decimalCoords != null) { + Log.d(TAG, "Decimal coords of image: " + decimalCoords); - if (decimalCoords != null) { - Log.d(TAG, "Decimal coords of image: " + decimalCoords); + // Only set cache for this point if image has coords + if (imageObj.imageCoordsExists) { + double decLongitude = imageObj.getDecLongitude(); + double decLatitude = imageObj.getDecLatitude(); + app.cacheData.setQtPoint(decLongitude, decLatitude); + } - //Only set cache for this point if image has coords - if (imageObj.imageCoordsExists) { - double decLongitude = imageObj.getDecLongitude(); - double decLatitude = imageObj.getDecLatitude(); - app.cacheData.setQtPoint(decLongitude, decLatitude); - } + MwVolleyApi apiCall = new MwVolleyApi(this); - fr.free.nrw.commons.upload.MwVolleyApi apiCall = new fr.free.nrw.commons.upload.MwVolleyApi(this); + List displayCatList = app.cacheData.findCategory(); + boolean catListEmpty = displayCatList.isEmpty(); - List displayCatList = app.cacheData.findCategory(); - boolean catListEmpty = displayCatList.isEmpty(); - - //if no categories found in cache, call MW API to match image coords with nearby Commons categories - if (catListEmpty) { - cacheFound = false; - apiCall.request(decimalCoords); - Log.d(TAG, "displayCatList size 0, calling MWAPI" + displayCatList.toString()); - - } else { - cacheFound = true; - Log.d(TAG, "Cache found, setting categoryList in MwVolleyApi to " + displayCatList.toString()); - fr.free.nrw.commons.upload.MwVolleyApi.setGpsCat(displayCatList); + // If no categories found in cache, call MediaWiki API to match image coords with nearby Commons categories + if (catListEmpty) { + cacheFound = false; + apiCall.request(decimalCoords); + Log.d(TAG, "displayCatList size 0, calling MWAPI" + displayCatList.toString()); + } else { + cacheFound = true; + Log.d(TAG, "Cache found, setting categoryList in MwVolleyApi to " + displayCatList.toString()); + MwVolleyApi.setGpsCat(displayCatList); + } + } } } } @@ -285,7 +307,10 @@ public class ShareActivity @Override public void onPause() { super.onPause(); - imageObj.unregisterLocationManager(); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(this, + Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + imageObj.unregisterLocationManager(); + } } @Override diff --git a/commons/app/src/main/res/values/strings.xml b/commons/app/src/main/res/values/strings.xml index f0bd2f760..82623916e 100644 --- a/commons/app/src/main/res/values/strings.xml +++ b/commons/app/src/main/res/values/strings.xml @@ -149,6 +149,8 @@ Campaigns Refresh - Storage permission is needed to access photos + Recommended: Storage for photo metadata + Optional: Location for geo-tag OK + Back