diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/util/media/preview/provider/TwitterMediaProvider.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/util/media/preview/provider/TwitterMediaProvider.java index 956290f42..eb94e9cb5 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/util/media/preview/provider/TwitterMediaProvider.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/util/media/preview/provider/TwitterMediaProvider.java @@ -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; + } + } diff --git a/twidere/build.gradle b/twidere/build.gradle index 297ec9bb7..30aa80753 100644 --- a/twidere/build.gradle +++ b/twidere/build.gradle @@ -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') diff --git a/twidere/src/androidTest/java/org/mariotaku/twidere/activity/support/ImagePageFragmentTest.java b/twidere/src/androidTest/java/org/mariotaku/twidere/activity/support/ImagePageFragmentTest.java new file mode 100644 index 000000000..564e39f24 --- /dev/null +++ b/twidere/src/androidTest/java/org/mariotaku/twidere/activity/support/ImagePageFragmentTest.java @@ -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()); + } +} \ No newline at end of file diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/MediaViewerActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/MediaViewerActivity.java index 99402bd52..9c7c98611 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/MediaViewerActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/MediaViewerActivity.java @@ -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); } } diff --git a/twidere/src/main/java/org/mariotaku/twidere/provider/CacheProvider.java b/twidere/src/main/java/org/mariotaku/twidere/provider/CacheProvider.java index 8b7d1d94e..64b07cf58 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/provider/CacheProvider.java +++ b/twidere/src/main/java/org/mariotaku/twidere/provider/CacheProvider.java @@ -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 diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/imageviewer/RapidImageDecoder.java b/twidere/src/main/java/org/mariotaku/twidere/util/imageviewer/RapidImageDecoder.java deleted file mode 100644 index 88a870af8..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/imageviewer/RapidImageDecoder.java +++ /dev/null @@ -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(); - } - -} \ No newline at end of file diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/imageviewer/RapidImageRegionDecoder.java b/twidere/src/main/java/org/mariotaku/twidere/util/imageviewer/RapidImageRegionDecoder.java deleted file mode 100644 index aa3d93687..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/imageviewer/RapidImageRegionDecoder.java +++ /dev/null @@ -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. - *

- * 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; - } -} \ No newline at end of file diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/media/MediaExtra.java b/twidere/src/main/java/org/mariotaku/twidere/util/media/MediaExtra.java index 924fb68e1..a26144f05 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/media/MediaExtra.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/media/MediaExtra.java @@ -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; + } } diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/media/TwidereMediaDownloader.java b/twidere/src/main/java/org/mariotaku/twidere/util/media/TwidereMediaDownloader.java index 09b983713..b0d5575f9 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/media/TwidereMediaDownloader.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/media/TwidereMediaDownloader.java @@ -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(); diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/media/UILFileCache.java b/twidere/src/main/java/org/mariotaku/twidere/util/media/UILFileCache.java index 3afe4cfe1..d187c20b0 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/media/UILFileCache.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/media/UILFileCache.java @@ -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