mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 12:53:55 +01:00
Mavenized (almost) everything - Transcode feature removed
This commit is contained in:
parent
0a493dc8a1
commit
3a313f3fb3
444 changed files with 1703 additions and 34416 deletions
|
|
@ -0,0 +1,119 @@
|
|||
package org.wikimedia.commons;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.xml.transform.*;
|
||||
|
||||
import android.accounts.*;
|
||||
import android.app.Application;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
|
||||
import org.mediawiki.api.*;
|
||||
import org.w3c.dom.Node;
|
||||
import org.wikimedia.commons.auth.WikiAccountAuthenticator;
|
||||
import org.apache.http.HttpVersion;
|
||||
import org.apache.http.conn.ConnectionKeepAliveStrategy;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.params.CoreProtocolPNames;
|
||||
|
||||
public class CommonsApplication extends Application {
|
||||
|
||||
private MWApi api;
|
||||
private Account currentAccount = null; // Unlike a savings account...
|
||||
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.
|
||||
// I have this here so if any 1.1 features start being used, it
|
||||
// throws up.
|
||||
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
|
||||
HttpVersion.HTTP_1_0);
|
||||
return new MWApi(API_URL, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
// TODO Auto-generated method stub
|
||||
super.onCreate();
|
||||
api = createMWApi();
|
||||
}
|
||||
|
||||
public MWApi getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
public Account getCurrentAccount() {
|
||||
if(currentAccount == null) {
|
||||
AccountManager accountManager = AccountManager.get(this);
|
||||
Account[] allAccounts = accountManager.getAccountsByType(WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE);
|
||||
if(allAccounts.length != 0) {
|
||||
currentAccount = allAccounts[0];
|
||||
}
|
||||
}
|
||||
return currentAccount;
|
||||
}
|
||||
|
||||
public Boolean revalidateAuthToken() {
|
||||
AccountManager accountManager = AccountManager.get(this);
|
||||
Account curAccount = getCurrentAccount();
|
||||
|
||||
if(curAccount == null) {
|
||||
return false; // This should never happen
|
||||
}
|
||||
|
||||
accountManager.invalidateAuthToken(WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE, api.getAuthCookie());
|
||||
try {
|
||||
String authCookie = accountManager.blockingGetAuthToken(curAccount, "", false);
|
||||
api.setAuthCookie(authCookie);
|
||||
return true;
|
||||
} catch (OperationCanceledException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} catch (AuthenticatorException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getStringFromDOM(Node dom) {
|
||||
javax.xml.transform.Transformer transformer = null;
|
||||
try {
|
||||
transformer = TransformerFactory.newInstance().newTransformer();
|
||||
} catch (TransformerConfigurationException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (TransformerFactoryConfigurationError e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
StringWriter outputStream = new StringWriter();
|
||||
javax.xml.transform.dom.DOMSource domSource = new javax.xml.transform.dom.DOMSource(dom);
|
||||
javax.xml.transform.stream.StreamResult strResult = new javax.xml.transform.stream.StreamResult(outputStream);
|
||||
|
||||
try {
|
||||
transformer.transform(domSource, strResult);
|
||||
} catch (TransformerException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return outputStream.toString();
|
||||
}
|
||||
|
||||
static public <T> void executeAsyncTask(AsyncTask<T, ?, ?> task,
|
||||
T... params) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
|
||||
}
|
||||
else {
|
||||
task.execute(params);
|
||||
}
|
||||
}
|
||||
}
|
||||
107
commons/src/main/java/org/wikimedia/commons/ImageLoaderTask.java
Normal file
107
commons/src/main/java/org/wikimedia/commons/ImageLoaderTask.java
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
package org.wikimedia.commons;
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.*;
|
||||
import android.net.Uri;
|
||||
import android.os.*;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.*;
|
||||
|
||||
class ImageLoaderTask extends AsyncTask<Uri, String, Bitmap> {
|
||||
ImageView view;
|
||||
|
||||
public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
|
||||
// Raw height and width of image
|
||||
final int height = options.outHeight;
|
||||
final int width = options.outWidth;
|
||||
int inSampleSize = 1;
|
||||
|
||||
if (height > reqHeight || width > reqWidth) {
|
||||
if (width > height) {
|
||||
inSampleSize = Math.round((float) height / (float) reqHeight);
|
||||
} else {
|
||||
inSampleSize = Math.round((float) width / (float) reqWidth);
|
||||
}
|
||||
}
|
||||
return inSampleSize;
|
||||
}
|
||||
|
||||
private int getOrientation(Uri photoUri) {
|
||||
/* it's on the external media. */
|
||||
Cursor cursor = view.getContext().getContentResolver().query(photoUri,
|
||||
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
|
||||
|
||||
if (cursor.getCount() != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cursor.moveToFirst();
|
||||
return cursor.getInt(0);
|
||||
}
|
||||
|
||||
public Bitmap getBitmap(Uri imageUri) throws FileNotFoundException {
|
||||
|
||||
|
||||
// FIXME: Use proper window width, not device width. But should do for now!
|
||||
WindowManager wm = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
|
||||
int reqHeight = wm.getDefaultDisplay().getHeight();
|
||||
int reqWidth = wm.getDefaultDisplay().getWidth();
|
||||
|
||||
int orientation = getOrientation(imageUri);
|
||||
|
||||
if(orientation == 90 || orientation == 270) {
|
||||
// Swap height and width if this is rotated
|
||||
int temp = reqHeight;
|
||||
reqHeight = reqWidth;
|
||||
reqWidth = temp;
|
||||
}
|
||||
// First decode with inJustDecodeBounds=true to check dimensions
|
||||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
InputStream bitmapStream = view.getContext().getContentResolver().openInputStream(imageUri);
|
||||
BitmapFactory.decodeStream(bitmapStream, null, options);
|
||||
|
||||
// Calculate inSampleSize
|
||||
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
|
||||
|
||||
// Decode bitmap with inSampleSize set
|
||||
options.inJustDecodeBounds = false;
|
||||
|
||||
// Re-get the InputStream!
|
||||
bitmapStream = view.getContext().getContentResolver().openInputStream(imageUri);
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(bitmapStream, null, options);
|
||||
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postRotate(orientation);
|
||||
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
ImageLoaderTask(ImageView view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bitmap doInBackground(Uri... params) {
|
||||
Uri url = params[0];
|
||||
Bitmap bitmap;
|
||||
try {
|
||||
bitmap = getBitmap(url);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap result) {
|
||||
super.onPostExecute(result);
|
||||
view.setImageBitmap(result);
|
||||
}
|
||||
}
|
||||
127
commons/src/main/java/org/wikimedia/commons/ShareActivity.java
Normal file
127
commons/src/main/java/org/wikimedia/commons/ShareActivity.java
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package org.wikimedia.commons;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.wikimedia.commons.auth.AuthenticatedActivity;
|
||||
import org.wikimedia.commons.auth.WikiAccountAuthenticator;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
import android.widget.ImageView;
|
||||
import android.support.v4.app.NavUtils;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.Window;
|
||||
import android.widget.*;
|
||||
import android.view.*;
|
||||
|
||||
|
||||
public class ShareActivity extends AuthenticatedActivity {
|
||||
|
||||
public ShareActivity() {
|
||||
super(WikiAccountAuthenticator.COMMONS_ACCOUNT_TYPE);
|
||||
}
|
||||
|
||||
private CommonsApplication app;
|
||||
|
||||
private ImageView backgroundImageView;
|
||||
private Button uploadButton;
|
||||
private EditText titleEdit;
|
||||
private EditText descEdit;
|
||||
|
||||
private Uri mediaUri;
|
||||
|
||||
@Override
|
||||
protected void onAuthCookieAcquired(String authCookie) {
|
||||
super.onAuthCookieAcquired(authCookie);
|
||||
app.getApi().setAuthCookie(authCookie);
|
||||
Intent intent = getIntent();
|
||||
|
||||
final Context that = this;
|
||||
|
||||
if(intent.getAction().equals(Intent.ACTION_SEND)) {
|
||||
mediaUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
|
||||
final String mimeType = intent.getType();
|
||||
if(mimeType.startsWith("image/")) {
|
||||
ImageLoaderTask loader = new ImageLoaderTask(backgroundImageView);
|
||||
loader.execute(mediaUri);
|
||||
}
|
||||
|
||||
uploadButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
Intent uploadIntent = new Intent(getApplicationContext(), UploadService.class);
|
||||
uploadIntent.putExtra(UploadService.EXTRA_MEDIA_URI, mediaUri);
|
||||
uploadIntent.putExtra(UploadService.EXTRA_TARGET_FILENAME, titleEdit.getText().toString());
|
||||
uploadIntent.putExtra(UploadService.EXTRA_DESCRIPTION, descEdit.getText().toString());
|
||||
uploadIntent.putExtra(UploadService.EXTRA_MIMETYPE, mimeType);
|
||||
uploadIntent.putExtra(UploadService.EXTRA_EDIT_SUMMARY, "Mobile upload from Wikimedia Commons Android app");
|
||||
startService(uploadIntent);
|
||||
Toast startingToast = Toast.makeText(that, R.string.uploading_started, Toast.LENGTH_LONG);
|
||||
startingToast.show();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onAuthFailure() {
|
||||
super.onAuthFailure();
|
||||
Toast failureToast = Toast.makeText(this, R.string.authentication_failed, Toast.LENGTH_LONG);
|
||||
failureToast.show();
|
||||
finish();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
//Actionbar overlay on top of imageview (should be called before .setcontentview)
|
||||
requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
|
||||
|
||||
setContentView(R.layout.activity_share);
|
||||
|
||||
app = (CommonsApplication)this.getApplicationContext();
|
||||
|
||||
backgroundImageView = (ImageView)findViewById(R.id.backgroundImage);
|
||||
titleEdit = (EditText)findViewById(R.id.titleEdit);
|
||||
descEdit = (EditText)findViewById(R.id.descEdit);
|
||||
uploadButton = (Button)findViewById(R.id.uploadButton);
|
||||
|
||||
requestAuthToken();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getSupportMenuInflater().inflate(R.menu.activity_share, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
NavUtils.navigateUpFromSameTask(this);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
}
|
||||
217
commons/src/main/java/org/wikimedia/commons/UploadService.java
Normal file
217
commons/src/main/java/org/wikimedia/commons/UploadService.java
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
package org.wikimedia.commons;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Date;
|
||||
|
||||
import org.mediawiki.api.*;
|
||||
import org.wikimedia.commons.media.Media;
|
||||
|
||||
import in.yuvi.http.fluent.ProgressListener;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.database.Cursor;
|
||||
import android.os.*;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.text.method.DateTimeKeyListener;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.Toast;
|
||||
import android.net.*;
|
||||
|
||||
public class UploadService extends IntentService {
|
||||
|
||||
private static final String EXTRA_PREFIX = "org.wikimedia.commons.uploader";
|
||||
public static final String EXTRA_MEDIA_URI = EXTRA_PREFIX + ".media_uri";
|
||||
public static final String EXTRA_TARGET_FILENAME = EXTRA_PREFIX + ".filename";
|
||||
public static final String EXTRA_DESCRIPTION = EXTRA_PREFIX + ".description";
|
||||
public static final String EXTRA_EDIT_SUMMARY = EXTRA_PREFIX + ".summary";
|
||||
public static final String EXTRA_MIMETYPE = EXTRA_PREFIX + ".mimetype";
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private CommonsApplication app;
|
||||
|
||||
public UploadService(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public UploadService() {
|
||||
super("UploadService");
|
||||
}
|
||||
// DO NOT HAVE NOTIFICATION ID OF 0 FOR ANYTHING
|
||||
// See http://stackoverflow.com/questions/8725909/startforeground-does-not-show-my-notification
|
||||
// Seriously, Android?
|
||||
public static final int NOTIFICATION_DOWNLOAD_IN_PROGRESS = 1;
|
||||
public static final int NOTIFICATION_DOWNLOAD_COMPLETE = 2;
|
||||
public static final int NOTIFICATION_UPLOAD_FAILED = 3;
|
||||
|
||||
private class NotificationUpdateProgressListener implements ProgressListener {
|
||||
|
||||
Notification curNotification;
|
||||
String notificationTag;
|
||||
boolean notificationTitleChanged;
|
||||
|
||||
String notificationProgressTitle;
|
||||
String notificationFinishingTitle;
|
||||
|
||||
private int lastPercent = 0;
|
||||
|
||||
public NotificationUpdateProgressListener(Notification curNotification, String notificationTag, String notificationProgressTitle, String notificationFinishingTitle) {
|
||||
this.curNotification = curNotification;
|
||||
this.notificationTag = notificationTag;
|
||||
this.notificationProgressTitle = notificationProgressTitle;
|
||||
this.notificationFinishingTitle = notificationFinishingTitle;
|
||||
}
|
||||
@Override
|
||||
public void onProgress(long transferred, long total) {
|
||||
RemoteViews curView = curNotification.contentView;
|
||||
if(!notificationTitleChanged) {
|
||||
curView.setTextViewText(R.id.uploadNotificationTitle, notificationProgressTitle);
|
||||
notificationTitleChanged = false;
|
||||
startForeground(NOTIFICATION_DOWNLOAD_IN_PROGRESS, curNotification);
|
||||
}
|
||||
int percent =(int) ((double)transferred / (double)total * 100);
|
||||
if(percent > lastPercent) {
|
||||
curNotification.contentView.setProgressBar(R.id.uploadNotificationProgress, 100, percent, false);
|
||||
startForeground(NOTIFICATION_DOWNLOAD_IN_PROGRESS, curNotification);
|
||||
lastPercent = percent;
|
||||
}
|
||||
if(percent == 100) {
|
||||
// Completed!
|
||||
curView.setTextViewText(R.id.uploadNotificationTitle, notificationFinishingTitle);
|
||||
startForeground(NOTIFICATION_DOWNLOAD_IN_PROGRESS, curNotification);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
Log.d("Commons", "ZOMG I AM BEING KILLED HALP!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
||||
app = (CommonsApplication)this.getApplicationContext();
|
||||
}
|
||||
|
||||
private String getRealPathFromURI(Uri contentUri) {
|
||||
String[] proj = { MediaStore.Images.Media.DATA };
|
||||
CursorLoader loader = new CursorLoader(this, contentUri, proj, null, null, null);
|
||||
Cursor cursor = loader.loadInBackground();
|
||||
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
||||
cursor.moveToFirst();
|
||||
return cursor.getString(column_index);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
MWApi api = app.getApi();
|
||||
InputStream file = null;
|
||||
long length = 0;
|
||||
ApiResult result;
|
||||
RemoteViews notificationView;
|
||||
|
||||
Bundle extras = intent.getExtras();
|
||||
Uri mediaUri = (Uri)extras.getParcelable(EXTRA_MEDIA_URI);
|
||||
String filename = intent.getStringExtra(EXTRA_TARGET_FILENAME);
|
||||
String description = intent.getStringExtra(EXTRA_DESCRIPTION);
|
||||
String editSummary = intent.getStringExtra(EXTRA_EDIT_SUMMARY);
|
||||
String mimeType = intent.getStringExtra(EXTRA_MIMETYPE);
|
||||
String notificationTag = mediaUri.toString();
|
||||
Date dateCreated = null;
|
||||
|
||||
try {
|
||||
Log.d("Commons", "MimeType is " + mimeType);
|
||||
if(mimeType.startsWith("image/")) {
|
||||
file = this.getContentResolver().openInputStream(mediaUri);
|
||||
length = this.getContentResolver().openAssetFileDescriptor(mediaUri, "r").getLength();
|
||||
Cursor cursor = this.getContentResolver().query(mediaUri,
|
||||
new String[] { MediaStore.Images.ImageColumns.DATE_TAKEN }, null, null, null);
|
||||
if(cursor.getCount() != 0) {
|
||||
cursor.moveToFirst();
|
||||
dateCreated = new Date(cursor.getLong(0));
|
||||
}
|
||||
} else if (mimeType.startsWith("audio/")) {
|
||||
/* Removed Audio implementationf or now */
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
notificationView = new RemoteViews(getPackageName(), R.layout.layout_upload_progress);
|
||||
notificationView.setTextViewText(R.id.uploadNotificationTitle, String.format(getString(R.string.upload_progress_notification_title_start), filename));
|
||||
notificationView.setProgressBar(R.id.uploadNotificationProgress, 100, 0, false);
|
||||
|
||||
Log.d("Commons", "Before execution!");
|
||||
Notification progressNotification = new NotificationCompat.Builder(this).setAutoCancel(true)
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setAutoCancel(true)
|
||||
.setContent(notificationView)
|
||||
.setOngoing(true)
|
||||
.setContentIntent(PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), 0))
|
||||
.setTicker(String.format(getString(R.string.upload_progress_notification_title_in_progress), filename))
|
||||
.getNotification();
|
||||
|
||||
this.startForeground(NOTIFICATION_DOWNLOAD_IN_PROGRESS, progressNotification);
|
||||
|
||||
Log.d("Commons", "Just before");
|
||||
NotificationUpdateProgressListener notificationUpdater = new NotificationUpdateProgressListener(progressNotification, notificationTag,
|
||||
String.format(getString(R.string.upload_progress_notification_title_in_progress), filename),
|
||||
String.format(getString(R.string.upload_progress_notification_title_finishing), filename)
|
||||
);
|
||||
try {
|
||||
if(!api.validateLogin()) {
|
||||
// Need to revalidate!
|
||||
if(app.revalidateAuthToken()) {
|
||||
Log.d("Commons", "Successfully revalidated token!");
|
||||
} else {
|
||||
Log.d("Commons", "Unable to revalidate :(");
|
||||
// TODO: Put up a new notification, ask them to re-login
|
||||
stopForeground(true);
|
||||
Toast failureToast = Toast.makeText(this, R.string.authentication_failed, Toast.LENGTH_LONG);
|
||||
failureToast.show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
Media media = new Media(mediaUri, filename, description, editSummary, app.getCurrentAccount().name, dateCreated);
|
||||
result = api.upload(filename, file, length, media.getPageContents(), editSummary, notificationUpdater);
|
||||
} catch (IOException e) {
|
||||
Log.d("Commons", "I have a network fuckup");
|
||||
stopForeground(true);
|
||||
Notification failureNotification = new NotificationCompat.Builder(this).setAutoCancel(true)
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setAutoCancel(true)
|
||||
.setContentIntent(PendingIntent.getService(getApplicationContext(), 0, intent, 0))
|
||||
.setTicker(String.format(getString(R.string.upload_failed_notification_title), filename))
|
||||
.setContentTitle(String.format(getString(R.string.upload_failed_notification_title), filename))
|
||||
.setContentText(getString(R.string.upload_failed_notification_subtitle))
|
||||
.getNotification();
|
||||
notificationManager.notify(NOTIFICATION_UPLOAD_FAILED, failureNotification);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d("Commons", "Response is" + CommonsApplication.getStringFromDOM(result.getDocument()));
|
||||
stopForeground(true);
|
||||
|
||||
String descUrl = result.getString("/api/upload/imageinfo/@descriptionurl");
|
||||
|
||||
Intent openUploadedPageIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(descUrl));
|
||||
Notification doneNotification = new NotificationCompat.Builder(this)
|
||||
.setAutoCancel(true)
|
||||
.setSmallIcon(R.drawable.ic_launcher)
|
||||
.setContentTitle(String.format(getString(R.string.upload_completed_notification_title), filename))
|
||||
.setContentText(getString(R.string.upload_completed_notification_text))
|
||||
.setTicker(String.format(getString(R.string.upload_completed_notification_title), filename))
|
||||
.setContentIntent(PendingIntent.getActivity(this, 0, openUploadedPageIntent, 0))
|
||||
.getNotification();
|
||||
|
||||
notificationManager.notify(notificationTag, NOTIFICATION_DOWNLOAD_COMPLETE, doneNotification);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
package org.wikimedia.commons.auth;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.wikimedia.commons.CommonsApplication;
|
||||
|
||||
import com.actionbarsherlock.app.*;
|
||||
|
||||
import android.accounts.*;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class AuthenticatedActivity extends SherlockActivity {
|
||||
|
||||
|
||||
String accountType;
|
||||
CommonsApplication app;
|
||||
|
||||
public AuthenticatedActivity(String accountType) {
|
||||
this.accountType = accountType;
|
||||
}
|
||||
|
||||
|
||||
private class GetAuthCookieTask extends AsyncTask<Void, String, String> {
|
||||
private Account account;
|
||||
private AccountManager accountManager;
|
||||
public GetAuthCookieTask(Account account, AccountManager accountManager) {
|
||||
this.account = account;
|
||||
this.accountManager = accountManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String result) {
|
||||
super.onPostExecute(result);
|
||||
if(result != null) {
|
||||
onAuthCookieAcquired(result);
|
||||
} else {
|
||||
onAuthFailure();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
try {
|
||||
return accountManager.blockingGetAuthToken(account, "", false);
|
||||
} catch (OperationCanceledException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (AuthenticatorException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class AddAccountTask extends AsyncTask<Void, String, String> {
|
||||
private AccountManager accountManager;
|
||||
public AddAccountTask(AccountManager accountManager) {
|
||||
this.accountManager = accountManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String result) {
|
||||
super.onPostExecute(result);
|
||||
if(result != null) {
|
||||
Account[] allAccounts =accountManager.getAccountsByType(accountType);
|
||||
Account curAccount = allAccounts[0];
|
||||
GetAuthCookieTask getCookieTask = new GetAuthCookieTask(curAccount, accountManager);
|
||||
getCookieTask.execute();
|
||||
} else {
|
||||
onAuthFailure();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
AccountManagerFuture<Bundle> resultFuture = accountManager.addAccount(accountType, null, null, null, AuthenticatedActivity.this, null, null);
|
||||
Bundle result;
|
||||
try {
|
||||
result = resultFuture.getResult();
|
||||
} catch (OperationCanceledException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (AuthenticatorException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
if(result.containsKey(AccountManager.KEY_ACCOUNT_NAME)) {
|
||||
return result.getString(AccountManager.KEY_ACCOUNT_NAME);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
protected void requestAuthToken() {
|
||||
AccountManager accountManager = AccountManager.get(this);
|
||||
Account curAccount = app.getCurrentAccount();
|
||||
if(curAccount == null) {
|
||||
AddAccountTask addAccountTask = new AddAccountTask(accountManager);
|
||||
// This AsyncTask blocks until the Login Activity returns
|
||||
// And since in Android 4.x+ only one background thread runs all AsyncTasks
|
||||
// And since LoginActivity can't return until it's own AsyncTask (that does the login)
|
||||
// returns, we have a deadlock!
|
||||
// Fixed by explicitly asking this to be executed in parallel
|
||||
// See: https://groups.google.com/forum/?fromgroups=#!topic/android-developers/8M0RTFfO7-M
|
||||
CommonsApplication.executeAsyncTask(addAccountTask);
|
||||
} else {
|
||||
GetAuthCookieTask task = new GetAuthCookieTask(curAccount, accountManager);
|
||||
task.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
app = (CommonsApplication)this.getApplicationContext();
|
||||
}
|
||||
|
||||
protected void onAuthCookieAcquired(String authCookie) {
|
||||
|
||||
}
|
||||
protected void onAuthFailure() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
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.util.Log;
|
||||
import android.view.*;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import android.support.v4.app.NavUtils;
|
||||
|
||||
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<String, String, String> {
|
||||
|
||||
Activity context;
|
||||
ProgressDialog dialog;
|
||||
String username;
|
||||
String password;
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String result) {
|
||||
super.onPostExecute(result);
|
||||
Log.d("Commons", "Login done!");
|
||||
if (result.equals("Success")) {
|
||||
dialog.dismiss();
|
||||
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);
|
||||
dialog.dismiss();
|
||||
failureToast.show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
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) {
|
||||
username = params[0];
|
||||
password = params[1];
|
||||
try {
|
||||
return app.getApi().login(username, password);
|
||||
} catch (IOException e) {
|
||||
// Do something better!
|
||||
return "Failure";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
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);
|
||||
final Activity that = this;
|
||||
loginButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String username = usernameEdit.getText().toString();
|
||||
// Because Mediawiki is upercase-first-char-then-case-sensitive :)
|
||||
String canonicalUsername = username.substring(0,1).toUpperCase() + username.substring(1);
|
||||
|
||||
String password = passwordEdit.getText().toString();
|
||||
|
||||
Log.d("Commons", "Login to start!");
|
||||
LoginTask task = new LoginTask(that);
|
||||
task.execute(canonicalUsername, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.activity_login, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
NavUtils.navigateUpFromSameTask(this);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
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;
|
||||
import android.util.Log;
|
||||
|
||||
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.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 {
|
||||
// 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!
|
||||
e.printStackTrace();
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
64
commons/src/main/java/org/wikimedia/commons/media/Media.java
Normal file
64
commons/src/main/java/org/wikimedia/commons/media/Media.java
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package org.wikimedia.commons.media;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import android.net.*;
|
||||
|
||||
public class Media {
|
||||
private Uri mediaUri;
|
||||
private String fileName;
|
||||
private String editSummary;
|
||||
private String mimeType;
|
||||
private String description;
|
||||
private String userName;
|
||||
private Date dateCreated;
|
||||
private Date dateUploaded;
|
||||
|
||||
public Media(Uri mediaUri, String fileName, String description, String editSummary, String userName, Date dateCreated) {
|
||||
this.mediaUri = mediaUri;
|
||||
this.fileName = fileName;
|
||||
this.description = description;
|
||||
this.editSummary = editSummary;
|
||||
this.userName = userName;
|
||||
this.dateCreated = dateCreated;
|
||||
}
|
||||
|
||||
public Uri getMediaUri() {
|
||||
return mediaUri;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public String getEditSummary() {
|
||||
return editSummary;
|
||||
}
|
||||
|
||||
public String getPageContents() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
buffer
|
||||
.append("== {{int:filedesc}} ==\n")
|
||||
.append("{{Information")
|
||||
.append("|Description=").append(description)
|
||||
.append("|source=").append("{{own}}")
|
||||
.append("|author=[[User:").append(userName).append("]]");
|
||||
if(dateCreated != null) {
|
||||
buffer
|
||||
.append("|date={{According to EXIF data|").append(isoFormat.format(dateCreated)).append("}}");
|
||||
}
|
||||
buffer
|
||||
.append("}}").append("\n")
|
||||
.append("== {{int:license-header}} ==\n")
|
||||
.append("{{self|cc-by-sa-3.0}}")
|
||||
;
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return mimeType;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue