parent
fcc7abf5e3
commit
b1fd5c7fdc
|
@ -15,16 +15,7 @@ import java.util.Locale;
|
|||
public class TwitterMediaProvider implements Provider {
|
||||
@Override
|
||||
public boolean supports(@NonNull String link) {
|
||||
final String authority = PreviewMediaExtractor.getAuthority(link);
|
||||
if (authority == null || !authority.endsWith(".twimg.com")) {
|
||||
return false;
|
||||
}
|
||||
final String path = PreviewMediaExtractor.getPath(link);
|
||||
if (path == null) return false;
|
||||
if (path.startsWith("/media/")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return isSupported(link);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -55,4 +46,17 @@ public class TwitterMediaProvider implements Provider {
|
|||
return from(link);
|
||||
}
|
||||
|
||||
public static boolean isSupported(@NonNull String link) {
|
||||
final String authority = PreviewMediaExtractor.getAuthority(link);
|
||||
if (authority == null || !authority.endsWith(".twimg.com")) {
|
||||
return false;
|
||||
}
|
||||
final String path = PreviewMediaExtractor.getPath(link);
|
||||
if (path == null) return false;
|
||||
if (path.startsWith("/media/")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,10 +19,10 @@ android {
|
|||
|
||||
defaultConfig {
|
||||
applicationId "org.mariotaku.twidere"
|
||||
minSdkVersion 21
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 23
|
||||
versionCode 155
|
||||
versionName "3.0.6.4"
|
||||
versionCode 156
|
||||
versionName "3.0.6.5"
|
||||
multiDexEnabled true
|
||||
|
||||
buildConfigField 'boolean', 'LEAK_CANARY_ENABLED', 'Boolean.parseBoolean("false")'
|
||||
|
@ -109,13 +109,10 @@ dependencies {
|
|||
compile 'com.lnikkila:extendedtouchview:0.1.0'
|
||||
compile 'com.google.dagger:dagger:2.0.2'
|
||||
compile 'org.attoparser:attoparser:1.4.0.RELEASE'
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:base:0.9.11'
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:subsample-image-view:0.9.11'
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:base:0.9.12'
|
||||
compile 'com.github.mariotaku.MediaViewerLibrary:subsample-image-view:0.9.12'
|
||||
compile 'com.github.mariotaku.SQLiteQB:library:0.9.5'
|
||||
compile 'com.github.mariotaku.ObjectCursor:core:0.9.5'
|
||||
compile 'rapid.decoder:library:0.3.0'
|
||||
compile 'rapid.decoder:jpeg-decoder:0.3.0'
|
||||
compile 'rapid.decoder:png-decoder:0.3.0'
|
||||
|
||||
compile project(':twidere.component.common')
|
||||
compile project(':twidere.component.nyan')
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package org.mariotaku.twidere.activity.support;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Created by mariotaku on 16/3/3.
|
||||
*/
|
||||
public class ImagePageFragmentTest {
|
||||
|
||||
@Test
|
||||
public void testReplaceTwitterMediaUri() throws Exception {
|
||||
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:large",
|
||||
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
|
||||
"https://pbs.twimg.com/media/DEADBEEF.png:large")).toString());
|
||||
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:orig",
|
||||
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
|
||||
"https://pbs.twimg.com/media/DEADBEEF.png:orig")).toString());
|
||||
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:large",
|
||||
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
|
||||
"https://pbs.twimg.com/media/DEADBEEF.jpg:large")).toString());
|
||||
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:large",
|
||||
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
|
||||
"https://pbs.twimg.com/media/DEADBEEF.jpg:orig")).toString());
|
||||
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png",
|
||||
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
|
||||
"https://pbs.twimg.com/media/DEADBEEF.jpg")).toString());
|
||||
assertEquals("https://pbs.twimg.com/media/DEADBEEF.png:",
|
||||
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
|
||||
"https://pbs.twimg.com/media/DEADBEEF.jpg:")).toString());
|
||||
assertEquals("https://example.com/media/DEADBEEF.jpg",
|
||||
MediaViewerActivity.ImagePageFragment.replaceTwitterMediaUri(Uri.parse(
|
||||
"https://example.com/media/DEADBEEF.jpg")).toString());
|
||||
}
|
||||
}
|
|
@ -93,9 +93,8 @@ import org.mariotaku.twidere.util.PermissionUtils;
|
|||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
import org.mariotaku.twidere.util.Utils;
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
|
||||
import org.mariotaku.twidere.util.imageviewer.RapidImageDecoder;
|
||||
import org.mariotaku.twidere.util.imageviewer.RapidImageRegionDecoder;
|
||||
import org.mariotaku.twidere.util.media.MediaExtra;
|
||||
import org.mariotaku.twidere.util.media.preview.provider.TwitterMediaProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -826,6 +825,13 @@ public final class MediaViewerActivity extends AbsMediaViewerActivity implements
|
|||
protected Object getDownloadExtra() {
|
||||
final MediaExtra mediaExtra = new MediaExtra();
|
||||
mediaExtra.setAccountId(getArguments().getLong(EXTRA_ACCOUNT_ID, -1));
|
||||
final Uri origDownloadUri = super.getDownloadUri();
|
||||
final Uri downloadUri = getDownloadUri();
|
||||
if (origDownloadUri != null && downloadUri != null) {
|
||||
final String fallbackUrl = origDownloadUri.toString();
|
||||
mediaExtra.setFallbackUrl(fallbackUrl);
|
||||
mediaExtra.setSkipUrlReplacing(!fallbackUrl.equals(downloadUri.toString()));
|
||||
}
|
||||
return mediaExtra;
|
||||
}
|
||||
|
||||
|
@ -844,6 +850,36 @@ public final class MediaViewerActivity extends AbsMediaViewerActivity implements
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Uri getDownloadUri() {
|
||||
final Uri downloadUri = super.getDownloadUri();
|
||||
if (downloadUri == null) return null;
|
||||
return replaceTwitterMediaUri(downloadUri);
|
||||
}
|
||||
|
||||
static Uri replaceTwitterMediaUri(Uri downloadUri) {
|
||||
String uriString = downloadUri.toString();
|
||||
if (TwitterMediaProvider.isSupported(uriString)) {
|
||||
final String suffix = ".jpg";
|
||||
int lastIndexOfJpegSuffix = uriString.lastIndexOf(suffix);
|
||||
if (lastIndexOfJpegSuffix == -1) return downloadUri;
|
||||
final int endOfSuffix = lastIndexOfJpegSuffix + suffix.length();
|
||||
if (endOfSuffix == uriString.length()) {
|
||||
return Uri.parse(uriString.substring(0, lastIndexOfJpegSuffix) + ".png");
|
||||
} else {
|
||||
// Seems :orig suffix won't work jpegs -> pngs
|
||||
String sizeSuffix = uriString.substring(endOfSuffix);
|
||||
if (":orig".equals(sizeSuffix)) {
|
||||
sizeSuffix = ":large";
|
||||
}
|
||||
return Uri.parse(uriString.substring(0, lastIndexOfJpegSuffix) + ".png" +
|
||||
sizeSuffix);
|
||||
}
|
||||
}
|
||||
return downloadUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDownloadedData() {
|
||||
return super.hasDownloadedData() && mMediaLoadState != State.ERROR;
|
||||
|
@ -860,8 +896,7 @@ public final class MediaViewerActivity extends AbsMediaViewerActivity implements
|
|||
|
||||
@Override
|
||||
protected void setupImageView(SubsamplingScaleImageView imageView) {
|
||||
imageView.setRegionDecoderClass(RapidImageRegionDecoder.class);
|
||||
imageView.setBitmapDecoderClass(RapidImageDecoder.class);
|
||||
imageView.setMaxScale(getResources().getDisplayMetrics().density);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ import android.webkit.MimeTypeMap;
|
|||
import com.bluelinelabs.logansquare.JsonMapper;
|
||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
||||
|
||||
import org.mariotaku.mediaviewer.library.CacheDownloadLoader;
|
||||
import org.mariotaku.restfu.RestFuUtils;
|
||||
import org.mariotaku.twidere.TwidereConstants;
|
||||
import org.mariotaku.twidere.model.CacheMetadata;
|
||||
|
@ -65,7 +64,11 @@ public class CacheProvider extends ContentProvider implements TwidereConstants {
|
|||
throw new IllegalArgumentException(uri.toString());
|
||||
if (!TwidereConstants.AUTHORITY_TWIDERE_CACHE.equals(uri.getAuthority()))
|
||||
throw new IllegalArgumentException(uri.toString());
|
||||
return CacheDownloadLoader.getExtraKey(ByteString.decodeBase64(uri.getLastPathSegment()).utf8());
|
||||
return getExtraKey(ByteString.decodeBase64(uri.getLastPathSegment()).utf8());
|
||||
}
|
||||
|
||||
public static String getExtraKey(String key) {
|
||||
return key + ".extra";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package org.mariotaku.twidere.util.imageviewer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.davemorrissey.labs.subscaleview.decoder.ImageDecoder;
|
||||
|
||||
import rapid.decoder.BitmapDecoder;
|
||||
|
||||
/**
|
||||
* A very simple implementation of {@link com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder}
|
||||
* using the RapidDecoder library (https://github.com/suckgamony/RapidDecoder). For PNGs, this can
|
||||
* give more reliable decoding and better performance. For JPGs, it is slower and can run out of
|
||||
* memory with large images, but has better support for grayscale and CMYK images.
|
||||
*
|
||||
* This is an incomplete and untested implementation provided as an example only.
|
||||
*/
|
||||
public class RapidImageDecoder implements ImageDecoder {
|
||||
|
||||
@Override
|
||||
public Bitmap decode(Context context, Uri uri) throws Exception {
|
||||
return BitmapDecoder.from(context, uri).useBuiltInDecoder(true).config(Bitmap.Config.RGB_565).decode();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package org.mariotaku.twidere.util.imageviewer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
|
||||
import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder;
|
||||
|
||||
import rapid.decoder.BitmapDecoder;
|
||||
|
||||
/**
|
||||
* A very simple implementation of {@link com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder}
|
||||
* using the RapidDecoder library (https://github.com/suckgamony/RapidDecoder). For PNGs, this can
|
||||
* give more reliable decoding and better performance. For JPGs, it is slower and can run out of
|
||||
* memory with large images, but has better support for grayscale and CMYK images.
|
||||
* <p/>
|
||||
* This is an incomplete and untested implementation provided as an example only.
|
||||
*/
|
||||
public class RapidImageRegionDecoder implements ImageRegionDecoder {
|
||||
|
||||
private BitmapDecoder decoder;
|
||||
|
||||
@Override
|
||||
public Point init(Context context, Uri uri) throws Exception {
|
||||
decoder = BitmapDecoder.from(context, uri);
|
||||
decoder.useBuiltInDecoder(true);
|
||||
return new Point(decoder.sourceWidth(), decoder.sourceHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Bitmap decodeRegion(Rect sRect, int sampleSize) {
|
||||
try {
|
||||
return decoder.reset().region(sRect).scale(sRect.width() / sampleSize, sRect.height() / sampleSize).decode();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady() {
|
||||
return decoder != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recycle() {
|
||||
BitmapDecoder.destroyMemoryCache();
|
||||
BitmapDecoder.destroyDiskCache();
|
||||
try {
|
||||
decoder.reset();
|
||||
} catch (UnsupportedOperationException ignore) {
|
||||
|
||||
}
|
||||
decoder = null;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ public class MediaExtra {
|
|||
long accountId;
|
||||
boolean useThumbor = true;
|
||||
String fallbackUrl;
|
||||
boolean skipUrlReplacing;
|
||||
|
||||
public long getAccountId() {
|
||||
return accountId;
|
||||
|
@ -31,4 +32,12 @@ public class MediaExtra {
|
|||
public void setFallbackUrl(String fallbackUrl) {
|
||||
this.fallbackUrl = fallbackUrl;
|
||||
}
|
||||
|
||||
public boolean isSkipUrlReplacing() {
|
||||
return skipUrlReplacing;
|
||||
}
|
||||
|
||||
public void setSkipUrlReplacing(boolean skipUrlReplacing) {
|
||||
this.skipUrlReplacing = skipUrlReplacing;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,12 +82,17 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
|
|||
@Override
|
||||
public CacheDownloadLoader.DownloadResult get(@NonNull String url, Object extra) throws IOException {
|
||||
try {
|
||||
final ParcelableMedia media = PreviewMediaExtractor.fromLink(url, mClient, extra);
|
||||
if (media != null && media.media_url != null) {
|
||||
return getInternal(media.media_url, extra);
|
||||
} else {
|
||||
return getInternal(url, extra);
|
||||
boolean skipUrlReplacing = false;
|
||||
if (extra instanceof MediaExtra) {
|
||||
skipUrlReplacing = ((MediaExtra) extra).isSkipUrlReplacing();
|
||||
}
|
||||
if (!skipUrlReplacing) {
|
||||
final ParcelableMedia media = PreviewMediaExtractor.fromLink(url, mClient, extra);
|
||||
if (media != null && media.media_url != null) {
|
||||
return getInternal(media.media_url, extra);
|
||||
}
|
||||
}
|
||||
return getInternal(url, extra);
|
||||
} catch (IOException e) {
|
||||
if (extra instanceof MediaExtra) {
|
||||
final String fallbackUrl = ((MediaExtra) extra).getFallbackUrl();
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.nostra13.universalimageloader.utils.IoUtils;
|
|||
import org.mariotaku.mediaviewer.library.FileCache;
|
||||
import org.mariotaku.twidere.provider.CacheProvider;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -34,13 +35,17 @@ public class UILFileCache implements FileCache {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void save(final String key, final InputStream is, final CopyListener listener) throws IOException {
|
||||
public void save(final String key, final InputStream is, byte[] extra,
|
||||
final CopyListener listener) throws IOException {
|
||||
cache.save(key, is, new IoUtils.CopyListener() {
|
||||
@Override
|
||||
public boolean onBytesCopied(final int current, final int total) {
|
||||
return listener == null || listener.onCopied(current);
|
||||
}
|
||||
});
|
||||
if (extra != null) {
|
||||
cache.save(CacheProvider.getExtraKey(key), new ByteArrayInputStream(extra), null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue