@picsa/capacitor-video-player 8.0.2 → 8.0.4

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.
@@ -301,7 +301,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
301
301
  new PlayerView.ControllerVisibilityListener() {
302
302
  @Override
303
303
  public void onVisibilityChanged(int visibility) {
304
- linearLayout.setVisibility(visibility);
304
+ if (linearLayout != null) {
305
+ linearLayout.setVisibility(visibility);
306
+ }
305
307
  }
306
308
  }
307
309
  );
@@ -310,6 +312,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
310
312
  new Player.Listener() {
311
313
  @Override
312
314
  public void onPlayerStateChanged(boolean playWhenReady, int state) {
315
+ if (isFragmentDestroyed || player == null || styledPlayerView == null) {
316
+ return;
317
+ }
313
318
  String stateString;
314
319
  Map<String, Object> info = new HashMap<String, Object>() {
315
320
  {
@@ -430,14 +435,17 @@ public class FullscreenExoPlayerFragment extends Fragment {
430
435
  }
431
436
  if (uri != null || Boolean.TRUE.equals(isInternal)) {
432
437
  // go fullscreen
433
- getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
434
- getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
438
+ Activity hostActivity = getActivity();
439
+ if (hostActivity != null && hostActivity.getWindow() != null) {
440
+ hostActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
441
+ hostActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
442
+ }
435
443
  if (savedInstanceState != null) {
436
444
  mCurrentPosition = savedInstanceState.getInt(PLAYBACK_TIME);
437
445
  }
438
446
 
439
- getActivity()
440
- .runOnUiThread(
447
+ if (hostActivity != null) {
448
+ hostActivity.runOnUiThread(
441
449
  new Runnable() {
442
450
  @Override
443
451
  public void run() {
@@ -511,10 +519,11 @@ public class FullscreenExoPlayerFragment extends Fragment {
511
519
  }
512
520
  }
513
521
  );
514
- } else {
515
- Log.d(TAG, "Video path wrong or type not supported");
516
- Toast.makeText(context, "Video path wrong or type not supported", Toast.LENGTH_SHORT).show();
517
- }
522
+ }
523
+ } else {
524
+ Log.d(TAG, "Video path wrong or type not supported");
525
+ Toast.makeText(context, "Video path wrong or type not supported", Toast.LENGTH_SHORT).show();
526
+ }
518
527
  adjustAspectRatio();
519
528
  return view;
520
529
  }
@@ -526,7 +535,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
526
535
 
527
536
  protected Bitmap doInBackground(Void... params) {
528
537
  final String image = artwork;
529
- if (image != "") {
538
+ if (image != null && !image.trim().isEmpty()) {
530
539
  try {
531
540
  URL url = new URL(image);
532
541
  HttpURLConnection connection = (HttpURLConnection) url.openConnection();
@@ -535,7 +544,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
535
544
  InputStream input = connection.getInputStream();
536
545
  Bitmap myBitmap = BitmapFactory.decodeStream(input);
537
546
  return myBitmap;
538
- } catch (IOException e) {
547
+ } catch (IOException | IllegalArgumentException e) {
539
548
  e.printStackTrace();
540
549
  return null;
541
550
  }
@@ -546,7 +555,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
546
555
 
547
556
  @Override
548
557
  protected void onPostExecute(Bitmap result) {
549
- cast_image.setImageBitmap(result);
558
+ if (cast_image != null) {
559
+ cast_image.setImageBitmap(result);
560
+ }
550
561
  }
551
562
  }
552
563
 
@@ -554,14 +565,16 @@ public class FullscreenExoPlayerFragment extends Fragment {
554
565
  * Show controller
555
566
  */
556
567
  public void showController() {
557
- styledPlayerView.showController();
568
+ if (styledPlayerView != null) {
569
+ styledPlayerView.showController();
570
+ }
558
571
  }
559
572
 
560
573
  /**
561
574
  * isControllerIsFullyVisible
562
575
  */
563
576
  public boolean isControllerIsFullyVisible() {
564
- return styledPlayerView.isControllerFullyVisible();
577
+ return styledPlayerView != null && styledPlayerView.isControllerFullyVisible();
565
578
  }
566
579
 
567
580
  /**
@@ -587,6 +600,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
587
600
  if (
588
601
  !isInPictureInPictureMode &&
589
602
  Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
603
+ packageManager != null &&
590
604
  packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) &&
591
605
  Boolean.TRUE.equals(isPIPModeeEnabled) &&
592
606
  Boolean.TRUE.equals(pipEnabled) &&
@@ -599,18 +613,21 @@ public class FullscreenExoPlayerFragment extends Fragment {
599
613
  }
600
614
 
601
615
  private void resizePressed() {
616
+ if (styledPlayerView == null) {
617
+ return;
618
+ }
602
619
  if (resizeStatus == AspectRatioFrameLayout.RESIZE_MODE_FIT) {
603
620
  styledPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FILL);
604
621
  resizeStatus = AspectRatioFrameLayout.RESIZE_MODE_FILL;
605
- resizeBtn.setImageResource(R.drawable.ic_zoom);
622
+ if (resizeBtn != null) resizeBtn.setImageResource(R.drawable.ic_zoom);
606
623
  } else if (resizeStatus == AspectRatioFrameLayout.RESIZE_MODE_FILL) {
607
624
  styledPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_ZOOM);
608
625
  resizeStatus = AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
609
- resizeBtn.setImageResource(R.drawable.ic_fit);
626
+ if (resizeBtn != null) resizeBtn.setImageResource(R.drawable.ic_fit);
610
627
  } else {
611
628
  styledPlayerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT);
612
629
  resizeStatus = AspectRatioFrameLayout.RESIZE_MODE_FIT;
613
- resizeBtn.setImageResource(R.drawable.ic_expand);
630
+ if (resizeBtn != null) resizeBtn.setImageResource(R.drawable.ic_expand);
614
631
  }
615
632
  }
616
633
 
@@ -645,7 +662,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
645
662
  * Perform pictureInPictureMode Action
646
663
  */
647
664
  private void pictureInPictureMode() {
648
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
665
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && packageManager != null && packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
649
666
  // Store activity reference to avoid multiple getActivity() calls and check for null
650
667
  // Fragment may be detached from activity during transitions or configuration changes
651
668
  Activity activity = getActivity();
@@ -653,9 +670,13 @@ public class FullscreenExoPlayerFragment extends Fragment {
653
670
  Log.v(TAG, "pictureInPictureMode: activity is null");
654
671
  return;
655
672
  }
656
- styledPlayerView.setUseController(false);
657
- styledPlayerView.setControllerAutoShow(false);
658
- linearLayout.setVisibility(View.INVISIBLE);
673
+ if (styledPlayerView != null) {
674
+ styledPlayerView.setUseController(false);
675
+ styledPlayerView.setControllerAutoShow(false);
676
+ }
677
+ if (linearLayout != null) {
678
+ linearLayout.setVisibility(View.INVISIBLE);
679
+ }
659
680
  Log.v(TAG, "PIP break 1");
660
681
  // require android O or higher
661
682
  if (
@@ -663,9 +684,13 @@ public class FullscreenExoPlayerFragment extends Fragment {
663
684
  ) {
664
685
  pictureInPictureParams = new PictureInPictureParams.Builder();
665
686
  // setup aspect ratio of the PIP window; fall back to 16:9 for audio-only or not-yet-decoded video
666
- VideoSize videoSize = player.getVideoSize();
667
- if (videoSize != VideoSize.UNKNOWN) {
668
- pictureInPictureParams.setAspectRatio(new Rational(videoSize.width, videoSize.height));
687
+ if (player != null) {
688
+ VideoSize videoSize = player.getVideoSize();
689
+ if (videoSize != VideoSize.UNKNOWN) {
690
+ pictureInPictureParams.setAspectRatio(new Rational(videoSize.width, videoSize.height));
691
+ } else {
692
+ pictureInPictureParams.setAspectRatio(new Rational(16, 9));
693
+ }
669
694
  } else {
670
695
  pictureInPictureParams.setAspectRatio(new Rational(16, 9));
671
696
  }
@@ -726,12 +751,10 @@ public class FullscreenExoPlayerFragment extends Fragment {
726
751
  if (castContext != null && Boolean.TRUE.equals(chromecast) && castPlayer != null && castPlayer.isCastSessionAvailable()) return;
727
752
 
728
753
  initializePlayer();
729
- if (player.getCurrentPosition() != 0) {
754
+ if (player != null && player.getCurrentPosition() != 0) {
730
755
  firstReadyToPlay = false;
731
756
  play();
732
757
  }
733
- } else {
734
- getActivity().finishAndRemoveTask();
735
758
  }
736
759
  }
737
760
  }
@@ -743,11 +766,16 @@ public class FullscreenExoPlayerFragment extends Fragment {
743
766
  public void onStop() {
744
767
  super.onStop();
745
768
  boolean isAppBackground = false;
746
- if (Boolean.TRUE.equals(bkModeEnabled)) isAppBackground = isApplicationSentToBackground(context);
769
+ if (context != null && Boolean.TRUE.equals(bkModeEnabled)) isAppBackground = isApplicationSentToBackground(context);
747
770
  if (isInPictureInPictureMode) {
748
- linearLayout.setVisibility(View.VISIBLE);
771
+ if (linearLayout != null) {
772
+ linearLayout.setVisibility(View.VISIBLE);
773
+ }
749
774
  playerExit();
750
- getActivity().finishAndRemoveTask();
775
+ Activity activity = getActivity();
776
+ if (activity != null) {
777
+ activity.finishAndRemoveTask();
778
+ }
751
779
  }
752
780
  }
753
781
 
@@ -756,12 +784,12 @@ public class FullscreenExoPlayerFragment extends Fragment {
756
784
  */
757
785
  @Override
758
786
  public void onDestroy() {
759
- isFragmentDestroyed = true;
760
-
761
- // Release player before calling super to ensure proper cleanup order
787
+ // Release player before setting isFragmentDestroyed and calling super to ensure proper cleanup order
762
788
  releasePlayer();
789
+ isFragmentDestroyed = true;
763
790
 
764
- // Clean up handler
791
+ // Clean up handlers
792
+ handler.removeCallbacks(mRunnable);
765
793
  if (mainHandler != null) {
766
794
  mainHandler.removeCallbacksAndMessages(null);
767
795
  mainHandler = null;
@@ -781,6 +809,18 @@ public class FullscreenExoPlayerFragment extends Fragment {
781
809
  super.onDetach();
782
810
  }
783
811
 
812
+ /**
813
+ * Perform onDestroyView Action
814
+ */
815
+ @Override
816
+ public void onDestroyView() {
817
+ if (styledPlayerView != null) {
818
+ styledPlayerView.setPlayer(null);
819
+ styledPlayerView = null;
820
+ }
821
+ super.onDestroyView();
822
+ }
823
+
784
824
  /**
785
825
  * Perform onPause Action
786
826
  */
@@ -791,7 +831,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
791
831
  castContext.removeCastStateListener(castStateListener);
792
832
  }
793
833
  boolean isAppBackground = false;
794
- if (Boolean.TRUE.equals(bkModeEnabled)) isAppBackground = isApplicationSentToBackground(context);
834
+ if (context != null && Boolean.TRUE.equals(bkModeEnabled)) isAppBackground = isApplicationSentToBackground(context);
795
835
 
796
836
  if (!isInPictureInPictureMode) {
797
837
  if (Util.SDK_INT < 24) {
@@ -807,7 +847,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
807
847
  }
808
848
  }
809
849
  } else {
810
- if (linearLayout.getVisibility() == View.VISIBLE) {
850
+ if (linearLayout != null && linearLayout.getVisibility() == View.VISIBLE) {
811
851
  linearLayout.setVisibility(View.INVISIBLE);
812
852
  }
813
853
  if ((isInPictureInPictureMode || isAppBackground) && player != null) play();
@@ -843,6 +883,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
843
883
  }
844
884
 
845
885
  private void releasePlayerInternal() {
886
+ if (styledPlayerView != null) {
887
+ styledPlayerView.setPlayer(null);
888
+ }
846
889
  if (player != null && !isFragmentDestroyed) {
847
890
  try {
848
891
  playWhenReady = player.getPlayWhenReady();
@@ -906,7 +949,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
906
949
  } else {
907
950
  isInPictureInPictureMode = false;
908
951
  if (
909
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
952
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
953
+ packageManager != null &&
954
+ packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
910
955
  ) {
911
956
  boolean isShowControls = showControls != null ? showControls : true;
912
957
  if (!isShowControls) {
@@ -940,9 +985,15 @@ public class FullscreenExoPlayerFragment extends Fragment {
940
985
  * Leave the fullsreen mode and reset the status bar to visible
941
986
  */
942
987
  private void showSystemUI() {
943
- getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
944
- getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
945
- getActivity().getWindow().getDecorView().setSystemUiVisibility(View.VISIBLE);
988
+ Activity activity = getActivity();
989
+ if (activity != null && activity.getWindow() != null) {
990
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
991
+ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
992
+ View decorView = activity.getWindow().getDecorView();
993
+ if (decorView != null) {
994
+ decorView.setSystemUiVisibility(View.VISIBLE);
995
+ }
996
+ }
946
997
  }
947
998
 
948
999
  /**
@@ -954,14 +1005,19 @@ public class FullscreenExoPlayerFragment extends Fragment {
954
1005
  if (styledPlayerView == null) {
955
1006
  return;
956
1007
  }
1008
+ Context playerContext = context != null ? context : getContext();
1009
+ if (playerContext == null) {
1010
+ Log.w(TAG, "initializePlayer: context is null, skipping");
1011
+ return;
1012
+ }
957
1013
  if (player == null) {
958
1014
  ExoTrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory();
959
- trackSelector = new DefaultTrackSelector(context, videoTrackSelectionFactory);
1015
+ trackSelector = new DefaultTrackSelector(playerContext, videoTrackSelectionFactory);
960
1016
  LoadControl loadControl = new DefaultLoadControl();
961
1017
 
962
1018
  // Media3 Migration Note: DefaultBandwidthMeter now configured automatically by default
963
1019
  player =
964
- new ExoPlayer.Builder(context)
1020
+ new ExoPlayer.Builder(playerContext)
965
1021
  .setSeekBackIncrementMs(10000)
966
1022
  .setSeekForwardIncrementMs(10000)
967
1023
  .setTrackSelector(trackSelector)
@@ -973,6 +1029,24 @@ public class FullscreenExoPlayerFragment extends Fragment {
973
1029
 
974
1030
  MediaSource mediaSource = null;
975
1031
  if (!Boolean.TRUE.equals(isInternal)) {
1032
+ // Re-derive uri/vType from videoPath on every init. They are cleared by
1033
+ // resetVariables() after release, and onStart/onResume can re-enter
1034
+ // initializePlayer() without going through onCreateView, which was the
1035
+ // sole place they were previously computed (NPE on vType.equals()).
1036
+ if (uri == null && videoPath != null && !videoPath.trim().isEmpty()) {
1037
+ try {
1038
+ uri = Uri.parse(videoPath);
1039
+ } catch (Exception e) {
1040
+ Log.e(TAG, "Invalid video path: " + videoPath, e);
1041
+ uri = null;
1042
+ }
1043
+ }
1044
+ if (vType == null && uri != null) {
1045
+ vType = getVideoType(uri);
1046
+ }
1047
+ if (vType == null) {
1048
+ vType = "";
1049
+ }
976
1050
  if (videoPath != null && (videoPath.startsWith("file:///android_asset") || videoPath.startsWith("content://media"))) {
977
1051
  mediaSource = buildAssetMediaSource(uri);
978
1052
  } else if (videoPath != null && !videoPath.trim().isEmpty()) {
@@ -1006,24 +1080,31 @@ public class FullscreenExoPlayerFragment extends Fragment {
1006
1080
  }
1007
1081
  // Media3 Migration Note: MediaSessionConnector replaced with MediaSession.Builder; null check prevents duplicate session ID
1008
1082
  if (mediaSession == null) {
1009
- mediaSession = new MediaSession.Builder(context, player)
1010
- .setId("capacitorvideoplayer")
1011
- .build();
1083
+ try {
1084
+ mediaSession = new MediaSession.Builder(playerContext, player)
1085
+ .setId("capacitorvideoplayer")
1086
+ .build();
1087
+ } catch (Exception e) {
1088
+ Log.e(TAG, "Failed to build MediaSession", e);
1089
+ }
1012
1090
  }
1013
1091
 
1014
1092
  NotificationCenter.defaultCenter().postNotification("initializePlayer", info);
1015
1093
  }
1016
1094
 
1017
1095
  private void setSubtitle(boolean transparent) {
1096
+ if (styledPlayerView == null || styledPlayerView.getSubtitleView() == null) {
1097
+ return;
1098
+ }
1018
1099
  int foreground;
1019
1100
  int background;
1020
1101
  if (!transparent) {
1021
1102
  foreground = Color.WHITE;
1022
1103
  background = Color.BLACK;
1023
- if (stForeColor.length() > 4 && stForeColor.substring(0, 4).equals("rgba")) {
1104
+ if (stForeColor != null && stForeColor.length() > 4 && stForeColor.substring(0, 4).equals("rgba")) {
1024
1105
  foreground = getColorFromRGBA(stForeColor);
1025
1106
  }
1026
- if (stBackColor.length() > 4 && stBackColor.substring(0, 4).equals("rgba")) {
1107
+ if (stBackColor != null && stBackColor.length() > 4 && stBackColor.substring(0, 4).equals("rgba")) {
1027
1108
  background = getColorFromRGBA(stBackColor);
1028
1109
  }
1029
1110
  } else {
@@ -1035,7 +1116,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
1035
1116
  .setStyle(
1036
1117
  new CaptionStyleCompat(foreground, background, Color.TRANSPARENT, CaptionStyleCompat.EDGE_TYPE_NONE, Color.WHITE, null)
1037
1118
  );
1038
- styledPlayerView.getSubtitleView().setFixedTextSize(TypedValue.COMPLEX_UNIT_DIP, stFontSize);
1119
+ styledPlayerView.getSubtitleView().setFixedTextSize(TypedValue.COMPLEX_UNIT_DIP, stFontSize != null ? stFontSize : 16);
1039
1120
  styledPlayerView.setShowSubtitleButton(true);
1040
1121
  }
1041
1122
 
@@ -1043,9 +1124,16 @@ public class FullscreenExoPlayerFragment extends Fragment {
1043
1124
  * Build the Asset MediaSource
1044
1125
  */
1045
1126
  private MediaSource buildAssetMediaSource(Uri uri) {
1127
+ if (uri == null) {
1128
+ return null;
1129
+ }
1130
+ Context dataContext = context != null ? context : getContext();
1131
+ if (dataContext == null) {
1132
+ return null;
1133
+ }
1046
1134
  MediaSource mediaSource = null;
1047
1135
  // Media3 Migration Note: DefaultDataSourceFactory replaced with DefaultDataSource.Factory
1048
- DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(context);
1136
+ DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(dataContext);
1049
1137
  mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(uri));
1050
1138
  // Get the subtitles if any
1051
1139
  if (sturi != null) {
@@ -1058,7 +1146,14 @@ public class FullscreenExoPlayerFragment extends Fragment {
1058
1146
  * Build the Internal MediaSource
1059
1147
  */
1060
1148
  private MediaSource buildInternalMediaSource(Uri uri) {
1061
- DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(context);
1149
+ if (uri == null) {
1150
+ return null;
1151
+ }
1152
+ Context dataContext = context != null ? context : getContext();
1153
+ if (dataContext == null) {
1154
+ return null;
1155
+ }
1156
+ DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(dataContext);
1062
1157
  return new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(uri));
1063
1158
  }
1064
1159
 
@@ -1067,6 +1162,13 @@ public class FullscreenExoPlayerFragment extends Fragment {
1067
1162
  * @return MediaSource
1068
1163
  */
1069
1164
  private MediaSource buildHttpMediaSource() {
1165
+ if (uri == null) {
1166
+ Log.e(TAG, "buildHttpMediaSource: uri is null, cannot build media source");
1167
+ return null;
1168
+ }
1169
+ // vType may still be null if getVideoType was never called (e.g. re-init
1170
+ // after release). Default to progressive rather than NPE on equals().
1171
+ String type = vType != null ? vType : "";
1070
1172
  MediaSource mediaSource = null;
1071
1173
 
1072
1174
  DefaultHttpDataSource.Factory httpDataSourceFactory = new DefaultHttpDataSource.Factory();
@@ -1076,38 +1178,57 @@ public class FullscreenExoPlayerFragment extends Fragment {
1076
1178
  httpDataSourceFactory.setAllowCrossProtocolRedirects(true);
1077
1179
 
1078
1180
  // If headers is not null and has data we pass them to the HttpDataSourceFactory
1079
- if (headers != null && headers.length() > 0) {
1080
- // We map the headers(JSObject) to a Map<String, String>
1081
- Map<String, String> headersMap = new HashMap<String, String>();
1082
- for (int i = 0; i < headers.names().length(); i++) {
1083
- try {
1084
- headersMap.put(headers.names().getString(i), headers.get(headers.names().getString(i)).toString());
1085
- } catch (JSONException e) {
1086
- e.printStackTrace();
1181
+ if (headers != null) {
1182
+ try {
1183
+ if (headers.length() > 0 && headers.names() != null) {
1184
+ // We map the headers(JSObject) to a Map<String, String>
1185
+ Map<String, String> headersMap = new HashMap<String, String>();
1186
+ for (int i = 0; i < headers.names().length(); i++) {
1187
+ try {
1188
+ String key = headers.names().getString(i);
1189
+ Object value = headers.get(key);
1190
+ if (key != null && value != null) {
1191
+ headersMap.put(key, value.toString());
1192
+ }
1193
+ } catch (JSONException e) {
1194
+ e.printStackTrace();
1195
+ }
1196
+ }
1197
+ httpDataSourceFactory.setDefaultRequestProperties(headersMap);
1087
1198
  }
1199
+ } catch (Exception e) {
1200
+ Log.e(TAG, "Error applying headers", e);
1088
1201
  }
1089
- httpDataSourceFactory.setDefaultRequestProperties(headersMap);
1090
1202
  }
1091
1203
 
1092
- DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(context, httpDataSourceFactory);
1204
+ DataSource.Factory dataSourceFactory;
1205
+ Context dataContext = context != null ? context : getContext();
1206
+ if (dataContext == null) {
1207
+ Log.e(TAG, "buildHttpMediaSource: context is null, cannot build media source");
1208
+ return null;
1209
+ }
1210
+ dataSourceFactory = new DefaultDataSource.Factory(dataContext, httpDataSourceFactory);
1093
1211
 
1094
1212
  if (
1095
- vType.equals("mp4") ||
1096
- vType.equals("webm") ||
1097
- vType.equals("ogv") ||
1098
- vType.equals("3gp") ||
1099
- vType.equals("flv") ||
1100
- vType.equals("")
1213
+ "mp4".equals(type) ||
1214
+ "webm".equals(type) ||
1215
+ "ogv".equals(type) ||
1216
+ "3gp".equals(type) ||
1217
+ "flv".equals(type) ||
1218
+ "".equals(type)
1101
1219
  ) {
1102
1220
  mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(uri));
1103
- } else if (vType.equals("dash") || vType.equals("mpd")) {
1221
+ } else if ("dash".equals(type) || "mpd".equals(type)) {
1104
1222
  /* adaptive streaming Dash stream */
1105
1223
  DashMediaSource.Factory mediaSourceFactory = new DashMediaSource.Factory(dataSourceFactory);
1106
1224
  mediaSource = mediaSourceFactory.createMediaSource(MediaItem.fromUri(uri));
1107
- } else if (vType.equals("m3u8")) {
1225
+ } else if ("m3u8".equals(type)) {
1108
1226
  mediaSource = new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(uri));
1109
- } else if (vType.equals("ism")) {
1227
+ } else if ("ism".equals(type)) {
1110
1228
  mediaSource = new SsMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(uri));
1229
+ } else {
1230
+ Log.w(TAG, "buildHttpMediaSource: unsupported video type '" + type + "', falling back to progressive");
1231
+ mediaSource = new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(uri));
1111
1232
  }
1112
1233
  // Get the subtitles if any
1113
1234
  if (sturi != null) {
@@ -1152,13 +1273,27 @@ public class FullscreenExoPlayerFragment extends Fragment {
1152
1273
  }
1153
1274
 
1154
1275
  private MediaSource getSubTitle(MediaSource mediaSource, Uri sturi, DataSource.Factory dataSourceFactory) {
1276
+ if (mediaSource == null || sturi == null) {
1277
+ return mediaSource;
1278
+ }
1155
1279
  // Create mediaSource with subtitle
1156
1280
  MediaSource[] mediaSources = new MediaSource[2];
1157
1281
  mediaSources[0] = mediaSource;
1158
1282
  String mimeType = getMimeType(sturi);
1283
+ if (mimeType == null || mimeType.isEmpty()) {
1284
+ Log.w(TAG, "getSubTitle: unknown subtitle mime type, skipping subtitles");
1285
+ return mediaSource;
1286
+ }
1159
1287
 
1160
1288
  // We get the language label from the language code
1161
- String languageLabel = Locale.forLanguageTag(language).getDisplayLanguage();
1289
+ String safeLanguage = language != null ? language : "";
1290
+ String languageLabel;
1291
+ try {
1292
+ languageLabel = Locale.forLanguageTag(safeLanguage).getDisplayLanguage();
1293
+ } catch (Exception e) {
1294
+ Log.e(TAG, "Invalid language tag: " + safeLanguage, e);
1295
+ languageLabel = safeLanguage;
1296
+ }
1162
1297
  MediaItem.SubtitleConfiguration subConfig = new MediaItem.SubtitleConfiguration.Builder(sturi)
1163
1298
  .setMimeType(mimeType)
1164
1299
  .setUri(sturi)
@@ -1166,7 +1301,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
1166
1301
  .setLabel(languageLabel)
1167
1302
  .setRoleFlags(C.ROLE_FLAG_CAPTION)
1168
1303
  .setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
1169
- .setLanguage(language)
1304
+ .setLanguage(safeLanguage)
1170
1305
  .build();
1171
1306
 
1172
1307
  SingleSampleMediaSource subtitleSource = new SingleSampleMediaSource.Factory(dataSourceFactory)
@@ -1179,16 +1314,29 @@ public class FullscreenExoPlayerFragment extends Fragment {
1179
1314
  }
1180
1315
 
1181
1316
  private String getMimeType(Uri sturi) {
1182
- String lastSegment = sturi.getLastPathSegment();
1183
- String extension = lastSegment.substring(lastSegment.lastIndexOf(".") + 1);
1317
+ if (sturi == null) {
1318
+ return "";
1319
+ }
1320
+ String lastSegment;
1321
+ try {
1322
+ lastSegment = sturi.getLastPathSegment();
1323
+ } catch (Exception e) {
1324
+ Log.e(TAG, "getMimeType: failed to get last path segment", e);
1325
+ return "";
1326
+ }
1327
+ if (lastSegment == null || lastSegment.isEmpty()) {
1328
+ return "";
1329
+ }
1330
+ int dotIndex = lastSegment.lastIndexOf(".");
1331
+ String extension = (dotIndex != -1 ? lastSegment.substring(dotIndex + 1) : lastSegment).toLowerCase(Locale.ROOT);
1184
1332
  String mimeType = "";
1185
- if (extension.equals("vtt")) {
1333
+ if ("vtt".equals(extension)) {
1186
1334
  mimeType = MimeTypes.TEXT_VTT;
1187
- } else if (extension.equals("srt")) {
1335
+ } else if ("srt".equals(extension)) {
1188
1336
  mimeType = MimeTypes.APPLICATION_SUBRIP;
1189
- } else if (extension.equals("ssa") || extension.equals("ass")) {
1337
+ } else if ("ssa".equals(extension) || "ass".equals(extension)) {
1190
1338
  mimeType = MimeTypes.TEXT_SSA;
1191
- } else if (extension.equals("ttml") || extension.equals("dfxp") || extension.equals("xml")) {
1339
+ } else if ("ttml".equals(extension) || "dfxp".equals(extension) || "xml".equals(extension)) {
1192
1340
  mimeType = MimeTypes.APPLICATION_TTML;
1193
1341
  }
1194
1342
  return mimeType;
@@ -1198,7 +1346,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
1198
1346
  * Fast Forward TV
1199
1347
  */
1200
1348
  private void fastForward(long position, int times) {
1201
- if (position < mDuration - videoStep) {
1349
+ if (player != null && position < mDuration - videoStep) {
1202
1350
  if (player.isPlaying()) {
1203
1351
  player.setPlayWhenReady(false);
1204
1352
  }
@@ -1211,7 +1359,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
1211
1359
  * Rewind TV
1212
1360
  */
1213
1361
  private void rewind(long position, int times) {
1214
- if (position > videoStep) {
1362
+ if (player != null && position > videoStep) {
1215
1363
  if (player.isPlaying()) {
1216
1364
  player.setPlayWhenReady(false);
1217
1365
  }
@@ -1224,7 +1372,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
1224
1372
  * Play Pause TV
1225
1373
  */
1226
1374
  private void play_pause() {
1227
- player.setPlayWhenReady(!player.isPlaying());
1375
+ if (player != null) {
1376
+ player.setPlayWhenReady(!player.isPlaying());
1377
+ }
1228
1378
  }
1229
1379
 
1230
1380
  /**
@@ -1232,7 +1382,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
1232
1382
  * @return boolean
1233
1383
  */
1234
1384
  public boolean isPlaying() {
1235
- return player.isPlaying();
1385
+ return player != null && player.isPlaying();
1236
1386
  }
1237
1387
 
1238
1388
  /**
@@ -1312,6 +1462,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
1312
1462
  * @return int in seconds
1313
1463
  */
1314
1464
  public int getDuration() {
1465
+ if (player == null) {
1466
+ return 0;
1467
+ }
1315
1468
  return player.getDuration() == UNKNOWN_TIME ? 0 : (int) (player.getDuration() / 1000);
1316
1469
  }
1317
1470
 
@@ -1338,8 +1491,12 @@ public class FullscreenExoPlayerFragment extends Fragment {
1338
1491
 
1339
1492
  try {
1340
1493
  if (isInPictureInPictureMode) {
1341
- styledPlayerView.setUseController(false);
1342
- linearLayout.setVisibility(View.INVISIBLE);
1494
+ if (styledPlayerView != null) {
1495
+ styledPlayerView.setUseController(false);
1496
+ }
1497
+ if (linearLayout != null) {
1498
+ linearLayout.setVisibility(View.INVISIBLE);
1499
+ }
1343
1500
  }
1344
1501
  long seekPosition = player.getCurrentPosition() == UNKNOWN_TIME
1345
1502
  ? 0
@@ -1355,7 +1512,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
1355
1512
  * @return float
1356
1513
  */
1357
1514
  public float getVolume() {
1358
- return player.getVolume();
1515
+ return player != null ? player.getVolume() : curVolume;
1359
1516
  }
1360
1517
 
1361
1518
  /**
@@ -1364,7 +1521,10 @@ public class FullscreenExoPlayerFragment extends Fragment {
1364
1521
  */
1365
1522
  public void setVolume(float _volume) {
1366
1523
  float volume = Math.min(Math.max(0, _volume), 1L);
1367
- player.setVolume(volume);
1524
+ curVolume = volume;
1525
+ if (player != null) {
1526
+ player.setVolume(volume);
1527
+ }
1368
1528
  }
1369
1529
 
1370
1530
  /**
@@ -1381,8 +1541,10 @@ public class FullscreenExoPlayerFragment extends Fragment {
1381
1541
  */
1382
1542
  public void setRate(float _rate) {
1383
1543
  videoRate = _rate;
1384
- PlaybackParameters param = new PlaybackParameters(videoRate);
1385
- player.setPlaybackParameters(param);
1544
+ if (player != null) {
1545
+ PlaybackParameters param = new PlaybackParameters(videoRate != null ? videoRate : 1.0f);
1546
+ player.setPlaybackParameters(param);
1547
+ }
1386
1548
  }
1387
1549
 
1388
1550
  /**
@@ -1391,11 +1553,13 @@ public class FullscreenExoPlayerFragment extends Fragment {
1391
1553
  */
1392
1554
  public void setMuted(boolean _isMuted) {
1393
1555
  isMuted = _isMuted;
1394
- if (isMuted) {
1395
- curVolume = player.getVolume();
1396
- player.setVolume(0L);
1397
- } else {
1398
- player.setVolume(curVolume);
1556
+ if (player != null) {
1557
+ if (isMuted) {
1558
+ curVolume = player.getVolume();
1559
+ player.setVolume(0L);
1560
+ } else {
1561
+ player.setVolume(curVolume);
1562
+ }
1399
1563
  }
1400
1564
  }
1401
1565
 
@@ -1412,7 +1576,7 @@ public class FullscreenExoPlayerFragment extends Fragment {
1412
1576
  * @param button
1413
1577
  */
1414
1578
  private void mediaRouteButtonColorWhite(MediaRouteButton button) {
1415
- if (button == null) return;
1579
+ if (button == null || getContext() == null) return;
1416
1580
  Context castContext = new ContextThemeWrapper(getContext(), androidx.mediarouter.R.style.Theme_MediaRouter);
1417
1581
 
1418
1582
  TypedArray a = castContext.obtainStyledAttributes(
@@ -1423,6 +1587,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
1423
1587
  );
1424
1588
  Drawable drawable = a.getDrawable(androidx.mediarouter.R.styleable.MediaRouteButton_externalRouteEnabledDrawable);
1425
1589
  a.recycle();
1590
+ if (drawable == null) {
1591
+ return;
1592
+ }
1426
1593
  DrawableCompat.setTint(drawable, getContext().getResources().getColor(R.color.white));
1427
1594
  drawable.setState(button.getDrawableState());
1428
1595
  button.setRemoteIndicatorDrawable(drawable);
@@ -1434,6 +1601,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
1434
1601
  * @return video type
1435
1602
  */
1436
1603
  private String getVideoType(Uri uri) {
1604
+ if (uri == null) {
1605
+ return "";
1606
+ }
1437
1607
  String ret = null;
1438
1608
  Object obj = uri.getLastPathSegment();
1439
1609
  String lastSegment = (obj == null) ? "" : uri.getLastPathSegment();
@@ -1442,17 +1612,19 @@ public class FullscreenExoPlayerFragment extends Fragment {
1442
1612
  if (lastSegment.length() > 0 && lastSegment.contains(type)) ret = type;
1443
1613
  if (ret == null) {
1444
1614
  List<String> segments = uri.getPathSegments();
1445
- if (segments.size() > 0) {
1615
+ if (segments != null && segments.size() > 0) {
1446
1616
  String segment;
1447
- if (segments.get(segments.size() - 1).equals("manifest")) {
1617
+ if (segments.get(segments.size() - 1).equals("manifest") && segments.size() >= 2) {
1448
1618
  segment = segments.get(segments.size() - 2);
1449
1619
  } else {
1450
1620
  segment = segments.get(segments.size() - 1);
1451
1621
  }
1452
- for (String sType : supportedFormat) {
1453
- if (segment.contains(sType)) {
1454
- ret = sType;
1455
- break;
1622
+ if (segment != null) {
1623
+ for (String sType : supportedFormat) {
1624
+ if (segment.contains(sType)) {
1625
+ ret = sType;
1626
+ break;
1627
+ }
1456
1628
  }
1457
1629
  }
1458
1630
  }
@@ -1467,7 +1639,6 @@ public class FullscreenExoPlayerFragment extends Fragment {
1467
1639
  */
1468
1640
  private void resetVariables() {
1469
1641
  vType = null;
1470
- styledPlayerView = null;
1471
1642
  playWhenReady = true;
1472
1643
  firstReadyToPlay = true;
1473
1644
  isEnded = false;
@@ -1485,8 +1656,14 @@ public class FullscreenExoPlayerFragment extends Fragment {
1485
1656
  * @return boolean
1486
1657
  */
1487
1658
  public boolean isApplicationSentToBackground(final Context context) {
1659
+ if (context == null) {
1660
+ return false;
1661
+ }
1488
1662
  int pid = android.os.Process.myPid();
1489
1663
  ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1664
+ if (am == null) {
1665
+ return false;
1666
+ }
1490
1667
  List<ActivityManager.RunningAppProcessInfo> procInfos = am.getRunningAppProcesses();
1491
1668
  if (procInfos != null) {
1492
1669
  for (ActivityManager.RunningAppProcessInfo appProcess : procInfos) {
@@ -1509,6 +1686,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
1509
1686
  task.addOnCompleteListener(new OnCompleteListener<CastContext>() {
1510
1687
  @Override
1511
1688
  public void onComplete(Task<CastContext> task) {
1689
+ if (isFragmentDestroyed || !isAdded() || context == null || mediaRouteButton == null) {
1690
+ return;
1691
+ }
1512
1692
  if (task.isSuccessful()) {
1513
1693
  castContext = task.getResult();
1514
1694
  castPlayer = new CastPlayer(castContext);
@@ -1525,6 +1705,9 @@ public class FullscreenExoPlayerFragment extends Fragment {
1525
1705
 
1526
1706
  castStateListener =
1527
1707
  state -> {
1708
+ if (mediaRouteButton == null) {
1709
+ return;
1710
+ }
1528
1711
  if (state == CastState.NO_DEVICES_AVAILABLE) {
1529
1712
  mediaRouteButton.setVisibility(View.GONE);
1530
1713
  } else {
@@ -1536,13 +1719,17 @@ public class FullscreenExoPlayerFragment extends Fragment {
1536
1719
  CastButtonFactory.setUpMediaRouteButton(context, mediaRouteButton);
1537
1720
 
1538
1721
  MediaMetadata movieMetadata;
1539
- if (artwork != "") {
1540
- movieMetadata = new MediaMetadata.Builder()
1541
- .setTitle(title)
1542
- .setSubtitle(smallTitle)
1543
- .setMediaType(MediaMetadata.MEDIA_TYPE_MOVIE)
1544
- .setArtworkUri(Uri.parse(artwork))
1545
- .build();
1722
+ if (artwork != null && !artwork.trim().isEmpty()) {
1723
+ MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder()
1724
+ .setTitle(title)
1725
+ .setSubtitle(smallTitle)
1726
+ .setMediaType(MediaMetadata.MEDIA_TYPE_MOVIE);
1727
+ try {
1728
+ metadataBuilder.setArtworkUri(Uri.parse(artwork));
1729
+ } catch (Exception e) {
1730
+ Log.e(TAG, "Invalid artwork uri: " + artwork, e);
1731
+ }
1732
+ movieMetadata = metadataBuilder.build();
1546
1733
  new setCastImage().execute();
1547
1734
  } else {
1548
1735
  movieMetadata = new MediaMetadata.Builder()
@@ -1562,35 +1749,53 @@ public class FullscreenExoPlayerFragment extends Fragment {
1562
1749
  @Override
1563
1750
  public void onCastSessionAvailable() {
1564
1751
  isCastSession = true;
1565
- final Long videoPosition = player.getCurrentPosition();
1566
- if (Boolean.TRUE.equals(pipEnabled)) {
1752
+ final Long videoPosition = player != null ? player.getCurrentPosition() : 0L;
1753
+ if (pipBtn != null && Boolean.TRUE.equals(pipEnabled)) {
1567
1754
  pipBtn.setVisibility(View.GONE);
1568
1755
  }
1569
- resizeBtn.setVisibility(View.GONE);
1570
- player.setPlayWhenReady(false);
1571
- cast_image.setVisibility(View.VISIBLE);
1756
+ if (resizeBtn != null) {
1757
+ resizeBtn.setVisibility(View.GONE);
1758
+ }
1759
+ if (player != null) {
1760
+ player.setPlayWhenReady(false);
1761
+ }
1762
+ if (cast_image != null) {
1763
+ cast_image.setVisibility(View.VISIBLE);
1764
+ }
1572
1765
  castPlayer.setMediaItem(mediaItem, videoPosition);
1573
- styledPlayerView.setPlayer(castPlayer);
1574
- styledPlayerView.setControllerShowTimeoutMs(0);
1575
- styledPlayerView.setControllerHideOnTouch(false);
1576
- //We perform a click because for some weird reason, the layout is black until the user clicks on it
1577
- styledPlayerView.performClick();
1766
+ if (styledPlayerView != null) {
1767
+ styledPlayerView.setPlayer(castPlayer);
1768
+ styledPlayerView.setControllerShowTimeoutMs(0);
1769
+ styledPlayerView.setControllerHideOnTouch(false);
1770
+ //We perform a click because for some weird reason, the layout is black until the user clicks on it
1771
+ styledPlayerView.performClick();
1772
+ }
1578
1773
  }
1579
1774
 
1580
1775
  @Override
1581
1776
  public void onCastSessionUnavailable() {
1582
1777
  isCastSession = false;
1583
- final Long videoPosition = castPlayer.getCurrentPosition();
1584
- if (Boolean.TRUE.equals(pipEnabled)) {
1778
+ final Long videoPosition = castPlayer != null ? castPlayer.getCurrentPosition() : 0L;
1779
+ if (pipBtn != null && Boolean.TRUE.equals(pipEnabled)) {
1585
1780
  pipBtn.setVisibility(View.VISIBLE);
1586
1781
  }
1587
- resizeBtn.setVisibility(View.VISIBLE);
1588
- cast_image.setVisibility(View.GONE);
1589
- styledPlayerView.setPlayer(player);
1590
- player.setPlayWhenReady(true);
1591
- player.seekTo(videoPosition);
1592
- styledPlayerView.setControllerShowTimeoutMs(3000);
1593
- styledPlayerView.setControllerHideOnTouch(true);
1782
+ if (resizeBtn != null) {
1783
+ resizeBtn.setVisibility(View.VISIBLE);
1784
+ }
1785
+ if (cast_image != null) {
1786
+ cast_image.setVisibility(View.GONE);
1787
+ }
1788
+ if (styledPlayerView != null) {
1789
+ styledPlayerView.setPlayer(player);
1790
+ }
1791
+ if (player != null) {
1792
+ player.setPlayWhenReady(true);
1793
+ player.seekTo(videoPosition);
1794
+ }
1795
+ if (styledPlayerView != null) {
1796
+ styledPlayerView.setControllerShowTimeoutMs(3000);
1797
+ styledPlayerView.setControllerHideOnTouch(true);
1798
+ }
1594
1799
  }
1595
1800
  }
1596
1801
  );
@@ -1602,12 +1807,12 @@ public class FullscreenExoPlayerFragment extends Fragment {
1602
1807
  Map<String, Object> info = new HashMap<String, Object>() {
1603
1808
  {
1604
1809
  put("fromPlayerId", playerId);
1605
- put("currentTime", String.valueOf(player.getCurrentPosition() / 1000));
1810
+ put("currentTime", String.valueOf(player != null ? player.getCurrentPosition() / 1000 : 0));
1606
1811
  }
1607
1812
  };
1608
1813
  switch (state) {
1609
1814
  case CastPlayer.STATE_READY:
1610
- if (castPlayer.isPlaying()) {
1815
+ if (castPlayer != null && castPlayer.isPlaying()) {
1611
1816
  NotificationCenter.defaultCenter().postNotification("playerItemPlay", info);
1612
1817
  } else {
1613
1818
  NotificationCenter.defaultCenter().postNotification("playerItemPause", info);
@@ -1621,11 +1826,17 @@ public class FullscreenExoPlayerFragment extends Fragment {
1621
1826
  );
1622
1827
 
1623
1828
  castContext.addCastStateListener(castStateListener);
1624
- mRouter.addCallback(mSelector, mCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
1829
+ if (mRouter != null && mSelector != null && mCallback != null) {
1830
+ mRouter.addCallback(mSelector, mCallback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
1831
+ }
1625
1832
 
1626
1833
  } else {
1627
1834
  Exception e = task.getException();
1628
- e.printStackTrace();
1835
+ if (e != null) {
1836
+ e.printStackTrace();
1837
+ } else {
1838
+ Log.e(TAG, "initializeCastService: CastContext task failed with no exception");
1839
+ }
1629
1840
  }
1630
1841
  }
1631
1842
  });
@@ -1640,6 +1851,8 @@ public class FullscreenExoPlayerFragment extends Fragment {
1640
1851
  }
1641
1852
 
1642
1853
  private void adjustAspectRatio() {
1643
- styledPlayerView.setResizeMode(resizeStatus);
1854
+ if (styledPlayerView != null) {
1855
+ styledPlayerView.setResizeMode(resizeStatus);
1856
+ }
1644
1857
  }
1645
1858
  }
@@ -78,6 +78,9 @@ public class PickerVideoFragment extends Fragment {
78
78
  }
79
79
 
80
80
  private void loadVideos() {
81
+ if (context == null) {
82
+ return;
83
+ }
81
84
  String[] projection = {
82
85
  MediaStore.Video.Media._ID,
83
86
  MediaStore.Video.Media.DISPLAY_NAME,
@@ -92,37 +95,46 @@ public class PickerVideoFragment extends Fragment {
92
95
  collection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
93
96
  }
94
97
 
95
- Cursor cursor = getActivity().getApplication().getContentResolver().query(collection, projection, null, null, sortOrder);
96
- if (cursor != null) {
97
- int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);
98
- int titleColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);
99
- int durationColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);
98
+ try (Cursor cursor = context.getContentResolver().query(collection, projection, null, null, sortOrder)) {
99
+ if (cursor != null) {
100
+ int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);
101
+ int titleColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);
102
+ int durationColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);
100
103
 
101
- while (cursor.moveToNext()) {
102
- long id = cursor.getLong(idColumn);
103
- String title = cursor.getString(titleColumn);
104
- int duration = cursor.getInt(durationColumn);
104
+ while (cursor.moveToNext()) {
105
+ long id = cursor.getLong(idColumn);
106
+ String title = cursor.getString(titleColumn);
107
+ int duration = cursor.getInt(durationColumn);
105
108
 
106
- Uri data = ContentUris.withAppendedId(collection, id);
109
+ Uri data = ContentUris.withAppendedId(collection, id);
107
110
 
108
- String duration_formatted;
109
- int sec = (duration / 1000) % 60;
110
- int min = (duration / (1000 * 60)) % 60;
111
- int hrs = duration / (1000 * 60 * 60);
111
+ String duration_formatted;
112
+ int sec = (duration / 1000) % 60;
113
+ int min = (duration / (1000 * 60)) % 60;
114
+ int hrs = duration / (1000 * 60 * 60);
112
115
 
113
- if (hrs == 0) {
114
- duration_formatted = String.valueOf(min).concat(":".concat(String.format(Locale.UK, "%02d", sec)));
115
- } else {
116
- duration_formatted =
117
- String
118
- .valueOf(hrs)
119
- .concat(
120
- ":".concat(String.format(Locale.UK, "%02d", min).concat(":".concat(String.format(Locale.UK, "%02d", sec))))
121
- );
116
+ if (hrs == 0) {
117
+ duration_formatted = String.valueOf(min).concat(":".concat(String.format(Locale.UK, "%02d", sec)));
118
+ } else {
119
+ duration_formatted = String.valueOf(hrs).concat(
120
+ ":".concat(String.format(Locale.UK, "%02d", min).concat(":".concat(String.format(Locale.UK, "%02d", sec))))
121
+ );
122
+ }
123
+ Log.v(TAG, "**** video " + id + " " + title + " " + duration_formatted + " ****");
124
+ videosList.add(new ModelVideo(id, data, title, duration_formatted));
122
125
  }
123
- Log.v(TAG, "**** video " + id + " " + title + " " + duration_formatted + " ****");
124
- videosList.add(new ModelVideo(id, data, title, duration_formatted));
125
126
  }
127
+ } catch (Exception e) {
128
+ Log.e(TAG, "Error loading videos from media store", e);
126
129
  }
127
130
  }
131
+
132
+ @Override
133
+ public void onDestroyView() {
134
+ recyclerView = null;
135
+ recyclerViewLayoutManager = null;
136
+ adapterVideoList = null;
137
+ view = null;
138
+ super.onDestroyView();
139
+ }
128
140
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picsa/capacitor-video-player",
3
- "version": "8.0.2",
3
+ "version": "8.0.4",
4
4
  "description": "custom Native Capacitor plugin to play a video",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",