2
2
3
3
import static com .google .android .exoplayer2 .Player .REPEAT_MODE_ALL ;
4
4
import static com .google .android .exoplayer2 .Player .REPEAT_MODE_OFF ;
5
+ import static com .jhomlala .better_player .DataSourceUtils .getDataSourceFactory ;
6
+ import static com .jhomlala .better_player .DataSourceUtils .getUserAgent ;
5
7
6
8
import android .app .NotificationChannel ;
7
9
import android .app .NotificationManager ;
61
63
import androidx .annotation .Nullable ;
62
64
63
65
import androidx .media .session .MediaButtonReceiver ;
66
+ import androidx .work .Data ;
67
+ import androidx .work .OneTimeWorkRequest ;
68
+ import androidx .work .WorkManager ;
64
69
65
70
import io .flutter .plugin .common .EventChannel ;
66
71
import io .flutter .plugin .common .MethodChannel .Result ;
67
72
import io .flutter .view .TextureRegistry ;
68
73
69
74
import java .io .File ;
70
- import java .io .IOException ;
71
75
import java .io .InputStream ;
72
76
import java .net .HttpURLConnection ;
73
77
import java .net .URL ;
@@ -87,9 +91,8 @@ final class BetterPlayer {
87
91
private static final String FORMAT_HLS = "hls" ;
88
92
private static final String FORMAT_OTHER = "other" ;
89
93
private static final String DEFAULT_NOTIFICATION_CHANNEL = "BETTER_PLAYER_NOTIFICATION" ;
90
- private static final String USER_AGENT = "User-Agent" ;
91
- private static final String USER_AGENT_PROPERTY = "http.agent" ;
92
94
private static final int NOTIFICATION_ID = 20772077 ;
95
+ private static final int DEFAULT_NOTIFICATION_IMAGE_SIZE_PX = 256 ;
93
96
94
97
private final SimpleExoPlayer exoPlayer ;
95
98
private final TextureRegistry .SurfaceTextureEntry textureEntry ;
@@ -132,13 +135,7 @@ void setDataSource(
132
135
Uri uri = Uri .parse (dataSource );
133
136
DataSource .Factory dataSourceFactory ;
134
137
135
- String userAgent = System .getProperty (USER_AGENT_PROPERTY );
136
- if (headers != null && headers .containsKey (USER_AGENT )) {
137
- String userAgentHeader = headers .get (USER_AGENT );
138
- if (userAgentHeader != null ) {
139
- userAgent = userAgentHeader ;
140
- }
141
- }
138
+ String userAgent = getUserAgent (headers );
142
139
143
140
if (licenseUrl != null && !licenseUrl .isEmpty ()) {
144
141
HttpMediaDrmCallback httpMediaDrmCallback =
@@ -175,16 +172,8 @@ void setDataSource(
175
172
drmSessionManager = null ;
176
173
}
177
174
178
- if (isHTTP (uri )) {
179
- dataSourceFactory = new DefaultHttpDataSource .Factory ()
180
- .setUserAgent (userAgent )
181
- .setAllowCrossProtocolRedirects (true )
182
- .setConnectTimeoutMs (DefaultHttpDataSource .DEFAULT_CONNECT_TIMEOUT_MILLIS )
183
- .setReadTimeoutMs (DefaultHttpDataSource .DEFAULT_READ_TIMEOUT_MILLIS );
184
-
185
- if (headers != null ) {
186
- ((DefaultHttpDataSource .Factory ) dataSourceFactory ).setDefaultRequestProperties (headers );
187
- }
175
+ if (DataSourceUtils .isHTTP (uri )) {
176
+ dataSourceFactory = getDataSourceFactory (userAgent , headers );
188
177
189
178
if (useCache && maxCacheSize > 0 && maxCacheFileSize > 0 ) {
190
179
dataSourceFactory =
@@ -410,36 +399,72 @@ public void disposeRemoteNotifications() {
410
399
bitmap = null ;
411
400
}
412
401
413
- private static Bitmap getBitmapFromInternalURL (String src ) {
402
+ private Bitmap getBitmapFromInternalURL (String src ) {
414
403
try {
404
+ final BitmapFactory .Options options = new BitmapFactory .Options ();
405
+ options .inJustDecodeBounds = true ;
406
+ options .inSampleSize = calculateBitmapInSmapleSize (options ,
407
+ DEFAULT_NOTIFICATION_IMAGE_SIZE_PX ,
408
+ DEFAULT_NOTIFICATION_IMAGE_SIZE_PX );
409
+ options .inJustDecodeBounds = false ;
415
410
return BitmapFactory .decodeFile (src );
416
411
} catch (Exception exception ) {
412
+ Log .e (TAG , "Failed to get bitmap from internal url: " + src );
417
413
return null ;
418
414
}
419
415
}
420
416
421
- private static Bitmap getBitmapFromExternalURL (String src ) {
417
+
418
+ private Bitmap getBitmapFromExternalURL (String src ) {
419
+ InputStream inputStream = null ;
422
420
try {
423
421
URL url = new URL (src );
424
422
HttpURLConnection connection = (HttpURLConnection ) url .openConnection ();
425
- connection .setDoInput (true );
426
- connection .connect ();
427
- InputStream input = connection .getInputStream ();
428
- return BitmapFactory .decodeStream (input );
429
- } catch (IOException exception ) {
423
+ inputStream = connection .getInputStream ();
424
+
425
+ final BitmapFactory .Options options = new BitmapFactory .Options ();
426
+ options .inJustDecodeBounds = true ;
427
+ BitmapFactory .decodeStream (inputStream , null , options );
428
+ inputStream .close ();
429
+ connection = (HttpURLConnection ) url .openConnection ();
430
+ inputStream = connection .getInputStream ();
431
+ options .inSampleSize = calculateBitmapInSmapleSize (
432
+ options , DEFAULT_NOTIFICATION_IMAGE_SIZE_PX , DEFAULT_NOTIFICATION_IMAGE_SIZE_PX );
433
+ options .inJustDecodeBounds = false ;
434
+ return BitmapFactory .decodeStream (inputStream , null , options );
435
+
436
+ } catch (Exception exception ) {
437
+ Log .e (TAG , "Failed to get bitmap from external url: " + src );
430
438
return null ;
439
+ } finally {
440
+ try {
441
+ if (inputStream != null ) {
442
+ inputStream .close ();
443
+ }
444
+ } catch (Exception exception ) {
445
+ Log .e (TAG , "Failed to close bitmap input stream/" );
446
+ }
431
447
}
432
448
}
433
449
450
+ private int calculateBitmapInSmapleSize (
451
+ BitmapFactory .Options options , int reqWidth , int reqHeight ) {
452
+ final int height = options .outHeight ;
453
+ final int width = options .outWidth ;
454
+ int inSampleSize = 1 ;
434
455
435
- private static boolean isHTTP (Uri uri ) {
436
- if (uri == null || uri .getScheme () == null ) {
437
- return false ;
456
+ if (height > reqHeight || width > reqWidth ) {
457
+ final int halfHeight = height / 2 ;
458
+ final int halfWidth = width / 2 ;
459
+ while ((halfHeight / inSampleSize ) >= reqHeight
460
+ && (halfWidth / inSampleSize ) >= reqWidth ) {
461
+ inSampleSize *= 2 ;
462
+ }
438
463
}
439
- String scheme = uri .getScheme ();
440
- return scheme .equals ("http" ) || scheme .equals ("https" );
464
+ return inSampleSize ;
441
465
}
442
466
467
+
443
468
private MediaSource buildMediaSource (
444
469
Uri uri , DataSource .Factory mediaDataSourceFactory , String formatHint , Context context ) {
445
470
int type ;
@@ -801,15 +826,44 @@ public void setMixWithOthers(Boolean mixWithOthers) {
801
826
802
827
//Clear cache without accessing BetterPlayerCache.
803
828
@ SuppressWarnings ("ResultOfMethodCallIgnored" )
804
- public void clearCache (Context context ) {
829
+ public static void clearCache (Context context , Result result ) {
805
830
try {
806
831
File file = context .getCacheDir ();
807
832
if (file != null ) {
808
833
file .delete ();
809
834
}
835
+ result .success (null );
810
836
} catch (Exception exception ) {
811
- Log .e ("Cache" , exception .toString ());
837
+ Log .e (TAG , exception .toString ());
838
+ result .error ("" , "" , "" );
839
+ }
840
+ }
841
+
842
+ //Start pre cache of video. Invoke work manager job and start caching in background.
843
+ static void preCache (Context context , String dataSource , long preCacheSize ,
844
+ long maxCacheSize , long maxCacheFileSize , Map <String , String > headers ,
845
+ Result result ) {
846
+ Data .Builder dataBuilder = new Data .Builder ()
847
+ .putString (BetterPlayerPlugin .URL_PARAMETER , dataSource )
848
+ .putLong (BetterPlayerPlugin .PRE_CACHE_SIZE_PARAMETER , preCacheSize )
849
+ .putLong (BetterPlayerPlugin .MAX_CACHE_SIZE_PARAMETER , maxCacheSize )
850
+ .putLong (BetterPlayerPlugin .MAX_CACHE_FILE_SIZE_PARAMETER , maxCacheFileSize );
851
+ for (String headerKey : headers .keySet ()) {
852
+ dataBuilder .putString (BetterPlayerPlugin .HEADER_PARAMETER + headerKey , headers .get (headerKey ));
812
853
}
854
+
855
+ OneTimeWorkRequest cacheWorkRequest = new OneTimeWorkRequest .Builder (CacheWorker .class )
856
+ .addTag (dataSource )
857
+ .setInputData (dataBuilder .build ()).build ();
858
+ WorkManager .getInstance (context ).enqueue (cacheWorkRequest );
859
+ result .success (null );
860
+ }
861
+
862
+ //Stop pre cache of video with given url. If there's no work manager job for given url, then
863
+ //it will be ignored.
864
+ static void stopPreCache (Context context , String url , Result result ) {
865
+ WorkManager .getInstance (context ).cancelAllWorkByTag (url );
866
+ result .success (null );
813
867
}
814
868
815
869
void dispose () {
0 commit comments