优化播放控制

This commit is contained in:
sifacai@outlook.com 2022-08-25 00:59:45 +08:00
parent 83d06aa630
commit 021424c37f
10 changed files with 219 additions and 80 deletions

2
.idea/misc.xml generated
View File

@ -4,10 +4,12 @@
<option name="filePathToZoomLevelMap">
<map>
<entry key="..\:/code/VlcJellyfin/app/src/main/res/drawable/ic_outline_play_circle_outline_128.xml" value="0.1555" />
<entry key="..\:/code/VlcJellyfin/app/src/main/res/drawable/played_percentage.xml" value="0.1765" />
<entry key="..\:/code/VlcJellyfin/app/src/main/res/drawable/popmenu_focus.xml" value="0.1555" />
<entry key="..\:/code/VlcJellyfin/app/src/main/res/drawable/shape_user_focus_vholder.xml" value="0.1555" />
<entry key="..\:/code/VlcJellyfin/app/src/main/res/layout/activity_detail.xml" value="0.14583333333333334" />
<entry key="..\:/code/VlcJellyfin/app/src/main/res/layout/activity_vlc_player.xml" value="0.286231884057971" />
<entry key="..\:/code/VlcJellyfin/app/src/main/res/layout/item_h.xml" value="0.16770833333333332" />
<entry key="..\:/code/VlcJellyfin/app/src/main/res/layout/item_v.xml" value="0.14583333333333334" />
<entry key="..\:/code/VlcJellyfin/app/src/main/res/layout/popmenu.xml" value="0.14479166666666668" />
<entry key="..\:/code/VlcJellyfin/app/src/main/res/layout/popmenu_item.xml" value="0.14479166666666668" />

View File

@ -7,6 +7,7 @@ import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.ColorDrawable;
import android.os.Looper;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@ -18,6 +19,9 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import me.jessyan.autosize.internal.CustomAdapt;
public class BaseActivity extends AppCompatActivity implements CustomAdapt {
@ -48,10 +52,33 @@ public class BaseActivity extends AppCompatActivity implements CustomAdapt {
return 0;
}
public void showLoadingDialog(String msg) {
mAA.runOnUiThread(new Runnable() {
@Override
public void run() {
showLoadingDialog(1);
setLoadingText(msg);
}
});
}
public void showLoadingDialog() {
mAA.runOnUiThread(new Runnable() {
@Override
public void run() {
showLoadingDialog(1);
}
});
}
/**
* 显示加载动画框
*/
public void showLoadingDialog() {
public void showLoadingDialog(int i) {
if (null != alertDialogLoading && alertDialogLoading.isShowing()) {
alertDialogLoading.dismiss();
}
alertDialogLoading = new AlertDialog.Builder(this).create();
alertDialogLoading.getWindow().setBackgroundDrawable(new ColorDrawable());
alertDialogLoading.setCancelable(false);
@ -71,10 +98,19 @@ public class BaseActivity extends AppCompatActivity implements CustomAdapt {
alertDialogLoading.setCanceledOnTouchOutside(false);
}
public void dismissLoadingDialog() {
mAA.runOnUiThread(new Runnable() {
@Override
public void run() {
dismissLoadingDialog(1);
}
});
}
/**
* 隐藏加载框
*/
public void dismissLoadingDialog() {
public void dismissLoadingDialog(int i) {
if (null != alertDialogLoading && alertDialogLoading.isShowing()) {
alertDialogLoading.dismiss();
}
@ -85,9 +121,14 @@ public class BaseActivity extends AppCompatActivity implements CustomAdapt {
* @param text
*/
public void setLoadingText(String text){
if (null != alertDialogLoading && alertDialogLoading.isShowing()) {
TextView tv = alertDialogLoading.getWindow().getDecorView().findViewById(R.id.progressText);
tv.setText(text);
}
mAA.runOnUiThread(new Runnable() {
@Override
public void run() {
if (null != alertDialogLoading && alertDialogLoading.isShowing()) {
TextView tv = alertDialogLoading.getWindow().getDecorView().findViewById(R.id.progressText);
tv.setText(text);
}
}
});
}
}

View File

@ -76,13 +76,11 @@ public class JAdapter extends RecyclerView.Adapter {
JsonObject ujo = jo.get("UserData").getAsJsonObject();
if(ujo.has("PlayedPercentage")){
int pp = ujo.get("PlayedPercentage").getAsInt();
v.tvPlayedPercentage.setVisibility(View.VISIBLE);
v.tvPlayedPercentage.setMax(100);
v.tvPlayedPercentage.setProgress(pp);
v.tvPlayedPercentage.setVisibility(View.VISIBLE);
}
}
if(jo.has("CollectionType")){
v.type = jo.get("CollectionType").getAsString();
}

View File

@ -62,8 +62,8 @@ public class MainActivity extends BaseActivity {
@Override
public void run() {
//showLoading("正在加载首页,请稍候…………");
showLoadingDialog();
setLoadingText("正在加载首页,请稍候…………");
showLoadingDialog("正在加载首页,请稍候…………");
tvContiner.removeAllViews();
}
});
@ -299,6 +299,7 @@ public class MainActivity extends BaseActivity {
* @return
*/
private boolean ValidUrl(String url) {
//showLoadingDialog("正在验证服务器地址!");
boolean valid = false;
if (url.length() > 0) {
if (url.startsWith("http://") || url.startsWith("https://")) {
@ -320,6 +321,7 @@ public class MainActivity extends BaseActivity {
}
}
}
//dismissLoadingDialog();
return false;
}
@ -333,8 +335,8 @@ public class MainActivity extends BaseActivity {
private boolean authenticateByName(String username, String password) {
String url = "/Users/authenticatebyname";
String reqjson = "{\"Username\":\"" + username + "\",\"Pw\":\"" + password + "\"}";
//showLoadingDialog("正在验证用户名和密码!");
String userinfo = Utils.okhttpSend(url, reqjson);
Log.d(TAG, "authenticateByName: " + userinfo);
if (userinfo.length() > 0) {
JsonObject userObj = new Gson().fromJson(userinfo, JsonObject.class);
String userId = userObj.getAsJsonObject("User").get("Id").getAsString();
@ -345,21 +347,14 @@ public class MainActivity extends BaseActivity {
return true;
}
}
//dismissLoadingDialog();
return false;
}
@Override
protected void onResume() {
if(!Utils.AccessToken.equals("")){
tvLoginOut.setVisibility(View.VISIBLE);
tvLoginOut.setText("注 销");
tvLoginOut.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
logout();
}
});
showLogoutBtn();
}
super.onResume();
}

View File

@ -74,8 +74,13 @@ public class PopMenu extends PopupWindow {
public void show(int index){
show();
if(index >=0 && index < items.size()) {
items.get(index).v.requestFocus();
// if(index >=0 && index < items.size()) {
// items.get(index).v.requestFocus();
// }
for (menu m:items) {
if(m.id == index){
m.v.requestFocus();
}
}
}

View File

@ -0,0 +1,56 @@
package org.sifacai.vlcjellyfin;
import android.annotation.SuppressLint;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class RxUtils {
@SuppressLint("TrulyRandom")
public static SSLSocketFactory createSSLSocketFactory() {
SSLSocketFactory sSLSocketFactory = null;
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{new TrustAllManager()},
new SecureRandom());
sSLSocketFactory = sc.getSocketFactory();
} catch (Exception ignored) {
}
return sSLSocketFactory;
}
public static class TrustAllManager implements X509TrustManager {
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
public static class TrustAllHostnameVerifier implements HostnameVerifier {
@SuppressLint("BadHostnameVerifier")
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
}

View File

@ -1,5 +1,8 @@
package org.sifacai.vlcjellyfin;
import static android.net.sip.SipErrorCode.TIME_OUT;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.util.DisplayMetrics;
@ -9,9 +12,21 @@ import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.io.IOException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
@ -51,7 +66,12 @@ public class Utils {
}else{
url = JellyfinUrl + url;
}
OkHttpClient client = new OkHttpClient();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = builder.sslSocketFactory(RxUtils.createSSLSocketFactory())
.hostnameVerifier(new RxUtils.TrustAllHostnameVerifier())
.retryOnConnectionFailure(true).build();
//OkHttpClient client = new OkHttpClient();
String xea = XEmbyAuthorization;
if(AccessToken != ""){
@ -125,9 +145,9 @@ public class Utils {
* 报告播放开始
* @param PositionTicks
*/
public static void ReportPlaying(long PositionTicks){
public static void ReportPlaying(String Id,long PositionTicks){
String url = JellyfinUrl + "/Sessions/Playing";
String json = "{\"itemId\":\"" + playList.get(playIndex).Id + "\",\"PositionTicks\":\"" + PositionTicks * 10000 + "\"}";
String json = "{\"itemId\":\"" + Id + "\",\"PositionTicks\":\"" + PositionTicks * 10000 + "\"}";
okhttpSend(url,json);
}
@ -136,8 +156,8 @@ public class Utils {
* @param paused
* @param PositionTicks
*/
public static void ReportPlaybackProgress(boolean paused, long PositionTicks) {
String json = "{\"itemId\" : \"" + playList.get(playIndex).Id + "\",\"canSeek\" : \"true\",\"isPaused\":\"" + paused + "\",\"isMuted\":\"false\",";
public static void ReportPlaybackProgress(String Id,boolean paused, long PositionTicks) {
String json = "{\"itemId\" : \"" + Id + "\",\"canSeek\" : \"true\",\"isPaused\":\"" + paused + "\",\"isMuted\":\"false\",";
json += "\"positionTicks\": \"" + PositionTicks * 10000 + "\",\"PlayMethod\":\"DirectPlay\"}";
String url = JellyfinUrl + "/Sessions/Playing/Progress";
okhttpSend(url,json);
@ -147,9 +167,9 @@ public class Utils {
* 播放停止
* @param PositionTicks
*/
public static void ReportPlaybackStop(long PositionTicks) {
public static void ReportPlaybackStop(String Id,long PositionTicks) {
String url = JellyfinUrl + "/Sessions/Playing/Stopped";
String json = "{\"itemId\":\"" + playList.get(playIndex).Id + "\",\"PositionTicks\":\"" + PositionTicks * 10000 + "\"}";
String json = "{\"itemId\":\"" + Id + "\",\"PositionTicks\":\"" + PositionTicks * 10000 + "\"}";
okhttpSend(url,json);
}
@ -175,4 +195,5 @@ public class Utils {
}
return "";
}
}

View File

@ -55,7 +55,8 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
private ImageView pauseFlag;
private SeekBar currPostion;
private Timer progressTime = null;
private Timer progressTime = null; //控制器进度条更新定时
private Timer reportProcessTime = null; // 报告进度定时器
private PopMenu playListMenu = null; //播放列表
private PopMenu subTrackMenu = null; //字幕菜单
@ -65,6 +66,7 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
private float speedRate[] = {0.5f, 1.0f, 1.5f, 2.0f}; //倍速播放列表
private long currPlaybackTimeTrack = 0; //当前播放进度
private int ReportTime = 20; // 报告进度间隔次数
private int ReportVal = 0; //累积次数
@ -98,14 +100,15 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
Hide();
pauseFlag.setVisibility(View.GONE);
Log.d(TAG, "onEvent: 打开成功");
ReportPlayState(Utils.ReportType.playing);
ReportPlayState(Utils.ReportType.playing, Utils.playList.get(Utils.playIndex).Id);
initMenu();
break;
case MediaPlayer.Event.Paused: //暂停
pauseFlag.setVisibility(View.VISIBLE);
break;
case MediaPlayer.Event.Stopped:
ReportPlayState(Utils.ReportType.stop);
Log.d(TAG, "onEvent: 播放停止");
ReportPlayState(Utils.ReportType.stop, Utils.playList.get(Utils.playIndex).Id);
playNext();
break;
case MediaPlayer.Event.Opening: //媒体打开
@ -117,7 +120,6 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
}
setLoadingText("加载进度:%" + Buffering);
if (Buffering >= 100) {
Log.d(TAG, "onEvent: 取消loading");
dismissLoadingDialog();
}
break;
@ -128,14 +130,9 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
Log.d(TAG, "onEvent: EncounteredError");
break;
case MediaPlayer.Event.TimeChanged://视频时间变化
ReportVal += 1;
if(ReportVal > ReportTime){
ReportPlayState(Utils.ReportType.Progress);
ReportVal = 0;
}
currPlaybackTimeTrack = event.getTimeChanged();
break;
case MediaPlayer.Event.PositionChanged://视频总时长的百分比
Log.d(TAG, "onEvent: 百分之:" + mediaPlayer.getPosition());
break;
case MediaPlayer.Event.SeekableChanged:
break;
@ -204,7 +201,7 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
}
/**
* 初始化字幕和轨菜单
* 初始化字幕和轨菜单
*/
private void initMenu() {
MediaPlayer.TrackDescription[] subTrackList = mediaPlayer.getSpuTracks();
@ -281,6 +278,7 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
public void onClick(View view) {
playListMenu.dismiss();
if (m.id != Utils.playIndex) {
ReportPlayState(Utils.ReportType.stop,Utils.playList.get(Utils.playIndex).Id);
Utils.playIndex = m.id;
play();
}
@ -298,7 +296,7 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
private void initSubTrackMenu(MediaPlayer.TrackDescription[] subTrackList) {
subTrackMenu = new PopMenu(this, subTracksBtn);
for (int i = 0; i < subTrackList.length; i++) {
PopMenu.menu m = subTrackMenu.add(Type_SubtitleTrack, i, i, subTrackList[i].name);
PopMenu.menu m = subTrackMenu.add(Type_SubtitleTrack, subTrackList[i].id, i, subTrackList[i].name);
m.v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@ -312,10 +310,15 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
subTracksBtn.setOnClickListener(this);
}
/**
* 初始化音轨菜单
*
* @param audioTrackList
*/
private void initAudioTrackMenu(MediaPlayer.TrackDescription[] audioTrackList) {
audioTrackMenu = new PopMenu(this, audioTracksBtn);
for (int i = 0; i < audioTrackList.length; i++) {
PopMenu.menu m = audioTrackMenu.add(Type_SubtitleTrack, i, i, audioTrackList[i].name);
PopMenu.menu m = audioTrackMenu.add(Type_SubtitleTrack, audioTrackList[i].id, i, audioTrackList[i].name);
m.v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@ -351,7 +354,7 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
setSeekBar(mediaPlayer.getTime());
setSeekBar(currPlaybackTimeTrack);
}
});
}
@ -412,6 +415,7 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
* 播放下一集
*/
public void playNext() {
ReportPlayState(Utils.ReportType.stop, Utils.playList.get(Utils.playIndex).Id);
Utils.playIndex += 1;
play();
}
@ -420,17 +424,18 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
* 上一集
*/
public void playPre() {
ReportPlayState(Utils.ReportType.stop, Utils.playList.get(Utils.playIndex).Id);
if (Utils.playIndex > 0) {
Utils.playIndex -= 1;
play();
}
}
/**
* 停止播放并结束Activity
*/
public void stop() {
ReportPlayState(Utils.ReportType.stop, Utils.playList.get(Utils.playIndex).Id);
if (progressTime != null) {
progressTime.cancel();
progressTime = null;
@ -540,17 +545,32 @@ public class VlcPlayerActivity extends BaseActivity implements MediaPlayer.Event
}
}
private void ReportPlayState(Utils.ReportType type){
long currplaytime = mediaPlayer.getTime();
private void ReportPlayState(Utils.ReportType type, String Id) {
if (type == Utils.ReportType.playing) {
reportProcessTime = new Timer();
reportProcessTime.schedule(new TimerTask() {
@Override
public void run() {
ReportPlayState(Utils.ReportType.Progress, Utils.playList.get(Utils.playIndex).Id);
}
}, 1000, 10000);
} else if (type == Utils.ReportType.stop) {
if (reportProcessTime != null) {
reportProcessTime.cancel();
reportProcessTime = null;
}
}
new Thread(new Runnable() {
@Override
public void run() {
if(type == Utils.ReportType.playing){
Utils.ReportPlaying(currplaytime);
}else if(type == Utils.ReportType.stop){
Utils.ReportPlaybackStop(currplaytime);
}else if(type == Utils.ReportType.Progress){
Utils.ReportPlaybackProgress(!mediaPlayer.isPlaying(),currplaytime);
if (type == Utils.ReportType.playing) {
Utils.ReportPlaying(Id, currPlaybackTimeTrack);
} else if (type == Utils.ReportType.stop) {
Utils.ReportPlaybackStop(Id, currPlaybackTimeTrack);
} else if (type == Utils.ReportType.Progress) {
Log.d(TAG, "run: 报告时空:" + currPlaybackTimeTrack);
Utils.ReportPlaybackProgress(Id, !mediaPlayer.isPlaying(), currPlaybackTimeTrack);
}
}
}).start();

View File

@ -23,7 +23,8 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@color/color_99000000"
android:padding="1dp">
android:padding="1dp"
android:orientation="vertical">
<TextView
android:id="@+id/tvName"
@ -35,20 +36,20 @@
android:gravity="center"
android:singleLine="true" />
<SeekBar
android:id="@+id/tvPlayedPercentage"
android:layout_width="match_parent"
android:layout_height="2dp"
android:max="100"
android:progress="0"
android:layout_gravity="bottom"
android:paddingEnd="0dp"
android:paddingStart="0dp"
android:thumb="@null"
android:progressDrawable="@drawable/played_percentage"
android:visibility="gone"/>
</LinearLayout>
</FrameLayout>
<SeekBar
android:id="@+id/tvPlayedPercentage"
android:layout_width="match_parent"
android:layout_height="2dp"
android:max="100"
android:progress="0"
android:layout_gravity="bottom"
android:paddingEnd="0dp"
android:paddingStart="0dp"
android:thumb="@null"
android:progressDrawable="@drawable/played_percentage"
android:visibility="gone"/>
</FrameLayout>

View File

@ -35,21 +35,21 @@
android:gravity="center"
android:singleLine="true" />
<SeekBar
android:id="@+id/tvPlayedPercentage"
android:layout_width="match_parent"
android:layout_height="2dp"
android:max="100"
android:progress="0"
android:layout_gravity="bottom"
android:paddingEnd="0dp"
android:paddingStart="0dp"
android:thumb="@null"
android:progressDrawable="@drawable/played_percentage"
android:visibility="gone"/>
</LinearLayout>
</FrameLayout>
<SeekBar
android:id="@+id/tvPlayedPercentage"
android:layout_width="match_parent"
android:layout_height="2dp"
android:max="100"
android:progress="0"
android:layout_gravity="bottom"
android:paddingEnd="0dp"
android:paddingStart="0dp"
android:thumb="@null"
android:progressDrawable="@drawable/played_percentage"
android:visibility="gone"/>
</FrameLayout>