@byteplus/react-native-live-pull 1.1.2 → 1.1.3-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  package com.volcengine.velive.rn.pull.pictureInpicture;
2
2
 
3
+ import android.animation.ValueAnimator;
3
4
  import android.app.Service;
4
5
  import android.content.BroadcastReceiver;
5
6
  import android.content.Context;
@@ -24,14 +25,19 @@ import androidx.annotation.Nullable;
24
25
  import com.volcengine.velive.rn.pull.R;
25
26
 
26
27
  public class FloatingWindowService extends Service {
28
+ private static final int MARGIN_TOP = 40;
29
+ private static final int MARGIN_BOTTOM = 40;
30
+ private static final int MARGIN_LEFT = 20;
31
+ private static final int MARGIN_RIGHT = 20;
27
32
  private static final String TAG = FloatingWindowService.class.getSimpleName();
28
- private static final int LONGER_SIDE_MAX_LEN = 1000;
29
33
 
30
34
  private WindowManager mWindowManager;
31
35
  private WindowManager.LayoutParams mLayoutParams;
32
36
  private SurfaceView mSurfaceView;
33
37
  private View mSmallWindowView;
34
38
  private ActivityLaunchReceiver mActivityLaunchReceiver;
39
+ private FloatingOnTouchListener
40
+ mFloatingOnTouchListener; // Store the listener instance
35
41
 
36
42
  public static final String ACTION_STOP_PIP_SERVICE =
37
43
  "com.volcengine.velive.rn.pull.STOP_PIP_SERVICE";
@@ -97,37 +103,68 @@ public class FloatingWindowService extends Service {
97
103
  int screenWidth = displayMetrics.widthPixels;
98
104
  int screenHeight = displayMetrics.heightPixels;
99
105
 
100
- // Calculate the minimum screen dimension
101
- int minScreenDim = Math.min(screenWidth, screenHeight);
106
+ int drawableWidth = screenWidth - MARGIN_LEFT - MARGIN_RIGHT;
107
+ int drawableHeight = screenHeight - MARGIN_TOP - MARGIN_BOTTOM;
102
108
 
103
- // Determine the maximum length based on the smaller of 1000 and
104
- // minScreenDim
105
- int maxLen = Math.min(LONGER_SIDE_MAX_LEN, minScreenDim);
109
+ boolean isPortrait = screenHeight > screenWidth;
110
+
111
+ int maxLen;
112
+ if (isPortrait) {
113
+ // 竖屏时,宽度不能超过 drawableWidth
114
+ maxLen = drawableWidth;
115
+ } else {
116
+ // 横屏时,高度不能超过 drawableHeight
117
+ maxLen = drawableHeight;
118
+ }
106
119
 
107
- // Limit the floating window size to prevent it from being too large or too
108
- // small, control the longer side to maxLen, scale the shorter
109
- // side proportionally
110
120
  int width, height;
111
- if (aspectRatio >= 1) {
112
- height = (int)(maxLen / aspectRatio);
121
+ if (aspectRatio >= 1) { // 宽大于等于高 (横向视频或方形)
113
122
  width = maxLen;
114
- } else {
115
- width = (int)(maxLen * aspectRatio);
123
+ height = (int)(width / aspectRatio);
124
+ if (isPortrait && width > drawableWidth) {
125
+ width = drawableWidth;
126
+ height = (int)(width / aspectRatio);
127
+ }
128
+ if (!isPortrait &&
129
+ height > drawableHeight) { // 横屏下,若计算出的高度超出drawableHeight
130
+ height = drawableHeight;
131
+ width = (int)(height * aspectRatio);
132
+ }
133
+ } else { // 高大于宽 (竖向视频)
116
134
  height = maxLen;
135
+ width = (int)(height * aspectRatio);
136
+ if (!isPortrait && height > drawableHeight) {
137
+ height = drawableHeight;
138
+ width = (int)(height * aspectRatio);
139
+ }
140
+ if (isPortrait &&
141
+ width > drawableWidth) { // 竖屏下,若计算出的宽度超出drawableWidth
142
+ width = drawableWidth;
143
+ height = (int)(width / aspectRatio);
144
+ }
117
145
  }
118
- mLayoutParams.width = width;
119
- mLayoutParams.height = height;
120
146
 
121
- // Initial position of the floating window
122
- mLayoutParams.x = x;
123
- mLayoutParams.y = y;
147
+ // Ensure dimensions are positive
148
+ mLayoutParams.width = Math.max(1, width);
149
+ mLayoutParams.height = Math.max(1, height);
150
+
151
+ // Initial position of the floating window, respecting margins
152
+ mLayoutParams.x =
153
+ Math.max(MARGIN_LEFT,
154
+ Math.min(x, screenWidth - mLayoutParams.width - MARGIN_RIGHT));
155
+ mLayoutParams.y =
156
+ Math.max(MARGIN_TOP, Math.min(y, screenHeight - mLayoutParams.height -
157
+ MARGIN_BOTTOM));
124
158
 
125
159
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
126
160
  if (Settings.canDrawOverlays(this)) {
127
161
  LayoutInflater layoutInflater = LayoutInflater.from(this);
128
162
  mSmallWindowView =
129
163
  layoutInflater.inflate(R.layout.floating_window_layout, null);
130
- mSmallWindowView.setOnTouchListener(new FloatingOnTouchListener());
164
+ this.mFloatingOnTouchListener =
165
+ new FloatingOnTouchListener(); // Create and store the instance
166
+ mSmallWindowView.setOnTouchListener(
167
+ this.mFloatingOnTouchListener); // Set the stored instance
131
168
  mWindowManager.addView(mSmallWindowView, mLayoutParams);
132
169
  mSurfaceView = mSmallWindowView.findViewById(R.id.surface_view);
133
170
  mSmallWindowView.findViewById(R.id.surface_close_btn)
@@ -204,6 +241,8 @@ public class FloatingWindowService extends Service {
204
241
  }
205
242
 
206
243
  private class FloatingOnTouchListener implements View.OnTouchListener {
244
+ private boolean isDoubleClickAnimating =
245
+ false; // Flag to indicate if double-click animation is running
207
246
  private final int touchSlop =
208
247
  ViewConfiguration
209
248
  .get(FloatingWindowService.this.getApplicationContext())
@@ -212,36 +251,289 @@ public class FloatingWindowService extends Service {
212
251
  private int x, y;
213
252
  private boolean isDragging;
214
253
 
254
+ private static final int MODE_NONE = 0;
255
+ private static final int MODE_DRAG = 1;
256
+ private static final int MODE_ZOOM = 2;
257
+ private int mode = MODE_NONE;
258
+
259
+ private float oldDist = 1f;
260
+ private float initialAspectRatio;
261
+ private int initialWidth;
262
+ private int initialHeight;
263
+
264
+ // Screen metrics
265
+ private DisplayMetrics displayMetrics = new DisplayMetrics();
266
+ private int screenWidth;
267
+ private int screenHeight;
268
+ private int drawableWidth;
269
+ private int drawableHeight;
270
+ private boolean isPortraitScreen;
271
+
272
+ private long lastClickTime = 0;
273
+ private static final long DOUBLE_CLICK_TIME_DELTA = 200; // milliseconds
274
+
275
+ private final float ZOOM_SCALE_FACTOR =
276
+ 1.5f; // Factor to zoom in/out on double tap
277
+
278
+ private void updateScreenMetrics() {
279
+ mWindowManager.getDefaultDisplay().getMetrics(displayMetrics);
280
+ screenWidth = displayMetrics.widthPixels;
281
+ screenHeight = displayMetrics.heightPixels;
282
+ drawableWidth = screenWidth - MARGIN_LEFT - MARGIN_RIGHT;
283
+ drawableHeight = screenHeight - MARGIN_TOP - MARGIN_BOTTOM;
284
+ isPortraitScreen = screenHeight > screenWidth;
285
+ }
286
+
215
287
  @Override
216
288
  public boolean onTouch(View view, MotionEvent event) {
217
- switch (event.getAction()) {
289
+ // Update screen metrics at the beginning of a touch gesture,
290
+ // as orientation or screen size might have changed since last touch.
291
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
292
+ updateScreenMetrics();
293
+ }
294
+ // If currently animating from double click, consume touch events to
295
+ // prevent interference
296
+ if (isDoubleClickAnimating) {
297
+ // Allow ACTION_UP to potentially clear the flag if animation ends early
298
+ // or is cancelled but primarily, prevent new gestures from starting.
299
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
300
+ mode = MODE_NONE; // Prevent drag/zoom from starting
301
+ }
302
+ return true; // Consume the event
303
+ }
304
+ switch (event.getAction() & MotionEvent.ACTION_MASK) {
305
+ case MotionEvent.ACTION_DOWN:
306
+ downX = x = (int)event.getRawX();
307
+ downY = y = (int)event.getRawY();
308
+ mode = MODE_DRAG;
309
+ initialAspectRatio = (float)mLayoutParams.width / mLayoutParams.height;
310
+ initialWidth = mLayoutParams.width;
311
+ initialHeight = mLayoutParams.height;
312
+
313
+ // Double tap detection
314
+ long clickTime = System.currentTimeMillis();
315
+ if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA) {
316
+ handleDoubleClick(view);
317
+ }
318
+ lastClickTime = clickTime;
319
+ break;
320
+ case MotionEvent.ACTION_POINTER_DOWN:
321
+ oldDist = spacing(event);
322
+ if (oldDist > 10f) {
323
+ mode = MODE_ZOOM;
324
+ }
325
+ break;
218
326
  case MotionEvent.ACTION_UP:
327
+ case MotionEvent.ACTION_POINTER_UP:
328
+ boolean wasZooming = (mode == MODE_ZOOM);
329
+ // Capture params before mode is reset
330
+ int xBeforeSnap = mLayoutParams.x;
331
+ int widthBeforeSnap = mLayoutParams.width;
332
+
333
+ mode = MODE_NONE; // Reset mode
334
+
219
335
  if (isDragging) {
220
336
  isDragging = false;
337
+ // Perform snap animation if it was a drag or end of zoom
338
+ if (event.getPointerCount() == 1 || wasZooming) {
339
+ Log.i(TAG, "ACTION_UP/POINTER_UP: Triggering snap. xBeforeSnap=" +
340
+ xBeforeSnap + ", widthBeforeSnap=" +
341
+ widthBeforeSnap + ", wasZooming=" + wasZooming +
342
+ ", pointerCount=" + event.getPointerCount());
343
+ animateSnapToEdge(view);
344
+ }
221
345
  } else {
222
- FloatingWindowHelper.getInstance().onClickFloatingWindow(
223
- FloatingWindowService.this);
346
+ // Only trigger click if not zooming and it's a single pointer up
347
+ if (event.getPointerCount() == 1 &&
348
+ (event.getAction() & MotionEvent.ACTION_MASK) ==
349
+ MotionEvent.ACTION_UP) {
350
+ // Check if it was a drag or a tap
351
+ if (Math.abs(event.getRawX() - downX) < touchSlop &&
352
+ Math.abs(event.getRawY() - downY) < touchSlop) {
353
+ // This is a tap, not a double tap, so handle as single click if
354
+ // needed For now, double tap handles zoom, single tap is handled
355
+ // by new_window_btn
356
+ }
357
+ }
224
358
  }
225
- downX = downY = 0;
226
- break;
227
- case MotionEvent.ACTION_DOWN:
228
- downX = x = (int)event.getRawX();
229
- downY = y = (int)event.getRawY();
359
+ // downX and downY are reset at ACTION_DOWN for the primary pointer
230
360
  break;
361
+
231
362
  case MotionEvent.ACTION_MOVE:
232
- int nowX = (int)event.getRawX();
233
- int nowY = (int)event.getRawY();
234
- if (Math.abs(nowX - downX) > touchSlop ||
235
- Math.abs(nowY - downY) > touchSlop) {
236
- isDragging = true;
237
- }
238
- int movedX = nowX - x;
239
- int movedY = nowY - y;
240
- x = nowX;
241
- y = nowY;
242
- mLayoutParams.x = mLayoutParams.x + movedX;
243
- mLayoutParams.y = mLayoutParams.y + movedY;
244
- mWindowManager.updateViewLayout(view, mLayoutParams);
363
+ if (mode == MODE_DRAG && event.getPointerCount() == 1) {
364
+ int nowX = (int)event.getRawX();
365
+ int nowY = (int)event.getRawY();
366
+ if (!isDragging && (Math.abs(nowX - downX) > touchSlop ||
367
+ Math.abs(nowY - downY) > touchSlop)) {
368
+ isDragging = true;
369
+ }
370
+ if (isDragging) {
371
+ int movedX = nowX - x;
372
+ int movedY = nowY - y;
373
+ mLayoutParams.x = mLayoutParams.x + movedX;
374
+ mLayoutParams.y = mLayoutParams.y + movedY;
375
+
376
+ // 使用预先获取的屏幕高度 screenHeight
377
+ // 限制y坐标在安全区域内
378
+ mLayoutParams.y = Math.max(
379
+ MARGIN_TOP, Math.min(mLayoutParams.y, this.screenHeight -
380
+ mLayoutParams.height -
381
+ MARGIN_BOTTOM));
382
+
383
+ mWindowManager.updateViewLayout(view, mLayoutParams);
384
+ }
385
+ x = nowX;
386
+ y = nowY;
387
+ } else if (mode == MODE_ZOOM && event.getPointerCount() >= 2) {
388
+ float newDist = spacing(event);
389
+ if (newDist > 10f) {
390
+ // Calculate midpoint of the two fingers
391
+ float midX = (event.getX(0) + event.getX(1)) / 2;
392
+ float midY = (event.getY(0) + event.getY(1)) / 2;
393
+
394
+ // Convert midpoint from view coordinates to screen coordinates
395
+ float screenMidX = mLayoutParams.x + midX;
396
+ float screenMidY = mLayoutParams.y + midY;
397
+
398
+ float scale = newDist / oldDist;
399
+ int oldWidth = mLayoutParams.width;
400
+ int oldHeight = mLayoutParams.height;
401
+ int newWidth = (int)(oldWidth * scale);
402
+ int newHeight = (int)(oldHeight * scale);
403
+
404
+ // Use pre-calculated screen metrics
405
+ // Screen metrics are now updated in onTouch ACTION_DOWN, so they
406
+ // should be current here.
407
+
408
+ // Min size constraints: 1/2 of initial size, but not smaller than a
409
+ // fraction of screen respecting margins
410
+ int minAllowedWidth;
411
+ int minAllowedHeight;
412
+ if (isPortraitScreen) {
413
+ minAllowedWidth = Math.max(initialWidth / 2, drawableWidth / 2);
414
+ minAllowedHeight = (int)(minAllowedWidth / initialAspectRatio);
415
+ } else {
416
+ minAllowedHeight =
417
+ Math.max(initialHeight / 2, drawableHeight / 2);
418
+ minAllowedWidth = (int)(minAllowedHeight * initialAspectRatio);
419
+ }
420
+ // Ensure min dimensions are at least 1
421
+ minAllowedWidth = Math.max(1, minAllowedWidth);
422
+ minAllowedHeight = Math.max(1, minAllowedHeight);
423
+
424
+ // Max size constraints based on orientation and margins
425
+ int maxAllowedWidth, maxAllowedHeight;
426
+ if (isPortraitScreen) {
427
+ maxAllowedWidth = drawableWidth;
428
+ maxAllowedHeight =
429
+ (int)(maxAllowedWidth /
430
+ initialAspectRatio); // Maintain aspect ratio
431
+ if (maxAllowedHeight >
432
+ drawableHeight) { // If calculated height is too much for
433
+ // portrait
434
+ maxAllowedHeight = drawableHeight;
435
+ maxAllowedWidth = (int)(maxAllowedHeight * initialAspectRatio);
436
+ }
437
+ } else { // Landscape screen
438
+ maxAllowedHeight = drawableHeight;
439
+ maxAllowedWidth =
440
+ (int)(maxAllowedHeight *
441
+ initialAspectRatio); // Maintain aspect ratio
442
+ if (maxAllowedWidth > drawableWidth) { // If calculated width is
443
+ // too much for landscape
444
+ maxAllowedWidth = drawableWidth;
445
+ maxAllowedHeight = (int)(maxAllowedWidth / initialAspectRatio);
446
+ }
447
+ }
448
+ // maxAllowedWidth = Math.min(maxAllowedWidth, LONGER_SIDE_MAX_LEN);
449
+ // // Global max len - Removed maxAllowedHeight =
450
+ // Math.min(maxAllowedHeight, LONGER_SIDE_MAX_LEN); // Global max
451
+ // len - Removed
452
+ if (initialAspectRatio >= 1)
453
+ maxAllowedHeight = (int)(maxAllowedWidth / initialAspectRatio);
454
+ else
455
+ maxAllowedWidth = (int)(maxAllowedHeight * initialAspectRatio);
456
+
457
+ // Apply scaling
458
+ newWidth = (int)(oldWidth * scale);
459
+ newHeight = (int)(oldHeight * scale);
460
+
461
+ // Clamp to min/max size while maintaining aspect ratio
462
+ if (scale < 1) { // Shrinking
463
+ newWidth = Math.max(minAllowedWidth, newWidth);
464
+ newHeight = (int)(newWidth / initialAspectRatio);
465
+ if (newHeight < minAllowedHeight) {
466
+ newHeight = minAllowedHeight;
467
+ newWidth = (int)(newHeight * initialAspectRatio);
468
+ }
469
+ } else { // Expanding
470
+ newWidth = Math.min(maxAllowedWidth, newWidth);
471
+ newHeight = (int)(newWidth / initialAspectRatio);
472
+ if (newHeight > maxAllowedHeight) {
473
+ newHeight = maxAllowedHeight;
474
+ newWidth = (int)(newHeight * initialAspectRatio);
475
+ }
476
+ }
477
+
478
+ // Final check to ensure dimensions are within absolute min/max
479
+ // bounds
480
+ newWidth =
481
+ Math.max(minAllowedWidth, Math.min(newWidth, maxAllowedWidth));
482
+ newHeight =
483
+ (int)(newWidth / initialAspectRatio); // Maintain aspect ratio
484
+ // Ensure height is also clamped correctly after width adjustment
485
+ if (newHeight < minAllowedHeight) {
486
+ newHeight = minAllowedHeight;
487
+ newWidth = (int)(newHeight * initialAspectRatio);
488
+ }
489
+ if (newHeight > maxAllowedHeight) {
490
+ newHeight = maxAllowedHeight;
491
+ newWidth = (int)(newHeight * initialAspectRatio);
492
+ }
493
+ // Re-clamp width just in case height clamping affected it and
494
+ // pushed it out of width bounds
495
+ newWidth =
496
+ Math.max(minAllowedWidth, Math.min(newWidth, maxAllowedWidth));
497
+
498
+ // Adjust position to keep the zoom centered on the midpoint
499
+ mLayoutParams.x = (int)(screenMidX - (midX * newWidth / oldWidth));
500
+ mLayoutParams.y =
501
+ (int)(screenMidY - (midY * newHeight / oldHeight));
502
+
503
+ mLayoutParams.width = newWidth;
504
+ mLayoutParams.height = newHeight;
505
+
506
+ // Prevent window from going off-screen after repositioning
507
+ // For Y, keep margin constraints
508
+ mLayoutParams.y = Math.max(
509
+ MARGIN_TOP,
510
+ Math.min(mLayoutParams.y,
511
+ screenHeight - mLayoutParams.height - MARGIN_BOTTOM));
512
+ // For X, constrain to screen physical edges only during zoom,
513
+ // let animateSnapToEdge handle final margin snapping.
514
+ mLayoutParams.x = Math.max(
515
+ 0, // Screen physical left edge
516
+ Math.min(
517
+ mLayoutParams.x,
518
+ screenWidth -
519
+ mLayoutParams.width)); // Screen physical right edge
520
+
521
+ // 更新SurfaceView的布局参数
522
+ if (mSurfaceView != null) {
523
+ android.view.ViewGroup.LayoutParams surfaceParams =
524
+ mSurfaceView.getLayoutParams();
525
+ if (surfaceParams != null) {
526
+ surfaceParams.width = mLayoutParams.width;
527
+ surfaceParams.height = mLayoutParams.height;
528
+ mSurfaceView.setLayoutParams(surfaceParams);
529
+ }
530
+ }
531
+ mWindowManager.updateViewLayout(view, mLayoutParams);
532
+ oldDist = newDist;
533
+ }
534
+ isDragging =
535
+ true; // Zooming implies dragging state for click handling
536
+ }
245
537
  break;
246
538
 
247
539
  default:
@@ -249,5 +541,392 @@ public class FloatingWindowService extends Service {
249
541
  }
250
542
  return true;
251
543
  }
544
+
545
+ private float spacing(MotionEvent event) {
546
+ if (event.getPointerCount() < 2)
547
+ return 0f;
548
+ float x = event.getX(0) - event.getX(1);
549
+ float y = event.getY(0) - event.getY(1);
550
+ return (float)Math.sqrt(x * x + y * y);
551
+ }
552
+
553
+ private void handleDoubleClick(View view) {
554
+ Log.d(TAG, "Double tap detected");
555
+ int targetWidth, targetHeight;
556
+
557
+ // Use pre-calculated screen metrics
558
+ // updateScreenMetrics(); // Ensure metrics are fresh if not updated in
559
+ // onTouch ACTION_DOWN Screen metrics are now updated in onTouch
560
+ // ACTION_DOWN, so they should be current here.
561
+
562
+ // Minimum size: 1/2 of initial size, but not smaller than a fraction of
563
+ // screen respecting margins
564
+ int minAllowedWidth = initialWidth / 2;
565
+ int minAllowedHeight = initialHeight / 2;
566
+ if (isPortraitScreen) {
567
+ minAllowedWidth = Math.max(minAllowedWidth, drawableWidth / 2);
568
+ minAllowedHeight = (int)(minAllowedWidth / initialAspectRatio);
569
+ } else {
570
+ minAllowedHeight = Math.max(minAllowedHeight, drawableHeight / 2);
571
+ minAllowedWidth = (int)(minAllowedHeight * initialAspectRatio);
572
+ }
573
+
574
+ // Maximum size based on orientation and margins
575
+ int maxAllowedTargetWidth, maxAllowedTargetHeight;
576
+ if (isPortraitScreen) {
577
+ maxAllowedTargetWidth = drawableWidth;
578
+ maxAllowedTargetHeight =
579
+ (int)(maxAllowedTargetWidth / initialAspectRatio);
580
+ if (maxAllowedTargetHeight > drawableHeight) {
581
+ maxAllowedTargetHeight = drawableHeight;
582
+ maxAllowedTargetWidth =
583
+ (int)(maxAllowedTargetHeight * initialAspectRatio);
584
+ }
585
+ } else { // Landscape screen
586
+ maxAllowedTargetHeight = drawableHeight;
587
+ maxAllowedTargetWidth =
588
+ (int)(maxAllowedTargetHeight * initialAspectRatio);
589
+ if (maxAllowedTargetWidth > drawableWidth) {
590
+ maxAllowedTargetWidth = drawableWidth;
591
+ maxAllowedTargetHeight =
592
+ (int)(maxAllowedTargetWidth / initialAspectRatio);
593
+ }
594
+ }
595
+ // Apply global LONGER_SIDE_MAX_LEN constraint - Removed
596
+ // if (initialAspectRatio >= 1) { // Landscape or square video
597
+ // maxAllowedTargetWidth =
598
+ // Math.min(maxAllowedTargetWidth, LONGER_SIDE_MAX_LEN);
599
+ // maxAllowedTargetHeight =
600
+ // (int)(maxAllowedTargetWidth / initialAspectRatio);
601
+ // } else { // Portrait video
602
+ // maxAllowedTargetHeight =
603
+ // Math.min(maxAllowedTargetHeight, LONGER_SIDE_MAX_LEN);
604
+ // maxAllowedTargetWidth =
605
+ // (int)(maxAllowedTargetHeight * initialAspectRatio);
606
+ // }
607
+
608
+ int currentX = mLayoutParams.x;
609
+ int currentY = mLayoutParams.y;
610
+ int currentWidth = mLayoutParams.width;
611
+ int currentHeight = mLayoutParams.height;
612
+
613
+ int finalTargetX = currentX;
614
+ int finalTargetY = currentY;
615
+
616
+ // 计算当前宽度与中间值的比较,决定缩放方向
617
+ int midWidth = (minAllowedWidth + maxAllowedTargetWidth) / 2;
618
+ if (currentWidth < midWidth) {
619
+ // 当前更接近最小值,放大到最大尺寸
620
+ targetWidth = maxAllowedTargetWidth;
621
+ targetHeight = maxAllowedTargetHeight;
622
+ Log.d(TAG, "Zooming in to max: " + targetWidth + "x" + targetHeight);
623
+ } else {
624
+ // 当前更接近最大值,缩小到最小尺寸
625
+ targetWidth = minAllowedWidth;
626
+ targetHeight = minAllowedHeight;
627
+ Log.d(TAG, "Zooming out to min: " + targetWidth + "x" + targetHeight);
628
+ }
629
+
630
+ // Ensure target dimensions respect calculated min/max and screen
631
+ // boundaries with margins
632
+ targetWidth = Math.max(minAllowedWidth,
633
+ Math.min(targetWidth, maxAllowedTargetWidth));
634
+ targetHeight = (int)(targetWidth / initialAspectRatio);
635
+ if (targetHeight < minAllowedHeight) {
636
+ targetHeight = minAllowedHeight;
637
+ targetWidth = (int)(targetHeight * initialAspectRatio);
638
+ }
639
+ if (targetHeight > maxAllowedTargetHeight) {
640
+ targetHeight = maxAllowedTargetHeight;
641
+ targetWidth = (int)(targetHeight * initialAspectRatio);
642
+ }
643
+ // Final check for width after height adjustment
644
+ targetWidth = Math.max(minAllowedWidth,
645
+ Math.min(targetWidth, maxAllowedTargetWidth));
646
+
647
+ // Instantly apply new size and update layout BEFORE starting
648
+ // position/size animations This helps in reducing black bars by setting
649
+ // the target container size first.
650
+ mLayoutParams.width = targetWidth;
651
+ mLayoutParams.height = targetHeight;
652
+ if (mSmallWindowView != null &&
653
+ mSmallWindowView.getWindowToken() != null) {
654
+ mWindowManager.updateViewLayout(mSmallWindowView, mLayoutParams);
655
+ // Also update SurfaceView's layout params to match the new window size
656
+ // immediately
657
+ if (mSurfaceView != null) {
658
+ android.view.ViewGroup.LayoutParams surfaceParams =
659
+ mSurfaceView.getLayoutParams();
660
+ if (surfaceParams != null) {
661
+ surfaceParams.width = targetWidth;
662
+ surfaceParams.height = targetHeight;
663
+ mSurfaceView.setLayoutParams(surfaceParams);
664
+ mSurfaceView
665
+ .requestLayout(); // Crucial for SurfaceView to redraw correctly
666
+ }
667
+ }
668
+ }
669
+
670
+ // Determine window corner for zoom anchor, considering margins
671
+ boolean isTop =
672
+ currentY < (screenHeight - MARGIN_TOP - MARGIN_BOTTOM) / 2 -
673
+ currentHeight / 2 + MARGIN_TOP;
674
+ boolean isLeft =
675
+ currentX < (screenWidth - MARGIN_LEFT - MARGIN_RIGHT) / 2 -
676
+ currentWidth / 2 + MARGIN_LEFT;
677
+
678
+ if (isLeft && isTop) { // Top-left
679
+ finalTargetX = MARGIN_LEFT;
680
+ finalTargetY = MARGIN_TOP;
681
+ } else if (!isLeft && isTop) { // Top-right
682
+ finalTargetX = screenWidth - targetWidth - MARGIN_RIGHT;
683
+ finalTargetY = MARGIN_TOP;
684
+ } else if (isLeft && !isTop) { // Bottom-left
685
+ finalTargetX = MARGIN_LEFT;
686
+ finalTargetY = screenHeight - targetHeight - MARGIN_BOTTOM;
687
+ } else { // Bottom-right
688
+ finalTargetX = screenWidth - targetWidth - MARGIN_RIGHT;
689
+ finalTargetY = screenHeight - targetHeight - MARGIN_BOTTOM;
690
+ }
691
+
692
+ // Ensure target position is within drawable area
693
+ finalTargetX = Math.max(
694
+ MARGIN_LEFT,
695
+ Math.min(finalTargetX, screenWidth - targetWidth - MARGIN_RIGHT));
696
+ finalTargetY = Math.max(
697
+ MARGIN_TOP,
698
+ Math.min(finalTargetY, screenHeight - targetHeight - MARGIN_BOTTOM));
699
+
700
+ final int finalTargetWidth = targetWidth;
701
+ final int finalTargetHeight = targetHeight;
702
+
703
+ // Make copies for use in animator listeners
704
+ final int animFinalTargetX = finalTargetX;
705
+ final int animFinalTargetY = finalTargetY;
706
+
707
+ ValueAnimator xAnimator = ValueAnimator.ofInt(currentX, finalTargetX);
708
+ xAnimator.setDuration(200);
709
+ xAnimator.addUpdateListener(animation -> {
710
+ mLayoutParams.x = (Integer)animation.getAnimatedValue();
711
+ mWindowManager.updateViewLayout(view, mLayoutParams);
712
+ });
713
+
714
+ ValueAnimator yAnimator = ValueAnimator.ofInt(currentY, finalTargetY);
715
+ yAnimator.setDuration(200);
716
+ yAnimator.addUpdateListener(animation -> {
717
+ mLayoutParams.y = (Integer)animation.getAnimatedValue();
718
+ mWindowManager.updateViewLayout(view, mLayoutParams);
719
+ });
720
+
721
+ ValueAnimator widthAnimator =
722
+ ValueAnimator.ofInt(currentWidth, finalTargetWidth);
723
+ widthAnimator.setDuration(200);
724
+ widthAnimator.addUpdateListener(animation -> {
725
+ mLayoutParams.width = (Integer)animation.getAnimatedValue();
726
+ if (mSurfaceView != null) { // Ensure mSurfaceView is not null
727
+ android.view.ViewGroup.LayoutParams surfaceParams =
728
+ mSurfaceView.getLayoutParams();
729
+ if (surfaceParams != null) { // Ensure surfaceParams is not null
730
+ surfaceParams.width = mLayoutParams.width;
731
+ mSurfaceView.setLayoutParams(surfaceParams);
732
+ }
733
+ }
734
+ mWindowManager.updateViewLayout(view, mLayoutParams);
735
+ });
736
+
737
+ ValueAnimator heightAnimator =
738
+ ValueAnimator.ofInt(currentHeight, finalTargetHeight);
739
+ heightAnimator.setDuration(200);
740
+ heightAnimator.addUpdateListener(animation -> {
741
+ mLayoutParams.height = (Integer)animation.getAnimatedValue();
742
+ if (mSurfaceView != null) { // Ensure mSurfaceView is not null
743
+ android.view.ViewGroup.LayoutParams surfaceParams =
744
+ mSurfaceView.getLayoutParams();
745
+ if (surfaceParams != null) { // Ensure surfaceParams is not null
746
+ surfaceParams.height = mLayoutParams.height;
747
+ mSurfaceView.setLayoutParams(surfaceParams);
748
+ }
749
+ }
750
+ mWindowManager.updateViewLayout(view, mLayoutParams);
751
+ });
752
+
753
+ android.animation.AnimatorSet animatorSet =
754
+ new android.animation.AnimatorSet();
755
+ animatorSet.playTogether(xAnimator, yAnimator, widthAnimator,
756
+ heightAnimator);
757
+ // The isDoubleClickAnimating flag is now managed by
758
+ // FloatingOnTouchListener but we still need to set it within
759
+ // handleDoubleClick's AnimatorSet listeners to ensure it's active for the
760
+ // duration of this specific animation.
761
+ animatorSet.addListener(new android.animation.AnimatorListenerAdapter() {
762
+ @Override
763
+ public void onAnimationStart(android.animation.Animator animation) {
764
+ if (FloatingWindowService.this.mFloatingOnTouchListener != null) {
765
+ FloatingWindowService.this.mFloatingOnTouchListener
766
+ .isDoubleClickAnimating = true;
767
+ }
768
+ Log.d(TAG, "Double tap AnimatorSet started.");
769
+ }
770
+
771
+ @Override
772
+ public void onAnimationEnd(android.animation.Animator animation) {
773
+ if (FloatingWindowService.this.mFloatingOnTouchListener != null) {
774
+ FloatingWindowService.this.mFloatingOnTouchListener
775
+ .isDoubleClickAnimating = false;
776
+ }
777
+ // ValueAnimators update mLayoutParams continuously via their
778
+ // AnimatorUpdateListener. For safety, explicitly set final position
779
+ // values as the last update might not be exact.
780
+ mLayoutParams.x = animFinalTargetX;
781
+ mLayoutParams.y = animFinalTargetY;
782
+ // mLayoutParams.width and mLayoutParams.height should be at
783
+ // finalTargetWidth/Height due to widthAnimator and heightAnimator's
784
+ // updates.
785
+
786
+ // Perform a final update of the window layout with all parameters.
787
+ if (mSmallWindowView != null &&
788
+ mSmallWindowView.getWindowToken() != null) {
789
+ mWindowManager.updateViewLayout(mSmallWindowView, mLayoutParams);
790
+ }
791
+
792
+ // Resize SurfaceView (logic moved from postDelayed and refined)
793
+ if (mSurfaceView != null && mLayoutParams != null) {
794
+ android.view.ViewGroup.LayoutParams surfaceParams =
795
+ mSurfaceView.getLayoutParams();
796
+ if (surfaceParams != null) {
797
+ boolean changed = false;
798
+ if (surfaceParams.width != mLayoutParams.width) {
799
+ surfaceParams.width =
800
+ mLayoutParams.width; // mLayoutParams.width is at its final
801
+ // animated value
802
+ changed = true;
803
+ }
804
+ if (surfaceParams.height != mLayoutParams.height) {
805
+ surfaceParams.height =
806
+ mLayoutParams.height; // mLayoutParams.height is at its
807
+ // final animated value
808
+ changed = true;
809
+ }
810
+ if (changed) {
811
+ mSurfaceView.setLayoutParams(surfaceParams);
812
+ }
813
+ mSurfaceView
814
+ .requestLayout(); // Ensure the SurfaceView redraws correctly
815
+ Log.d(TAG,
816
+ "SurfaceView dimensions finalized in onAnimationEnd to: " +
817
+ mLayoutParams.width + "x" + mLayoutParams.height);
818
+ }
819
+ }
820
+ Log.d(TAG, "Double tap AnimatorSet ended. Final state: x=" +
821
+ mLayoutParams.x + ", y=" + mLayoutParams.y + ", w=" +
822
+ mLayoutParams.width + ", h=" + mLayoutParams.height);
823
+ }
824
+
825
+ @Override
826
+ public void onAnimationCancel(android.animation.Animator animation) {
827
+ if (FloatingWindowService.this.mFloatingOnTouchListener != null) {
828
+ FloatingWindowService.this.mFloatingOnTouchListener
829
+ .isDoubleClickAnimating = false;
830
+ }
831
+ // Animation was cancelled, so explicitly set all mLayoutParams to
832
+ // their final target values.
833
+ mLayoutParams.x = animFinalTargetX;
834
+ mLayoutParams.y = animFinalTargetY;
835
+ mLayoutParams.width = finalTargetWidth;
836
+ mLayoutParams.height = finalTargetHeight;
837
+
838
+ if (mSmallWindowView != null &&
839
+ mSmallWindowView.getWindowToken() != null) {
840
+ mWindowManager.updateViewLayout(mSmallWindowView, mLayoutParams);
841
+ }
842
+
843
+ // Resize SurfaceView to final target dimensions
844
+ if (mSurfaceView != null && mLayoutParams != null) {
845
+ android.view.ViewGroup.LayoutParams surfaceParams =
846
+ mSurfaceView.getLayoutParams();
847
+ if (surfaceParams != null) {
848
+ if (surfaceParams.width != mLayoutParams.width ||
849
+ surfaceParams.height != mLayoutParams.height) {
850
+ surfaceParams.width =
851
+ mLayoutParams.width; // Now finalTargetWidth
852
+ surfaceParams.height =
853
+ mLayoutParams.height; // Now finalTargetHeight
854
+ mSurfaceView.setLayoutParams(surfaceParams);
855
+ }
856
+ mSurfaceView
857
+ .requestLayout(); // Ensure the SurfaceView redraws correctly
858
+ }
859
+ }
860
+ Log.d(TAG,
861
+ "Double tap AnimatorSet cancelled. State set to targets: x=" +
862
+ mLayoutParams.x + ", y=" + mLayoutParams.y + ", w=" +
863
+ mLayoutParams.width + ", h=" + mLayoutParams.height);
864
+ }
865
+ });
866
+ animatorSet.start();
867
+ }
868
+
869
+ private void animateSnapToEdge(View view) {
870
+ // Use pre-calculated screen metrics
871
+ // updateScreenMetrics(); // Ensure metrics are fresh if not updated in
872
+ // onTouch ACTION_DOWN Screen metrics are now updated in onTouch
873
+ // ACTION_DOWN, so they should be current here.
874
+ final int screenWidth = this.screenWidth; // Make final for use in lambda
875
+ final int windowWidthAtAnimationStart =
876
+ mLayoutParams.width; // Capture width at start
877
+
878
+ int currentX =
879
+ mLayoutParams
880
+ .x; // This is the x at the moment animateSnapToEdge is called
881
+ int targetX;
882
+
883
+ // Determine targetX based on current position and captured width
884
+ if (currentX + windowWidthAtAnimationStart / 2 < screenWidth / 2) {
885
+ targetX = MARGIN_LEFT;
886
+ } else {
887
+ targetX = screenWidth - windowWidthAtAnimationStart - MARGIN_RIGHT;
888
+ }
889
+
890
+ Log.i(TAG, "animateSnapToEdge: currentX=" + currentX +
891
+ ", windowWidthAtAnimStart=" + windowWidthAtAnimationStart +
892
+ ", screenWidth=" + screenWidth + ", calculatedTargetX=" +
893
+ targetX + ", currentY=" + mLayoutParams.y +
894
+ ", currentHeight=" + mLayoutParams.height);
895
+
896
+ if (currentX == targetX) {
897
+ Log.i(TAG, "animateSnapToEdge: Already at targetX (" + targetX +
898
+ "). No animation needed.");
899
+ return;
900
+ }
901
+
902
+ ValueAnimator snapAnimator = ValueAnimator.ofInt(currentX, targetX);
903
+ snapAnimator.setDuration(200);
904
+ snapAnimator.addUpdateListener(animation -> {
905
+ mLayoutParams.x = (Integer)animation.getAnimatedValue();
906
+ // Boundary checks using width captured at animation start
907
+ if (mLayoutParams.x < 0) { // Physical screen boundary
908
+ mLayoutParams.x = 0;
909
+ }
910
+ // Ensure the right edge does not go beyond screen width
911
+ if (mLayoutParams.x + windowWidthAtAnimationStart >
912
+ screenWidth) { // Physical screen boundary
913
+ mLayoutParams.x = screenWidth - windowWidthAtAnimationStart;
914
+ }
915
+ try {
916
+ if (mSmallWindowView != null &&
917
+ mSmallWindowView.getWindowToken() !=
918
+ null) { // Check if view is still attached
919
+ mWindowManager.updateViewLayout(view, mLayoutParams);
920
+ }
921
+ } catch (IllegalArgumentException e) {
922
+ Log.w(TAG, "animateSnapToEdge: View not attached? " + e.getMessage());
923
+ // Cancel animator if view is gone to prevent further errors
924
+ if (animation.isRunning()) {
925
+ animation.cancel();
926
+ }
927
+ }
928
+ });
929
+ snapAnimator.start();
930
+ }
252
931
  }
253
932
  }
@@ -4566,6 +4566,7 @@ var TVLManager = function () {
4566
4566
  var _setEnableSuperResolution_decorators;
4567
4567
  var _setVolume_decorators;
4568
4568
  var _setEnableIgnoreAudioInterruption_decorators;
4569
+ var _setAllowsVideoRendering_decorators;
4569
4570
  _classThis = /** @class */ (function () {
4570
4571
  function TVLManager_1() {
4571
4572
  /** {zh}
@@ -4876,6 +4877,9 @@ var TVLManager = function () {
4876
4877
  TVLManager_1.prototype.setEnableIgnoreAudioInterruption = function (enable) {
4877
4878
  throw new Error('not implement');
4878
4879
  };
4880
+ TVLManager_1.prototype.setAllowsVideoRendering = function (enable) {
4881
+ throw new Error('not implement');
4882
+ };
4879
4883
  return TVLManager_1;
4880
4884
  }());
4881
4885
  __setFunctionName(_classThis, "TVLManager");
@@ -4912,6 +4916,7 @@ var TVLManager = function () {
4912
4916
  _setEnableSuperResolution_decorators = [NativeMethodSync('setEnableSuperResolution:')];
4913
4917
  _setVolume_decorators = [NativeMethodSync('setVolume:')];
4914
4918
  _setEnableIgnoreAudioInterruption_decorators = [NativeMethodSync('setEnableIgnoreAudioInterruption:')];
4919
+ _setAllowsVideoRendering_decorators = [NativeMethodSync('setAllowsVideoRendering:')];
4915
4920
  __esDecorate(_classThis, null, _static_setLogLevel_decorators, { kind: "method", name: "setLogLevel", static: true, private: false, access: { has: function (obj) { return "setLogLevel" in obj; }, get: function (obj) { return obj.setLogLevel; } }, metadata: _metadata }, null, _staticExtraInitializers);
4916
4921
  __esDecorate(_classThis, null, _static_getVersion_decorators, { kind: "method", name: "getVersion", static: true, private: false, access: { has: function (obj) { return "getVersion" in obj; }, get: function (obj) { return obj.getVersion; } }, metadata: _metadata }, null, _staticExtraInitializers);
4917
4922
  __esDecorate(_classThis, null, _static_setHttpDNSHostIP_decorators, { kind: "method", name: "setHttpDNSHostIP", static: true, private: false, access: { has: function (obj) { return "setHttpDNSHostIP" in obj; }, get: function (obj) { return obj.setHttpDNSHostIP; } }, metadata: _metadata }, null, _staticExtraInitializers);
@@ -4939,6 +4944,7 @@ var TVLManager = function () {
4939
4944
  __esDecorate(_classThis, null, _setEnableSuperResolution_decorators, { kind: "method", name: "setEnableSuperResolution", static: false, private: false, access: { has: function (obj) { return "setEnableSuperResolution" in obj; }, get: function (obj) { return obj.setEnableSuperResolution; } }, metadata: _metadata }, null, _instanceExtraInitializers);
4940
4945
  __esDecorate(_classThis, null, _setVolume_decorators, { kind: "method", name: "setVolume", static: false, private: false, access: { has: function (obj) { return "setVolume" in obj; }, get: function (obj) { return obj.setVolume; } }, metadata: _metadata }, null, _instanceExtraInitializers);
4941
4946
  __esDecorate(_classThis, null, _setEnableIgnoreAudioInterruption_decorators, { kind: "method", name: "setEnableIgnoreAudioInterruption", static: false, private: false, access: { has: function (obj) { return "setEnableIgnoreAudioInterruption" in obj; }, get: function (obj) { return obj.setEnableIgnoreAudioInterruption; } }, metadata: _metadata }, null, _instanceExtraInitializers);
4947
+ __esDecorate(_classThis, null, _setAllowsVideoRendering_decorators, { kind: "method", name: "setAllowsVideoRendering", static: false, private: false, access: { has: function (obj) { return "setAllowsVideoRendering" in obj; }, get: function (obj) { return obj.setAllowsVideoRendering; } }, metadata: _metadata }, null, _instanceExtraInitializers);
4942
4948
  __esDecorate(null, null, _observer_decorators, { kind: "field", name: "observer", static: false, private: false, access: { has: function (obj) { return "observer" in obj; }, get: function (obj) { return obj.observer; }, set: function (obj, value) { obj.observer = value; } }, metadata: _metadata }, _observer_initializers, _observer_extraInitializers);
4943
4949
  __esDecorate(null, null, _playerView_decorators, { kind: "field", name: "playerView", static: false, private: false, access: { has: function (obj) { return "playerView" in obj; }, get: function (obj) { return obj.playerView; }, set: function (obj, value) { obj.playerView = value; } }, metadata: _metadata }, _playerView_initializers, _playerView_extraInitializers);
4944
4950
  __esDecorate(null, null, _volume_decorators, { kind: "field", name: "volume", static: false, private: false, access: { has: function (obj) { return "volume" in obj; }, get: function (obj) { return obj.volume; }, set: function (obj, value) { obj.volume = value; } }, metadata: _metadata }, _volume_initializers, _volume_extraInitializers);
@@ -11222,6 +11228,42 @@ var ios_PictureInPictureManagerListener = /** @class */ (function (_super) {
11222
11228
  return ios_PictureInPictureManagerListener;
11223
11229
  }(VeLivePictureInPictureManagerListener));
11224
11230
 
11231
+ /**
11232
+ * ios player pool list
11233
+ */
11234
+ var playerPool = new Set();
11235
+ function handleIOS(nextAppState) {
11236
+ switch (nextAppState) {
11237
+ case 'active':
11238
+ playerPool.forEach(function (player) {
11239
+ var iosPlayer = unpackObject(player);
11240
+ iosPlayer.setAllowsVideoRendering(true);
11241
+ });
11242
+ break;
11243
+ case 'background':
11244
+ playerPool.forEach(function (player) {
11245
+ var iosPlayer = unpackObject(player);
11246
+ iosPlayer.setAllowsVideoRendering(false);
11247
+ });
11248
+ break;
11249
+ }
11250
+ }
11251
+ reactNative.AppState.addEventListener('change', function (nextAppState) {
11252
+ switch (reactNative.Platform.OS) {
11253
+ case 'android':
11254
+ break;
11255
+ case 'ios':
11256
+ handleIOS(nextAppState);
11257
+ break;
11258
+ }
11259
+ });
11260
+ function addPlayer(player) {
11261
+ playerPool.add(player);
11262
+ }
11263
+ function removePlayer(player) {
11264
+ playerPool.delete(player);
11265
+ }
11266
+
11225
11267
  function runImpl(context, androidImpl, iosImpl) {
11226
11268
  if (env.getOS() === 'android') {
11227
11269
  var androidEngine = unpackObject(context);
@@ -11343,6 +11385,7 @@ extendsClassMethod(VeLivePlayer, 'disablePictureInPicture', function () {
11343
11385
  extendsClassMethod(VeLivePlayer, 'destroy', function (origin) {
11344
11386
  return function destroy() {
11345
11387
  var _this = this;
11388
+ removePlayer(this);
11346
11389
  return runImpl(this, function () { return __awaiter(_this, void 0, void 0, function () {
11347
11390
  return __generator(this, function (_a) {
11348
11391
  origin();
@@ -11654,14 +11697,28 @@ function initIOSPlayer(options) {
11654
11697
  */
11655
11698
  function initPlayer(options) {
11656
11699
  return __awaiter(this, void 0, void 0, function () {
11657
- return __generator(this, function (_a) {
11658
- switch (reactNative.Platform.OS) {
11659
- case 'android':
11660
- return [2 /*return*/, initAndroidPlayer(options)];
11661
- case 'ios':
11662
- return [2 /*return*/, initIOSPlayer(options)];
11663
- default:
11664
- throw new Error('Unsupported platform');
11700
+ var player, _a;
11701
+ return __generator(this, function (_b) {
11702
+ switch (_b.label) {
11703
+ case 0:
11704
+ _a = reactNative.Platform.OS;
11705
+ switch (_a) {
11706
+ case 'android': return [3 /*break*/, 1];
11707
+ case 'ios': return [3 /*break*/, 3];
11708
+ }
11709
+ return [3 /*break*/, 5];
11710
+ case 1: return [4 /*yield*/, initAndroidPlayer(options)];
11711
+ case 2:
11712
+ player = (_b.sent());
11713
+ return [3 /*break*/, 6];
11714
+ case 3: return [4 /*yield*/, initIOSPlayer(options)];
11715
+ case 4:
11716
+ player = (_b.sent());
11717
+ return [3 /*break*/, 6];
11718
+ case 5: throw new Error('Unsupported platform');
11719
+ case 6:
11720
+ addPlayer(player);
11721
+ return [2 /*return*/, player];
11665
11722
  }
11666
11723
  });
11667
11724
  });
@@ -1,4 +1,4 @@
1
- import { NativeEventEmitter, Image, Platform, requireNativeComponent, NativeModules } from 'react-native';
1
+ import { NativeEventEmitter, Image, Platform, requireNativeComponent, AppState, NativeModules } from 'react-native';
2
2
  import React from 'react';
3
3
 
4
4
  /**
@@ -4564,6 +4564,7 @@ var TVLManager = function () {
4564
4564
  var _setEnableSuperResolution_decorators;
4565
4565
  var _setVolume_decorators;
4566
4566
  var _setEnableIgnoreAudioInterruption_decorators;
4567
+ var _setAllowsVideoRendering_decorators;
4567
4568
  _classThis = /** @class */ (function () {
4568
4569
  function TVLManager_1() {
4569
4570
  /** {zh}
@@ -4874,6 +4875,9 @@ var TVLManager = function () {
4874
4875
  TVLManager_1.prototype.setEnableIgnoreAudioInterruption = function (enable) {
4875
4876
  throw new Error('not implement');
4876
4877
  };
4878
+ TVLManager_1.prototype.setAllowsVideoRendering = function (enable) {
4879
+ throw new Error('not implement');
4880
+ };
4877
4881
  return TVLManager_1;
4878
4882
  }());
4879
4883
  __setFunctionName(_classThis, "TVLManager");
@@ -4910,6 +4914,7 @@ var TVLManager = function () {
4910
4914
  _setEnableSuperResolution_decorators = [NativeMethodSync('setEnableSuperResolution:')];
4911
4915
  _setVolume_decorators = [NativeMethodSync('setVolume:')];
4912
4916
  _setEnableIgnoreAudioInterruption_decorators = [NativeMethodSync('setEnableIgnoreAudioInterruption:')];
4917
+ _setAllowsVideoRendering_decorators = [NativeMethodSync('setAllowsVideoRendering:')];
4913
4918
  __esDecorate(_classThis, null, _static_setLogLevel_decorators, { kind: "method", name: "setLogLevel", static: true, private: false, access: { has: function (obj) { return "setLogLevel" in obj; }, get: function (obj) { return obj.setLogLevel; } }, metadata: _metadata }, null, _staticExtraInitializers);
4914
4919
  __esDecorate(_classThis, null, _static_getVersion_decorators, { kind: "method", name: "getVersion", static: true, private: false, access: { has: function (obj) { return "getVersion" in obj; }, get: function (obj) { return obj.getVersion; } }, metadata: _metadata }, null, _staticExtraInitializers);
4915
4920
  __esDecorate(_classThis, null, _static_setHttpDNSHostIP_decorators, { kind: "method", name: "setHttpDNSHostIP", static: true, private: false, access: { has: function (obj) { return "setHttpDNSHostIP" in obj; }, get: function (obj) { return obj.setHttpDNSHostIP; } }, metadata: _metadata }, null, _staticExtraInitializers);
@@ -4937,6 +4942,7 @@ var TVLManager = function () {
4937
4942
  __esDecorate(_classThis, null, _setEnableSuperResolution_decorators, { kind: "method", name: "setEnableSuperResolution", static: false, private: false, access: { has: function (obj) { return "setEnableSuperResolution" in obj; }, get: function (obj) { return obj.setEnableSuperResolution; } }, metadata: _metadata }, null, _instanceExtraInitializers);
4938
4943
  __esDecorate(_classThis, null, _setVolume_decorators, { kind: "method", name: "setVolume", static: false, private: false, access: { has: function (obj) { return "setVolume" in obj; }, get: function (obj) { return obj.setVolume; } }, metadata: _metadata }, null, _instanceExtraInitializers);
4939
4944
  __esDecorate(_classThis, null, _setEnableIgnoreAudioInterruption_decorators, { kind: "method", name: "setEnableIgnoreAudioInterruption", static: false, private: false, access: { has: function (obj) { return "setEnableIgnoreAudioInterruption" in obj; }, get: function (obj) { return obj.setEnableIgnoreAudioInterruption; } }, metadata: _metadata }, null, _instanceExtraInitializers);
4945
+ __esDecorate(_classThis, null, _setAllowsVideoRendering_decorators, { kind: "method", name: "setAllowsVideoRendering", static: false, private: false, access: { has: function (obj) { return "setAllowsVideoRendering" in obj; }, get: function (obj) { return obj.setAllowsVideoRendering; } }, metadata: _metadata }, null, _instanceExtraInitializers);
4940
4946
  __esDecorate(null, null, _observer_decorators, { kind: "field", name: "observer", static: false, private: false, access: { has: function (obj) { return "observer" in obj; }, get: function (obj) { return obj.observer; }, set: function (obj, value) { obj.observer = value; } }, metadata: _metadata }, _observer_initializers, _observer_extraInitializers);
4941
4947
  __esDecorate(null, null, _playerView_decorators, { kind: "field", name: "playerView", static: false, private: false, access: { has: function (obj) { return "playerView" in obj; }, get: function (obj) { return obj.playerView; }, set: function (obj, value) { obj.playerView = value; } }, metadata: _metadata }, _playerView_initializers, _playerView_extraInitializers);
4942
4948
  __esDecorate(null, null, _volume_decorators, { kind: "field", name: "volume", static: false, private: false, access: { has: function (obj) { return "volume" in obj; }, get: function (obj) { return obj.volume; }, set: function (obj, value) { obj.volume = value; } }, metadata: _metadata }, _volume_initializers, _volume_extraInitializers);
@@ -11220,6 +11226,42 @@ var ios_PictureInPictureManagerListener = /** @class */ (function (_super) {
11220
11226
  return ios_PictureInPictureManagerListener;
11221
11227
  }(VeLivePictureInPictureManagerListener));
11222
11228
 
11229
+ /**
11230
+ * ios player pool list
11231
+ */
11232
+ var playerPool = new Set();
11233
+ function handleIOS(nextAppState) {
11234
+ switch (nextAppState) {
11235
+ case 'active':
11236
+ playerPool.forEach(function (player) {
11237
+ var iosPlayer = unpackObject(player);
11238
+ iosPlayer.setAllowsVideoRendering(true);
11239
+ });
11240
+ break;
11241
+ case 'background':
11242
+ playerPool.forEach(function (player) {
11243
+ var iosPlayer = unpackObject(player);
11244
+ iosPlayer.setAllowsVideoRendering(false);
11245
+ });
11246
+ break;
11247
+ }
11248
+ }
11249
+ AppState.addEventListener('change', function (nextAppState) {
11250
+ switch (Platform.OS) {
11251
+ case 'android':
11252
+ break;
11253
+ case 'ios':
11254
+ handleIOS(nextAppState);
11255
+ break;
11256
+ }
11257
+ });
11258
+ function addPlayer(player) {
11259
+ playerPool.add(player);
11260
+ }
11261
+ function removePlayer(player) {
11262
+ playerPool.delete(player);
11263
+ }
11264
+
11223
11265
  function runImpl(context, androidImpl, iosImpl) {
11224
11266
  if (env.getOS() === 'android') {
11225
11267
  var androidEngine = unpackObject(context);
@@ -11341,6 +11383,7 @@ extendsClassMethod(VeLivePlayer, 'disablePictureInPicture', function () {
11341
11383
  extendsClassMethod(VeLivePlayer, 'destroy', function (origin) {
11342
11384
  return function destroy() {
11343
11385
  var _this = this;
11386
+ removePlayer(this);
11344
11387
  return runImpl(this, function () { return __awaiter(_this, void 0, void 0, function () {
11345
11388
  return __generator(this, function (_a) {
11346
11389
  origin();
@@ -11652,14 +11695,28 @@ function initIOSPlayer(options) {
11652
11695
  */
11653
11696
  function initPlayer(options) {
11654
11697
  return __awaiter(this, void 0, void 0, function () {
11655
- return __generator(this, function (_a) {
11656
- switch (Platform.OS) {
11657
- case 'android':
11658
- return [2 /*return*/, initAndroidPlayer(options)];
11659
- case 'ios':
11660
- return [2 /*return*/, initIOSPlayer(options)];
11661
- default:
11662
- throw new Error('Unsupported platform');
11698
+ var player, _a;
11699
+ return __generator(this, function (_b) {
11700
+ switch (_b.label) {
11701
+ case 0:
11702
+ _a = Platform.OS;
11703
+ switch (_a) {
11704
+ case 'android': return [3 /*break*/, 1];
11705
+ case 'ios': return [3 /*break*/, 3];
11706
+ }
11707
+ return [3 /*break*/, 5];
11708
+ case 1: return [4 /*yield*/, initAndroidPlayer(options)];
11709
+ case 2:
11710
+ player = (_b.sent());
11711
+ return [3 /*break*/, 6];
11712
+ case 3: return [4 /*yield*/, initIOSPlayer(options)];
11713
+ case 4:
11714
+ player = (_b.sent());
11715
+ return [3 /*break*/, 6];
11716
+ case 5: throw new Error('Unsupported platform');
11717
+ case 6:
11718
+ addPlayer(player);
11719
+ return [2 /*return*/, player];
11663
11720
  }
11664
11721
  });
11665
11722
  });
@@ -63,6 +63,7 @@ export declare class TVLManager {
63
63
  setEnableSuperResolution(enable: BOOL): void;
64
64
  setVolume(volume: float): void;
65
65
  setEnableIgnoreAudioInterruption(enable: BOOL): void;
66
+ setAllowsVideoRendering(enable: BOOL): void;
66
67
  }
67
68
  export declare enum VeLivePlayerType {
68
69
 
@@ -0,0 +1,3 @@
1
+ import type { VeLivePlayer } from './api';
2
+ export declare function addPlayer(player: VeLivePlayer): void;
3
+ export declare function removePlayer(player: VeLivePlayer): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byteplus/react-native-live-pull",
3
- "version": "1.1.2",
3
+ "version": "1.1.3-rc.1",
4
4
  "peerDependencies": {
5
5
  "react": "*",
6
6
  "react-native": "*"