Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
T
tx_player_fork
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
蒋俊
tx_player_fork
Commits
5e964a51
提交
5e964a51
authored
7月 27, 2022
作者:
kongdywang
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
SuperPlayer supports screen autorotation for Android&iOS platform
上级
3cdf0ab2
显示空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
215 行增加
和
985 行删除
+215
-985
FTXEvent.java
...droid/src/main/java/com/tencent/vod/flutter/FTXEvent.java
+13
-0
SuperPlayerPlugin.java
.../main/java/com/tencent/vod/flutter/SuperPlayerPlugin.java
+45
-3
SuperPlayerView.java
.../com/tencent/liteav/demo/superplayer/SuperPlayerView.java
+0
-911
superplayer_widget.dart
Flutter/example/lib/superplayer/ui/superplayer_widget.dart
+89
-49
FTXAudioManager.m
Flutter/ios/Classes/FTXAudioManager.m
+2
-0
FTXEvent.h
Flutter/ios/Classes/FTXEvent.h
+13
-21
SuperPlayerPlugin.m
Flutter/ios/Classes/SuperPlayerPlugin.m
+46
-0
superplayer_plugin.dart
Flutter/lib/Core/superplayer_plugin.dart
+1
-1
txplayer_define.dart
Flutter/lib/Core/txplayer_define.dart
+6
-0
没有找到文件。
Flutter/android/src/main/java/com/tencent/vod/flutter/FTXEvent.java
浏览文件 @
5e964a51
...
@@ -58,4 +58,17 @@ public class FTXEvent {
...
@@ -58,4 +58,17 @@ public class FTXEvent {
// pip 错误,当前界面已销毁
// pip 错误,当前界面已销毁
public
static
final
int
ERROR_PIP_ACTIVITY_DESTROYED
=
-
103
;
public
static
final
int
ERROR_PIP_ACTIVITY_DESTROYED
=
-
103
;
// 屏幕旋转事件
public
static
final
int
EVENT_ORIENTATION_CHANGED
=
401
;
// 屏幕旋转方向
public
static
final
String
EXTRA_NAME_ORIENTATION
=
"orientation"
;
// 正竖屏
public
static
final
int
ORIENTATION_PORTRAIT_UP
=
411
;
// 横屏,底部在右
public
static
final
int
ORIENTATION_LANDSCAPE_RIGHT
=
412
;
// 竖屏,顶部在下
public
static
final
int
ORIENTATION_PORTRAIT_DOWN
=
413
;
// 横屏,底部在左
public
static
final
int
ORIENTATION_LANDSCAPE_LEFT
=
414
;
}
}
Flutter/android/src/main/java/com/tencent/vod/flutter/SuperPlayerPlugin.java
浏览文件 @
5e964a51
...
@@ -7,8 +7,10 @@ import android.content.Intent;
...
@@ -7,8 +7,10 @@ import android.content.Intent;
import
android.content.IntentFilter
;
import
android.content.IntentFilter
;
import
android.media.AudioManager
;
import
android.media.AudioManager
;
import
android.os.Bundle
;
import
android.os.Bundle
;
import
android.provider.Settings
;
import
android.text.TextUtils
;
import
android.text.TextUtils
;
import
android.util.SparseArray
;
import
android.util.SparseArray
;
import
android.view.OrientationEventListener
;
import
android.view.Window
;
import
android.view.Window
;
import
android.view.WindowManager
;
import
android.view.WindowManager
;
...
@@ -58,6 +60,9 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
...
@@ -58,6 +60,9 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
private
FTXAudioManager
mTxAudioManager
;
private
FTXAudioManager
mTxAudioManager
;
private
FTXPIPManager
mTxPipManager
;
private
FTXPIPManager
mTxPipManager
;
private
OrientationEventListener
mOrientationManager
;
private
int
mCurrentOrientation
=
FTXEvent
.
ORIENTATION_PORTRAIT_UP
;
private
final
FTXAudioManager
.
AudioFocusChangeListener
audioFocusChangeListener
=
private
final
FTXAudioManager
.
AudioFocusChangeListener
audioFocusChangeListener
=
new
FTXAudioManager
.
AudioFocusChangeListener
()
{
new
FTXAudioManager
.
AudioFocusChangeListener
()
{
@Override
@Override
...
@@ -78,8 +83,7 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
...
@@ -78,8 +83,7 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
channel
.
setMethodCallHandler
(
this
);
channel
.
setMethodCallHandler
(
this
);
mPlayers
=
new
SparseArray
();
mPlayers
=
new
SparseArray
();
initAudioManagerIfNeed
();
initAudioManagerIfNeed
();
mEventChannel
=
new
EventChannel
(
flutterPluginBinding
.
getBinaryMessenger
(),
"cloud.tencent"
+
mEventChannel
=
new
EventChannel
(
flutterPluginBinding
.
getBinaryMessenger
(),
"cloud.tencent.com/playerPlugin/event"
);
".com/playerPlugin/event"
);
mEventChannel
.
setStreamHandler
(
new
EventChannel
.
StreamHandler
()
{
mEventChannel
.
setStreamHandler
(
new
EventChannel
.
StreamHandler
()
{
@Override
@Override
public
void
onListen
(
Object
o
,
EventChannel
.
EventSink
eventSink
)
{
public
void
onListen
(
Object
o
,
EventChannel
.
EventSink
eventSink
)
{
...
@@ -92,6 +96,31 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
...
@@ -92,6 +96,31 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
}
}
});
});
mFTXDownloadManager
=
new
FTXDownloadManager
(
mFlutterPluginBinding
);
mFTXDownloadManager
=
new
FTXDownloadManager
(
mFlutterPluginBinding
);
mOrientationManager
=
new
OrientationEventListener
(
flutterPluginBinding
.
getApplicationContext
())
{
@Override
public
void
onOrientationChanged
(
int
orientation
)
{
if
(
isAutoRotateOn
())
{
int
orientationEvent
=
mCurrentOrientation
;
// 每个方向判断当前方向正负30度,共计60度的区间
if
(((
orientation
>=
0
)
&&
(
orientation
<
30
))
||
(
orientation
>
330
))
{
orientationEvent
=
FTXEvent
.
ORIENTATION_PORTRAIT_UP
;
}
else
if
(
orientation
>
240
&&
orientation
<
300
)
{
orientationEvent
=
FTXEvent
.
ORIENTATION_LANDSCAPE_RIGHT
;
}
else
if
(
orientation
>
150
&&
orientation
<
210
)
{
orientationEvent
=
FTXEvent
.
ORIENTATION_PORTRAIT_DOWN
;
}
else
if
(
orientation
>
60
&&
orientation
<
110
)
{
orientationEvent
=
FTXEvent
.
ORIENTATION_LANDSCAPE_LEFT
;
}
if
(
orientationEvent
!=
mCurrentOrientation
)
{
mCurrentOrientation
=
orientationEvent
;
Bundle
bundle
=
new
Bundle
();
bundle
.
putInt
(
FTXEvent
.
EXTRA_NAME_ORIENTATION
,
orientationEvent
);
mEventSink
.
success
(
getParams
(
FTXEvent
.
EVENT_ORIENTATION_CHANGED
,
bundle
));
}
}
}
};
mOrientationManager
.
enable
();
}
}
@Override
@Override
...
@@ -228,6 +257,9 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
...
@@ -228,6 +257,9 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
if
(
null
!=
mTxPipManager
)
{
if
(
null
!=
mTxPipManager
)
{
mTxPipManager
.
releaseReceiver
();
mTxPipManager
.
releaseReceiver
();
}
}
if
(
null
!=
mOrientationManager
)
{
mOrientationManager
.
disable
();
}
unregisterReceiver
();
unregisterReceiver
();
}
}
...
@@ -240,10 +272,20 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
...
@@ -240,10 +272,20 @@ public class SuperPlayerPlugin implements FlutterPlugin, MethodCallHandler, Acti
}
}
/**
/**
*
注册音量广播接收器
*
系统是否允许自动旋转屏幕
*
*
* @return
* @return
*/
*/
protected
boolean
isAutoRotateOn
()
{
//获取系统是否允许自动旋转屏幕
return
(
android
.
provider
.
Settings
.
System
.
getInt
(
mFlutterPluginBinding
.
getApplicationContext
().
getContentResolver
(),
Settings
.
System
.
ACCELEROMETER_ROTATION
,
0
)
==
1
);
}
/**
* 注册音量广播接收器
*/
public
void
registerReceiver
()
{
public
void
registerReceiver
()
{
// volume receiver
// volume receiver
mVolumeBroadcastReceiver
=
new
VolumeBroadcastReceiver
();
mVolumeBroadcastReceiver
=
new
VolumeBroadcastReceiver
();
...
...
Flutter/example/android/superplayerkit/src/main/java/com/tencent/liteav/demo/superplayer/SuperPlayerView.java
deleted
100644 → 0
浏览文件 @
3cdf0ab2
package
com
.
tencent
.
liteav
.
demo
.
superplayer
;
import
android.app.Activity
;
import
android.app.AppOpsManager
;
import
android.content.ContentResolver
;
import
android.content.ContentValues
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.pm.ActivityInfo
;
import
android.graphics.Bitmap
;
import
android.graphics.PixelFormat
;
import
android.net.Uri
;
import
android.os.AsyncTask
;
import
android.os.Binder
;
import
android.os.Build
;
import
android.provider.MediaStore
;
import
android.provider.Settings
;
import
android.util.AttributeSet
;
import
android.util.Log
;
import
android.view.Gravity
;
import
android.view.LayoutInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
android.view.WindowManager
;
import
android.widget.ImageView
;
import
android.widget.PopupWindow
;
import
android.widget.RelativeLayout
;
import
android.widget.Toast
;
import
com.tencent.liteav.basic.log.TXCLog
;
import
com.tencent.liteav.demo.superplayer.model.SuperPlayer
;
import
com.tencent.liteav.demo.superplayer.model.SuperPlayerImpl
;
import
com.tencent.liteav.demo.superplayer.model.SuperPlayerObserver
;
import
com.tencent.liteav.demo.superplayer.model.entity.PlayImageSpriteInfo
;
import
com.tencent.liteav.demo.superplayer.model.entity.PlayKeyFrameDescInfo
;
import
com.tencent.liteav.demo.superplayer.model.entity.VideoQuality
;
import
com.tencent.liteav.demo.superplayer.model.net.LogReport
;
import
com.tencent.liteav.demo.superplayer.model.utils.NetWatcher
;
import
com.tencent.liteav.demo.superplayer.ui.player.FloatPlayer
;
import
com.tencent.liteav.demo.superplayer.ui.player.FullScreenPlayer
;
import
com.tencent.liteav.demo.superplayer.ui.player.Player
;
import
com.tencent.liteav.demo.superplayer.ui.player.WindowPlayer
;
import
com.tencent.liteav.demo.superplayer.ui.view.DanmuView
;
import
com.tencent.rtmp.TXLivePlayer
;
import
com.tencent.rtmp.ui.TXCloudVideoView
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Method
;
import
java.util.List
;
/**
*
* 超级播放器view
*
* 具备播放器基本功能,此外还包括横竖屏切换、悬浮窗播放、画质切换、硬件加速、倍速播放、镜像播放、手势控制等功能,同时支持直播与点播
* 使用方式极为简单,只需要在布局文件中引入并获取到该控件,通过{@link #playWithModel(SuperPlayerModel)}传入{@link SuperPlayerModel}即可实现视频播放
*
* 1、播放视频{@link #playWithModel(SuperPlayerModel)}
* 2、设置回调{@link #setPlayerViewCallback(OnSuperPlayerViewCallback)}
* 3、controller回调实现{@link #mControllerCallback}
* 4、退出播放释放内存{@link #resetPlayer()}
*/
public
class
SuperPlayerView
extends
RelativeLayout
{
private
static
final
String
TAG
=
"SuperPlayerView"
;
private
final
int
OP_SYSTEM_ALERT_WINDOW
=
24
;
// 支持TYPE_TOAST悬浮窗的最高API版本
private
Context
mContext
;
private
ViewGroup
mRootView
;
// SuperPlayerView的根view
private
TXCloudVideoView
mTXCloudVideoView
;
// 腾讯云视频播放view
private
FullScreenPlayer
mFullScreenPlayer
;
// 全屏模式控制view
private
WindowPlayer
mWindowPlayer
;
// 窗口模式控制view
private
FloatPlayer
mFloatPlayer
;
// 悬浮窗模式控制view
private
DanmuView
mDanmuView
;
// 弹幕
private
ViewGroup
.
LayoutParams
mLayoutParamWindowMode
;
// 窗口播放时SuperPlayerView的布局参数
private
ViewGroup
.
LayoutParams
mLayoutParamFullScreenMode
;
// 全屏播放时SuperPlayerView的布局参数
private
LayoutParams
mVodControllerWindowParams
;
// 窗口controller的布局参数
private
LayoutParams
mVodControllerFullScreenParams
;
// 全屏controller的布局参数
private
WindowManager
mWindowManager
;
// 悬浮窗窗口管理器
private
WindowManager
.
LayoutParams
mWindowParams
;
// 悬浮窗布局参数
private
OnSuperPlayerViewCallback
mPlayerViewCallback
;
// SuperPlayerView回调
private
NetWatcher
mWatcher
;
// 网络质量监视器
private
SuperPlayer
mSuperPlayer
;
public
SuperPlayerView
(
Context
context
)
{
super
(
context
);
initialize
(
context
);
}
public
SuperPlayerView
(
Context
context
,
AttributeSet
attrs
)
{
super
(
context
,
attrs
);
initialize
(
context
);
}
public
SuperPlayerView
(
Context
context
,
AttributeSet
attrs
,
int
defStyleAttr
)
{
super
(
context
,
attrs
,
defStyleAttr
);
initialize
(
context
);
}
private
void
initialize
(
Context
context
)
{
mContext
=
context
;
initView
();
initPlayer
();
}
/**
* 初始化view
*/
private
void
initView
()
{
mRootView
=
(
ViewGroup
)
LayoutInflater
.
from
(
mContext
).
inflate
(
R
.
layout
.
superplayer_vod_view
,
null
);
mTXCloudVideoView
=
(
TXCloudVideoView
)
mRootView
.
findViewById
(
R
.
id
.
superplayer_cloud_video_view
);
mFullScreenPlayer
=
(
FullScreenPlayer
)
mRootView
.
findViewById
(
R
.
id
.
superplayer_controller_large
);
mWindowPlayer
=
(
WindowPlayer
)
mRootView
.
findViewById
(
R
.
id
.
superplayer_controller_small
);
mFloatPlayer
=
(
FloatPlayer
)
mRootView
.
findViewById
(
R
.
id
.
superplayer_controller_float
);
mDanmuView
=
(
DanmuView
)
mRootView
.
findViewById
(
R
.
id
.
superplayer_danmuku_view
);
mVodControllerWindowParams
=
new
LayoutParams
(
LayoutParams
.
MATCH_PARENT
,
LayoutParams
.
MATCH_PARENT
);
mVodControllerFullScreenParams
=
new
LayoutParams
(
LayoutParams
.
MATCH_PARENT
,
LayoutParams
.
MATCH_PARENT
);
mFullScreenPlayer
.
setCallback
(
mControllerCallback
);
mWindowPlayer
.
setCallback
(
mControllerCallback
);
mFloatPlayer
.
setCallback
(
mControllerCallback
);
removeAllViews
();
mRootView
.
removeView
(
mDanmuView
);
mRootView
.
removeView
(
mTXCloudVideoView
);
mRootView
.
removeView
(
mWindowPlayer
);
mRootView
.
removeView
(
mFullScreenPlayer
);
mRootView
.
removeView
(
mFloatPlayer
);
addView
(
mTXCloudVideoView
);
addView
(
mDanmuView
);
}
private
void
initPlayer
()
{
mSuperPlayer
=
new
SuperPlayerImpl
(
mContext
,
mTXCloudVideoView
);
mSuperPlayer
.
setObserver
(
mSuperPlayerObserver
);
if
(
mSuperPlayer
.
getPlayerMode
()
==
SuperPlayerDef
.
PlayerMode
.
FULLSCREEN
)
{
addView
(
mFullScreenPlayer
);
mFullScreenPlayer
.
hide
();
}
else
if
(
mSuperPlayer
.
getPlayerMode
()
==
SuperPlayerDef
.
PlayerMode
.
WINDOW
)
{
addView
(
mWindowPlayer
);
mWindowPlayer
.
hide
();
}
post
(
new
Runnable
()
{
@Override
public
void
run
()
{
if
(
mSuperPlayer
.
getPlayerMode
()
==
SuperPlayerDef
.
PlayerMode
.
WINDOW
)
{
mLayoutParamWindowMode
=
getLayoutParams
();
}
try
{
// 依据上层Parent的LayoutParam类型来实例化一个新的fullscreen模式下的LayoutParam
Class
parentLayoutParamClazz
=
getLayoutParams
().
getClass
();
Constructor
constructor
=
parentLayoutParamClazz
.
getDeclaredConstructor
(
int
.
class
,
int
.
class
);
mLayoutParamFullScreenMode
=
(
ViewGroup
.
LayoutParams
)
constructor
.
newInstance
(
ViewGroup
.
LayoutParams
.
MATCH_PARENT
,
ViewGroup
.
LayoutParams
.
MATCH_PARENT
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
});
LogReport
.
getInstance
().
setAppName
(
mContext
);
LogReport
.
getInstance
().
setPackageName
(
mContext
);
if
(
mWatcher
==
null
)
{
mWatcher
=
new
NetWatcher
(
mContext
);
}
}
/**
* 播放视频
*
* @param model
*/
public
void
playWithModel
(
final
SuperPlayerModel
model
)
{
if
(
model
.
videoId
!=
null
)
{
mSuperPlayer
.
play
(
model
.
appId
,
model
.
videoId
.
fileId
,
model
.
videoId
.
pSign
);
}
else
if
(
model
.
videoIdV2
!=
null
)
{
}
else
if
(
model
.
multiURLs
!=
null
&&
!
model
.
multiURLs
.
isEmpty
())
{
mSuperPlayer
.
play
(
model
.
appId
,
model
.
multiURLs
,
model
.
playDefaultIndex
);
}
else
{
mSuperPlayer
.
play
(
model
.
url
);
}
}
/**
* 开始播放
*
* @param url 视频地址
*/
public
void
play
(
String
url
)
{
mSuperPlayer
.
play
(
url
);
}
/**
* 开始播放
*
* @param appId 腾讯云视频appId
* @param url 直播播放地址
*/
public
void
play
(
int
appId
,
String
url
)
{
mSuperPlayer
.
play
(
appId
,
url
);
}
/**
* 开始播放
*
* @param appId 腾讯云视频appId
* @param fileId 腾讯云视频fileId
* @param psign 防盗链签名,开启防盗链的视频必填,非防盗链视频可不填
*/
public
void
play
(
int
appId
,
String
fileId
,
String
psign
)
{
mSuperPlayer
.
play
(
appId
,
fileId
,
psign
);
}
/**
* 多分辨率播放
*
* @param appId 腾讯云视频appId
* @param superPlayerURLS 不同分辨率数据
* @param defaultIndex 默认播放Index
*/
public
void
play
(
int
appId
,
List
<
SuperPlayerModel
.
SuperPlayerURL
>
superPlayerURLS
,
int
defaultIndex
)
{
mSuperPlayer
.
play
(
appId
,
superPlayerURLS
,
defaultIndex
);
}
/**
* 更新标题
*
* @param title 视频名称
*/
private
void
updateTitle
(
String
title
)
{
mWindowPlayer
.
updateTitle
(
title
);
mFullScreenPlayer
.
updateTitle
(
title
);
}
/**
* resume生命周期回调
*/
public
void
onResume
()
{
if
(
mDanmuView
!=
null
&&
mDanmuView
.
isPrepared
()
&&
mDanmuView
.
isPaused
())
{
mDanmuView
.
resume
();
}
mSuperPlayer
.
resume
();
}
/**
* pause生命周期回调
*/
public
void
onPause
()
{
if
(
mDanmuView
!=
null
&&
mDanmuView
.
isPrepared
())
{
mDanmuView
.
pause
();
}
mSuperPlayer
.
pauseVod
();
}
/**
* 重置播放器
*/
public
void
resetPlayer
()
{
if
(
mDanmuView
!=
null
)
{
mDanmuView
.
release
();
mDanmuView
=
null
;
}
stopPlay
();
}
/**
* 停止播放
*/
private
void
stopPlay
()
{
mSuperPlayer
.
stop
();
if
(
mWatcher
!=
null
)
{
mWatcher
.
stop
();
}
}
/**
* 设置超级播放器的回掉
*
* @param callback
*/
public
void
setPlayerViewCallback
(
OnSuperPlayerViewCallback
callback
)
{
mPlayerViewCallback
=
callback
;
}
/**
* 控制是否全屏显示
*/
private
void
fullScreen
(
boolean
isFull
)
{
if
(
getContext
()
instanceof
Activity
)
{
Activity
activity
=
(
Activity
)
getContext
();
if
(
isFull
)
{
//隐藏虚拟按键,并且全屏
View
decorView
=
activity
.
getWindow
().
getDecorView
();
if
(
decorView
==
null
)
return
;
if
(
Build
.
VERSION
.
SDK_INT
>
11
&&
Build
.
VERSION
.
SDK_INT
<
19
)
{
// lower api
decorView
.
setSystemUiVisibility
(
View
.
GONE
);
}
else
if
(
Build
.
VERSION
.
SDK_INT
>=
19
)
{
int
uiOptions
=
View
.
SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
View
.
SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
View
.
SYSTEM_UI_FLAG_FULLSCREEN
;
decorView
.
setSystemUiVisibility
(
uiOptions
);
}
}
else
{
View
decorView
=
activity
.
getWindow
().
getDecorView
();
if
(
decorView
==
null
)
return
;
if
(
Build
.
VERSION
.
SDK_INT
>
11
&&
Build
.
VERSION
.
SDK_INT
<
19
)
{
// lower api
decorView
.
setSystemUiVisibility
(
View
.
VISIBLE
);
}
else
if
(
Build
.
VERSION
.
SDK_INT
>=
19
)
{
decorView
.
setSystemUiVisibility
(
View
.
SYSTEM_UI_FLAG_VISIBLE
);
}
}
}
}
/**
* 初始化controller回调
*/
private
Player
.
Callback
mControllerCallback
=
new
Player
.
Callback
()
{
@Override
public
void
onSwitchPlayMode
(
SuperPlayerDef
.
PlayerMode
playerMode
)
{
if
(
playerMode
==
SuperPlayerDef
.
PlayerMode
.
FULLSCREEN
)
{
fullScreen
(
true
);
}
else
{
fullScreen
(
false
);
}
mFullScreenPlayer
.
hide
();
mWindowPlayer
.
hide
();
mFloatPlayer
.
hide
();
//请求全屏模式
if
(
playerMode
==
SuperPlayerDef
.
PlayerMode
.
FULLSCREEN
)
{
if
(
mLayoutParamFullScreenMode
==
null
)
{
return
;
}
removeView
(
mWindowPlayer
);
addView
(
mFullScreenPlayer
,
mVodControllerFullScreenParams
);
setLayoutParams
(
mLayoutParamFullScreenMode
);
rotateScreenOrientation
(
SuperPlayerDef
.
Orientation
.
LANDSCAPE
);
if
(
mPlayerViewCallback
!=
null
)
{
mPlayerViewCallback
.
onStartFullScreenPlay
();
}
}
else
if
(
playerMode
==
SuperPlayerDef
.
PlayerMode
.
WINDOW
)
{
// 请求窗口模式
// 当前是悬浮窗
if
(
mSuperPlayer
.
getPlayerMode
()
==
SuperPlayerDef
.
PlayerMode
.
FLOAT
)
{
try
{
Context
viewContext
=
getContext
();
Intent
intent
=
null
;
if
(
viewContext
instanceof
Activity
)
{
intent
=
new
Intent
(
viewContext
,
viewContext
.
getClass
());
}
else
{
showToast
(
R
.
string
.
superplayer_float_play_fail
);
return
;
}
mContext
.
startActivity
(
intent
);
mSuperPlayer
.
pause
();
if
(
mLayoutParamWindowMode
==
null
)
{
return
;
}
mWindowManager
.
removeView
(
mFloatPlayer
);
mSuperPlayer
.
setPlayerView
(
mTXCloudVideoView
);
mSuperPlayer
.
resume
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
else
if
(
mSuperPlayer
.
getPlayerMode
()
==
SuperPlayerDef
.
PlayerMode
.
FULLSCREEN
)
{
// 当前是全屏模式
if
(
mLayoutParamWindowMode
==
null
)
{
return
;
}
removeView
(
mFullScreenPlayer
);
addView
(
mWindowPlayer
,
mVodControllerWindowParams
);
setLayoutParams
(
mLayoutParamWindowMode
);
rotateScreenOrientation
(
SuperPlayerDef
.
Orientation
.
PORTRAIT
);
if
(
mPlayerViewCallback
!=
null
)
{
mPlayerViewCallback
.
onStopFullScreenPlay
();
}
}
}
else
if
(
playerMode
==
SuperPlayerDef
.
PlayerMode
.
FLOAT
)
{
//请求悬浮窗模式
TXCLog
.
i
(
TAG
,
"requestPlayMode Float :"
+
Build
.
MANUFACTURER
);
SuperPlayerGlobalConfig
prefs
=
SuperPlayerGlobalConfig
.
getInstance
();
if
(!
prefs
.
enableFloatWindow
)
{
return
;
}
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
M
)
{
// 6.0动态申请悬浮窗权限
if
(!
Settings
.
canDrawOverlays
(
mContext
))
{
Intent
intent
=
new
Intent
(
Settings
.
ACTION_MANAGE_OVERLAY_PERMISSION
);
intent
.
setData
(
Uri
.
parse
(
"package:"
+
mContext
.
getPackageName
()));
mContext
.
startActivity
(
intent
);
return
;
}
}
else
{
if
(!
checkOp
(
mContext
,
OP_SYSTEM_ALERT_WINDOW
))
{
showToast
(
R
.
string
.
superplayer_enter_setting_fail
);
return
;
}
}
mSuperPlayer
.
pause
();
mWindowManager
=
(
WindowManager
)
mContext
.
getApplicationContext
().
getSystemService
(
Context
.
WINDOW_SERVICE
);
mWindowParams
=
new
WindowManager
.
LayoutParams
();
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
O
)
{
mWindowParams
.
type
=
WindowManager
.
LayoutParams
.
TYPE_APPLICATION_OVERLAY
;
}
else
{
mWindowParams
.
type
=
WindowManager
.
LayoutParams
.
TYPE_PHONE
;
}
mWindowParams
.
flags
=
WindowManager
.
LayoutParams
.
FLAG_NOT_TOUCH_MODAL
|
WindowManager
.
LayoutParams
.
FLAG_NOT_FOCUSABLE
;
mWindowParams
.
format
=
PixelFormat
.
TRANSLUCENT
;
mWindowParams
.
gravity
=
Gravity
.
LEFT
|
Gravity
.
TOP
;
SuperPlayerGlobalConfig
.
TXRect
rect
=
prefs
.
floatViewRect
;
mWindowParams
.
x
=
rect
.
x
;
mWindowParams
.
y
=
rect
.
y
;
mWindowParams
.
width
=
rect
.
width
;
mWindowParams
.
height
=
rect
.
height
;
try
{
mWindowManager
.
addView
(
mFloatPlayer
,
mWindowParams
);
}
catch
(
Exception
e
)
{
showToast
(
R
.
string
.
superplayer_float_play_fail
);
return
;
}
TXCloudVideoView
videoView
=
mFloatPlayer
.
getFloatVideoView
();
if
(
videoView
!=
null
)
{
mSuperPlayer
.
setPlayerView
(
videoView
);
mSuperPlayer
.
resume
();
}
// 悬浮窗上报
LogReport
.
getInstance
().
uploadLogs
(
LogReport
.
ELK_ACTION_FLOATMOE
,
0
,
0
);
}
mSuperPlayer
.
switchPlayMode
(
playerMode
);
}
@Override
public
void
onBackPressed
(
SuperPlayerDef
.
PlayerMode
playMode
)
{
switch
(
playMode
)
{
case
FULLSCREEN:
// 当前是全屏模式,返回切换成窗口模式
onSwitchPlayMode
(
SuperPlayerDef
.
PlayerMode
.
WINDOW
);
break
;
case
WINDOW:
// 当前是窗口模式,返回退出播放器
if
(
mPlayerViewCallback
!=
null
)
{
mPlayerViewCallback
.
onSuperPlayerBackAction
();
}
break
;
case
FLOAT:
// 当前是悬浮窗,退出
mWindowManager
.
removeView
(
mFloatPlayer
);
if
(
mPlayerViewCallback
!=
null
)
{
mPlayerViewCallback
.
onClickFloatCloseBtn
();
}
break
;
default
:
break
;
}
}
@Override
public
void
onFloatPositionChange
(
int
x
,
int
y
)
{
mWindowParams
.
x
=
x
;
mWindowParams
.
y
=
y
;
mWindowManager
.
updateViewLayout
(
mFloatPlayer
,
mWindowParams
);
}
@Override
public
void
onPause
()
{
mSuperPlayer
.
pause
();
if
(
mSuperPlayer
.
getPlayerType
()
!=
SuperPlayerDef
.
PlayerType
.
VOD
)
{
if
(
mWatcher
!=
null
)
{
mWatcher
.
stop
();
}
}
}
@Override
public
void
onResume
()
{
if
(
mSuperPlayer
.
getPlayerState
()
==
SuperPlayerDef
.
PlayerState
.
END
)
{
//重播
mSuperPlayer
.
reStart
();
}
else
if
(
mSuperPlayer
.
getPlayerState
()
==
SuperPlayerDef
.
PlayerState
.
PAUSE
)
{
//继续播放
mSuperPlayer
.
resume
();
}
}
@Override
public
void
onSeekTo
(
int
position
)
{
mSuperPlayer
.
seek
(
position
);
}
@Override
public
void
onResumeLive
()
{
mSuperPlayer
.
resumeLive
();
}
@Override
public
void
onDanmuToggle
(
boolean
isOpen
)
{
if
(
mDanmuView
!=
null
)
{
mDanmuView
.
toggle
(
isOpen
);
}
}
@Override
public
void
onSnapshot
()
{
mSuperPlayer
.
snapshot
(
new
TXLivePlayer
.
ITXSnapshotListener
()
{
@Override
public
void
onSnapshot
(
Bitmap
bitmap
)
{
if
(
bitmap
!=
null
)
{
showSnapshotWindow
(
bitmap
);
}
else
{
showToast
(
R
.
string
.
superplayer_screenshot_fail
);
}
}
});
}
@Override
public
void
onQualityChange
(
VideoQuality
quality
)
{
mFullScreenPlayer
.
updateVideoQuality
(
quality
);
mSuperPlayer
.
switchStream
(
quality
);
}
@Override
public
void
onSpeedChange
(
float
speedLevel
)
{
mSuperPlayer
.
setRate
(
speedLevel
);
}
@Override
public
void
onMirrorToggle
(
boolean
isMirror
)
{
mSuperPlayer
.
setMirror
(
isMirror
);
}
@Override
public
void
onHWAccelerationToggle
(
boolean
isAccelerate
)
{
mSuperPlayer
.
enableHardwareDecode
(
isAccelerate
);
}
};
/**
* 显示截图窗口
*
* @param bmp
*/
private
void
showSnapshotWindow
(
final
Bitmap
bmp
)
{
final
PopupWindow
popupWindow
=
new
PopupWindow
(
mContext
);
popupWindow
.
setWidth
(
ViewGroup
.
LayoutParams
.
WRAP_CONTENT
);
popupWindow
.
setHeight
(
ViewGroup
.
LayoutParams
.
WRAP_CONTENT
);
View
view
=
LayoutInflater
.
from
(
mContext
).
inflate
(
R
.
layout
.
superplayer_layout_new_vod_snap
,
null
);
ImageView
imageView
=
(
ImageView
)
view
.
findViewById
(
R
.
id
.
superplayer_iv_snap
);
imageView
.
setImageBitmap
(
bmp
);
popupWindow
.
setContentView
(
view
);
popupWindow
.
setOutsideTouchable
(
true
);
popupWindow
.
showAtLocation
(
mRootView
,
Gravity
.
TOP
,
1800
,
300
);
AsyncTask
.
execute
(
new
Runnable
()
{
@Override
public
void
run
()
{
save2MediaStore
(
mContext
,
bmp
);
}
});
postDelayed
(
new
Runnable
()
{
@Override
public
void
run
()
{
popupWindow
.
dismiss
();
}
},
3000
);
}
/**
* 旋转屏幕方向
*
* @param orientation
*/
private
void
rotateScreenOrientation
(
SuperPlayerDef
.
Orientation
orientation
)
{
switch
(
orientation
)
{
case
LANDSCAPE:
((
Activity
)
mContext
).
setRequestedOrientation
(
ActivityInfo
.
SCREEN_ORIENTATION_LANDSCAPE
);
break
;
case
PORTRAIT:
((
Activity
)
mContext
).
setRequestedOrientation
(
ActivityInfo
.
SCREEN_ORIENTATION_PORTRAIT
);
break
;
}
}
/**
* 检查悬浮窗权限
* <p>
* API <18,默认有悬浮窗权限,不需要处理。无法接收无法接收触摸和按键事件,不需要权限和无法接受触摸事件的源码分析
* API >= 19 ,可以接收触摸和按键事件
* API >=23,需要在manifest中申请权限,并在每次需要用到权限的时候检查是否已有该权限,因为用户随时可以取消掉。
* API >25,TYPE_TOAST 已经被谷歌制裁了,会出现自动消失的情况
*/
private
boolean
checkOp
(
Context
context
,
int
op
)
{
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
KITKAT
)
{
AppOpsManager
manager
=
(
AppOpsManager
)
context
.
getSystemService
(
Context
.
APP_OPS_SERVICE
);
try
{
Method
method
=
AppOpsManager
.
class
.
getDeclaredMethod
(
"checkOp"
,
int
.
class
,
int
.
class
,
String
.
class
);
return
AppOpsManager
.
MODE_ALLOWED
==
(
int
)
method
.
invoke
(
manager
,
op
,
Binder
.
getCallingUid
(),
context
.
getPackageName
());
}
catch
(
Exception
e
)
{
TXCLog
.
e
(
TAG
,
Log
.
getStackTraceString
(
e
));
}
}
return
true
;
}
/**
* SuperPlayerView的回调接口
*/
public
interface
OnSuperPlayerViewCallback
{
/**
* 开始全屏播放
*/
void
onStartFullScreenPlay
();
/**
* 结束全屏播放
*/
void
onStopFullScreenPlay
();
/**
* 点击悬浮窗模式下的x按钮
*/
void
onClickFloatCloseBtn
();
/**
* 点击小播放模式的返回按钮
*/
void
onSuperPlayerBackAction
();
/**
* 开始悬浮窗播放
*/
void
onStartFloatWindowPlay
();
/**
* 播放开始通知
*/
void
onSuperPlayerDidStart
();
/**
* 播放结束通知
*/
void
onSuperPlayerDidEnd
();
/**
* 播放错误通知
*/
void
onSuperPlayerError
();
}
public
void
release
()
{
if
(
mWindowPlayer
!=
null
)
{
mWindowPlayer
.
release
();
}
if
(
mFullScreenPlayer
!=
null
)
{
mFullScreenPlayer
.
release
();
}
if
(
mFloatPlayer
!=
null
)
{
mFloatPlayer
.
release
();
}
}
@Override
protected
void
finalize
()
throws
Throwable
{
super
.
finalize
();
try
{
release
();
}
catch
(
Throwable
e
)
{
TXCLog
.
e
(
TAG
,
Log
.
getStackTraceString
(
e
));
}
}
public
void
switchPlayMode
(
SuperPlayerDef
.
PlayerMode
playerMode
)
{
if
(
playerMode
==
SuperPlayerDef
.
PlayerMode
.
WINDOW
)
{
if
(
mControllerCallback
!=
null
)
{
mControllerCallback
.
onSwitchPlayMode
(
SuperPlayerDef
.
PlayerMode
.
WINDOW
);
}
}
else
if
(
playerMode
==
SuperPlayerDef
.
PlayerMode
.
FLOAT
)
{
if
(
mPlayerViewCallback
!=
null
)
{
mPlayerViewCallback
.
onStartFloatWindowPlay
();
}
if
(
mControllerCallback
!=
null
)
{
mControllerCallback
.
onSwitchPlayMode
(
SuperPlayerDef
.
PlayerMode
.
FLOAT
);
}
}
}
public
SuperPlayerDef
.
PlayerMode
getPlayerMode
()
{
return
mSuperPlayer
.
getPlayerMode
();
}
public
SuperPlayerDef
.
PlayerState
getPlayerState
()
{
return
mSuperPlayer
.
getPlayerState
();
}
private
SuperPlayerObserver
mSuperPlayerObserver
=
new
SuperPlayerObserver
()
{
@Override
public
void
onPlayBegin
(
String
name
)
{
mWindowPlayer
.
updatePlayState
(
SuperPlayerDef
.
PlayerState
.
PLAYING
);
mFullScreenPlayer
.
updatePlayState
(
SuperPlayerDef
.
PlayerState
.
PLAYING
);
updateTitle
(
name
);
mWindowPlayer
.
hideBackground
();
if
(
mDanmuView
!=
null
&&
mDanmuView
.
isPrepared
()
&&
mDanmuView
.
isPaused
())
{
mDanmuView
.
resume
();
}
if
(
mWatcher
!=
null
)
{
mWatcher
.
exitLoading
();
}
if
(
mPlayerViewCallback
!=
null
)
{
mPlayerViewCallback
.
onSuperPlayerDidStart
();
}
}
@Override
public
void
onPlayPause
()
{
mWindowPlayer
.
updatePlayState
(
SuperPlayerDef
.
PlayerState
.
PAUSE
);
mFullScreenPlayer
.
updatePlayState
(
SuperPlayerDef
.
PlayerState
.
PAUSE
);
}
@Override
public
void
onPlayStop
()
{
mWindowPlayer
.
updatePlayState
(
SuperPlayerDef
.
PlayerState
.
END
);
mFullScreenPlayer
.
updatePlayState
(
SuperPlayerDef
.
PlayerState
.
END
);
// 清空关键帧和视频打点信息
if
(
mWatcher
!=
null
)
{
mWatcher
.
stop
();
}
if
(
null
!=
mPlayerViewCallback
)
{
mPlayerViewCallback
.
onSuperPlayerDidEnd
();
}
}
@Override
public
void
onPlayLoading
()
{
mWindowPlayer
.
updatePlayState
(
SuperPlayerDef
.
PlayerState
.
LOADING
);
mFullScreenPlayer
.
updatePlayState
(
SuperPlayerDef
.
PlayerState
.
LOADING
);
if
(
mWatcher
!=
null
)
{
mWatcher
.
enterLoading
();
}
}
@Override
public
void
onPlayProgress
(
long
current
,
long
duration
)
{
mWindowPlayer
.
updateVideoProgress
(
current
,
duration
);
mFullScreenPlayer
.
updateVideoProgress
(
current
,
duration
);
}
@Override
public
void
onSeek
(
int
position
)
{
if
(
mSuperPlayer
.
getPlayerType
()
!=
SuperPlayerDef
.
PlayerType
.
VOD
)
{
if
(
mWatcher
!=
null
)
{
mWatcher
.
stop
();
}
}
}
@Override
public
void
onSwitchStreamStart
(
boolean
success
,
SuperPlayerDef
.
PlayerType
playerType
,
VideoQuality
quality
)
{
if
(
playerType
==
SuperPlayerDef
.
PlayerType
.
LIVE
)
{
if
(
success
)
{
Toast
.
makeText
(
mContext
,
"正在切换到"
+
quality
.
title
+
"..."
,
Toast
.
LENGTH_SHORT
).
show
();
}
else
{
Toast
.
makeText
(
mContext
,
"切换"
+
quality
.
title
+
"清晰度失败,请稍候重试"
,
Toast
.
LENGTH_SHORT
).
show
();
}
}
}
@Override
public
void
onSwitchStreamEnd
(
boolean
success
,
SuperPlayerDef
.
PlayerType
playerType
,
VideoQuality
quality
)
{
if
(
playerType
==
SuperPlayerDef
.
PlayerType
.
LIVE
)
{
if
(
success
)
{
Toast
.
makeText
(
mContext
,
"清晰度切换成功"
,
Toast
.
LENGTH_SHORT
).
show
();
}
else
{
Toast
.
makeText
(
mContext
,
"清晰度切换失败"
,
Toast
.
LENGTH_SHORT
).
show
();
}
}
}
@Override
public
void
onPlayerTypeChange
(
SuperPlayerDef
.
PlayerType
playType
)
{
mWindowPlayer
.
updatePlayType
(
playType
);
mFullScreenPlayer
.
updatePlayType
(
playType
);
}
@Override
public
void
onPlayTimeShiftLive
(
TXLivePlayer
player
,
String
url
)
{
if
(
mWatcher
==
null
)
{
mWatcher
=
new
NetWatcher
(
mContext
);
}
mWatcher
.
start
(
url
,
player
);
}
@Override
public
void
onVideoQualityListChange
(
List
<
VideoQuality
>
videoQualities
,
VideoQuality
defaultVideoQuality
)
{
mFullScreenPlayer
.
setVideoQualityList
(
videoQualities
);
mFullScreenPlayer
.
updateVideoQuality
(
defaultVideoQuality
);
}
@Override
public
void
onVideoImageSpriteAndKeyFrameChanged
(
PlayImageSpriteInfo
info
,
List
<
PlayKeyFrameDescInfo
>
list
)
{
mFullScreenPlayer
.
updateImageSpriteInfo
(
info
);
mFullScreenPlayer
.
updateKeyFrameDescInfo
(
list
);
}
@Override
public
void
onError
(
int
code
,
String
message
)
{
showToast
(
message
);
if
(
null
!=
mPlayerViewCallback
)
{
mPlayerViewCallback
.
onSuperPlayerError
();
}
}
};
private
void
showToast
(
String
message
)
{
Toast
.
makeText
(
mContext
,
message
,
Toast
.
LENGTH_SHORT
).
show
();
}
private
void
showToast
(
int
resId
)
{
Toast
.
makeText
(
mContext
,
resId
,
Toast
.
LENGTH_SHORT
).
show
();
}
public
static
void
save2MediaStore
(
Context
context
,
Bitmap
image
)
{
File
sdcardDir
=
context
.
getExternalFilesDir
(
null
);
if
(
sdcardDir
==
null
)
{
Log
.
e
(
TAG
,
"sdcardDir is null"
);
return
;
}
File
appDir
=
new
File
(
sdcardDir
,
"superplayer"
);
if
(!
appDir
.
exists
())
{
appDir
.
mkdir
();
}
long
dateSeconds
=
System
.
currentTimeMillis
()
/
1000
;
String
fileName
=
dateSeconds
+
".jpg"
;
File
file
=
new
File
(
appDir
,
fileName
);
String
filePath
=
file
.
getAbsolutePath
();
File
f
=
new
File
(
filePath
);
if
(
f
.
exists
())
{
f
.
delete
();
}
FileOutputStream
fos
=
null
;
try
{
fos
=
new
FileOutputStream
(
f
);
image
.
compress
(
Bitmap
.
CompressFormat
.
JPEG
,
100
,
fos
);
fos
.
flush
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
finally
{
if
(
fos
!=
null
)
{
try
{
fos
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
}
try
{
// Save the screenshot to the MediaStore
ContentValues
values
=
new
ContentValues
();
ContentResolver
resolver
=
context
.
getContentResolver
();
values
.
put
(
MediaStore
.
Images
.
ImageColumns
.
DATA
,
filePath
);
values
.
put
(
MediaStore
.
Images
.
ImageColumns
.
TITLE
,
fileName
);
values
.
put
(
MediaStore
.
Images
.
ImageColumns
.
DISPLAY_NAME
,
fileName
);
values
.
put
(
MediaStore
.
Images
.
ImageColumns
.
DATE_ADDED
,
dateSeconds
);
values
.
put
(
MediaStore
.
Images
.
ImageColumns
.
DATE_MODIFIED
,
dateSeconds
);
values
.
put
(
MediaStore
.
Images
.
ImageColumns
.
MIME_TYPE
,
"image/jpeg"
);
values
.
put
(
MediaStore
.
Images
.
ImageColumns
.
WIDTH
,
image
.
getWidth
());
values
.
put
(
MediaStore
.
Images
.
ImageColumns
.
HEIGHT
,
image
.
getHeight
());
Uri
uri
=
resolver
.
insert
(
MediaStore
.
Images
.
Media
.
EXTERNAL_CONTENT_URI
,
values
);
OutputStream
out
=
resolver
.
openOutputStream
(
uri
);
image
.
compress
(
Bitmap
.
CompressFormat
.
JPEG
,
100
,
out
);
out
.
flush
();
out
.
close
();
// update file size in the database
values
.
clear
();
values
.
put
(
MediaStore
.
Images
.
ImageColumns
.
SIZE
,
new
File
(
filePath
).
length
());
resolver
.
update
(
uri
,
values
,
null
,
null
);
}
catch
(
Exception
e
)
{
TXCLog
.
e
(
TAG
,
Log
.
getStackTraceString
(
e
));
}
}
public
void
disableGesture
(
boolean
flag
)
{
if
(
null
!=
mFullScreenPlayer
)
{
mFullScreenPlayer
.
disableGesture
(
flag
);
}
if
(
null
!=
mWindowPlayer
)
{
mWindowPlayer
.
disableGesture
(
flag
);
}
}
public
void
setIsAutoPlay
(
boolean
b
)
{
mSuperPlayer
.
setAutoPlay
(
b
);
}
public
void
setStartTime
(
double
startTime
)
{
mSuperPlayer
.
setStartTime
((
float
)
startTime
);
}
public
void
setLoop
(
boolean
b
)
{
mSuperPlayer
.
setLoop
(
b
);
}
}
Flutter/example/lib/superplayer/ui/superplayer_widget.dart
浏览文件 @
5e964a51
...
@@ -2,7 +2,8 @@
...
@@ -2,7 +2,8 @@
part of
demo_super_player_lib
;
part of
demo_super_player_lib
;
final
double
topBottomOffset
=
0
;
final
double
topBottomOffset
=
0
;
DeviceOrientation
landscapeOrientation
=
DeviceOrientation
.
landscapeLeft
;
int
manualOrientationDirection
=
TXVodPlayEvent
.
ORIENTATION_LANDSCAPE_RIGHT
;
FullScreenController
_fullScreenController
=
FullScreenController
();
/// superplayer view widget
/// superplayer view widget
class
SuperPlayerView
extends
StatefulWidget
{
class
SuperPlayerView
extends
StatefulWidget
{
...
@@ -40,7 +41,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
...
@@ -40,7 +41,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
late
_BottomViewController
_bottomViewController
;
late
_BottomViewController
_bottomViewController
;
late
_QualityListViewController
_qualitListViewController
;
late
_QualityListViewController
_qualitListViewController
;
late
_VideoTitleController
_titleViewController
;
late
_VideoTitleController
_titleViewController
;
late
_SuperPlayerFullScreenController
_
fullScreen
Controller
;
late
_SuperPlayerFullScreenController
_
superPlayerFullUI
Controller
;
late
_CoverViewController
_coverViewController
;
late
_CoverViewController
_coverViewController
;
late
_MoreViewController
_moreViewController
;
late
_MoreViewController
_moreViewController
;
...
@@ -59,14 +60,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
...
@@ -59,14 +60,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
@override
@override
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
// ios need landscapeRight,android need landscapeLeft
if
(
defaultTargetPlatform
==
TargetPlatform
.
iOS
)
{
landscapeOrientation
=
DeviceOrientation
.
landscapeRight
;
}
else
{
landscapeOrientation
=
DeviceOrientation
.
landscapeLeft
;
}
_playController
=
widget
.
_controller
;
_playController
=
widget
.
_controller
;
_
fullScreen
Controller
=
_SuperPlayerFullScreenController
(
_updateState
);
_
superPlayerFullUI
Controller
=
_SuperPlayerFullScreenController
(
_updateState
);
_titleViewController
=
_VideoTitleController
(
_onTapBack
,
()
{
_titleViewController
=
_VideoTitleController
(
_onTapBack
,
()
{
_moreViewKey
.
currentState
?.
toggleShowMoreView
();
_moreViewKey
.
currentState
?.
toggleShowMoreView
();
});
});
...
@@ -143,6 +138,11 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
...
@@ -143,6 +138,11 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
_onResume
();
_onResume
();
}
}
}
}
// 画中画模式下,不进行旋转屏幕操作
if
(
eventCode
==
TXVodPlayEvent
.
EVENT_ORIENTATION_CHANGED
&&
!
_isFloatingMode
)
{
int
orientation
=
event
[
TXVodPlayEvent
.
EXTRA_NAME_ORIENTATION
];
_fullScreenController
.
switchToOrientation
(
orientation
);
}
});
});
_registerObserver
();
_registerObserver
();
_initPlayerState
();
_initPlayerState
();
...
@@ -214,6 +214,22 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
...
@@ -214,6 +214,22 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
// onDispose
// onDispose
_playController
.
_observer
=
null
;
// close observer
_playController
.
_observer
=
null
;
// close observer
});
});
_fullScreenController
.
setListener
(()
{
Navigator
.
of
(
context
).
push
(
MaterialPageRoute
(
builder:
(
context
)
{
return
SuperPlayerFullScreenView
(
_playController
,
_superPlayerFullUIController
);
}));
WidgetsBinding
.
instance
?.
removeObserver
(
this
);
_videoBottomKey
.
currentState
?.
updateFullScreen
(
true
);
_videoTitleKey
.
currentState
?.
updateFullScreen
(
true
);
_playController
.
_updateFullScreenState
(
true
);
hideControlView
();
},
()
{
Navigator
.
of
(
context
).
pop
();
_videoBottomKey
.
currentState
?.
updateFullScreen
(
false
);
_videoTitleKey
.
currentState
?.
updateFullScreen
(
false
);
_playController
.
_updateFullScreenState
(
false
);
hideControlView
();
});
WidgetsBinding
.
instance
?.
addObserver
(
this
);
WidgetsBinding
.
instance
?.
addObserver
(
this
);
}
}
...
@@ -238,11 +254,6 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
...
@@ -238,11 +254,6 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
_isLoading
=
true
;
_isLoading
=
true
;
break
;
break
;
}
}
if
(
_isFullScreen
)
{
SystemChrome
.
setPreferredOrientations
([
landscapeOrientation
]);
}
else
{
SystemChrome
.
setPreferredOrientations
([
DeviceOrientation
.
portraitUp
]);
}
}
}
void
_updateState
()
{
void
_updateState
()
{
...
@@ -268,10 +279,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
...
@@ -268,10 +279,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
Orientation
currentOrientation
=
MediaQuery
.
of
(
context
).
orientation
;
Orientation
currentOrientation
=
MediaQuery
.
of
(
context
).
orientation
;
bool
isLandscape
=
currentOrientation
==
Orientation
.
landscape
;
bool
isLandscape
=
currentOrientation
==
Orientation
.
landscape
;
if
(!
isLandscape
)
{
if
(!
isLandscape
)
{
///关闭状态栏,与RootViewController底部虚拟操作按钮
_fullScreenController
.
forceSwitchOrientation
(
manualOrientationDirection
);
SystemChrome
.
setPreferredOrientations
([
landscapeOrientation
]);
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
immersive
);
AutoOrientation
.
landscapeAutoMode
();
}
}
}
}
}
else
if
(
state
==
AppLifecycleState
.
inactive
)
{
}
else
if
(
state
==
AppLifecycleState
.
inactive
)
{
...
@@ -467,7 +475,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
...
@@ -467,7 +475,7 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
forwardIcon:
"images/ic_pip_play_forward.png"
);
forwardIcon:
"images/ic_pip_play_forward.png"
);
if
(
null
!=
result
)
{
if
(
null
!=
result
)
{
String
failedStr
=
""
;
String
failedStr
=
""
;
if
(
result
!=
TXVodPlayEvent
.
NO_ERROR
)
{
if
(
result
!=
TXVodPlayEvent
.
NO_ERROR
)
{
if
(
result
==
TXVodPlayEvent
.
ERROR_PIP_LOWER_VERSION
)
{
if
(
result
==
TXVodPlayEvent
.
ERROR_PIP_LOWER_VERSION
)
{
failedStr
=
"enterPip failed,because android version is too low,Minimum supported version is android 24"
;
failedStr
=
"enterPip failed,because android version is too low,Minimum supported version is android 24"
;
}
else
if
(
result
==
TXVodPlayEvent
.
ERROR_PIP_DENIED_PERMISSION
)
{
}
else
if
(
result
==
TXVodPlayEvent
.
ERROR_PIP_DENIED_PERMISSION
)
{
...
@@ -546,37 +554,17 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
...
@@ -546,37 +554,17 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
}
}
}
}
void
_fullScreenOrientation
()
{
void
_handleFullScreen
(
bool
toSwitchFullScreen
)
{
if
(
_isFullScreen
)
{
if
(
toSwitchFullScreen
)
{
Navigator
.
of
(
context
).
push
(
MaterialPageRoute
(
builder:
(
context
)
{
_fullScreenController
.
switchToOrientation
(
manualOrientationDirection
);
return
SuperPlayerFullScreenView
(
_playController
,
_fullScreenController
);
}));
WidgetsBinding
.
instance
?.
removeObserver
(
this
);
}
else
{
}
else
{
// exit fullscreen widget
_fullScreenController
.
switchToOrientation
(
TXVodPlayEvent
.
ORIENTATION_PORTRAIT_UP
);
Navigator
.
of
(
context
).
pop
();
///显示状态栏,与底部虚拟操作按钮
SystemChrome
.
setPreferredOrientations
([
DeviceOrientation
.
portraitUp
]);
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
manual
,
overlays:
SystemUiOverlay
.
values
);
AutoOrientation
.
portraitAutoMode
();
/// 隐藏moreView
_moreViewKey
.
currentState
?.
hideShowMoreView
();
}
}
_videoBottomKey
.
currentState
?.
updateFullScreen
(
_isFullScreen
);
_videoTitleKey
.
currentState
?.
updateFullScreen
(
_isFullScreen
);
}
}
void
_onControlFullScreen
()
{
void
_onControlFullScreen
()
{
_isFullScreen
=
!
_isFullScreen
;
_isFullScreen
=
!
_isFullScreen
;
if
(
_isFullScreen
)
{
_handleFullScreen
(
_isFullScreen
);
hideControlView
();
_fullScreenOrientation
();
}
else
{
hideControlView
();
_fullScreenOrientation
();
}
_playController
.
_updateFullScreenState
(
_isFullScreen
);
_playController
.
_updateFullScreenState
(
_isFullScreen
);
}
}
...
@@ -625,6 +613,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
...
@@ -625,6 +613,8 @@ class SuperPlayerViewState extends State<SuperPlayerView> with WidgetsBindingObs
if
(!
_isShowControlView
||
!
mounted
)
{
if
(!
_isShowControlView
||
!
mounted
)
{
return
;
return
;
}
}
/// 隐藏moreView
_moreViewKey
.
currentState
?.
hideShowMoreView
();
setState
(()
{
setState
(()
{
_isShowQualityListView
=
false
;
_isShowQualityListView
=
false
;
_isShowControlView
=
false
;
_isShowControlView
=
false
;
...
@@ -654,11 +644,6 @@ class SuperPlayerFullScreenState extends State<SuperPlayerFullScreenView> {
...
@@ -654,11 +644,6 @@ class SuperPlayerFullScreenState extends State<SuperPlayerFullScreenView> {
@override
@override
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
///关闭状态栏,与底部虚拟操作按钮
SystemChrome
.
setPreferredOrientations
([
landscapeOrientation
]);
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
immersive
);
AutoOrientation
.
landscapeAutoMode
();
}
}
@override
@override
...
@@ -834,3 +819,58 @@ class _SuperPlayerFloatState extends State<SuperPlayerFloatView> {
...
@@ -834,3 +819,58 @@ class _SuperPlayerFloatState extends State<SuperPlayerFloatView> {
sizeStreamSubscription
?.
cancel
();
sizeStreamSubscription
?.
cancel
();
}
}
}
}
class
FullScreenController
{
bool
_isInFullScreenUI
=
false
;
int
currentOrientation
=
TXVodPlayEvent
.
ORIENTATION_PORTRAIT_UP
;
Function
?
onEnterFullScreenUI
;
Function
?
onExitFullScreenUI
;
FullScreenController
();
void
switchToOrientation
(
int
orientationDirection
)
{
if
(
currentOrientation
!=
orientationDirection
)
{
forceSwitchOrientation
(
orientationDirection
);
}
}
void
forceSwitchOrientation
(
int
orientationDirection
)
{
currentOrientation
=
orientationDirection
;
if
(
orientationDirection
==
TXVodPlayEvent
.
ORIENTATION_PORTRAIT_UP
)
{
exitFullScreen
();
SystemChrome
.
setPreferredOrientations
([
DeviceOrientation
.
portraitUp
]);
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
manual
,
overlays:
SystemUiOverlay
.
values
);
AutoOrientation
.
portraitUpMode
();
}
else
if
(
orientationDirection
==
TXVodPlayEvent
.
ORIENTATION_LANDSCAPE_RIGHT
)
{
enterFullScreen
();
SystemChrome
.
setPreferredOrientations
(
Platform
.
isIOS
?
[
DeviceOrientation
.
landscapeRight
]
:
[
DeviceOrientation
.
landscapeLeft
]);
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
immersive
);
AutoOrientation
.
landscapeRightMode
();
}
else
if
(
orientationDirection
==
TXVodPlayEvent
.
ORIENTATION_PORTRAIT_DOWN
)
{
}
else
if
(
orientationDirection
==
TXVodPlayEvent
.
ORIENTATION_LANDSCAPE_LEFT
)
{
enterFullScreen
();
SystemChrome
.
setPreferredOrientations
(
Platform
.
isIOS
?
[
DeviceOrientation
.
landscapeLeft
]
:
[
DeviceOrientation
.
landscapeRight
]);
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
immersive
);
AutoOrientation
.
landscapeLeftMode
();
}
}
void
enterFullScreen
()
{
if
(!
_isInFullScreenUI
)
{
_isInFullScreenUI
=
true
;
onEnterFullScreenUI
?.
call
();
}
}
void
exitFullScreen
()
{
if
(
_isInFullScreenUI
)
{
_isInFullScreenUI
=
false
;
onExitFullScreenUI
?.
call
();
}
}
void
setListener
(
Function
enterfullScreen
,
Function
exitFullScreen
)
{
this
.
onExitFullScreenUI
=
exitFullScreen
;
this
.
onEnterFullScreenUI
=
enterfullScreen
;
}
}
Flutter/ios/Classes/FTXAudioManager.m
浏览文件 @
5e964a51
...
@@ -16,6 +16,8 @@
...
@@ -16,6 +16,8 @@
[
volumeView
sizeToFit
];
[
volumeView
sizeToFit
];
// 单例slider
// 单例slider
_volumeSlider
=
nil
;
_volumeSlider
=
nil
;
//开始接收遥控事件
[[
UIApplication
sharedApplication
]
beginReceivingRemoteControlEvents
];
for
(
UIView
*
view
in
[
volumeView
subviews
])
{
for
(
UIView
*
view
in
[
volumeView
subviews
])
{
if
([
view
.
class
.
description
isEqualToString
:
@"MPVolumeSlider"
])
{
if
([
view
.
class
.
description
isEqualToString
:
@"MPVolumeSlider"
])
{
_volumeSlider
=
(
UISlider
*
)
view
;
_volumeSlider
=
(
UISlider
*
)
view
;
...
...
Flutter/ios/Classes/FTXEvent.h
浏览文件 @
5e964a51
...
@@ -28,27 +28,6 @@
...
@@ -28,27 +28,6 @@
// 画中画事件code
#define EVENT_PIP_MODE_ALREADY_ENTER 1
#define EVENT_PIP_MODE_ALREADY_EXIT 2
#define EVENT_PIP_MODE_REQUEST_START 3
#define EVENT_PIP_MODE_UI_STATE_CHANGED 4
#define EVENT_PIP_MODE_RESTORE_UI 5
#define EVENT_PIP_MODE_WILL_EXIT 6
// 画中画错误事件code
#define NO_ERROR 0 ///< 无错误
#define ERROR_IOS_PIP_DEVICE_NOT_SUPPORT -104 ///< 设备或系统版本不支持(iPad iOS9+ 才支持PIP)
#define ERROR_IOS_PIP_PLAYER_NOT_SUPPORT -105 ///< 播放器不支持
#define ERROR_IOS_PIP_VIDEO_NOT_SUPPORT -106 ///< 视频不支持
#define ERROR_IOS_PIP_IS_NOT_POSSIBLE -107 ///< PIP控制器不可用
#define ERROR_IOS_PIP_FROM_SYSTEM -108 ///< PIP控制器报错
#define ERROR_IOS_PIP_PLAYER_NOT_EXIST -109 ///< 播放器对象不存在
#define ERROR_IOS_PIP_IS_RUNNING -110 ///< PIP功能已经运行
#define ERROR_IOS_PIP_NOT_RUNNING -111 ///< PIP功能没有启动
// 视频预下载完成
// 视频预下载完成
#define EVENT_PREDOWNLOAD_ON_COMPLETE 200
#define EVENT_PREDOWNLOAD_ON_COMPLETE 200
// 视频预下载出错
// 视频预下载出错
...
@@ -65,4 +44,17 @@
...
@@ -65,4 +44,17 @@
// 视频下载错误
// 视频下载错误
#define EVENT_DOWNLOAD_ERROR 305
#define EVENT_DOWNLOAD_ERROR 305
// 屏幕旋转事件
#define EVENT_ORIENTATION_CHANGED 401
// 屏幕旋转方向
#define EXTRA_NAME_ORIENTATION @"orientation"
// 正竖屏
#define ORIENTATION_PORTRAIT_UP 411
// 横屏,底部在右
#define ORIENTATION_LANDSCAPE_RIGHT 412
// 竖屏,顶部在下
#define ORIENTATION_PORTRAIT_DOWN 413
// 横屏,底部在左
#define ORIENTATION_LANDSCAPE_LEFT 414
#endif
/* FTXEvent_h */
#endif
/* FTXEvent_h */
Flutter/ios/Classes/SuperPlayerPlugin.m
浏览文件 @
5e964a51
...
@@ -25,6 +25,7 @@
...
@@ -25,6 +25,7 @@
FTXPlayerEventSinkQueue
*
_pipEventSink
;
FTXPlayerEventSinkQueue
*
_pipEventSink
;
FTXAudioManager
*
audioManager
;
FTXAudioManager
*
audioManager
;
FTXDownloadManager
*
_FTXDownloadManager
;
FTXDownloadManager
*
_FTXDownloadManager
;
int
mCurrentOrientation
;
}
}
SuperPlayerPlugin
*
instance
;
SuperPlayerPlugin
*
instance
;
...
@@ -44,6 +45,7 @@ SuperPlayerPlugin* instance;
...
@@ -44,6 +45,7 @@ SuperPlayerPlugin* instance;
if
(
nil
!=
_FTXDownloadManager
)
{
if
(
nil
!=
_FTXDownloadManager
)
{
[
_FTXDownloadManager
destroy
];
[
_FTXDownloadManager
destroy
];
}
}
[[
NSNotificationCenter
defaultCenter
]
removeObserver
:
self
];
}
}
-
(
instancetype
)
initWithRegistrar
:
-
(
instancetype
)
initWithRegistrar
:
...
@@ -67,6 +69,13 @@ SuperPlayerPlugin* instance;
...
@@ -67,6 +69,13 @@ SuperPlayerPlugin* instance;
[
audioManager
registerVolumeChangeListener
:
self
selector
:
@selector
(
systemVolumeDidChangeNoti
:
)
name
:
@"AVSystemController_SystemVolumeDidChangeNotification"
object
:
nil
];
[
audioManager
registerVolumeChangeListener
:
self
selector
:
@selector
(
systemVolumeDidChangeNoti
:
)
name
:
@"AVSystemController_SystemVolumeDidChangeNotification"
object
:
nil
];
_FTXDownloadManager
=
[[
FTXDownloadManager
alloc
]
initWithRegistrar
:
registrar
];
_FTXDownloadManager
=
[[
FTXDownloadManager
alloc
]
initWithRegistrar
:
registrar
];
// orientation
mCurrentOrientation
=
ORIENTATION_PORTRAIT_UP
;
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(
onDeviceOrientationChange
:
)
name:
UIDeviceOrientationDidChangeNotification
object:
nil
];
return
self
;
return
self
;
}
}
...
@@ -204,6 +213,7 @@ SuperPlayerPlugin* instance;
...
@@ -204,6 +213,7 @@ SuperPlayerPlugin* instance;
if
([
arguments
isKindOfClass
:
NSString
.
class
])
{
if
([
arguments
isKindOfClass
:
NSString
.
class
])
{
if
([
arguments
isEqualToString
:
@"event"
])
{
if
([
arguments
isEqualToString
:
@"event"
])
{
[
_eventSink
setDelegate
:
events
];
[
_eventSink
setDelegate
:
events
];
}
else
if
([
arguments
isEqualToString
:
@"pipEvent"
])
{
[
_pipEventSink
setDelegate
:
events
];
[
_pipEventSink
setDelegate
:
events
];
}
}
}
}
...
@@ -216,6 +226,7 @@ SuperPlayerPlugin* instance;
...
@@ -216,6 +226,7 @@ SuperPlayerPlugin* instance;
if
([
arguments
isKindOfClass
:
NSString
.
class
])
{
if
([
arguments
isKindOfClass
:
NSString
.
class
])
{
if
([
arguments
isEqualToString
:
@"event"
])
{
if
([
arguments
isEqualToString
:
@"event"
])
{
[
_eventSink
setDelegate
:
nil
];
[
_eventSink
setDelegate
:
nil
];
}
else
if
([
arguments
isEqualToString
:
@"pipEvent"
])
{
[
_pipEventSink
setDelegate
:
nil
];
[
_pipEventSink
setDelegate
:
nil
];
}
}
}
}
...
@@ -248,4 +259,39 @@ SuperPlayerPlugin* instance;
...
@@ -248,4 +259,39 @@ SuperPlayerPlugin* instance;
[
_pipEventSink
success
:@{
@"event"
:
@
(
EVENT_PIP_MODE_RESTORE_UI
)}];
[
_pipEventSink
success
:@{
@"event"
:
@
(
EVENT_PIP_MODE_RESTORE_UI
)}];
}
}
#pragma mark - orientation
-
(
void
)
onDeviceOrientationChange
:
(
NSNotification
*
)
notification
{
// IOS 此处不需要判断是否打开自动屏幕旋转/竖排锁定开关,当IOS打开锁定之后,这里默认是收不到回调的
UIDeviceOrientation
orientation
=
[
UIDevice
currentDevice
].
orientation
;
UIInterfaceOrientation
interfaceOrientation
=
(
UIInterfaceOrientation
)
orientation
;
int
tempOrientationCode
=
mCurrentOrientation
;
switch
(
interfaceOrientation
)
{
case
UIInterfaceOrientationPortrait
:
// 电池栏在上
tempOrientationCode
=
ORIENTATION_PORTRAIT_UP
;
break
;
case
UIInterfaceOrientationLandscapeLeft
:
// 电池栏在左
tempOrientationCode
=
ORIENTATION_LANDSCAPE_LEFT
;
break
;
case
UIInterfaceOrientationPortraitUpsideDown
:
// 电池栏在下
tempOrientationCode
=
ORIENTATION_PORTRAIT_DOWN
;
break
;
case
UIInterfaceOrientationLandscapeRight
:
// 电池栏在右
tempOrientationCode
=
ORIENTATION_LANDSCAPE_RIGHT
;
break
;
default
:
break
;
}
if
(
tempOrientationCode
!=
mCurrentOrientation
)
{
mCurrentOrientation
=
tempOrientationCode
;
[
_eventSink
success
:@{
@"event"
:
@
(
EVENT_ORIENTATION_CHANGED
),
EXTRA_NAME_ORIENTATION
:
@
(
tempOrientationCode
)}];
}
}
@end
@end
Flutter/lib/Core/superplayer_plugin.dart
浏览文件 @
5e964a51
...
@@ -27,7 +27,7 @@ class SuperPlayerPlugin {
...
@@ -27,7 +27,7 @@ class SuperPlayerPlugin {
eventChannel
.
receiveBroadcastStream
(
"event"
).
listen
(
_eventHandler
,
onError:
_errorHandler
);
eventChannel
.
receiveBroadcastStream
(
"event"
).
listen
(
_eventHandler
,
onError:
_errorHandler
);
EventChannel
pipEventChanne
=
EventChannel
(
"cloud.tencent.com/playerPlugin/pipEvent"
);
EventChannel
pipEventChanne
=
EventChannel
(
"cloud.tencent.com/playerPlugin/pipEvent"
);
pipEventChanne
.
receiveBroadcastStream
(
"
e
vent"
).
listen
(
_pipEventHandler
,
onError:
_errorHandler
);
pipEventChanne
.
receiveBroadcastStream
(
"
pipE
vent"
).
listen
(
_pipEventHandler
,
onError:
_errorHandler
);
}
}
_pipEventHandler
(
event
)
{
_pipEventHandler
(
event
)
{
...
...
Flutter/lib/Core/txplayer_define.dart
浏览文件 @
5e964a51
...
@@ -97,6 +97,12 @@ abstract class TXVodPlayEvent {
...
@@ -97,6 +97,12 @@ abstract class TXVodPlayEvent {
static
const
EVENT_IOS_PIP_MODE_RESTORE_UI
=
5
;
// 重置UI only support iOS
static
const
EVENT_IOS_PIP_MODE_RESTORE_UI
=
5
;
// 重置UI only support iOS
static
const
EVENT_IOS_PIP_MODE_WILL_EXIT
=
6
;
// 将要退出画中画 only support iOS
static
const
EVENT_IOS_PIP_MODE_WILL_EXIT
=
6
;
// 将要退出画中画 only support iOS
static
const
EVENT_ORIENTATION_CHANGED
=
401
;
// 屏幕发生旋转
static
const
EXTRA_NAME_ORIENTATION
=
"orientation"
;
// 屏幕旋转方向
static
const
ORIENTATION_PORTRAIT_UP
=
411
;
// 竖屏,顶部在上
static
const
ORIENTATION_LANDSCAPE_RIGHT
=
412
;
// 横屏,顶部在左,底部在右
static
const
ORIENTATION_PORTRAIT_DOWN
=
413
;
// 竖屏,顶部在下
static
const
ORIENTATION_LANDSCAPE_LEFT
=
414
;
// 横屏,顶部在右,底部在左
static
const
NO_ERROR
=
0
;
static
const
NO_ERROR
=
0
;
static
const
ERROR_PIP_LOWER_VERSION
=
-
101
;
// pip 错误,android版本过低
static
const
ERROR_PIP_LOWER_VERSION
=
-
101
;
// pip 错误,android版本过低
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论