Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android][iOS] Upgrade react-native-view-shot to 3.4.0 #19405

Merged
merged 7 commits into from Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -9,6 +9,7 @@ Package-specific changes not released in any SDK will be added here just before

- Updated `@stripe/stripe-react-native` from `0.13.1` to `0.18.1` on iOS. ([#19055](https://github.com/expo/expo/pull/19055) by [@tsapeta](https://github.com/tsapeta))
- Updated `@shopify/flash-list` from `1.1.0` to `1.3.0`. ([#19317](https://github.com/expo/expo/pull/19317) by [@kudo](https://github.com/kudo))
- Updated `react-native-view-shot` from `3.3.0` to `3.4.0`. ([#19405](https://github.com/expo/expo/pull/19405) by [@douglowder](https://github.com/douglowder))
- Updated `react-native-webview` from `11.23.0` to `11.23.1`. ([#19375](https://github.com/expo/expo/pull/19375) by [@aleqsio](https://github.com/aleqsio))
- Updated `react-native-gesture-handler` from `2.5.0` to `2.7.0`. ([#19362](https://github.com/expo/expo/pull/19362) by [@tsapeta](https://github.com/tsapeta))
- Updated `@react-native-picker/picker` from `2.4.2` to `2.4.6`. ([#19390](https://github.com/expo/expo/pull/19390) by [@aleqsio](https://github.com/aleqsio))
Expand Down
Expand Up @@ -84,11 +84,12 @@ public void captureRef(int tag, ReadableMap options, Promise promise) {
: 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 Integer scaleWidth = options.hasKey("width") ? options.getInt("width") : null;
final Integer scaleHeight = options.hasKey("height") ? options.getInt("height") : null;
final String resultStreamFormat = options.getString("result");
final String fileName = options.hasKey("fileName") ? options.getString("fileName") : null;
final Boolean snapshotContentContainer = options.getBoolean("snapshotContentContainer");
final boolean handleGLSurfaceView = options.hasKey("handleGLSurfaceViewOnAndroid") && options.getBoolean("handleGLSurfaceViewOnAndroid");

try {
File outputFile = null;
Expand All @@ -102,7 +103,7 @@ public void captureRef(int tag, ReadableMap options, Promise promise) {
uiManager.addUIBlock(new ViewShot(
tag, extension, imageFormat, quality,
scaleWidth, scaleHeight, outputFile, resultStreamFormat,
snapshotContentContainer, reactContext, activity, promise)
snapshotContentContainer, reactContext, activity, handleGLSurfaceView, promise)
);
} catch (final Throwable ex) {
Log.e(RNVIEW_SHOT, "Failed to snapshot view tag " + tag, ex);
Expand Down
@@ -0,0 +1,29 @@

package versioned.host.exp.exponent.modules.api.viewshot;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.bridge.JavaScriptModule;
public class RNViewShotPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new RNViewShotModule(reactContext));
}

// Deprecated RN 0.47
// @Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Expand Up @@ -8,16 +8,20 @@
import android.graphics.Paint;
import android.graphics.Point;
import android.net.Uri;

import android.os.Build;
import android.os.Handler;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.StringDef;

import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.util.Base64;
import android.util.Log;
import android.view.PixelCopy;
import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -44,6 +48,8 @@
import java.util.Locale;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.zip.Deflater;

import javax.annotation.Nullable;
Expand Down Expand Up @@ -71,6 +77,10 @@ public class ViewShot implements UIBlock, LifecycleEventListener {
* ARGB size in bytes.
*/
private static final int ARGB_SIZE = 4;
/**
* Wait timeout for surface view capture.
*/
private static final int SURFACE_VIEW_READ_PIXELS_TIMEOUT = 5;

private HandlerThread mBgThread;
private Handler mBgHandler;
Expand Down Expand Up @@ -157,6 +167,7 @@ public void run() {
private final Boolean snapshotContentContainer;
@SuppressWarnings({"unused", "FieldCanBeLocal"})
private final ReactApplicationContext reactContext;
private final boolean handleGLSurfaceView;
private final Activity currentActivity;
//endregion

Expand All @@ -174,6 +185,7 @@ public ViewShot(
final Boolean snapshotContentContainer,
final ReactApplicationContext reactContext,
final Activity currentActivity,
final boolean handleGLSurfaceView,
final Promise promise) {
this.tag = tag;
this.extension = extension;
Expand All @@ -186,6 +198,7 @@ public ViewShot(
this.snapshotContentContainer = snapshotContentContainer;
this.reactContext = reactContext;
this.currentActivity = currentActivity;
this.handleGLSurfaceView = handleGLSurfaceView;
this.promise = promise;

reactContext.addLifecycleEventListener(this);
Expand Down Expand Up @@ -405,26 +418,54 @@ private Point captureViewImpl(@NonNull final View view, @NonNull final OutputStr

for (final View child : childrenList) {
// skip any child that we don't know how to process
if (!(child instanceof TextureView)) continue;

// skip all invisible to user child views
if (child.getVisibility() != VISIBLE) continue;

final TextureView tvChild = (TextureView) child;
tvChild.setOpaque(false); // <-- switch off background fill

// NOTE (olku): get re-usable bitmap. TextureView should use bitmaps with matching size,
// otherwise content of the TextureView will be scaled to provided bitmap dimensions
final Bitmap childBitmapBuffer = tvChild.getBitmap(getExactBitmapForScreenshot(child.getWidth(), child.getHeight()));

final int countCanvasSave = c.save();
applyTransformations(c, view, child);

// due to re-use of bitmaps for screenshot, we can get bitmap that is bigger in size than requested
c.drawBitmap(childBitmapBuffer, 0, 0, paint);

c.restoreToCount(countCanvasSave);
recycleBitmap(childBitmapBuffer);
if (child instanceof TextureView) {
// skip all invisible to user child views
if (child.getVisibility() != VISIBLE) continue;

final TextureView tvChild = (TextureView) child;
tvChild.setOpaque(false); // <-- switch off background fill

// NOTE (olku): get re-usable bitmap. TextureView should use bitmaps with matching size,
// otherwise content of the TextureView will be scaled to provided bitmap dimensions
final Bitmap childBitmapBuffer = tvChild.getBitmap(getExactBitmapForScreenshot(child.getWidth(), child.getHeight()));

final int countCanvasSave = c.save();
applyTransformations(c, view, child);

// due to re-use of bitmaps for screenshot, we can get bitmap that is bigger in size than requested
c.drawBitmap(childBitmapBuffer, 0, 0, paint);

c.restoreToCount(countCanvasSave);
recycleBitmap(childBitmapBuffer);
} else if (child instanceof SurfaceView && handleGLSurfaceView) {
final SurfaceView svChild = (SurfaceView)child;
final CountDownLatch latch = new CountDownLatch(1);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
final Bitmap childBitmapBuffer = getExactBitmapForScreenshot(child.getWidth(), child.getHeight());
try {
PixelCopy.request(svChild, childBitmapBuffer, new PixelCopy.OnPixelCopyFinishedListener() {
@Override
public void onPixelCopyFinished(int copyResult) {
final int countCanvasSave = c.save();
applyTransformations(c, view, child);
c.drawBitmap(childBitmapBuffer, 0, 0, paint);
c.restoreToCount(countCanvasSave);
recycleBitmap(childBitmapBuffer);
latch.countDown();
}
}, new Handler(Looper.getMainLooper()));
latch.await(SURFACE_VIEW_READ_PIXELS_TIMEOUT, TimeUnit.SECONDS);
} catch (Exception e) {
Log.e(TAG, "Cannot PixelCopy for " + svChild, e);
}
} else {
Bitmap cache = svChild.getDrawingCache();
if (cache != null) {
c.drawBitmap(svChild.getDrawingCache(), 0, 0, paint);
}
}
}
}

if (width != null && height != null && (width != w || height != h)) {
Expand Down
24 changes: 12 additions & 12 deletions apps/bare-expo/ios/Podfile.lock
Expand Up @@ -1357,18 +1357,18 @@ SPEC CHECKSUMS:
react-native-view-shot: da768466e1cd371de50a3a5c722d1e95456b5b2c
react-native-viewpager: b99b53127d830885917ef84809c5065edd614a78
react-native-webview: d33e2db8925d090871ffeb232dfa50cb3a727581
React-perflogger: 6009895616a455781293950bbd63d53cfc7ffbc5
React-RCTActionSheet: 5e90aa5712af18bfc86c2c6d97d4dbe0e5451c1d
React-RCTAnimation: 50c44d6501f8bfb2fe885e544501f8798b4ff3d6
React-RCTBlob: 3cc08e7112dd7b77faf3fa481ba22ca2bba5f20a
React-RCTImage: ca8335860b5f64c383ad27f52a28d85089d49b7a
React-RCTLinking: 297cd91bdbf427efc861fc7943e6d683e61860fa
React-RCTNetwork: 8a197bff6f1dc5353484507a4cdcd47e9356316f
React-RCTSettings: d3db1f1e61a5ad8deb50f44f5cb6c7c3ef32b3ac
React-RCTText: c2c05ab3dbfb1cf5855b14802f392148970e48da
React-RCTVibration: 89e2cbea456ac5ec623943661d00e4dc45fe74b9
React-runtimeexecutor: 80065f60af4f4b05603661070c8622bb3740bf16
ReactCommon: 1209130f460e4aa9d255ddc75fa0a827ebf93dfb
React-perflogger: 48c6b363e867d64b682e84f80ca45636bd65e19c
React-RCTActionSheet: 33c74fe5c754835e3715c300618da9aa2f7203fa
React-RCTAnimation: 2dbf0120d4d1ab7716079b4180f2ca89c465e46b
React-RCTBlob: ccf17363f809c5030746fdb56641527e6bf9adb7
React-RCTImage: 88a61b23cd5a6feb8d4436f1e306d9f2ecee3462
React-RCTLinking: c63a07ce60a6cb7642acebc80a447fb3f1872eba
React-RCTNetwork: f79b6e7c64e7317d34dec7dcfabd1279a6c1d2e7
React-RCTSettings: 1ff0f34d41646c7942adea36ab5706320e693756
React-RCTText: 7cb05abb91cae0ab7841d551e811ccefa3714dbd
React-RCTVibration: e9164827303fb6a5cf79e4c4af4846a09956b11f
React-runtimeexecutor: a11d0c2e14140baf1e449264ca9168ae9ae6bbd0
ReactCommon: 7f86326b92009925c6dcf93f8e825060171c379f
douglowder marked this conversation as resolved.
Show resolved Hide resolved
RNCAsyncStorage: 466b9df1a14bccda91da86e0b7d9a345d78e1673
RNCMaskedView: c298b644a10c0c142055b3ae24d83879ecb13ccd
RNCPicker: 2f71e09c52ab6327e2c393213368ea0e5bfbcb65
Expand Down
2 changes: 1 addition & 1 deletion apps/bare-expo/package.json
Expand Up @@ -118,7 +118,7 @@
"react-native-screens": "~3.18.0",
"react-native-shared-element": "0.8.4",
"react-native-svg": "12.3.0",
"react-native-view-shot": "3.3.0",
"react-native-view-shot": "3.4.0",
"react-native-webview": "11.23.1",
"test-suite": "*"
},
Expand Down
2 changes: 1 addition & 1 deletion apps/native-component-list/package.json
Expand Up @@ -155,7 +155,7 @@
"react-native-screens": "~3.18.0",
"react-native-shared-element": "0.8.4",
"react-native-svg": "12.3.0",
"react-native-view-shot": "3.3.0",
"react-native-view-shot": "3.4.0",
"react-native-web": "~0.18.9",
"react-native-webview": "11.23.1",
"react-navigation": "^4.4.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/expo/bundledNativeModules.json
Expand Up @@ -99,7 +99,7 @@
"react-native-screens": "~3.18.0",
"react-native-shared-element": "0.8.4",
"react-native-svg": "12.3.0",
"react-native-view-shot": "3.3.0",
"react-native-view-shot": "3.4.0",
"react-native-webview": "11.23.1",
"sentry-expo": "~5.0.0",
"unimodules-app-loader": "~3.1.0",
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Expand Up @@ -17305,10 +17305,10 @@ react-native-svg@12.3.0:
css-select "^4.2.1"
css-tree "^1.0.0-alpha.39"

react-native-view-shot@3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/react-native-view-shot/-/react-native-view-shot-3.3.0.tgz#7f0c6d2e09e5af770f5b74231a72625b379d60f8"
integrity sha512-dc3ZHCd0lvn1jtSI8bPQDta8YxzCvZ73vA8zzFH4S3TRlXLe8r5DF3wUUBlWv1p/bxbEa/A0J4kMUPeVt/v8TQ==
react-native-view-shot@3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/react-native-view-shot/-/react-native-view-shot-3.4.0.tgz#787b31b2d0525a197864e12aaea214e905e97f9a"
integrity sha512-b0CcWJGO0xLCXRsstIYRUEg/UStrR7uujQV9jFHRIVyPfBH0gRplT7Vlgimr+PX+Xg+9/rCyIKPjqK1Knv8hxg==

react-native-web@~0.18.9:
version "0.18.9"
Expand Down