fixed #425
fixed #423
This commit is contained in:
Mariotaku Lee 2016-03-03 22:39:03 +08:00
parent fcc7abf5e3
commit b1fd5c7fdc
10 changed files with 126 additions and 113 deletions

View File

@ -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;
}
}

View File

@ -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')

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -82,12 +82,17 @@ public class TwidereMediaDownloader implements MediaDownloader, Constants {
@Override
public CacheDownloadLoader.DownloadResult get(@NonNull String url, Object extra) throws IOException {
try {
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);
} else {
return getInternal(url, extra);
}
}
return getInternal(url, extra);
} catch (IOException e) {
if (extra instanceof MediaExtra) {
final String fallbackUrl = ((MediaExtra) extra).getFallbackUrl();

View File

@ -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