零距离 v1.0版本的 MD5 值为:250cd43fb2f0f5dc8d41b0026cf86adf
以下内容为反编译后的 SkiaPooledImageRegionDecoder.java 源代码,内容仅作参考
package io.dcloud.feature.nativeObj.photoview.subscaleview.decoder;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.support.v4.media.session.PlaybackStateCompat;
import android.text.TextUtils;
import android.util.Log;
import com.dmcbig.mediapicker.PickerConfig;
import io.dcloud.feature.nativeObj.photoview.subscaleview.SubsamplingScaleImageView;
import java.io.File;
import java.io.FileFilter;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.regex.Pattern;
public class SkiaPooledImageRegionDecoder implements ImageRegionDecoder {
private static final String ASSET_PREFIX = "file:///android_asset/";
private static final String FILE_PREFIX = "file://";
private static final String RESOURCE_PREFIX = "android.resource://";
private static final String TAG = "SkiaPooledImageRegionDecoder";
private static boolean debug = false;
private final Bitmap.Config bitmapConfig;
private Context context;
private final ReadWriteLock decoderLock;
private DecoderPool decoderPool;
private long fileLength;
private final Point imageDimensions;
private final AtomicBoolean lazyInited;
private Uri uri;
public static class DecoderPool {
private final Semaphore available;
private final Map<BitmapRegionDecoder, Boolean> decoders;
private DecoderPool() {
this.available = new Semaphore(0, true);
this.decoders = new ConcurrentHashMap();
}
public BitmapRegionDecoder acquire() {
this.available.acquireUninterruptibly();
return getNextAvailable();
}
public synchronized void add(BitmapRegionDecoder bitmapRegionDecoder) {
this.decoders.put(bitmapRegionDecoder, Boolean.FALSE);
this.available.release();
}
private synchronized BitmapRegionDecoder getNextAvailable() {
for (Map.Entry<BitmapRegionDecoder, Boolean> entry : this.decoders.entrySet()) {
if (!entry.getValue().booleanValue()) {
entry.setValue(Boolean.TRUE);
return entry.getKey();
}
}
return null;
}
public synchronized boolean isEmpty() {
return this.decoders.isEmpty();
}
private synchronized boolean markAsUnused(BitmapRegionDecoder bitmapRegionDecoder) {
for (Map.Entry<BitmapRegionDecoder, Boolean> entry : this.decoders.entrySet()) {
if (bitmapRegionDecoder == entry.getKey()) {
if (entry.getValue().booleanValue()) {
entry.setValue(Boolean.FALSE);
return true;
}
return false;
}
}
return false;
}
public synchronized void recycle() {
while (!this.decoders.isEmpty()) {
BitmapRegionDecoder acquire = acquire();
acquire.recycle();
this.decoders.remove(acquire);
}
}
public void release(BitmapRegionDecoder bitmapRegionDecoder) {
if (markAsUnused(bitmapRegionDecoder)) {
this.available.release();
}
}
public synchronized int size() {
return this.decoders.size();
}
}
public SkiaPooledImageRegionDecoder() {
this(null);
}
public void debug(String str) {
if (debug) {
Log.d(TAG, str);
}
}
private int getNumCoresOldPhones() {
try {
return new File("/sys/devices/system/cpu/").listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return Pattern.matches("cpu[0-9]+", file.getName());
}
}).length;
} catch (Exception unused) {
return 1;
}
}
private int getNumberOfCores() {
if (Build.VERSION.SDK_INT >= 17) {
return Runtime.getRuntime().availableProcessors();
}
return getNumCoresOldPhones();
}
public void initialiseDecoder() throws Exception {
BitmapRegionDecoder bitmapRegionDecoder;
Resources resourcesForApplication;
int i;
String uri = this.uri.toString();
boolean startsWith = uri.startsWith(RESOURCE_PREFIX);
long j = PickerConfig.DEFAULT_SELECTED_MAX_SIZE;
if (startsWith) {
String authority = this.uri.getAuthority();
if (this.context.getPackageName().equals(authority)) {
resourcesForApplication = this.context.getResources();
} else {
resourcesForApplication = this.context.getPackageManager().getResourcesForApplication(authority);
}
List<String> pathSegments = this.uri.getPathSegments();
int size = pathSegments.size();
if (size == 2 && pathSegments.get(0).equals("drawable")) {
i = resourcesForApplication.getIdentifier(pathSegments.get(1), "drawable", authority);
} else {
if (size == 1 && TextUtils.isDigitsOnly(pathSegments.get(0))) {
try {
i = Integer.parseInt(pathSegments.get(0));
} catch (NumberFormatException unused) {
}
}
i = 0;
}
try {
j = this.context.getResources().openRawResourceFd(i).getLength();
} catch (Exception unused2) {
}
bitmapRegionDecoder = BitmapRegionDecoder.newInstance(this.context.getResources().openRawResource(i), false);
} else if (uri.startsWith("file:///android_asset/")) {
String substring = uri.substring(22);
try {
j = this.context.getAssets().openFd(substring).getLength();
} catch (Exception unused3) {
}
bitmapRegionDecoder = BitmapRegionDecoder.newInstance(this.context.getAssets().open(substring, 1), false);
} else if (uri.startsWith("file://")) {
BitmapRegionDecoder newInstance = BitmapRegionDecoder.newInstance(uri.substring(7), false);
try {
File file = new File(uri);
if (file.exists()) {
j = file.length();
}
} catch (Exception unused4) {
}
bitmapRegionDecoder = newInstance;
} else {
InputStream inputStream = null;
try {
ContentResolver contentResolver = this.context.getContentResolver();
inputStream = contentResolver.openInputStream(this.uri);
BitmapRegionDecoder newInstance2 = BitmapRegionDecoder.newInstance(inputStream, false);
try {
AssetFileDescriptor openAssetFileDescriptor = contentResolver.openAssetFileDescriptor(this.uri, "r");
if (openAssetFileDescriptor != null) {
j = openAssetFileDescriptor.getLength();
}
} catch (Exception unused5) {
}
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception unused6) {
}
}
bitmapRegionDecoder = newInstance2;
} catch (Throwable th) {
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception unused7) {
}
}
throw th;
}
}
this.fileLength = j;
this.imageDimensions.set(bitmapRegionDecoder.getWidth(), bitmapRegionDecoder.getHeight());
this.decoderLock.writeLock().lock();
try {
DecoderPool decoderPool = this.decoderPool;
if (decoderPool != null) {
decoderPool.add(bitmapRegionDecoder);
}
} finally {
this.decoderLock.writeLock().unlock();
}
}
private boolean isLowMemory() {
ActivityManager activityManager = (ActivityManager) this.context.getSystemService("activity");
if (activityManager != null) {
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
return memoryInfo.lowMemory;
}
return true;
}
private void lazyInit() {
if (!this.lazyInited.compareAndSet(false, true) || this.fileLength >= PickerConfig.DEFAULT_SELECTED_MAX_SIZE) {
return;
}
debug("Starting lazy init of additional decoders");
new Thread() {
@Override
public void run() {
while (SkiaPooledImageRegionDecoder.this.decoderPool != null) {
SkiaPooledImageRegionDecoder skiaPooledImageRegionDecoder = SkiaPooledImageRegionDecoder.this;
if (!skiaPooledImageRegionDecoder.allowAdditionalDecoder(skiaPooledImageRegionDecoder.decoderPool.size(), SkiaPooledImageRegionDecoder.this.fileLength)) {
return;
}
try {
if (SkiaPooledImageRegionDecoder.this.decoderPool != null) {
long currentTimeMillis = System.currentTimeMillis();
SkiaPooledImageRegionDecoder.this.debug("Starting decoder");
SkiaPooledImageRegionDecoder.this.initialiseDecoder();
long currentTimeMillis2 = System.currentTimeMillis();
SkiaPooledImageRegionDecoder skiaPooledImageRegionDecoder2 = SkiaPooledImageRegionDecoder.this;
skiaPooledImageRegionDecoder2.debug("Started decoder, took " + (currentTimeMillis2 - currentTimeMillis) + "ms");
}
} catch (Exception e) {
SkiaPooledImageRegionDecoder skiaPooledImageRegionDecoder3 = SkiaPooledImageRegionDecoder.this;
skiaPooledImageRegionDecoder3.debug("Failed to start decoder: " + e.getMessage());
}
}
}
}.start();
}
public static void setDebug(boolean z) {
debug = z;
}
protected boolean allowAdditionalDecoder(int i, long j) {
if (i >= 4) {
debug("No additional decoders allowed, reached hard limit (4)");
return false;
}
long j2 = i * j;
if (j2 > 20971520) {
debug("No additional encoders allowed, reached hard memory limit (20Mb)");
return false;
} else if (i >= getNumberOfCores()) {
debug("No additional encoders allowed, limited by CPU cores (" + getNumberOfCores() + ")");
return false;
} else if (isLowMemory()) {
debug("No additional encoders allowed, memory is low");
return false;
} else {
debug("Additional decoder allowed, current count is " + i + ", estimated native memory " + (j2 / PlaybackStateCompat.ACTION_SET_CAPTIONING_ENABLED) + "Mb");
return true;
}
}
@Override
public Bitmap decodeRegion(Rect rect, int i) {
debug("Decode region " + rect + " on thread " + Thread.currentThread().getName());
if (rect.width() < this.imageDimensions.x || rect.height() < this.imageDimensions.y) {
lazyInit();
}
this.decoderLock.readLock().lock();
try {
DecoderPool decoderPool = this.decoderPool;
if (decoderPool != null) {
BitmapRegionDecoder acquire = decoderPool.acquire();
if (acquire != null && !acquire.isRecycled()) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = i;
options.inPreferredConfig = this.bitmapConfig;
Bitmap decodeRegion = acquire.decodeRegion(rect, options);
if (decodeRegion != null) {
if (acquire != null) {
this.decoderPool.release(acquire);
}
return decodeRegion;
}
throw new RuntimeException("Skia image decoder returned null bitmap - image format may not be supported");
} else if (acquire != null) {
this.decoderPool.release(acquire);
}
}
throw new IllegalStateException("Cannot decode region after decoder has been recycled");
} finally {
this.decoderLock.readLock().unlock();
}
}
@Override
public Point init(Context context, Uri uri) throws Exception {
this.context = context;
this.uri = uri;
initialiseDecoder();
return this.imageDimensions;
}
@Override
public synchronized boolean isReady() {
boolean z;
DecoderPool decoderPool = this.decoderPool;
if (decoderPool != null) {
z = decoderPool.isEmpty() ? false : true;
}
return z;
}
@Override
public synchronized void recycle() {
this.decoderLock.writeLock().lock();
DecoderPool decoderPool = this.decoderPool;
if (decoderPool != null) {
decoderPool.recycle();
this.decoderPool = null;
this.context = null;
this.uri = null;
}
this.decoderLock.writeLock().unlock();
}
public SkiaPooledImageRegionDecoder(Bitmap.Config config) {
this.decoderPool = new DecoderPool();
this.decoderLock = new ReentrantReadWriteLock(true);
this.fileLength = PickerConfig.DEFAULT_SELECTED_MAX_SIZE;
this.imageDimensions = new Point(0, 0);
this.lazyInited = new AtomicBoolean(false);
Bitmap.Config preferredBitmapConfig = SubsamplingScaleImageView.getPreferredBitmapConfig();
if (config != null) {
this.bitmapConfig = config;
} else if (preferredBitmapConfig != null) {
this.bitmapConfig = preferredBitmapConfig;
} else {
this.bitmapConfig = Bitmap.Config.RGB_565;
}
}
}