Make fresco a stand-alone gradle project (#548)

Summary:
Pull Request resolved: https://github.com/facebook/flipper/pull/548

First project to pull out of the "fat distribution" we currently have.
Still needs setup for Maven and registration in Bintray.

Reviewed By: jknoxville

Differential Revision: D17395660

fbshipit-source-id: 6244495a2e25d705dd930ef87c7e5e1f038eb921
This commit is contained in:
Pascal Hartig
2019-09-19 02:58:43 -07:00
committed by Facebook Github Bot
parent a77faa5318
commit 7ac82bec4e
10 changed files with 44 additions and 3 deletions

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
apply plugin: 'com.android.library'
apply plugin: 'maven'
android {
compileSdkVersion rootProject.compileSdkVersion
buildToolsVersion rootProject.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
targetSdkVersion rootProject.targetSdkVersion
}
dependencies {
implementation project(':android')
implementation deps.fresco
implementation deps.frescoFlipper
implementation deps.frescoStetho
compileOnly deps.jsr305
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Facebook, Inc. and its affiliates.
~
~ This source code is licensed under the MIT license found in the LICENSE
~ file in the root directory of this source tree.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.facebook.flipper.plugins.fresco">
</manifest>

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.flipper.plugins.fresco;
public interface FrescoFlipperDebugPrefHelper {
interface Listener {
void onEnabledStatusChanged(boolean enabled);
}
void setDebugOverlayEnabled(boolean enabled);
boolean isDebugOverlayEnabled();
void setDebugOverlayEnabledListener(Listener l);
}

View File

@@ -0,0 +1,500 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.flipper.plugins.fresco;
import android.graphics.Bitmap;
import android.util.Base64;
import com.facebook.cache.common.CacheKey;
import com.facebook.common.internal.Predicate;
import com.facebook.common.memory.manager.DebugMemoryManager;
import com.facebook.common.memory.manager.NoOpDebugMemoryManager;
import com.facebook.common.references.CloseableReference;
import com.facebook.common.references.SharedReference;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.backends.pipeline.info.ImageLoadStatus;
import com.facebook.drawee.backends.pipeline.info.ImageOriginUtils;
import com.facebook.drawee.backends.pipeline.info.ImagePerfData;
import com.facebook.drawee.backends.pipeline.info.ImagePerfDataListener;
import com.facebook.flipper.core.FlipperArray;
import com.facebook.flipper.core.FlipperConnection;
import com.facebook.flipper.core.FlipperObject;
import com.facebook.flipper.core.FlipperReceiver;
import com.facebook.flipper.core.FlipperResponder;
import com.facebook.flipper.perflogger.FlipperPerfLogger;
import com.facebook.flipper.perflogger.NoOpFlipperPerfLogger;
import com.facebook.flipper.plugins.common.BufferingFlipperPlugin;
import com.facebook.flipper.plugins.fresco.objecthelper.FlipperObjectHelper;
import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory;
import com.facebook.imagepipeline.cache.CountingMemoryCacheInspector;
import com.facebook.imagepipeline.cache.CountingMemoryCacheInspector.DumpInfoEntry;
import com.facebook.imagepipeline.core.ImagePipelineFactory;
import com.facebook.imagepipeline.debug.CloseableReferenceLeakTracker;
import com.facebook.imagepipeline.debug.DebugImageTracker;
import com.facebook.imagepipeline.debug.FlipperImageTracker;
import com.facebook.imagepipeline.image.CloseableBitmap;
import com.facebook.imagepipeline.image.CloseableImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Allows Sonar to display the contents of Fresco's caches. This is useful for developers to debug
* what images are being held in cache as they navigate through their app.
*/
public class FrescoFlipperPlugin extends BufferingFlipperPlugin
implements ImagePerfDataListener, CloseableReferenceLeakTracker.Listener {
private static final String FRESCO_EVENT = "events";
private static final String FRESCO_DEBUGOVERLAY_EVENT = "debug_overlay_event";
private static final String FRESCO_CLOSEABLE_REFERENCE_LEAK_EVENT =
"closeable_reference_leak_event";
private static final int BITMAP_PREVIEW_WIDTH = 150;
private static final int BITMAP_PREVIEW_HEIGHT = 150;
private static final int BITMAP_SCALING_THRESHOLD_WIDTH = 200;
private static final int BITMAP_SCALING_THRESHOLD_HEIGHT = 200;
/** Helper for clearing cache. */
private static final Predicate<CacheKey> ALWAYS_TRUE_PREDICATE =
new Predicate<CacheKey>() {
@Override
public boolean apply(CacheKey cacheKey) {
return true;
}
};
private final FlipperImageTracker mFlipperImageTracker;
private final PlatformBitmapFactory mPlatformBitmapFactory;
@Nullable private final FlipperObjectHelper mSonarObjectHelper;
private final DebugMemoryManager mMemoryManager;
private final FlipperPerfLogger mPerfLogger;
@Nullable private final FrescoFlipperDebugPrefHelper mDebugPrefHelper;
private final List<FlipperObject> mEvents = new ArrayList<>();
public FrescoFlipperPlugin(
DebugImageTracker imageTracker,
PlatformBitmapFactory bitmapFactory,
@Nullable FlipperObjectHelper flipperObjectHelper,
DebugMemoryManager memoryManager,
FlipperPerfLogger perfLogger,
@Nullable FrescoFlipperDebugPrefHelper debugPrefHelper,
@Nullable CloseableReferenceLeakTracker closeableReferenceLeakTracker) {
mFlipperImageTracker =
imageTracker instanceof FlipperImageTracker
? (FlipperImageTracker) imageTracker
: new FlipperImageTracker();
mPlatformBitmapFactory = bitmapFactory;
mSonarObjectHelper = flipperObjectHelper;
mMemoryManager = memoryManager;
mPerfLogger = perfLogger;
mDebugPrefHelper = debugPrefHelper;
if (closeableReferenceLeakTracker != null) {
closeableReferenceLeakTracker.setListener(this);
}
}
public FrescoFlipperPlugin() {
this(
new FlipperImageTracker(),
Fresco.getImagePipelineFactory().getPlatformBitmapFactory(),
null,
new NoOpDebugMemoryManager(),
new NoOpFlipperPerfLogger(),
null,
null);
}
public FlipperImageTracker getFlipperImageTracker() {
return mFlipperImageTracker;
}
@Override
public String getId() {
return "Fresco";
}
@Override
public void onConnect(FlipperConnection connection) {
super.onConnect(connection);
connection.receive(
"getAllImageEventsInfo",
new FlipperReceiver() {
@Override
public void onReceive(FlipperObject params, FlipperResponder responder) throws Exception {
if (!ensureFrescoInitialized(responder)) {
return;
}
FlipperArray.Builder arrayBuilder = new FlipperArray.Builder();
for (FlipperObject obj : mEvents) {
arrayBuilder.put(obj);
}
mEvents.clear();
FlipperObject object =
new FlipperObject.Builder().put("events", arrayBuilder.build()).build();
responder.success(object);
}
});
connection.receive(
"listImages",
new FlipperReceiver() {
@Override
public void onReceive(FlipperObject params, FlipperResponder responder) throws Exception {
if (!ensureFrescoInitialized(responder)) {
return;
}
mPerfLogger.startMarker("Sonar.Fresco.listImages");
final ImagePipelineFactory imagePipelineFactory = Fresco.getImagePipelineFactory();
final CountingMemoryCacheInspector.DumpInfo memoryCache =
new CountingMemoryCacheInspector<>(
imagePipelineFactory.getBitmapCountingMemoryCache())
.dumpCacheContent();
responder.success(
getImageList(
memoryCache,
buildImageIdList(memoryCache.sharedEntries),
buildImageIdList(memoryCache.lruEntries)));
mPerfLogger.endMarker("Sonar.Fresco.listImages");
}
});
connection.receive(
"getImage",
new FlipperReceiver() {
@Override
public void onReceive(FlipperObject params, final FlipperResponder responder)
throws Exception {
if (!ensureFrescoInitialized(responder)) {
return;
}
mPerfLogger.startMarker("Sonar.Fresco.getImage");
String imageId = params.getString("imageId");
CacheKey cacheKey = mFlipperImageTracker.getCacheKey(imageId);
if (cacheKey == null) {
respondError(responder, "ImageId " + imageId + " was evicted from cache");
mPerfLogger.cancelMarker("Sonar.Fresco.getImage");
return;
}
final ImagePipelineFactory imagePipelineFactory = Fresco.getImagePipelineFactory();
CloseableReference<CloseableImage> ref =
imagePipelineFactory.getBitmapCountingMemoryCache().get(cacheKey);
if (ref == null) {
respondError(responder, "no bitmap withId=" + imageId);
mPerfLogger.cancelMarker("Sonar.Fresco.getImage");
return;
}
if (ref.get() instanceof CloseableBitmap) {
final CloseableBitmap bitmap = (CloseableBitmap) ref.get();
String encodedBitmap =
bitmapToBase64Preview(bitmap.getUnderlyingBitmap(), mPlatformBitmapFactory);
responder.success(
getImageData(
imageId, encodedBitmap, bitmap, mFlipperImageTracker.getUriString(cacheKey)));
} else {
// TODO: T48376327, it might happened that ref.get() may not be casted to
// CloseableBitmap, this issue is tracked in the before mentioned task
responder.success();
}
mPerfLogger.endMarker("Sonar.Fresco.getImage");
}
});
connection.receive(
"clear",
new FlipperReceiver() {
@Override
public void onReceive(FlipperObject params, FlipperResponder responder) {
if (!ensureFrescoInitialized(responder)) {
return;
}
mPerfLogger.startMarker("Sonar.Fresco.clear");
final String type = params.getString("type");
switch (type) {
case "memory":
final ImagePipelineFactory imagePipelineFactory = Fresco.getImagePipelineFactory();
imagePipelineFactory.getBitmapMemoryCache().removeAll(ALWAYS_TRUE_PREDICATE);
break;
case "disk":
Fresco.getImagePipeline().clearDiskCaches();
break;
}
mPerfLogger.endMarker("Sonar.Fresco.clear");
}
});
connection.receive(
"trimMemory",
new FlipperReceiver() {
@Override
public void onReceive(FlipperObject params, FlipperResponder responder) throws Exception {
if (!ensureFrescoInitialized(responder)) {
return;
}
if (mMemoryManager != null) {
mMemoryManager.trimMemory(
DebugMemoryManager.ON_SYSTEM_LOW_MEMORY_WHILE_APP_IN_FOREGROUND);
}
}
});
connection.receive(
"enableDebugOverlay",
new FlipperReceiver() {
@Override
public void onReceive(FlipperObject params, FlipperResponder responder) throws Exception {
if (!ensureFrescoInitialized(responder)) {
return;
}
final boolean enabled = params.getBoolean("enabled");
if (mDebugPrefHelper != null) {
mDebugPrefHelper.setDebugOverlayEnabled(enabled);
}
}
});
if (mDebugPrefHelper != null) {
mDebugPrefHelper.setDebugOverlayEnabledListener(
new FrescoFlipperDebugPrefHelper.Listener() {
@Override
public void onEnabledStatusChanged(boolean enabled) {
sendDebugOverlayEnabledEvent(enabled);
}
});
sendDebugOverlayEnabledEvent(mDebugPrefHelper.isDebugOverlayEnabled());
}
}
private FlipperObject getImageList(
CountingMemoryCacheInspector.DumpInfo memoryCache,
FlipperArray memoryCacheSharedEntries,
FlipperArray memoryCacheLRUEntries) {
return new FlipperObject.Builder()
.put(
"levels",
new FlipperArray.Builder()
.put(
new FlipperObject.Builder()
.put("cacheType", "On screen bitmaps")
.put("sizeBytes", memoryCache.size - memoryCache.lruSize)
.put("imageIds", memoryCacheSharedEntries)
.build())
.put(
new FlipperObject.Builder()
.put("cacheType", "Bitmap memory cache")
.put("clearKey", "memory")
.put("sizeBytes", memoryCache.size)
.put("maxSizeBytes", memoryCache.maxSize)
.put("imageIds", memoryCacheLRUEntries)
.build())
// TODO (t31947642): list images on disk
.build())
.build();
}
private FlipperObject getImageData(
String imageID, String encodedBitmap, CloseableBitmap bitmap, String uriString) {
return new FlipperObject.Builder()
.put("imageId", imageID)
.put("uri", uriString)
.put("width", bitmap.getWidth())
.put("height", bitmap.getHeight())
.put("sizeBytes", bitmap.getSizeInBytes())
.put("data", encodedBitmap)
.build();
}
private boolean ensureFrescoInitialized(FlipperResponder responder) {
mPerfLogger.startMarker("Sonar.Fresco.ensureFrescoInitialized");
try {
Fresco.getImagePipelineFactory();
return true;
} catch (NullPointerException e) {
respondError(responder, "Fresco is not initialized yet");
return false;
} finally {
mPerfLogger.endMarker("Sonar.Fresco.ensureFrescoInitialized");
}
}
private FlipperArray buildImageIdList(List<DumpInfoEntry<CacheKey, CloseableImage>> images) {
FlipperArray.Builder builder = new FlipperArray.Builder();
for (DumpInfoEntry<CacheKey, CloseableImage> entry : images) {
final FlipperImageTracker.ImageDebugData imageDebugData =
mFlipperImageTracker.getImageDebugData(entry.key);
if (imageDebugData == null) {
builder.put(mFlipperImageTracker.trackImage(entry.key).getUniqueId());
} else {
builder.put(imageDebugData.getUniqueId());
}
}
return builder.build();
}
private String bitmapToBase64Preview(Bitmap bitmap, PlatformBitmapFactory bitmapFactory) {
if (bitmap.getWidth() < BITMAP_SCALING_THRESHOLD_WIDTH
&& bitmap.getHeight() < BITMAP_SCALING_THRESHOLD_HEIGHT) {
return bitmapToBase64WithoutScaling(bitmap);
}
mPerfLogger.startMarker("Sonar.Fresco.bitmap2base64-resize");
// TODO (t19034797): properly load images
CloseableReference<Bitmap> scaledBitmapReference = null;
try {
float previewAspectRatio = BITMAP_PREVIEW_WIDTH / BITMAP_PREVIEW_HEIGHT;
float imageAspectRatio = bitmap.getWidth() / bitmap.getHeight();
int scaledWidth;
int scaledHeight;
if (previewAspectRatio > imageAspectRatio) {
scaledWidth = bitmap.getWidth() * BITMAP_PREVIEW_HEIGHT / bitmap.getHeight();
scaledHeight = BITMAP_PREVIEW_HEIGHT;
} else {
scaledWidth = BITMAP_PREVIEW_WIDTH;
scaledHeight = bitmap.getHeight() * BITMAP_PREVIEW_WIDTH / bitmap.getWidth();
}
scaledBitmapReference =
bitmapFactory.createScaledBitmap(bitmap, scaledWidth, scaledHeight, false);
return bitmapToBase64WithoutScaling(scaledBitmapReference.get());
} finally {
CloseableReference.closeSafely(scaledBitmapReference);
mPerfLogger.endMarker("Sonar.Fresco.bitmap2base64-resize");
}
}
private String bitmapToBase64WithoutScaling(Bitmap bitmap) {
mPerfLogger.startMarker("Sonar.Fresco.bitmap2base64-orig");
ByteArrayOutputStream byteArrayOutputStream = null;
try {
byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
return "data:image/png;base64,"
+ Base64.encodeToString(byteArrayOutputStream.toByteArray(), Base64.DEFAULT);
} finally {
if (byteArrayOutputStream != null) {
try {
byteArrayOutputStream.close();
} catch (IOException e) {
// ignore
}
}
mPerfLogger.endMarker("Sonar.Fresco.bitmap2base64-orig");
}
}
public void onImageLoadStatusUpdated(
ImagePerfData imagePerfData, @ImageLoadStatus int imageLoadStatus) {
if (imageLoadStatus != ImageLoadStatus.SUCCESS) {
return;
}
String requestId = imagePerfData.getRequestId();
if (requestId == null) {
return;
}
FlipperImageTracker.ImageDebugData data =
mFlipperImageTracker.getDebugDataForRequestId(requestId);
if (data == null) {
return;
}
FlipperArray.Builder imageIdsBuilder = new FlipperArray.Builder();
Set<CacheKey> cks = data.getCacheKeys();
if (cks != null) {
for (CacheKey ck : cks) {
FlipperImageTracker.ImageDebugData d = mFlipperImageTracker.getImageDebugData(ck);
if (d != null) {
imageIdsBuilder.put(d.getUniqueId());
}
}
} else {
imageIdsBuilder.put(data.getUniqueId());
}
FlipperArray attribution;
Object callerContext = imagePerfData.getCallerContext();
if (callerContext == null) {
attribution = new FlipperArray.Builder().put("unknown").build();
} else if (mSonarObjectHelper == null) {
attribution = new FlipperArray.Builder().put(callerContext.toString()).build();
} else {
attribution = mSonarObjectHelper.fromCallerContext(callerContext);
}
FlipperObject.Builder response =
new FlipperObject.Builder()
.put("imageIds", imageIdsBuilder.build())
.put("attribution", attribution)
.put("startTime", imagePerfData.getControllerSubmitTimeMs())
.put("endTime", imagePerfData.getControllerFinalImageSetTimeMs())
.put("source", ImageOriginUtils.toString(imagePerfData.getImageOrigin()));
if (!imagePerfData.isPrefetch()) {
response.put(
"viewport",
new FlipperObject.Builder()
// TODO (t31947746): scan times
.put("width", imagePerfData.getOnScreenWidthPx())
.put("height", imagePerfData.getOnScreenHeightPx())
.build());
}
FlipperObject responseObject = response.build();
mEvents.add(responseObject);
send(FRESCO_EVENT, responseObject);
}
public void onImageVisibilityUpdated(ImagePerfData imagePerfData, int visibilityState) {
// ignored
}
public void sendDebugOverlayEnabledEvent(final boolean enabled) {
final FlipperObject.Builder builder = new FlipperObject.Builder().put("enabled", enabled);
send(FRESCO_DEBUGOVERLAY_EVENT, builder.build());
}
private static void respondError(FlipperResponder responder, String errorReason) {
responder.error(new FlipperObject.Builder().put("reason", errorReason).build());
}
@Override
public void onCloseableReferenceLeak(
SharedReference<Object> reference, @Nullable Throwable stacktrace) {
final FlipperObject.Builder builder =
new FlipperObject.Builder()
.put("identityHashCode", System.identityHashCode(reference))
.put("className", reference.get().getClass().getName());
if (stacktrace != null) {
builder.put("stacktrace", getStackTraceString(stacktrace));
}
send(FRESCO_CLOSEABLE_REFERENCE_LEAK_EVENT, builder.build());
}
public static String getStackTraceString(Throwable tr) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
tr.printStackTrace(pw);
return sw.toString();
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.flipper.plugins.fresco;
import com.facebook.imagepipeline.debug.DebugImageTracker;
import com.facebook.imagepipeline.listener.BaseRequestListener;
import com.facebook.imagepipeline.request.ImageRequest;
/** Fresco image {@link RequestListener} that logs events for Sonar. */
public class FrescoFlipperRequestListener extends BaseRequestListener {
private final DebugImageTracker mDebugImageTracker;
public FrescoFlipperRequestListener(DebugImageTracker debugImageTracker) {
mDebugImageTracker = debugImageTracker;
}
@Override
public void onRequestStart(
ImageRequest request, Object callerContext, String requestId, boolean isPrefetch) {
mDebugImageTracker.trackImageRequest(request, requestId);
}
}

View File

@@ -0,0 +1,215 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.flipper.plugins.fresco.objecthelper;
import static com.facebook.flipper.plugins.inspector.InspectorValue.Type.Color;
import android.text.TextUtils;
import com.facebook.drawee.backends.pipeline.info.ImageOriginUtils;
import com.facebook.drawee.backends.pipeline.info.ImagePerfData;
import com.facebook.drawee.generic.RoundingParams;
import com.facebook.flipper.core.FlipperArray;
import com.facebook.flipper.core.FlipperObject;
import com.facebook.flipper.plugins.inspector.InspectorValue;
import com.facebook.imagepipeline.common.ImageDecodeOptions;
import com.facebook.imagepipeline.common.ResizeOptions;
import com.facebook.imagepipeline.common.RotationOptions;
import com.facebook.imagepipeline.debug.FlipperImageTracker;
import com.facebook.imagepipeline.image.ImageInfo;
import com.facebook.imagepipeline.image.QualityInfo;
import com.facebook.imagepipeline.request.ImageRequest;
import java.util.Map;
import javax.annotation.Nullable;
/** Serialization helper to create {@link FlipperObject}s. */
public abstract class FlipperObjectHelper {
public FlipperObject keyValuePair(String key, @Nullable String value) {
return new FlipperObject.Builder().put(key, value).build();
}
@Nullable
public FlipperObject toFlipperObject(@Nullable Map<String, String> stringMap) {
if (stringMap == null) {
return null;
}
FlipperObject.Builder optionsJson = new FlipperObject.Builder();
for (Map.Entry<String, String> entry : stringMap.entrySet()) {
optionsJson.put(entry.getKey(), entry.getValue());
}
return optionsJson.build();
}
@Nullable
public FlipperObject toFlipperObject(@Nullable ImageRequest imageRequest) {
if (imageRequest == null) {
return null;
}
FlipperObject.Builder optionsJson = new FlipperObject.Builder();
return addImageRequestProperties(optionsJson, imageRequest).build();
}
@Nullable
public FlipperObject toFlipperObject(
@Nullable FlipperImageTracker.ImageDebugData imageDebugData) {
if (imageDebugData == null) {
return null;
}
FlipperObject.Builder optionsJson = new FlipperObject.Builder();
optionsJson.put("imageId", imageDebugData.getUniqueId());
optionsJson.put("imageRequest", toFlipperObject(imageDebugData.getImageRequest()));
optionsJson.put(
"requestId",
imageDebugData.getRequestIds() != null
? TextUtils.join(", ", imageDebugData.getRequestIds())
: "");
optionsJson.put("imagePerfData", toFlipperObject(imageDebugData.getImagePerfData()));
return optionsJson.build();
}
@Nullable
public FlipperObject toFlipperObject(@Nullable ImageDecodeOptions options) {
if (options == null) {
return null;
}
FlipperObject.Builder optionsJson = new FlipperObject.Builder();
optionsJson.put("minDecodeIntervalMs", options.minDecodeIntervalMs);
optionsJson.put("decodePreviewFrame", options.decodePreviewFrame);
optionsJson.put("useLastFrameForPreview", options.useLastFrameForPreview);
optionsJson.put("decodeAllFrames", options.decodeAllFrames);
optionsJson.put("forceStaticImage", options.forceStaticImage);
optionsJson.put("bitmapConfig", options.bitmapConfig.name());
optionsJson.put(
"customImageDecoder",
options.customImageDecoder == null ? "" : options.customImageDecoder.toString());
return optionsJson.build();
}
@Nullable
public FlipperObject toFlipperObject(@Nullable ResizeOptions resizeOptions) {
if (resizeOptions == null) {
return null;
}
FlipperObject.Builder optionsJson = new FlipperObject.Builder();
optionsJson.put("width", resizeOptions.width);
optionsJson.put("height", resizeOptions.height);
optionsJson.put("maxBitmapSize", resizeOptions.maxBitmapSize);
optionsJson.put("roundUpFraction", resizeOptions.roundUpFraction);
return optionsJson.build();
}
@Nullable
public FlipperObject toFlipperObject(@Nullable RotationOptions rotationOptions) {
if (rotationOptions == null) {
return null;
}
FlipperObject.Builder optionsJson = new FlipperObject.Builder();
optionsJson.put("rotationEnabled", rotationOptions.rotationEnabled());
optionsJson.put("canDeferUntilRendered", rotationOptions.canDeferUntilRendered());
optionsJson.put("useImageMetadata", rotationOptions.useImageMetadata());
if (!rotationOptions.useImageMetadata()) {
optionsJson.put("forcedAngle", rotationOptions.getForcedAngle());
}
return optionsJson.build();
}
@Nullable
public FlipperObject toFlipperObject(@Nullable RoundingParams roundingParams) {
if (roundingParams == null) {
return null;
}
FlipperObject.Builder optionsJson = new FlipperObject.Builder();
optionsJson.put("borderWidth", roundingParams.getBorderWidth());
optionsJson.put("cornersRadii", toSonarArray(roundingParams.getCornersRadii()));
optionsJson.put("padding", roundingParams.getPadding());
optionsJson.put("roundAsCircle", roundingParams.getRoundAsCircle());
optionsJson.put("roundingMethod", roundingParams.getRoundingMethod());
optionsJson.put(
"borderColor", InspectorValue.immutable(Color, roundingParams.getBorderColor()));
optionsJson.put(
"overlayColor", InspectorValue.immutable(Color, roundingParams.getOverlayColor()));
return optionsJson.build();
}
@Nullable
public FlipperObject toFlipperObject(@Nullable ImagePerfData imagePerfData) {
if (imagePerfData == null) {
return null;
}
FlipperObject.Builder objectJson = new FlipperObject.Builder();
objectJson.put("requestId", imagePerfData.getRequestId());
objectJson.put("controllerSubmitTimeMs", imagePerfData.getControllerSubmitTimeMs());
objectJson.put("controllerFinalTimeMs", imagePerfData.getControllerFinalImageSetTimeMs());
objectJson.put("imageRequestStartTimeMs", imagePerfData.getImageRequestStartTimeMs());
objectJson.put("imageRequestEndTimeMs", imagePerfData.getImageRequestEndTimeMs());
objectJson.put("imageOrigin", ImageOriginUtils.toString(imagePerfData.getImageOrigin()));
objectJson.put("isPrefetch", imagePerfData.isPrefetch());
objectJson.put("callerContext", imagePerfData.getCallerContext());
objectJson.put("imageRequest", toFlipperObject(imagePerfData.getImageRequest()));
objectJson.put("imageInfo", toFlipperObject(imagePerfData.getImageInfo()));
return objectJson.build();
}
@Nullable
public FlipperObject toFlipperObject(ImageInfo imageInfo) {
if (imageInfo == null) {
return null;
}
FlipperObject.Builder objectJson = new FlipperObject.Builder();
objectJson.put("imageWidth", imageInfo.getWidth());
objectJson.put("imageHeight", imageInfo.getHeight());
objectJson.put("qualityInfo", toFlipperObject(imageInfo.getQualityInfo()));
return objectJson.build();
}
@Nullable
public FlipperObject toFlipperObject(QualityInfo qualityInfo) {
if (qualityInfo == null) {
return null;
}
FlipperObject.Builder objectJson = new FlipperObject.Builder();
objectJson.put("quality", qualityInfo.getQuality());
objectJson.put("isGoodEnoughQuality", qualityInfo.isOfGoodEnoughQuality());
objectJson.put("isFullQuality", qualityInfo.isOfFullQuality());
return objectJson.build();
}
public FlipperObject.Builder addImageRequestProperties(
FlipperObject.Builder builder, @Nullable ImageRequest request) {
if (request == null) {
return builder;
}
builder
.put("sourceUri", request.getSourceUri())
.put("preferredWidth", request.getPreferredWidth())
.put("preferredHeight", request.getPreferredHeight())
.put("cacheChoice", request.getCacheChoice())
.put("diskCacheEnabled", request.isDiskCacheEnabled())
.put("localThumbnailPreviewsEnabled", request.getLocalThumbnailPreviewsEnabled())
.put("lowestPermittedRequestLevel", request.getLowestPermittedRequestLevel())
.put("priority", request.getPriority().name())
.put("progressiveRenderingEnabled", request.getProgressiveRenderingEnabled())
.put("postprocessor", String.valueOf(request.getPostprocessor()))
.put("requestListener", String.valueOf(request.getRequestListener()))
.put("imageDecodeOptions", toFlipperObject(request.getImageDecodeOptions()))
.put("bytesRange", request.getBytesRange())
.put("resizeOptions", toFlipperObject(request.getResizeOptions()))
.put("rotationOptions", toFlipperObject(request.getRotationOptions()));
return builder;
}
private FlipperArray toSonarArray(float[] floats) {
final FlipperArray.Builder builder = new FlipperArray.Builder();
for (float f : floats) {
builder.put(f);
}
return builder.build();
}
@Nullable
public abstract FlipperArray fromCallerContext(@Nullable Object callerContext);
}