123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
-
- package fr.greweb.reactnativeviewshot;
-
- import android.app.Activity;
- import android.content.Context;
- import android.net.Uri;
- import android.os.AsyncTask;
- import android.support.annotation.NonNull;
- import android.util.DisplayMetrics;
- import android.util.Log;
-
- import com.facebook.react.bridge.GuardedAsyncTask;
- import com.facebook.react.bridge.Promise;
- import com.facebook.react.bridge.ReactApplicationContext;
- import com.facebook.react.bridge.ReactContext;
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
- import com.facebook.react.bridge.ReactMethod;
- import com.facebook.react.bridge.ReadableMap;
- import com.facebook.react.uimanager.UIManagerModule;
-
- import java.io.File;
- import java.io.FilenameFilter;
- import java.io.IOException;
- import java.util.Collections;
- import java.util.Map;
-
- import fr.greweb.reactnativeviewshot.ViewShot.Formats;
- import fr.greweb.reactnativeviewshot.ViewShot.Results;
-
- public class RNViewShotModule extends ReactContextBaseJavaModule {
-
- public static final String RNVIEW_SHOT = "RNViewShot";
-
- private final ReactApplicationContext reactContext;
-
- public RNViewShotModule(ReactApplicationContext reactContext) {
- super(reactContext);
- this.reactContext = reactContext;
- }
-
- @Override
- public String getName() {
- return RNVIEW_SHOT;
- }
-
- @Override
- public Map<String, Object> getConstants() {
- return Collections.emptyMap();
- }
-
- @Override
- public void onCatalystInstanceDestroy() {
- super.onCatalystInstanceDestroy();
- new CleanTask(getReactApplicationContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- @ReactMethod
- public void releaseCapture(String uri) {
- final String path = Uri.parse(uri).getPath();
- if (path == null) return;
- File file = new File(path);
- if (!file.exists()) return;
- File parent = file.getParentFile();
- if (parent.equals(reactContext.getExternalCacheDir()) || parent.equals(reactContext.getCacheDir())) {
- file.delete();
- }
- }
-
- @ReactMethod
- public void captureRef(int tag, ReadableMap options, Promise promise) {
- final ReactApplicationContext context = getReactApplicationContext();
- final DisplayMetrics dm = context.getResources().getDisplayMetrics();
-
- final String extension = options.getString("format");
- final int imageFormat = "jpg".equals(extension)
- ? Formats.JPEG
- : "webm".equals(extension)
- ? Formats.WEBP
- : "raw".equals(extension)
- ? Formats.RAW
- : Formats.PNG;
-
- final double quality = options.getDouble("quality");
- final Integer scaleWidth = options.hasKey("width") ? (int) (dm.density * options.getDouble("width")) : null;
- final Integer scaleHeight = options.hasKey("height") ? (int) (dm.density * options.getDouble("height")) : null;
- final String resultStreamFormat = options.getString("result");
- final Boolean snapshotContentContainer = options.getBoolean("snapshotContentContainer");
-
- try {
- File outputFile = null;
- if (Results.TEMP_FILE.equals(resultStreamFormat)) {
- outputFile = createTempFile(getReactApplicationContext(), extension);
- }
-
- final Activity activity = getCurrentActivity();
- final UIManagerModule uiManager = this.reactContext.getNativeModule(UIManagerModule.class);
-
- uiManager.addUIBlock(new ViewShot(
- tag, extension, imageFormat, quality,
- scaleWidth, scaleHeight, outputFile, resultStreamFormat,
- snapshotContentContainer, reactContext, activity, promise)
- );
- } catch (final Throwable ex) {
- Log.e(RNVIEW_SHOT, "Failed to snapshot view tag " + tag, ex);
- promise.reject(ViewShot.ERROR_UNABLE_TO_SNAPSHOT, "Failed to snapshot view tag " + tag);
- }
- }
-
- @ReactMethod
- public void captureScreen(ReadableMap options, Promise promise) {
- captureRef(-1, options, promise);
- }
-
- private static final String TEMP_FILE_PREFIX = "ReactNative-snapshot-image";
-
- /**
- * Asynchronous task that cleans up cache dirs (internal and, if available, external) of cropped
- * image files. This is run when the catalyst instance is being destroyed (i.e. app is shutting
- * down) and when the module is instantiated, to handle the case where the app crashed.
- */
- private static class CleanTask extends GuardedAsyncTask<Void, Void> implements FilenameFilter {
- private final File cacheDir;
- private final File externalCacheDir;
-
- private CleanTask(ReactContext context) {
- super(context);
-
- cacheDir = context.getCacheDir();
- externalCacheDir = context.getExternalCacheDir();
- }
-
- @Override
- protected void doInBackgroundGuarded(Void... params) {
- if (null != cacheDir) {
- cleanDirectory(cacheDir);
- }
-
- if (externalCacheDir != null) {
- cleanDirectory(externalCacheDir);
- }
- }
-
- @Override
- public final boolean accept(File dir, String filename) {
- return filename.startsWith(TEMP_FILE_PREFIX);
- }
-
- private void cleanDirectory(@NonNull final File directory) {
- final File[] toDelete = directory.listFiles(this);
-
- if (toDelete != null) {
- for (File file : toDelete) {
- if (file.delete()) {
- Log.d(RNVIEW_SHOT, "deleted file: " + file.getAbsolutePath());
- }
- }
- }
- }
- }
-
- /**
- * Create a temporary file in the cache directory on either internal or external storage,
- * whichever is available and has more free space.
- */
- @NonNull
- private File createTempFile(@NonNull final Context context, @NonNull final String ext) throws IOException {
- final File externalCacheDir = context.getExternalCacheDir();
- final File internalCacheDir = context.getCacheDir();
- final File cacheDir;
-
- if (externalCacheDir == null && internalCacheDir == null) {
- throw new IOException("No cache directory available");
- }
-
- if (externalCacheDir == null) {
- cacheDir = internalCacheDir;
- } else if (internalCacheDir == null) {
- cacheDir = externalCacheDir;
- } else {
- cacheDir = externalCacheDir.getFreeSpace() > internalCacheDir.getFreeSpace() ?
- externalCacheDir : internalCacheDir;
- }
-
- final String suffix = "." + ext;
- return File.createTempFile(TEMP_FILE_PREFIX, suffix, cacheDir);
- }
- }
|