diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2e4bada1b..e73336ac8 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -8,6 +8,9 @@
android:targetSdkVersion="15" />
+
+
+
@@ -24,11 +27,27 @@
android:label="@string/title_activity_share" >
+
+
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/libs/java-mwapi.jar b/libs/java-mwapi.jar
index 33e68af74..77ce4d244 100644
Binary files a/libs/java-mwapi.jar and b/libs/java-mwapi.jar differ
diff --git a/src/org/wikimedia/commons/CommonsApplication.java b/src/org/wikimedia/commons/CommonsApplication.java
index fbf1470ff..b38028426 100644
--- a/src/org/wikimedia/commons/CommonsApplication.java
+++ b/src/org/wikimedia/commons/CommonsApplication.java
@@ -10,11 +10,9 @@ import org.apache.http.params.CoreProtocolPNames;
public class CommonsApplication extends Application {
private MWApi api;
-
- @Override
- public void onCreate() {
- // TODO Auto-generated method stub
- super.onCreate();
+ public static final String API_URL = "http://test.wikipedia.org/w/api.php";
+
+ public static MWApi createMWApi() {
DefaultHttpClient client = new DefaultHttpClient();
// Because WMF servers support only HTTP/1.0. Biggest difference that
// this makes is support for Chunked Transfer Encoding.
@@ -22,7 +20,14 @@ public class CommonsApplication extends Application {
// throws up.
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
HttpVersion.HTTP_1_0);
- api = new MWApi("http://test.wikipedia.org/w/api.php", client);
+ return new MWApi(API_URL, client);
+ }
+
+ @Override
+ public void onCreate() {
+ // TODO Auto-generated method stub
+ super.onCreate();
+ api = createMWApi();
}
public MWApi getApi() {
diff --git a/src/org/wikimedia/commons/ShareActivity.java b/src/org/wikimedia/commons/ShareActivity.java
index 174bd49a1..7fe4ae2b3 100644
--- a/src/org/wikimedia/commons/ShareActivity.java
+++ b/src/org/wikimedia/commons/ShareActivity.java
@@ -4,6 +4,7 @@ import java.io.*;
import org.mediawiki.api.ApiResult;
import org.mediawiki.api.MWApi;
+import org.wikimedia.commons.auth.LoginActivity;
import android.net.Uri;
import android.os.AsyncTask;
diff --git a/src/org/wikimedia/commons/UploadService.java b/src/org/wikimedia/commons/UploadService.java
index 8cfc2b919..abe02855c 100644
--- a/src/org/wikimedia/commons/UploadService.java
+++ b/src/org/wikimedia/commons/UploadService.java
@@ -11,6 +11,7 @@ import android.content.*;
import android.os.*;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
+import android.view.View;
import android.widget.RemoteViews;
import android.widget.Toast;
import android.net.*;
@@ -83,10 +84,6 @@ public class UploadService extends IntentService {
length = this.getContentResolver().openAssetFileDescriptor(mediaUri, "r").getLength();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
- } catch (IOException e) {
- //I'm hoping there are no streams that can be opened and read only once.
- e.printStackTrace();
- throw new RuntimeException(e);
}
notificationView = new RemoteViews(getPackageName(), R.layout.layout_upload_progress);
diff --git a/src/org/wikimedia/commons/LoginActivity.java b/src/org/wikimedia/commons/auth/LoginActivity.java
similarity index 55%
rename from src/org/wikimedia/commons/LoginActivity.java
rename to src/org/wikimedia/commons/auth/LoginActivity.java
index 6a20851e9..6c8f255c5 100644
--- a/src/org/wikimedia/commons/LoginActivity.java
+++ b/src/org/wikimedia/commons/auth/LoginActivity.java
@@ -1,9 +1,20 @@
-package org.wikimedia.commons;
+package org.wikimedia.commons.auth;
import java.io.IOException;
+import org.wikimedia.commons.CommonsApplication;
+import org.wikimedia.commons.R;
+import org.wikimedia.commons.R.id;
+import org.wikimedia.commons.R.layout;
+import org.wikimedia.commons.R.menu;
+import org.wikimedia.commons.R.string;
+
import android.os.AsyncTask;
import android.os.Bundle;
+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.view.*;
@@ -12,51 +23,69 @@ import android.widget.EditText;
import android.widget.Toast;
import android.support.v4.app.NavUtils;
-public class LoginActivity extends Activity {
-
+public class LoginActivity extends AccountAuthenticatorActivity {
+
+ public static final String PARAM_USERNAME = "org.wikimedia.commons.login.username";
+
private CommonsApplication app;
-
+
Button loginButton;
EditText usernameEdit;
EditText passwordEdit;
-
+
private class LoginTask extends AsyncTask {
Activity context;
ProgressDialog dialog;
+ String username;
+ String password;
+
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
- if(result.equals("Success")) {
+ if (result.equals("Success")) {
dialog.cancel();
Toast successToast = Toast.makeText(context, R.string.login_success, Toast.LENGTH_SHORT);
successToast.show();
+ Account account = new Account(username, WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE);
+ boolean accountCreated = AccountManager.get(context).addAccountExplicitly(account, password, null);
+
+ Bundle extras = context.getIntent().getExtras();
+ if (extras != null) {
+ if (accountCreated) { // Pass the new account back to the account manager
+ AccountAuthenticatorResponse response = extras.getParcelable(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
+ Bundle authResult = new Bundle();
+ authResult.putString(AccountManager.KEY_ACCOUNT_NAME, username);
+ authResult.putString(AccountManager.KEY_ACCOUNT_TYPE, WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE);
+ response.onResult(authResult);
+ }
+ }
context.finish();
} else {
Toast failureToast = Toast.makeText(context, R.string.login_failed, Toast.LENGTH_LONG);
failureToast.show();
}
-
+
}
@Override
protected void onPreExecute() {
super.onPreExecute();
- dialog = new ProgressDialog(context);
+ dialog = new ProgressDialog(context);
dialog.setIndeterminate(true);
dialog.setTitle(getString(R.string.logging_in_title));
dialog.setMessage(getString(R.string.logging_in_message));
dialog.show();
}
-
+
LoginTask(Activity context) {
this.context = context;
}
-
+
@Override
protected String doInBackground(String... params) {
- String username = params[0];
- String password = params[1];
+ username = params[0];
+ password = params[1];
try {
return app.getApi().login(username, password);
} catch (IOException e) {
@@ -64,24 +93,24 @@ public class LoginActivity extends Activity {
return "Failure";
}
}
-
+
}
-
+
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- app = (CommonsApplication)this.getApplicationContext();
+ app = (CommonsApplication) this.getApplicationContext();
setContentView(R.layout.activity_login);
- loginButton = (Button)findViewById(R.id.loginButton);
- usernameEdit = (EditText)findViewById(R.id.loginUsername);
- passwordEdit = (EditText)findViewById(R.id.loginPassword);
+ loginButton = (Button) findViewById(R.id.loginButton);
+ usernameEdit = (EditText) findViewById(R.id.loginUsername);
+ passwordEdit = (EditText) findViewById(R.id.loginPassword);
final Activity that = this;
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = usernameEdit.getText().toString();
String password = passwordEdit.getText().toString();
-
+
LoginTask task = new LoginTask(that);
task.execute(username, password);
}
@@ -94,18 +123,14 @@ public class LoginActivity extends Activity {
return true;
}
-
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- NavUtils.navigateUpFromSameTask(this);
- return true;
+ case android.R.id.home:
+ NavUtils.navigateUpFromSameTask(this);
+ return true;
}
return super.onOptionsItemSelected(item);
}
-
-
-
}
diff --git a/src/org/wikimedia/commons/auth/WikiAccountAuthenticator.java b/src/org/wikimedia/commons/auth/WikiAccountAuthenticator.java
new file mode 100644
index 000000000..1da6d5259
--- /dev/null
+++ b/src/org/wikimedia/commons/auth/WikiAccountAuthenticator.java
@@ -0,0 +1,119 @@
+package org.wikimedia.commons.auth;
+
+import java.io.IOException;
+
+import org.mediawiki.api.ApiResult;
+import org.mediawiki.api.MWApi;
+import org.wikimedia.commons.CommonsApplication;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class WikiAccountAuthenticator extends AbstractAccountAuthenticator {
+
+ public static final String COMMONS_ACCOUNT_TYPE = "org.wikimedia.commons";
+ private Context context;
+ public WikiAccountAuthenticator(Context context) {
+ super(context);
+ this.context = context;
+ }
+
+ @Override
+ public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
+ // TODO Auto-generated method stub
+ final Intent intent = new Intent(context, LoginActivity.class);
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+ return bundle;
+ }
+
+ @Override
+ public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ private String getAuthCookie(String username, String password) throws IOException {
+ MWApi api = ((CommonsApplication)context.getApplicationContext()).createMWApi();
+ String result = api.login(username, password);
+ if(result.equals("Success")) {
+ return api.getAuthCookie();
+ } else {
+ return null;
+ }
+ }
+ @Override
+ public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
+ // If the caller requested an authToken type we don't support, then
+ // return an error
+ if (!authTokenType.equals(COMMONS_ACCOUNT_TYPE)) {
+ final Bundle result = new Bundle();
+ result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType");
+ return result;
+ }
+
+ // Extract the username and password from the Account Manager, and ask
+ // the server for an appropriate AuthToken.
+ final AccountManager am = AccountManager.get(context);
+ final String password = am.getPassword(account);
+ if (password != null) {
+ String authCookie;
+ try {
+ authCookie = getAuthCookie(account.name, password);
+ } catch (IOException e) {
+ // Network error!
+ throw new NetworkErrorException(e);
+ }
+ if (authCookie != null) {
+ final Bundle result = new Bundle();
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, COMMONS_ACCOUNT_TYPE);
+ result.putString(AccountManager.KEY_AUTHTOKEN, authCookie);
+ return result;
+ }
+ }
+
+ // If we get here, then we couldn't access the user's password - so we
+ // need to re-prompt them for their credentials. We do that by creating
+ // an intent to display our AuthenticatorActivity panel.
+ final Intent intent = new Intent(context, LoginActivity.class);
+ intent.putExtra(LoginActivity.PARAM_USERNAME, account.name);
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+ return bundle;
+ }
+
+ @Override
+ public String getAuthTokenLabel(String authTokenType) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
+ final Bundle result = new Bundle();
+ result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+ return result;
+ }
+
+ @Override
+ public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/src/org/wikimedia/commons/auth/WikiAccountAuthenticatorService.java b/src/org/wikimedia/commons/auth/WikiAccountAuthenticatorService.java
new file mode 100644
index 000000000..c22c970aa
--- /dev/null
+++ b/src/org/wikimedia/commons/auth/WikiAccountAuthenticatorService.java
@@ -0,0 +1,23 @@
+package org.wikimedia.commons.auth;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class WikiAccountAuthenticatorService extends Service{
+
+ private static WikiAccountAuthenticator wikiAccountAuthenticator = null;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (!intent.getAction().equals(android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
+ return null;
+ }
+
+ if(wikiAccountAuthenticator == null) {
+ wikiAccountAuthenticator = new WikiAccountAuthenticator(this);
+ }
+ return wikiAccountAuthenticator.getIBinder();
+ }
+
+}