1
0
mirror of https://github.com/TwidereProject/Twidere-Android synced 2025-02-02 17:56:56 +01:00

improving extension

This commit is contained in:
Mariotaku Lee 2016-02-27 18:58:52 +08:00
parent ca20ca865e
commit d4ca49ccdc
11 changed files with 224 additions and 71 deletions

View File

@ -18,12 +18,10 @@
*/
package org.mariotaku.twidere;
import org.mariotaku.twidere.model.MediaUploadResult;
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
import org.mariotaku.twidere.model.UploaderMediaItem;
interface IMediaUploader {
MediaUploadResult upload(in ParcelableStatusUpdate status, in UploaderMediaItem[] media);
String upload(String statusJson, String mediaJson);
boolean callback(String resultJson, String statusJson);
}

View File

@ -18,11 +18,9 @@
*/
package org.mariotaku.twidere;
import org.mariotaku.twidere.model.Account;
interface ITimelineSyncHelper {
boolean put(in Account account, String key, long value);
boolean put(long accountId, String key, long value);
long get(in Account account, String key);
long get(long accountId, String key);
}

View File

@ -3,20 +3,30 @@ package org.mariotaku.twidere.model;
import android.os.Parcel;
import android.os.Parcelable;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
import java.util.Arrays;
@ParcelablePlease
@JsonObject
public class MediaUploadResult implements Parcelable {
@ParcelableThisPlease
@JsonField(name = "media_uris")
public String[] media_uris;
@ParcelableThisPlease
@JsonField(name = "error_code")
public int error_code;
@ParcelableThisPlease
@JsonField(name = "error_message")
public String error_message;
@ParcelableThisPlease
@JsonField(name = "extras")
public String extras;
public static final Creator<MediaUploadResult> CREATOR = new Creator<MediaUploadResult>() {
public MediaUploadResult createFromParcel(Parcel source) {
MediaUploadResult target = new MediaUploadResult();
@ -29,6 +39,9 @@ public class MediaUploadResult implements Parcelable {
}
};
MediaUploadResult() {
}
public MediaUploadResult(final int errorCode, final String errorMessage) {
if (errorCode == 0) throw new IllegalArgumentException("Error code must not be 0");
media_uris = null;
@ -36,9 +49,6 @@ public class MediaUploadResult implements Parcelable {
error_message = errorMessage;
}
MediaUploadResult() {
}
public MediaUploadResult(final String[] mediaUris) {
if (mediaUris == null) throw new IllegalArgumentException("Media uris must not be null");
media_uris = mediaUris;
@ -46,14 +56,6 @@ public class MediaUploadResult implements Parcelable {
error_message = null;
}
public static MediaUploadResult getInstance(final int errorCode, final String errorMessage) {
return new MediaUploadResult(errorCode, errorMessage);
}
public static MediaUploadResult getInstance(final String... mediaUris) {
return new MediaUploadResult(mediaUris);
}
@Override
public String toString() {
return "MediaUploadResult{media_uris=" + Arrays.toString(media_uris) + ", error_code=" + error_code
@ -69,4 +71,12 @@ public class MediaUploadResult implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
MediaUploadResultParcelablePlease.writeToParcel(this, dest, flags);
}
public static MediaUploadResult getInstance(final int errorCode, final String errorMessage) {
return new MediaUploadResult(errorCode, errorMessage);
}
public static MediaUploadResult getInstance(final String... mediaUris) {
return new MediaUploadResult(mediaUris);
}
}

View File

@ -28,14 +28,13 @@ public class TwitLongerReaderActivity extends Activity implements Constants, OnC
private ParcelableStatus mStatus;
private TwitLongerReaderTask mTwitLongerPostTask;
private static final Pattern PATTERN_TWITLONGER = Pattern.compile(
"((tl\\.gd|www.twitlonger.com\\/show)\\/([\\w\\d]+))", Pattern.CASE_INSENSITIVE);
"((tl\\.gd|www.twitlonger.com/show)/([\\w\\d]+))", Pattern.CASE_INSENSITIVE);
private static final int GROUP_TWITLONGER_ID = 3;
@Override
public void onClick(final View view) {
switch (view.getId()) {
case R.id.action: {
if (mResult == null) {
if (mStatus == null) return;
if (mTwitLongerPostTask != null) {
@ -43,11 +42,11 @@ public class TwitLongerReaderActivity extends Activity implements Constants, OnC
}
final Matcher m = PATTERN_TWITLONGER.matcher(mStatus.text_html);
if (m.find()) {
mTwitLongerPostTask = new TwitLongerReaderTask(m.group(GROUP_TWITLONGER_ID));
mTwitLongerPostTask.execute();
mTwitLongerPostTask = new TwitLongerReaderTask(this);
mTwitLongerPostTask.execute(m.group(GROUP_TWITLONGER_ID));
}
} else {
if (mUser == null || mResult == null) return;
if (mUser == null) return;
final Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, "@" + mUser + ": " + mResult);
@ -89,8 +88,8 @@ public class TwitLongerReaderActivity extends Activity implements Constants, OnC
if (mTwitLongerPostTask != null) {
mTwitLongerPostTask.cancel(true);
}
mTwitLongerPostTask = new TwitLongerReaderTask(m.group(GROUP_TWITLONGER_ID));
mTwitLongerPostTask.execute();
mTwitLongerPostTask = new TwitLongerReaderTask(this);
mTwitLongerPostTask.execute(m.group(GROUP_TWITLONGER_ID));
} else {
finish();
return;
@ -109,12 +108,12 @@ public class TwitLongerReaderActivity extends Activity implements Constants, OnC
super.onSaveInstanceState(outState);
}
public final class TwitLongerReaderTask extends AsyncTask<String, Object, TaskResponse<Post, TwitLongerException>> {
public static class TwitLongerReaderTask extends AsyncTask<String, Object, TaskResponse<Post, TwitLongerException>> {
private final String id;
private final TwitLongerReaderActivity activity;
public TwitLongerReaderTask(final String id) {
this.id = id;
public TwitLongerReaderTask(TwitLongerReaderActivity activity) {
this.activity = activity;
}
@Override
@ -129,23 +128,37 @@ public class TwitLongerReaderActivity extends Activity implements Constants, OnC
@Override
protected void onPostExecute(final TaskResponse<Post, TwitLongerException> result) {
mProgress.setVisibility(View.GONE);
mActionButton.setVisibility(View.VISIBLE);
if (result.hasError()) {
mActionButton.setImageResource(R.drawable.ic_menu_send);
activity.showError(result.getThrowable());
} else {
mActionButton.setImageResource(R.drawable.ic_menu_share);
activity.showResult(result.getObject());
}
super.onPostExecute(result);
}
@Override
protected void onPreExecute() {
mProgress.setVisibility(View.VISIBLE);
mActionButton.setVisibility(View.GONE);
super.onPreExecute();
activity.showProgress();
}
}
private void showProgress() {
mProgress.setVisibility(View.VISIBLE);
mActionButton.setVisibility(View.GONE);
}
private void showResult(Post post) {
mProgress.setVisibility(View.GONE);
mActionButton.setVisibility(View.VISIBLE);
mActionButton.setImageResource(R.drawable.ic_menu_share);
mPreview.setText(post.content);
}
private void showError(TwitLongerException e) {
mProgress.setVisibility(View.GONE);
mActionButton.setVisibility(View.VISIBLE);
mActionButton.setImageResource(R.drawable.ic_menu_send);
}
}

View File

@ -0,0 +1,87 @@
package org.mariotaku.twidere.service;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import org.mariotaku.twidere.IMediaUploader;
import org.mariotaku.twidere.model.MediaUploadResult;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
import org.mariotaku.twidere.model.UploaderMediaItem;
import org.mariotaku.twidere.util.LoganSquareMapperFinder;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.List;
/**
* Abstract media uploader service
* <p/>
* Created by mariotaku on 16/2/27.
*/
public abstract class MediaUploaderService extends Service {
private final MediaUploaderStub mBinder = new MediaUploaderStub(this);
public final IBinder onBind(final Intent intent) {
return mBinder;
}
protected abstract MediaUploadResult upload(ParcelableStatusUpdate status,
UploaderMediaItem[] media);
protected abstract boolean callback(MediaUploadResult result, ParcelableStatus status);
/*
* By making this a static class with a WeakReference to the Service, we
* ensure that the Service can be GCd even when the system process still has
* a remote reference to the stub.
*/
private static final class MediaUploaderStub extends IMediaUploader.Stub {
final WeakReference<MediaUploaderService> mService;
public MediaUploaderStub(final MediaUploaderService service) {
mService = new WeakReference<>(service);
}
@Override
public String upload(String statusJson, String mediaJson) throws RemoteException {
try {
final ParcelableStatusUpdate statusUpdate = LoganSquareMapperFinder.mapperFor(ParcelableStatusUpdate.class)
.parse(statusJson);
final List<UploaderMediaItem> media = LoganSquareMapperFinder.mapperFor(UploaderMediaItem.class)
.parseList(mediaJson);
final MediaUploadResult shorten = mService.get().upload(statusUpdate, media.toArray(new UploaderMediaItem[media.size()]));
return LoganSquareMapperFinder.mapperFor(MediaUploadResult.class).serialize(shorten);
} catch (IOException e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
throw new RemoteException(e.getMessage());
} else {
throw new RemoteException();
}
}
}
@Override
public boolean callback(String resultJson, String statusJson) throws RemoteException {
try {
final MediaUploadResult result = LoganSquareMapperFinder.mapperFor(MediaUploadResult.class)
.parse(resultJson);
final ParcelableStatus status = LoganSquareMapperFinder.mapperFor(ParcelableStatus.class)
.parse(statusJson);
return mService.get().callback(result, status);
} catch (IOException e) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
throw new RemoteException(e.getMessage());
} else {
throw new RemoteException();
}
}
}
}
}

View File

@ -16,12 +16,14 @@ import java.io.IOException;
import java.lang.ref.WeakReference;
/**
* Abstract status shortener service
* <p/>
* Created by mariotaku on 16/2/20.
*/
public abstract class StatusShortenerService extends Service {
private final StatusShortenerStub mBinder = new StatusShortenerStub(this);
public IBinder onBind(final Intent intent) {
public final IBinder onBind(final Intent intent) {
return mBinder;
}

View File

@ -518,6 +518,23 @@ public class BackgroundOperationService extends IntentService implements Constan
if (uploader == null) {
throw new UploaderNotFoundException(getString(R.string.error_message_media_uploader_not_found));
}
try {
uploader.checkService(new AbsServiceInterface.CheckServiceAction() {
@Override
public void check(@Nullable Bundle metaData) throws AbsServiceInterface.CheckServiceException {
if (metaData == null) throw new ExtensionVersionMismatchException();
final String extensionVersion = metaData.getString(METADATA_KEY_EXTENSION_VERSION_MEDIA_UPLOADER);
if (!TextUtils.equals(extensionVersion, getString(R.string.media_uploader_service_interface_version))) {
throw new ExtensionVersionMismatchException();
}
}
});
} catch (AbsServiceInterface.CheckServiceException e) {
if (e instanceof ExtensionVersionMismatchException) {
throw new UploadException(getString(R.string.uploader_version_incompatible));
}
throw new UploadException(e);
}
}
if (!ServicePickerPreference.isNoneValue(shortenerComponent)) {
shortener = StatusShortenerInterface.getInstance(app, shortenerComponent);
@ -577,8 +594,8 @@ public class BackgroundOperationService extends IntentService implements Constan
String statusText = statusUpdate.text;
// Use custom uploader to upload media
MediaUploadResult uploadResult = null;
if (uploader != null && hasMedia) {
final MediaUploadResult uploadResult;
try {
uploadResult = uploader.upload(statusUpdate,
UploaderMediaItem.getFromStatusUpdate(this, statusUpdate));
@ -685,6 +702,9 @@ public class BackgroundOperationService extends IntentService implements Constan
if (shouldShorten && shortener != null && shortenedResult != null) {
shortener.callback(shortenedResult, result);
}
if (uploader != null && uploadResult != null) {
uploader.callback(uploadResult, result);
}
results.add(SingleResponse.getInstance(result));
} catch (final TwitterException e) {
Log.w(LOGTAG, e);
@ -869,13 +889,6 @@ public class BackgroundOperationService extends IntentService implements Constan
}
}
static class StatusTooLongException extends UpdateStatusException {
public StatusTooLongException(final Context context) {
super(context.getString(R.string.error_message_status_too_long));
}
}
static class UpdateStatusException extends Exception {
public UpdateStatusException() {
super();

View File

@ -30,6 +30,8 @@ import android.support.annotation.Nullable;
import android.util.Log;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.model.MediaUploadResult;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.ServiceUtils.ServiceToken;
import static org.mariotaku.twidere.util.ServiceUtils.bindToService;

View File

@ -30,18 +30,57 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.IMediaUploader;
import org.mariotaku.twidere.model.MediaUploadResult;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
import org.mariotaku.twidere.model.UploaderMediaItem;
import java.util.List;
public final class MediaUploaderInterface extends AbsServiceInterface<IMediaUploader> implements IMediaUploader {
public final class MediaUploaderInterface extends AbsServiceInterface<IMediaUploader> {
protected MediaUploaderInterface(Context context, String uploaderName, Bundle metaData) {
super(context, uploaderName, metaData);
}
public MediaUploadResult upload(final ParcelableStatusUpdate status, final UploaderMediaItem[] media)
throws RemoteException {
final IMediaUploader iface = getInterface();
if (iface == null) return null;
try {
final String statusJson = JsonSerializer.serialize(status, ParcelableStatusUpdate.class);
final String mediaJson = JsonSerializer.serialize(media, UploaderMediaItem.class);
return JsonSerializer.parse(iface.upload(statusJson, mediaJson), MediaUploadResult.class);
} catch (final RemoteException e) {
if (BuildConfig.DEBUG) {
Log.w(LOGTAG, e);
}
}
return null;
}
public boolean callback(MediaUploadResult uploadResult, ParcelableStatus status) {
final IMediaUploader iface = getInterface();
if (iface == null) return false;
try {
final String resultJson = JsonSerializer.serialize(uploadResult, MediaUploadResult.class);
final String statusJson = JsonSerializer.serialize(status, ParcelableStatus.class);
return iface.callback(resultJson, statusJson);
} catch (final RemoteException e) {
if (BuildConfig.DEBUG) {
Log.w(LOGTAG, e);
}
}
return false;
}
@Override
protected IMediaUploader onServiceConnected(ComponentName service, IBinder obj) {
return IMediaUploader.Stub.asInterface(obj);
}
public static MediaUploaderInterface getInstance(final Application application, final String uploaderName) {
if (uploaderName == null) return null;
final Intent intent = new Intent(INTENT_ACTION_EXTENSION_UPLOAD_MEDIA);
@ -52,22 +91,4 @@ public final class MediaUploaderInterface extends AbsServiceInterface<IMediaUplo
if (services.size() != 1) return null;
return new MediaUploaderInterface(application, uploaderName, services.get(0).serviceInfo.metaData);
}
@Override
public MediaUploadResult upload(final ParcelableStatusUpdate status, final UploaderMediaItem[] media)
throws RemoteException {
final IMediaUploader iface = getInterface();
if (iface == null) return null;
try {
return iface.upload(status, media);
} catch (final RemoteException e) {
Log.w(LOGTAG, e);
}
return null;
}
@Override
protected IMediaUploader onServiceConnected(ComponentName service, IBinder obj) {
return IMediaUploader.Stub.asInterface(obj);
}
}

View File

@ -28,7 +28,9 @@ import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import org.mariotaku.twidere.BuildConfig;
import org.mariotaku.twidere.IStatusShortener;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableStatusUpdate;
@ -57,8 +59,11 @@ public final class StatusShortenerInterface extends AbsServiceInterface<IStatusS
final String resultJson = iface.shorten(statusJson, currentAccountId, overrideStatusText);
return JsonSerializer.parse(resultJson, StatusShortenResult.class);
} catch (final RemoteException e) {
return null;
if (BuildConfig.DEBUG) {
Log.w(LOGTAG, e);
}
}
return null;
}
public boolean callback(StatusShortenResult result, ParcelableStatus status) {
@ -69,8 +74,11 @@ public final class StatusShortenerInterface extends AbsServiceInterface<IStatusS
final String statusJson = JsonSerializer.serialize(status, ParcelableStatus.class);
return iface.callback(resultJson, statusJson);
} catch (final RemoteException e) {
return false;
if (BuildConfig.DEBUG) {
Log.w(LOGTAG, e);
}
}
return false;
}
public static StatusShortenerInterface getInstance(final Application application, final String shortenerName) {

View File

@ -752,5 +752,6 @@
<string name="status_menu_title_format"><xliff:g id="name">%1$s</xliff:g>: <xliff:g id="text">%2$s</xliff:g></string>
<string name="translate_from_language">Translate from <xliff:g id="language">%s</xliff:g></string>
<string name="translation">Translation</string>
<string name="shortener_version_incompatible">Incompatible shortener</string>
<string name="shortener_version_incompatible">Incompatible tweet shortener</string>
<string name="uploader_version_incompatible">Incompatible media uploader</string>
</resources>