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 all 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
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
4 changes: 2 additions & 2 deletions apps/bare-expo/ios/Podfile.lock
Expand Up @@ -634,7 +634,7 @@ PODS:
- React-Core
- react-native-slider (4.2.3):
- React-Core
- react-native-view-shot (3.3.0):
- react-native-view-shot (3.4.0):
- React-Core
- react-native-viewpager (5.0.11):
- React-Core
Expand Down Expand Up @@ -1354,7 +1354,7 @@ SPEC CHECKSUMS:
react-native-safe-area-context: 6c12e3859b6f27b25de4fee8201cfb858432d8de
react-native-segmented-control: 06607462630512ff8eef652ec560e6235a30cc3e
react-native-slider: 98b724cd3e44c3454a6d0724e796d4e9c52189ce
react-native-view-shot: da768466e1cd371de50a3a5c722d1e95456b5b2c
react-native-view-shot: a60a98a18c72bcaaaf2138f9aab960ae9b0d96c7
react-native-viewpager: b99b53127d830885917ef84809c5065edd614a78
react-native-webview: d33e2db8925d090871ffeb232dfa50cb3a727581
React-perflogger: 6009895616a455781293950bbd63d53cfc7ffbc5
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