package com.dlc.exam.ui.learn import android.annotation.SuppressLint import android.content.Intent import android.graphics.Bitmap import android.os.Build import android.os.Bundle import android.os.Handler import android.os.Looper import android.os.Message import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.webkit.ConsoleMessage import android.webkit.WebChromeClient import android.webkit.WebResourceError import android.webkit.WebResourceRequest import android.webkit.WebSettings import android.webkit.WebView import android.webkit.WebViewClient import android.widget.LinearLayout import androidx.annotation.RequiresApi import com.blankj.utilcode.util.LogUtils import com.bumptech.glide.Glide import com.dlc.exam.R import com.dlc.exam.common.CommonUtils import com.dlc.exam.databinding.ActivityLearnDetailBinding import com.dlc.exam.ui.common.BaseCountDownActivity import com.dlc.exam.ui.learn.test.ClassTestActivity import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.MediaItem import com.rc.core.log.RcLog import com.rc.core.util.EscapeUnescape import com.rc.httpcore.HttpConfig import com.rc.httpcore.client.ApiRepository import com.rc.httpcore.vo.request.ExamLearnReq /** * 学习详情 * * @author ReiChin_ */ class LearnDetailActivity : BaseCountDownActivity() { override fun createViewBinding() = ActivityLearnDetailBinding.inflate(LayoutInflater.from(this)) private var mNextChapterList: ArrayList? = null private var mCurrentPosition = 0 private lateinit var mCurrentChapter: LearnChapterBean private var mLearnCompleted = false private var mLearnTimeSecond = 0L private var mRelearn = false private var mVideoDraggable = false // 视频是否可以拖拽 private var mAssessStatus = false // 是否需要课后考核 private var exoPlayer: ExoPlayer? = null private var webView: WebView? = null private val indexUrl = "file:///android_asset/web/index.html" companion object { const val WHAT_LEARN_COUNT_DOWN = 1 } override fun onResume() { super.onResume() exoPlayer?.play() } override fun initViews(savedInstanceState: Bundle?) { super.initViews(savedInstanceState) mNextChapterList = intent.getParcelableArrayListExtra("nextChapter") if (mNextChapterList.isNullOrEmpty()) { finish() return } mRelearn = intent.getBooleanExtra("relearn", false) mVideoDraggable = intent.getBooleanExtra("videoDraggable", false) mAssessStatus = intent.getBooleanExtra("assessStatus", false) exoPlayer = ExoPlayer.Builder(this).build() viewBinding.styledPlayerView.player = exoPlayer viewBinding.styledPlayerView.useController = false viewBinding.back.setOnClickListener { onBackPressed() } viewBinding.learnCompleted.visibility = if (mRelearn) View.GONE else View.VISIBLE viewBinding.learnCompleted.setOnClickListener { mLearnTimeSecond = 0L mLearnCountDownHandler.removeMessages(WHAT_LEARN_COUNT_DOWN) // 完成学习 callFinishLearnApi() } initWebView() //TODO 等待webview初始化完毕后调用 // showChapterInfo() } private fun initWebView() { val params = LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) webView = WebView(applicationContext) webView?.layoutParams = params viewBinding.mainLL.addView(webView) WebView.setWebContentsDebuggingEnabled(true) val webSettings: WebSettings? = webView?.getSettings() webSettings?.javaScriptCanOpenWindowsAutomatically = true webSettings?.setSupportZoom(true) webSettings?.loadWithOverviewMode = true webSettings?.useWideViewPort = true webSettings?.domStorageEnabled = true //DOM Storage webSettings?.allowFileAccessFromFileURLs = true webSettings?.allowFileAccess = true webSettings?.allowContentAccess = true webSettings?.allowUniversalAccessFromFileURLs = true webSettings?.builtInZoomControls = true webSettings?.defaultTextEncodingName = "utf-8" webSettings?.javaScriptEnabled = true //设置webview支持javascript脚本 webSettings?.mixedContentMode = WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE webView!!.webChromeClient = object : WebChromeClient() { override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { if (ConsoleMessage.MessageLevel.ERROR == consoleMessage.messageLevel()) { LogUtils.e( "Jayce", "${consoleMessage.message()}+\n+${consoleMessage.lineNumber()}+\n+${consoleMessage.sourceId()}" ) // pptxjs.js 该库异常会奔溃 if (consoleMessage.sourceId().contains("pptxjs.js")) { showToast("该ppt不可用") this@LearnDetailActivity.finish() } } else { LogUtils.d( "Jayce", "${consoleMessage.message()}+\n+${consoleMessage.lineNumber()}+\n+${consoleMessage.sourceId()}" ) } return true } override fun onProgressChanged(view: WebView, newProgress: Int) { super.onProgressChanged(view, newProgress) Log.d("Jayce", "p:$newProgress") } override fun onCloseWindow(window: WebView) { super.onCloseWindow(window) val js = "javascript:objPreviewerDestroy()" webView!!.evaluateJavascript( js ) { value -> } } } webView!!.webViewClient = object : WebViewClient() { /** * 页面开始加载 * @param view The WebView that is initiating the callback. * @param url The url to be loaded. * @param favicon The favicon for this page if it already exists in the * database. */ override fun onPageStarted(view: WebView, url: String, favicon: Bitmap) { super.onPageStarted(view, url, favicon) } /** * 页面加载完成 * @param view The WebView that is initiating the callback. * @param url The url of the page. */ override fun onPageFinished(view: WebView, url: String) { super.onPageFinished(view, url) // 等页面初始化完成后再去请求接口展示详情 runOnUiThread { showChapterInfo() } } /** * 页面加载错误 * @param view The WebView that is initiating the callback. * @param request The originating request. * @param error Information about the error occurred. */ @RequiresApi(Build.VERSION_CODES.M) override fun onReceivedError( view: WebView, request: WebResourceRequest, error: WebResourceError ) { super.onReceivedError(view, request, error) Log.d( "Jayce", "${error.description}" ) } } webView!!.requestFocus() webView!!.loadUrl(indexUrl) } private fun callFinishLearnApi() { showLoading("保存中...") val param = ExamLearnReq().apply { chapterId = mCurrentChapter.chapterId courseId = mCurrentChapter.courseId } val disposable = ApiRepository.examLearnFinish(param) .subscribe({ data -> dismissLoading() mLearnCompleted = true // 显示完成学习的Dialog val endChapter = mCurrentPosition == mNextChapterList!!.size - 1 LearnCompletedDialog(this, data, endChapter, mCurrentChapter.assessStatus) { viewBinding.learnCompleted.isEnabled = false if (mCurrentChapter.assessStatus) { // 需要课后考核 val intent = Intent(this, ClassTestActivity::class.java) intent.putExtra("chapterId", mCurrentChapter.chapterId) startActivity(intent) setResult(RESULT_OK) finish() } else { mCurrentPosition++ showChapterInfo() } }.show() }, { throwable -> dismissLoading() throwable.printStackTrace() showNetError(throwable) }) addDisposable(disposable) } @SuppressLint("SetTextI18n") private fun showChapterInfo() { Log.d("Jayce", "showChapterInfo") if (mCurrentPosition >= mNextChapterList!!.size) return mCurrentChapter = mNextChapterList!![mCurrentPosition] viewBinding.titleText.text = mCurrentChapter.title // 显示学习内容 showLearnContent() if (mRelearn) { viewBinding.learnDuration.text = "已学习时长:${CommonUtils.formatLearnTime(mCurrentChapter.duration)}" } else { // 调用开始学习的API callStartLearnApi() } } // var str = // "http://192.168.251.2//labSystem//statics//bigFile//2023040314//2c7593c7-c6ba-4bf2-9dab-da7db456494e.mp4" var str = "https://vd4.bdstatic.com/mda-kfmi6042m94u0pdb/sc/mda-kfmi6042m94u0pdb.mp4" private fun showLearnContent() { when (mCurrentChapter.type) { "1" -> { // 文档 webView?.visibility = View.VISIBLE viewBinding.progressbar.visibility = View.VISIBLE viewBinding.unknownFile.visibility = View.INVISIBLE viewBinding.imageContent.visibility = View.INVISIBLE viewBinding.styledPlayerView.visibility = View.INVISIBLE var url = if (mCurrentChapter.chapterData.startsWith("http")) { mCurrentChapter.chapterData } else { HttpConfig.API_BASE_URL + mCurrentChapter.chapterData } // RcLog.info("fileBrowsers_s:${s}") // val infoData = //// Base64.encodeToString(mCurrentChapter.chapterData.toByteArray(), Base64.DEFAULT) // Base64.encodeToString(s.toByteArray(), Base64.DEFAULT) // val baseurl = "${HttpConfig.FILE_BROWSER_BASE_URL}onlinePreview?url=$infoData" // RcLog.info("fileBrowser:${baseurl}") var function = "" var loadUrl = "" // ppt if (url.endsWith(".ppt") || url.endsWith(".pptx")) { function = "openPPT" loadUrl = "http://192.168.1.43:81/666/ppt.pptx" } // excel else if (url.endsWith(".xlsx") || url.endsWith(".xls")) { function = "openEXCEL" loadUrl = "http://192.168.1.43:81/666/excel.xlsx" } // word else if (url.endsWith(".docx") || url.endsWith(".doc")) { function = "openWORD" loadUrl = "http://192.168.1.43:81/666/word.docx" } else if (url.endsWith(".pdf")) { function = "openPDF" loadUrl = "http://192.168.1.43:81/666/pdf.pdf" } else { showToast("不支持的文件") this.finish() return } val js = "javascript:$function(\"$loadUrl\")" webView!!.evaluateJavascript(js) { value -> } // webView?.loadUrl(url) } "2" -> { // 视频 VISIBLE webView?.visibility = View.GONE viewBinding.progressbar.visibility = View.GONE viewBinding.unknownFile.visibility = View.GONE viewBinding.imageContent.visibility = View.GONE viewBinding.styledPlayerView.visibility = View.VISIBLE var url = if (mCurrentChapter.chapterData.startsWith("http")) { mCurrentChapter.chapterData // viewBinding.jzVideo.setUp(mCurrentChapter.chapterData, mCurrentChapter.title) } else { HttpConfig.API_BASE_URL + mCurrentChapter.chapterData // viewBinding.jzVideo.setUp(HttpConfig.API_BASE_URL + mCurrentChapter.chapterData, // mCurrentChapter.title) } // showToast("视频地址:" + HttpConfig.API_BASE_URL + mCurrentChapter.chapterData) val mediaItem = MediaItem.fromUri(url) exoPlayer?.let { it.setMediaItem(mediaItem) it.prepare() it.play() } // viewBinding.webView.loadUrl(str) // viewBinding.webView.loadUrl(mCurrentChapter.chapterData) // 这个对宿主没什么影响,建议声明 // window.setFormat(PixelFormat.TRANSLUCENT) // viewBinding.webView.settings.mediaPlaybackRequiresUserGesture = false //设置自动播放 // viewBinding.webView.overScrollMode = View.OVER_SCROLL_ALWAYS // //TODO 饺子播放器在内网环境 不可使用 加载缓慢 // val bundle = Bundle() // bundle.putBoolean("standardFullScreen", false) // bundle.putBoolean("supportLiteWnd", true) // bundle.putInt("DefaultVideoScreen", 1) //// TbsVideo.openVideo(this, str, bundle) // TbsVideo.openVideo(this, url, bundle) } "3" -> { // 图片 webView?.visibility = View.INVISIBLE viewBinding.progressbar.visibility = View.INVISIBLE viewBinding.unknownFile.visibility = View.INVISIBLE viewBinding.imageContent.visibility = View.VISIBLE viewBinding.styledPlayerView.visibility = View.INVISIBLE // var s = if (mCurrentChapter.chapterData.startsWith("http")) { // mCurrentChapter.chapterData // } else { // mCurrentChapter.chapterData // } Glide.with(this) .load(mCurrentChapter.chapterData) .placeholder(R.mipmap.img_bg_jzz) .error(R.mipmap.img_error) .into(viewBinding.imageContent) } "5" -> { // 富文本 webView?.visibility = View.VISIBLE viewBinding.progressbar.visibility = View.VISIBLE viewBinding.unknownFile.visibility = View.INVISIBLE viewBinding.imageContent.visibility = View.INVISIBLE viewBinding.styledPlayerView.visibility = View.INVISIBLE webView?.loadDataWithBaseURL( null, EscapeUnescape.unescape(mCurrentChapter.chapterData), "text/html", "utf-8", null ) } else -> { webView?.visibility = View.INVISIBLE viewBinding.progressbar.visibility = View.INVISIBLE viewBinding.unknownFile.visibility = View.VISIBLE viewBinding.imageContent.visibility = View.INVISIBLE viewBinding.styledPlayerView.visibility = View.INVISIBLE } } } private fun callStartLearnApi() { showLoading("加载中...") val param = ExamLearnReq().apply { chapterId = mCurrentChapter.chapterId courseId = mCurrentChapter.courseId } val disposable = ApiRepository.examLearnStart(param) .subscribe({ dismissLoading() // 开始倒计时 mLearnTimeSecond = 0 mLearnCountDownHandler.sendEmptyMessage(WHAT_LEARN_COUNT_DOWN) }, { throwable -> dismissLoading() throwable.printStackTrace() showNetError(throwable) }) addDisposable(disposable) } private val mLearnCountDownHandler = object : Handler(Looper.getMainLooper()) { @SuppressLint("SetTextI18n") override fun handleMessage(msg: Message) { mLearnTimeSecond++ viewBinding.learnDuration.text = "已学习时长:${CommonUtils.formatLearnTime(mLearnTimeSecond)}" sendEmptyMessageDelayed(WHAT_LEARN_COUNT_DOWN, 1000) if (mLearnTimeSecond >= mCurrentChapter.duration) { viewBinding.learnCompleted.isEnabled = true } } } override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) if (hasFocus) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) } } } override fun onPause() { RcLog.info("onPause=======================================") super.onPause() exoPlayer?.pause() } override fun onDestroy() { mLearnCountDownHandler.removeMessages(WHAT_LEARN_COUNT_DOWN) mLearnCountDownHandler.removeCallbacksAndMessages(null) super.onDestroy() exoPlayer?.release() } override fun onBackPressed() { RcLog.info("onBackPressed============================") if (mLearnCompleted) { setResult(RESULT_OK) } super.onBackPressed() } }