@capgo/capacitor-video-player 8.1.19 → 8.1.20
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.
package/README.md
CHANGED
|
@@ -115,6 +115,22 @@ await VideoPlayer.initPlayer({
|
|
|
115
115
|
- Widevine DRM metadata is forwarded to the Cast media item. DRM-protected streams may still require a receiver that supports your license server and DRM flow.
|
|
116
116
|
- Request headers used by the Android local player are not automatically available to the Chromecast receiver. Use public URLs, signed URLs, cookies supported by your receiver, or a custom receiver for secured media.
|
|
117
117
|
|
|
118
|
+
## Android Picture in Picture
|
|
119
|
+
|
|
120
|
+
Picture in Picture on Android requires your app activity to declare PiP support in `android/app/src/main/AndroidManifest.xml`:
|
|
121
|
+
|
|
122
|
+
```xml
|
|
123
|
+
<activity
|
|
124
|
+
android:name=".MainActivity"
|
|
125
|
+
android:supportsPictureInPicture="true"
|
|
126
|
+
android:launchMode="singleTask"
|
|
127
|
+
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"
|
|
128
|
+
...>
|
|
129
|
+
</activity>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`launchMode="singleTask"` and the `configChanges` flags prevent the player activity from being recreated when entering or leaving PiP.
|
|
133
|
+
|
|
118
134
|
## API
|
|
119
135
|
|
|
120
136
|
<docgen-index>
|
|
@@ -49,6 +49,7 @@ import com.getcapacitor.JSObject;
|
|
|
49
49
|
import com.google.android.exoplayer2.C;
|
|
50
50
|
import com.google.android.exoplayer2.DefaultLoadControl;
|
|
51
51
|
import com.google.android.exoplayer2.ExoPlayer;
|
|
52
|
+
import com.google.android.exoplayer2.Format;
|
|
52
53
|
import com.google.android.exoplayer2.LoadControl;
|
|
53
54
|
import com.google.android.exoplayer2.MediaItem;
|
|
54
55
|
import com.google.android.exoplayer2.MediaMetadata;
|
|
@@ -132,6 +133,10 @@ public class FullscreenExoPlayerFragment extends Fragment {
|
|
|
132
133
|
public JSObject drmOptions;
|
|
133
134
|
|
|
134
135
|
private static final String TAG = FullscreenExoPlayerFragment.class.getName();
|
|
136
|
+
private static final Rational DEFAULT_PIP_ASPECT_RATIO = new Rational(16, 9);
|
|
137
|
+
// Android PiP aspect ratio must stay within [100/239, 239/100].
|
|
138
|
+
private static final Rational MIN_PIP_ASPECT_RATIO = new Rational(100, 239);
|
|
139
|
+
private static final Rational MAX_PIP_ASPECT_RATIO = new Rational(239, 100);
|
|
135
140
|
public static final long UNKNOWN_TIME = -1L;
|
|
136
141
|
private final List<String> supportedFormat = Arrays.asList(
|
|
137
142
|
new String[] { "mp4", "webm", "ogv", "3gp", "flv", "dash", "mpd", "m3u8", "ism", "ytube", "" }
|
|
@@ -459,7 +464,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
|
|
|
459
464
|
new View.OnClickListener() {
|
|
460
465
|
@Override
|
|
461
466
|
public void onClick(View view) {
|
|
462
|
-
|
|
467
|
+
if (playerReady) {
|
|
468
|
+
pictureInPictureMode();
|
|
469
|
+
}
|
|
463
470
|
}
|
|
464
471
|
}
|
|
465
472
|
);
|
|
@@ -595,35 +602,92 @@ public class FullscreenExoPlayerFragment extends Fragment {
|
|
|
595
602
|
* Perform pictureInPictureMode Action
|
|
596
603
|
*/
|
|
597
604
|
private void pictureInPictureMode() {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
605
|
+
Activity activity = getActivity();
|
|
606
|
+
if (
|
|
607
|
+
activity == null ||
|
|
608
|
+
player == null ||
|
|
609
|
+
!playerReady ||
|
|
610
|
+
!pipEnabled ||
|
|
611
|
+
!packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
|
612
|
+
) {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
styledPlayerView.setUseController(false);
|
|
617
|
+
styledPlayerView.setControllerAutoShow(false);
|
|
618
|
+
linearLayout.setVisibility(View.INVISIBLE);
|
|
619
|
+
|
|
620
|
+
try {
|
|
621
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
622
|
+
pictureInPictureParams = new PictureInPictureParams.Builder().setAspectRatio(getPipAspectRatio());
|
|
623
|
+
if (!activity.enterPictureInPictureMode(pictureInPictureParams.build())) {
|
|
624
|
+
Log.w(TAG, "pictureInPictureMode: enterPictureInPictureMode returned false");
|
|
625
|
+
restorePlayerUiAfterFailedPip();
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
613
628
|
} else {
|
|
614
|
-
|
|
615
|
-
Log.v(TAG, "PIP break 3");
|
|
629
|
+
activity.enterPictureInPictureMode();
|
|
616
630
|
}
|
|
617
|
-
|
|
631
|
+
} catch (IllegalArgumentException | IllegalStateException exception) {
|
|
632
|
+
Log.e(TAG, "pictureInPictureMode failed", exception);
|
|
633
|
+
restorePlayerUiAfterFailedPip();
|
|
634
|
+
Toast.makeText(context, "Unable to start Picture in Picture", Toast.LENGTH_SHORT).show();
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
isInPictureInPictureMode = activity.isInPictureInPictureMode();
|
|
639
|
+
if (sturi != null) {
|
|
640
|
+
setSubtitle(true);
|
|
641
|
+
}
|
|
642
|
+
play();
|
|
643
|
+
handler.postDelayed(mRunnable, 100);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
private void restorePlayerUiAfterFailedPip() {
|
|
647
|
+
linearLayout.setVisibility(View.INVISIBLE);
|
|
648
|
+
if (showControls) {
|
|
649
|
+
styledPlayerView.setUseController(true);
|
|
650
|
+
styledPlayerView.setControllerAutoShow(true);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
private Rational getPipAspectRatio() {
|
|
655
|
+
if (player == null) {
|
|
656
|
+
return DEFAULT_PIP_ASPECT_RATIO;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
Format videoFormat = player.getVideoFormat();
|
|
660
|
+
if (videoFormat == null || videoFormat.width <= 0 || videoFormat.height <= 0) {
|
|
661
|
+
return DEFAULT_PIP_ASPECT_RATIO;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
Rational aspectRatio = new Rational(videoFormat.width, videoFormat.height);
|
|
665
|
+
if (aspectRatio.floatValue() < MIN_PIP_ASPECT_RATIO.floatValue()) {
|
|
666
|
+
return MIN_PIP_ASPECT_RATIO;
|
|
667
|
+
}
|
|
668
|
+
if (aspectRatio.floatValue() > MAX_PIP_ASPECT_RATIO.floatValue()) {
|
|
669
|
+
return MAX_PIP_ASPECT_RATIO;
|
|
670
|
+
}
|
|
671
|
+
return aspectRatio;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
public void handlePictureInPictureModeChanged(boolean inPictureInPictureMode) {
|
|
675
|
+
isInPictureInPictureMode = inPictureInPictureMode;
|
|
676
|
+
if (inPictureInPictureMode) {
|
|
677
|
+
linearLayout.setVisibility(View.INVISIBLE);
|
|
678
|
+
styledPlayerView.setUseController(false);
|
|
618
679
|
if (sturi != null) {
|
|
619
680
|
setSubtitle(true);
|
|
620
681
|
}
|
|
621
|
-
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
622
684
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
685
|
+
isPIPModeEnabled = true;
|
|
686
|
+
if (showControls) {
|
|
687
|
+
styledPlayerView.setUseController(true);
|
|
688
|
+
}
|
|
689
|
+
if (sturi != null) {
|
|
690
|
+
setSubtitle(false);
|
|
627
691
|
}
|
|
628
692
|
}
|
|
629
693
|
|
|
@@ -662,12 +726,17 @@ public class FullscreenExoPlayerFragment extends Fragment {
|
|
|
662
726
|
@Override
|
|
663
727
|
public void onStop() {
|
|
664
728
|
super.onStop();
|
|
665
|
-
|
|
666
|
-
if (
|
|
667
|
-
|
|
729
|
+
Activity activity = getActivity();
|
|
730
|
+
if (activity != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInPictureInPictureMode()) {
|
|
731
|
+
isInPictureInPictureMode = true;
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (isInPictureInPictureMode && activity != null) {
|
|
736
|
+
isInPictureInPictureMode = false;
|
|
668
737
|
linearLayout.setVisibility(View.VISIBLE);
|
|
669
738
|
playerExit();
|
|
670
|
-
|
|
739
|
+
activity.finishAndRemoveTask();
|
|
671
740
|
}
|
|
672
741
|
}
|
|
673
742
|
|
|
@@ -1706,6 +1775,10 @@ public class FullscreenExoPlayerFragment extends Fragment {
|
|
|
1706
1775
|
@Override
|
|
1707
1776
|
public void onConfigurationChanged(Configuration newConfig) {
|
|
1708
1777
|
super.onConfigurationChanged(newConfig);
|
|
1778
|
+
Activity activity = getActivity();
|
|
1779
|
+
if (activity != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
1780
|
+
handlePictureInPictureModeChanged(activity.isInPictureInPictureMode());
|
|
1781
|
+
}
|
|
1709
1782
|
adjustAspectRatio();
|
|
1710
1783
|
}
|
|
1711
1784
|
|
|
@@ -6,6 +6,7 @@ import android.app.UiModeManager;
|
|
|
6
6
|
import android.content.Context;
|
|
7
7
|
import android.content.pm.ActivityInfo;
|
|
8
8
|
import android.content.res.Configuration;
|
|
9
|
+
import android.content.res.Configuration;
|
|
9
10
|
import android.os.Build;
|
|
10
11
|
import android.util.Log;
|
|
11
12
|
import android.view.ViewGroup;
|
|
@@ -38,7 +39,7 @@ import java.util.Map;
|
|
|
38
39
|
)
|
|
39
40
|
public class VideoPlayerPlugin extends Plugin {
|
|
40
41
|
|
|
41
|
-
private final String pluginVersion = "8.1.
|
|
42
|
+
private final String pluginVersion = "8.1.20";
|
|
42
43
|
|
|
43
44
|
// Permission alias constants
|
|
44
45
|
private static final String PERMISSION_DENIED_ERROR = "Unable to access media videos, user denied permission request";
|
|
@@ -93,6 +94,14 @@ public class VideoPlayerPlugin extends Plugin {
|
|
|
93
94
|
this.fragmentUtils = new FragmentUtils(getBridge());
|
|
94
95
|
}
|
|
95
96
|
|
|
97
|
+
@Override
|
|
98
|
+
protected void handleOnConfigurationChanged(Configuration newConfig) {
|
|
99
|
+
super.handleOnConfigurationChanged(newConfig);
|
|
100
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && fsFragment != null && getActivity() != null) {
|
|
101
|
+
fsFragment.handlePictureInPictureModeChanged(getActivity().isInPictureInPictureMode());
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
96
105
|
@PermissionCallback
|
|
97
106
|
private void permissionsCallback(PluginCall call) {
|
|
98
107
|
if (!isPermissionsGranted()) {
|
|
@@ -8,7 +8,7 @@ import AVKit
|
|
|
8
8
|
*/
|
|
9
9
|
@objc(VideoPlayerPlugin)
|
|
10
10
|
public class VideoPlayerPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
11
|
-
private let pluginVersion: String = "8.1.
|
|
11
|
+
private let pluginVersion: String = "8.1.20"
|
|
12
12
|
public let identifier = "VideoPlayerPlugin"
|
|
13
13
|
public let jsName = "VideoPlayer"
|
|
14
14
|
public let pluginMethods: [CAPPluginMethod] = [
|