|
@@ -0,0 +1,440 @@
|
|
|
+package com.hc.webapp.web;
|
|
|
+
|
|
|
+import android.app.Activity;
|
|
|
+import android.app.Dialog;
|
|
|
+import android.content.Context;
|
|
|
+import android.content.Intent;
|
|
|
+import android.database.Cursor;
|
|
|
+import android.net.Uri;
|
|
|
+import android.os.Build;
|
|
|
+import android.support.annotation.NonNull;
|
|
|
+import android.support.annotation.StringDef;
|
|
|
+import android.text.TextUtils;
|
|
|
+import android.util.Log;
|
|
|
+import android.util.TypedValue;
|
|
|
+import android.webkit.JavascriptInterface;
|
|
|
+import android.webkit.WebView;
|
|
|
+import android.widget.TextView;
|
|
|
+
|
|
|
+import com.hc.lib.DownloadUtils;
|
|
|
+import com.hc.lib.MacUtil;
|
|
|
+import com.hc.model.YNYD.YNYDContentProvider;
|
|
|
+import com.hc.model.YNYD.YNYDService;
|
|
|
+import com.hc.request.Config;
|
|
|
+import com.hc.request.core.DefaultCallback;
|
|
|
+import com.hc.webapp.BuildConfig;
|
|
|
+import com.jewel.lib.java.StringUtil;
|
|
|
+import com.orhanobut.logger.Logger;
|
|
|
+
|
|
|
+import java.lang.annotation.Retention;
|
|
|
+import java.lang.annotation.RetentionPolicy;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+
|
|
|
+import static com.hc.lib.video.IVideoPlayer.PLAY_TIME_NO_LIMIT;
|
|
|
+
|
|
|
+
|
|
|
+@SuppressWarnings("unused")
|
|
|
+public class AndroidToJS {
|
|
|
+
|
|
|
+ public static final String JS_EVENT_BACK = "javascript:onBackEvent()";
|
|
|
+ public static final String JS_EVENT_PLAY_FINISH = "javascript:onPlayBackEvent()";
|
|
|
+ private static final String JS_EVENT_AUTH_RESULT = "javascript:onAuthResult(%s, %s)";
|
|
|
+ public static final String JS_EVENT_PLAY_NEXT = "javascript:onPlayNextEvent()";
|
|
|
+
|
|
|
+ private static final String HAD_FLOAT_VIDEO = "1"; // 当前H5页面存在小窗视频
|
|
|
+ private static final String NEED_MUTE = "0";
|
|
|
+
|
|
|
+ String TAG ="AndroidToJS";
|
|
|
+
|
|
|
+// private String testVideo = "http://hnh5pic.oss-cn-shenzhen.aliyuncs.com/3.mp4";
|
|
|
+// private String testVideo = "http://163.com-www-letv.com/20180509/457_79ed60e3/index.m3u8";
|
|
|
+ private String testVideo = "http://192.168.2.112/000079/000079.m3u8";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * JS调用类型
|
|
|
+ */
|
|
|
+ @StringDef({JS_EVENT_BACK, JS_EVENT_PLAY_FINISH, JS_EVENT_PLAY_NEXT})
|
|
|
+ @Retention(RetentionPolicy.SOURCE)
|
|
|
+ private @interface JsEvent {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private Context context;
|
|
|
+ private WebView webView;
|
|
|
+ private YNYDContentProvider contentProvider;
|
|
|
+ private YNYDService service;
|
|
|
+ private PlayVideoListener playVideoListener;
|
|
|
+ private long playTime = PLAY_TIME_NO_LIMIT;
|
|
|
+
|
|
|
+ public AndroidToJS(Context context, WebView webView) {
|
|
|
+ this.context = context;
|
|
|
+ this.webView = webView;
|
|
|
+ contentProvider = new YNYDContentProvider(context);
|
|
|
+ service = new YNYDService(context);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setPlayVideoListener(PlayVideoListener playVideoListener) {
|
|
|
+ this.playVideoListener = playVideoListener;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 全屏播放
|
|
|
+ *
|
|
|
+ * @param time 可播放时间。如果为{@link com.hc.lib.video.IVideoPlayer#PLAY_TIME_NO_LIMIT},代表无限制播放
|
|
|
+ * @param hadFloatVideo 当前H5页面是否有小窗
|
|
|
+ * @param isNextVideo 是否为下一个视频,1表示当前播放的为下一个视频,其他值为第一个视频
|
|
|
+ * @param showCompleteDialog 是否显示播放结束弹窗,1表示显示结束弹窗,其他值为不显示结束弹窗,显示结束弹窗时不会调用JS方法中的请求下一个视频方法
|
|
|
+ */
|
|
|
+ @JavascriptInterface
|
|
|
+ public void playFull(String url, String sourceId, String title, String time, String hadFloatVideo, String isNextVideo, String showCompleteDialog) {
|
|
|
+ Logger.d("调用全屏播放。源ID(%s),标题(%s),播放地址(%s)", sourceId, title, url);
|
|
|
+ if (playVideoListener != null) {
|
|
|
+
|
|
|
+ playTime = PLAY_TIME_NO_LIMIT;
|
|
|
+ if (isDigitsOnly(time)) {
|
|
|
+ playTime = Long.parseLong(time);
|
|
|
+ }
|
|
|
+ boolean hadFloat = TextUtils.equals(HAD_FLOAT_VIDEO, hadFloatVideo);
|
|
|
+ boolean isCurrentNextVideo = TextUtils.equals(HAD_FLOAT_VIDEO, isNextVideo);
|
|
|
+ boolean isShowCompleteDialog = TextUtils.equals(HAD_FLOAT_VIDEO, showCompleteDialog);
|
|
|
+ Logger.d("调用全屏播放。有小窗(%s),当前为非初始视频(%s),显示结束弹窗(%s)", hadFloat, isCurrentNextVideo, isShowCompleteDialog);
|
|
|
+ ((Activity) context).runOnUiThread(() -> playFull(url, sourceId, title, playTime, hadFloat, isCurrentNextVideo, isShowCompleteDialog, 0));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 全屏播放
|
|
|
+ *
|
|
|
+ * @param time 可播放时间。如果为{@link com.hc.lib.video.IVideoPlayer#PLAY_TIME_NO_LIMIT},代表无限制播放
|
|
|
+ * @param hadFloatVideo 当前H5页面是否有小窗
|
|
|
+ * @param isNextVideo 是否为下一个视频,1表示当前播放的为下一个视频,其他值为第一个视频
|
|
|
+ * @param showCompleteDialog 是否显示播放结束弹窗,1表示显示结束弹窗,其他值为不显示结束弹窗,显示结束弹窗时不会调用JS方法中的请求下一个视频方法
|
|
|
+ * @param seekTime 需要快进的时间
|
|
|
+ */
|
|
|
+ @JavascriptInterface
|
|
|
+ public void playFull(String url, String sourceId, String title, String time, String hadFloatVideo, String isNextVideo, String showCompleteDialog, int seekTime) {
|
|
|
+ Logger.d("调用全屏播放。源ID(%s),标题(%s),播放地址(%s)", sourceId, title, url);
|
|
|
+ if (playVideoListener != null) {
|
|
|
+
|
|
|
+ playTime = PLAY_TIME_NO_LIMIT;
|
|
|
+ if (isDigitsOnly(time)) {
|
|
|
+ playTime = Long.parseLong(time);
|
|
|
+ }
|
|
|
+ boolean hadFloat = TextUtils.equals(HAD_FLOAT_VIDEO, hadFloatVideo);
|
|
|
+ boolean isCurrentNextVideo = TextUtils.equals(HAD_FLOAT_VIDEO, isNextVideo);
|
|
|
+ boolean isShowCompleteDialog = TextUtils.equals(HAD_FLOAT_VIDEO, showCompleteDialog);
|
|
|
+ Logger.d("调用全屏播放。有小窗(%s),当前为非初始视频(%s),显示结束弹窗(%s),快进时间(%s)", hadFloat, isCurrentNextVideo, isShowCompleteDialog, seekTime);
|
|
|
+ ((Activity) context).runOnUiThread(() -> playFull(url, sourceId, title, playTime, hadFloat, isCurrentNextVideo, isShowCompleteDialog, seekTime));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void playFull(String url, String sourceId, String title, long time, boolean hadFloat, boolean isNextVideo, boolean showCompleteDialog, int seekTime) {
|
|
|
+ if (isNextVideo) { // 播放下一条视频时,直接在当前全屏窗口开启新视频的播放
|
|
|
+ playVideoListener.playFullVideo(url, title, getUserName(), sourceId, time, hadFloat, showCompleteDialog, seekTime);
|
|
|
+ } else if (hadFloat) { // 有小窗时,直接切换成全屏
|
|
|
+ playVideoListener.playFullVideo(null, title, getUserName(), sourceId, time, true, showCompleteDialog, 0);
|
|
|
+ } else { // 开启新的全屏播放窗口
|
|
|
+ playVideoListener.playFullVideo(url, title, getUserName(), sourceId, time, false, showCompleteDialog, seekTime);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param url 播放地址
|
|
|
+ * @param sourceId 素材ID
|
|
|
+ * @param title 视频标题
|
|
|
+ * @param x 小窗起始x坐标
|
|
|
+ * @param y 小窗起始y坐标
|
|
|
+ * @param width 小窗宽度
|
|
|
+ * @param height 小窗高度
|
|
|
+ */
|
|
|
+ @JavascriptInterface
|
|
|
+ public void playFloat(String url, String sourceId, String title,
|
|
|
+ final String x, final String y, final String width, final String height, String needMute) {
|
|
|
+ Logger.d("调用小窗口播放。播放地址(%s), 源ID(%s),标题(%s)", url, sourceId, title);
|
|
|
+ Logger.d("调用小窗口播放。坐标(%s, %s),宽高(%s, %s)", x, y, width, height);
|
|
|
+ boolean isMute = TextUtils.equals(NEED_MUTE, needMute);
|
|
|
+ Logger.d("调用小窗口播放。需要静音:%s", isMute);
|
|
|
+ if (isDigitsOnly(x) && isDigitsOnly(y) && isDigitsOnly(width) && isDigitsOnly(height) && playVideoListener != null) {
|
|
|
+ ((Activity) context).runOnUiThread(() -> playFloat(url, sourceId, title,
|
|
|
+ (int) Float.parseFloat(x),
|
|
|
+ (int) Float.parseFloat(y),
|
|
|
+ (int) Float.parseFloat(width),
|
|
|
+ (int) Float.parseFloat(height), isMute));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void playFloat(String url, String sourceId, String title, final int x, final int y, final int width, final int height, boolean needMute) {
|
|
|
+ playVideoListener.playFloatVideo(url,
|
|
|
+ x, y, width, height,
|
|
|
+ getUserName(), sourceId, title, needMute);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 关闭小窗播放
|
|
|
+ */
|
|
|
+ @JavascriptInterface
|
|
|
+ public void closeFloat() {
|
|
|
+ Logger.d("关闭小窗口播放。");
|
|
|
+ if (playVideoListener != null) {
|
|
|
+ playVideoListener.stopFloatVideo();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取EPG结果
|
|
|
+ */
|
|
|
+ @JavascriptInterface
|
|
|
+ public void getEPGAuthResult(String body) {
|
|
|
+ service.auth(body, new DefaultCallback<String>() {
|
|
|
+ @Override
|
|
|
+ public void onSuccess(int what, @NonNull String data) {
|
|
|
+ super.onSuccess(what, data);
|
|
|
+ evaluateJavascript(webView, StringUtil.get(JS_EVENT_AUTH_RESULT, data, Config.RESPONSE_SUCCESS));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onFail(int what, String msg) {
|
|
|
+ super.onFail(what, msg);
|
|
|
+ evaluateJavascript(webView, StringUtil.get(JS_EVENT_AUTH_RESULT, msg, Config.RESPONSE_ERROR));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(int what, Throwable e) {
|
|
|
+ super.onError(what, e);
|
|
|
+ evaluateJavascript(webView, StringUtil.get(JS_EVENT_AUTH_RESULT, e.getMessage(), Config.RESPONSE_ERROR));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public String getUserId() {
|
|
|
+ return getUserName();
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public String getUser() {
|
|
|
+ return contentProvider.getUserName();
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public String getEpgServer() {
|
|
|
+ return getUserEpgServer();
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public String getPlatform() {
|
|
|
+ return contentProvider.getPlatform();
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public String getToken() {
|
|
|
+ return getUserToken();
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public int getVipState() {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public int getVersionCode() {
|
|
|
+ return BuildConfig.VERSION_CODE;
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public String getVersionName() {
|
|
|
+ return BuildConfig.VERSION_NAME;
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public String getMac() {
|
|
|
+ return MacUtil.getMac(context);
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public void pay() {
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public void appExit() {
|
|
|
+ ((Activity) context).runOnUiThread(() -> ((Activity) context).finish());
|
|
|
+ System.exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public void update(String apkUrl) {
|
|
|
+ ((Activity) context).runOnUiThread(() -> download(apkUrl));
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public void install(String apkPath) {
|
|
|
+ ((Activity) context).runOnUiThread(() -> installApk(apkPath));
|
|
|
+ }
|
|
|
+
|
|
|
+ @JavascriptInterface
|
|
|
+ public void uninstall() {
|
|
|
+ ((Activity) context).runOnUiThread(() -> {
|
|
|
+ Uri uri = Uri.fromParts("package", context.getPackageName(), null);
|
|
|
+ Intent intent = new Intent(Intent.ACTION_DELETE, uri);
|
|
|
+ context.startActivity(intent);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void download(String apkUrl) {
|
|
|
+ Dialog dialog = new Dialog(context);
|
|
|
+ dialog.setCancelable(false);
|
|
|
+ dialog.setCanceledOnTouchOutside(false);
|
|
|
+ TextView progressText = new TextView(context);
|
|
|
+ progressText.setText("开始下载新版本");
|
|
|
+ progressText.setTextColor(context.getResources().getColor(android.R.color.black));
|
|
|
+ progressText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40);
|
|
|
+ dialog.setContentView(progressText);
|
|
|
+ dialog.setTitle("新版本更新");
|
|
|
+ DownloadUtils.download(apkUrl, context.getPackageName() + getVersionCode(), "apk", new DownloadUtils.DownloadProgressListener() {
|
|
|
+ @Override
|
|
|
+ public void onDownloadStart(String fileName) {
|
|
|
+ dialog.show();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onDownloadProgress(int progress) {
|
|
|
+ if (dialog != null && dialog.isShowing()) {
|
|
|
+ progressText.setText(String.format("下载中...%s%s", progress, "%"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onDownloadSuccessful(String filePath) {
|
|
|
+ if (dialog != null && dialog.isShowing()) {
|
|
|
+ dialog.dismiss();
|
|
|
+ }
|
|
|
+ installApk(filePath);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void installApk(String filePath) {
|
|
|
+ Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
|
+ intent.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
|
|
|
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//4.0以上系统弹出安装成功打开界面
|
|
|
+ context.startActivity(intent);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 调用js事件
|
|
|
+ *
|
|
|
+ * @param webView webView
|
|
|
+ * @param script {@link AndroidToJS#JS_EVENT_BACK}、{@link AndroidToJS#JS_EVENT_PLAY_FINISH}
|
|
|
+ */
|
|
|
+ public static void evaluateJavascript(WebView webView, @JsEvent String script) {
|
|
|
+ if (webView == null) {
|
|
|
+ Logger.e("webView对象为空,JS事件调用无法执行");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
|
|
+ webView.evaluateJavascript(script, value -> {
|
|
|
+ //此处为 js 返回的结果
|
|
|
+ Log.d(com.hc.lib.TAG.TAG, value);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ webView.loadUrl(script);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isDigitsOnly(String str) {
|
|
|
+ return isInteger(str) || isDouble(str);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断整数(int)
|
|
|
+ private boolean isInteger(String str) {
|
|
|
+ if (null == str || "".equals(str)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
|
|
|
+ return pattern.matcher(str).matches();
|
|
|
+ }
|
|
|
+
|
|
|
+ //判断浮点数(double和float)
|
|
|
+ private boolean isDouble(String str) {
|
|
|
+ if (null == str || "".equals(str)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
|
|
|
+ return pattern.matcher(str).matches();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getUserName(){
|
|
|
+ try{
|
|
|
+ Uri queryUri = Uri.parse("content://stbauthinfo/authentication/");
|
|
|
+ Cursor cursor = context.getContentResolver().query(queryUri,new String[]{"value"},"name='username'",null,null);
|
|
|
+ cursor.moveToFirst();
|
|
|
+ String userName = cursor.getString(cursor.getColumnIndexOrThrow("value"));
|
|
|
+ Log.d(TAG,"userName:" + userName);
|
|
|
+ return userName;
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getUserToken(){
|
|
|
+ try{
|
|
|
+ Uri queryUri = Uri.parse("content://stbauthinfo/authentication/");
|
|
|
+ Cursor cursor = context.getContentResolver().query(queryUri,new String[]{"value"},"name='user_token'",null,null);
|
|
|
+ cursor.moveToFirst();
|
|
|
+ String userToken = cursor.getString(cursor.getColumnIndexOrThrow("value"));
|
|
|
+ Log.d(TAG,"userToken:" + userToken);
|
|
|
+ return userToken;
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getUserEpgServer(){
|
|
|
+ try{
|
|
|
+ Uri queryUri = Uri.parse("content://stbauthinfo/authentication/");
|
|
|
+ Cursor cursor = context.getContentResolver().query(queryUri,new String[]{"value"},"name='epg_server'",null,null);
|
|
|
+ cursor.moveToFirst();
|
|
|
+ String epgServer = cursor.getString(cursor.getColumnIndexOrThrow("value"));
|
|
|
+ Log.d(TAG,"epgServer:" + epgServer);
|
|
|
+ return epgServer;
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public interface PlayVideoListener {
|
|
|
+ /**
|
|
|
+ * 小窗播放视频
|
|
|
+ *
|
|
|
+ * @param url 视频地址
|
|
|
+ * @param x 小窗X坐标
|
|
|
+ * @param y 小窗Y坐标
|
|
|
+ * @param width 小窗宽度
|
|
|
+ * @param height 小窗高度
|
|
|
+ * @param needMute 是否静音
|
|
|
+ */
|
|
|
+ void playFloatVideo(String url, int x, int y, int width, int height, String uid, String sourceId, String title, boolean needMute);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 全屏播放
|
|
|
+ *
|
|
|
+ * @param url 视频地址
|
|
|
+ * @param title 视频标题
|
|
|
+ * @param uid 用户id
|
|
|
+ * @param sourceId 源ID
|
|
|
+ * @param playTime 可播放时间。如果为{@link com.hc.lib.video.IVideoPlayer#PLAY_TIME_NO_LIMIT},代表无限制播放
|
|
|
+ * @param hadFloatVideo 当前H5页面是否有小窗
|
|
|
+ * @param seekTime 全屏时需要快进的时间
|
|
|
+ */
|
|
|
+ void playFullVideo(String url, String title, String uid, String sourceId, long playTime, boolean hadFloatVideo, boolean showCompleteDialog, int seekTime);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 结束小窗播放
|
|
|
+ */
|
|
|
+ void stopFloatVideo();
|
|
|
+ }
|
|
|
+}
|