Просмотр исходного кода

1.使用后台提供的libOffice加载文档

JaycePC месяцев назад: 6
Родитель
Сommit
583826ad77

+ 3 - 0
RcCore/src/main/java/com/rc/core/ui/common/UIDelegateImpl.kt

@@ -1,6 +1,7 @@
 package com.rc.core.ui.common
 
 import android.content.Context
+import android.util.Log
 import android.widget.Toast
 import androidx.core.content.ContextCompat
 import androidx.recyclerview.widget.DividerItemDecoration
@@ -61,11 +62,13 @@ class UIDelegateImpl : AbsUIDelegate() {
                     throwable.message!!
                 }
             }
+
             is SocketTimeoutException -> "请求超时,请稍后重试"
             is ConnectException -> "无法连接服务器,请检查网络"
             is HttpException -> "服务器繁忙,请稍后重试"
             else -> null
         }?.let { showToast(context, it) }
+        Log.d("Jayce", Log.getStackTraceString(throwable))
     }
 
     private var mCompositeDisposable: CompositeDisposable? = null

+ 1 - 1
app/build.gradle

@@ -12,7 +12,7 @@ android {
         minSdkVersion 24
         targetSdkVersion 34
         versionCode 3
-        versionName "1.08"
+        versionName "1.09"
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
 

+ 1 - 1
app/src/main/AndroidManifest.xml

@@ -48,7 +48,7 @@
             android:name=".ui.learn.LearnDetailExoActivity"
             android:exported="false" />
         <activity
-            android:name=".ui.learn.LearnDetailWebActivity"
+            android:name=".ui.learn.LearnDetailLibOfficeActivity"
             android:exported="false" />
 
         <receiver

+ 0 - 689
app/src/main/java/com/dlc/exam/ui/SplashActivity.kt

@@ -1,689 +0,0 @@
-//package com.dlc.exam.ui
-//
-//import android.Manifest
-//import android.annotation.SuppressLint
-//import android.content.Intent
-//import android.graphics.Bitmap
-//import android.os.Bundle
-//import android.os.Handler
-//import android.os.Looper
-//import android.os.Message
-//import android.view.LayoutInflater
-//import androidx.appcompat.app.AlertDialog
-//import com.arcsoft.face.ActiveFileInfo
-//import com.arcsoft.face.ErrorInfo
-//import com.arcsoft.face.FaceEngine
-//import com.bumptech.glide.Glide
-//import com.bumptech.glide.load.DataSource
-//import com.bumptech.glide.load.engine.GlideException
-//import com.bumptech.glide.request.RequestListener
-//import com.bumptech.glide.request.target.Target
-//import com.dlc.exam.BuildConfig
-//import com.dlc.exam.camera.ArcSoftErrCode
-//import com.dlc.exam.common.CommonUtils
-//import com.dlc.exam.common.Constants
-//import com.dlc.exam.databinding.ActivitySplashBinding
-//import com.dlc.exam.ui.settings.PasswordDialog
-//import com.dlc.exam.ui.settings.SettingsActivity
-//import com.rc.core.log.RcLog
-//import com.rc.core.ui.activity.RcBaseActivity
-//import com.rc.core.util.ApkUpdater
-//import com.rc.core.util.DateUtils
-//import com.rc.core.util.DeviceUtils
-//import com.rc.httpcore.HttpConfig
-//import com.rc.httpcore.client.ApiRepository
-//import com.rc.httpcore.vo.response.BannerImageBean
-//import com.tbruyelle.rxpermissions2.RxPermissions
-//import io.reactivex.Observable
-//import io.reactivex.android.schedulers.AndroidSchedulers
-//import io.reactivex.schedulers.Schedulers
-//import java.io.File
-//import java.lang.ref.WeakReference
-//
-///**
-// * info
-// *
-// * @author ReiChin_
-// */
-//class SplashActivity : RcBaseActivity<ActivitySplashBinding>() {
-//
-//    private val weakHandler by lazy { WeakReferenceHandler(this) }
-//    private val weakHandlerTwo by lazy { WeakReferenceHandlerTwo(this) }
-//    private val weakHandlerBannerData by lazy { WeakReferenceHandlerBannerData(this) }
-//    private lateinit var runnable: Runnable
-//    private var handler: Handler = Handler(Looper.getMainLooper())
-//
-//    override fun createViewBinding() = ActivitySplashBinding.inflate(LayoutInflater.from(this))
-//
-//    @SuppressLint("SetTextI18n")
-//    override fun initViews(savedInstanceState: Bundle?) {
-//        RcLog.info(
-//            "versionName:${DeviceUtils.getVersionName(this)}, versionCode:${
-//                DeviceUtils.getVersionCode(
-//                    this
-//                )
-//            }"
-//        )
-//        viewBinding.versionName.text = "版本号:${DeviceUtils.getVersionName(this)}"
-//
-//        viewBinding.copyRight.setOnLongClickListener {
-//            PasswordDialog(this) {
-//                val intent = Intent(this, SettingsActivity::class.java)
-//                startActivity(intent)
-//            }.show()
-//            true
-//        }
-//
-//        requestPermission()
-//
-//        viewBinding.banner.setOnClickListener {
-//            // 登录获取token
-//            authLogin()
-//        }
-//        viewBinding.settings.setOnLongClickListener {
-//            PasswordDialog(this) {
-//                val intent = Intent(this, SettingsActivity::class.java)
-//                startActivity(intent)
-//            }.show()
-//            true
-//        }
-//        // 创建定时任务
-//        runnable = object : Runnable {
-//            override fun run() {
-//                // 每隔一个小时执行一次操作
-//                // 这里可以添加你需要执行的代码
-//                subAddData()
-//                // 重新启动定时任务
-//                handler.postDelayed(this, 3600000) // 3600000 毫秒为一小时
-//            }
-//        }
-//        // 第一次启动定时任务
-//        handler.post(runnable)
-//    }
-//    private fun subAddData() {
-//        val androidId = CommonUtils.getAndroidId(this)
-//        val disposable = ApiRepository.monitor(androidId)
-//            .subscribe({ data ->
-//
-//            }, { throwable ->
-//                showNetError(throwable)
-//            })
-//        addDisposable(disposable)
-//    }
-//    private fun requestPermission() {
-//        val disposable = RxPermissions(this)
-//            .request(
-//                Manifest.permission.WRITE_EXTERNAL_STORAGE,
-//                Manifest.permission.READ_EXTERNAL_STORAGE,
-//                Manifest.permission.CAMERA,
-//                Manifest.permission.READ_PHONE_STATE,
-//                Manifest.permission.RECORD_AUDIO,
-//            )
-//            .subscribe { granted ->
-//                if (granted) {
-//                    queryBanner()
-//                } else {
-//                    AlertDialog.Builder(this)
-//                        .setTitle("提示")
-//                        .setMessage("您必须同意所有权限才可以继续使用")
-//                        .setNegativeButton("确定") { _, _ ->
-//                            requestPermission()
-//                        }.show()
-//                }
-//            }
-//        addDisposable(disposable)
-//    }
-//
-//    private fun queryBanner() {
-//        val disposable = ApiRepository.bannerImages(CommonUtils.getAndroidId(this))
-//            .subscribe({
-//                preloadBannerImg(it)
-//            }, {
-//                showDefaultImg()
-//            })
-//        addDisposable(disposable)
-//    }
-//
-//    private val mBannerMap: MutableMap<Int, Boolean> = mutableMapOf()
-//    private val mBannerPathMap: MutableMap<String, String?> =
-//        mutableMapOf() // key: md5  value: path
-//
-//    private fun preloadBannerImg(data: List<BannerImageBean>) {
-//        mBannerMap.clear()
-//        mBannerPathMap.clear()
-//
-//        data.forEachIndexed { index, item ->
-//            val key = CommonUtils.stringToMD5(item.imgUrl) ?: ""
-//            var url = ""
-//            if (item.imgUrl != null) {
-//                url = if (item.imgUrl.startsWith("http")) {
-//                    item.imgUrl
-//                } else {
-//                    HttpConfig.API_BASE_URL + item.imgUrl
-//                }
-//            }
-//            Glide.with(this)
-//                .asBitmap()
-//                .load(url)
-//                .listener(object : RequestListener<Bitmap> {
-//                    override fun onLoadFailed(
-//                        e: GlideException?,
-//                        model: Any?,
-//                        target: Target<Bitmap>?,
-//                        isFirstResource: Boolean
-//                    ): Boolean {
-//                        mBannerMap[index] = false
-//                        mBannerPathMap[key] = null
-//                        showBanner(data)
-//                        return false
-//                    }
-//
-//                    override fun onResourceReady(
-//                        resource: Bitmap?,
-//                        model: Any?,
-//                        target: Target<Bitmap>?,
-//                        dataSource: DataSource?,
-//                        isFirstResource: Boolean
-//                    ): Boolean {
-//                        mBannerMap[index] = true
-//                        mBannerPathMap[key] = saveFile(key, resource)
-//                        showBanner(data)
-//                        return false
-//                    }
-//                })
-//                .preload()
-//        }
-//    }
-//
-//    private fun saveFile(key: String, resource: Bitmap?): String {
-//        val fileDir = File(cacheDir, "exam/")
-//        if (!fileDir.exists()) fileDir.mkdir()
-//        val filepath = "${fileDir.absolutePath}/${key}.jpg"
-//        // val filePath = "${Environment.getExternalStorageDirectory().path}/${key}.jpg"
-//        CommonUtils.saveBitmapToFile(resource, filepath)
-//        return filepath
-//    }
-//
-//    private fun showBanner(data: List<BannerImageBean>) {
-//        if (data.size != mBannerMap.size) return
-//
-//        // 保存文件到key到sp中
-//        getSharedPreferences("banner", MODE_PRIVATE)
-//            .edit()
-//            .putStringSet("banner_paths", mBannerPathMap.values.toHashSet())
-//            .apply()
-//
-//        // 使用Handler获取message对象,两种获取都可以
-//        val msg: Message = Handler().obtainMessage()
-//        msg.obj = data
-//        weakHandler.sendMessage(msg)
-//        weakHandler.sendEmptyMessage(1)
-////        var index = 0
-////        object : Handler(Looper.getMainLooper()) {
-////            override fun handleMessage(msg: Message) {
-////                if (isDestroyed) return
-////
-////                val activeIndex = index % data.size
-////                val delayMillis = if (true == mBannerMap[activeIndex]) {
-////                    Glide.with(this@SplashActivity)
-////                        .load(data[activeIndex].imgUrl)
-////                        .into(viewBinding.banner)
-////
-////                    3000L
-////                } else 0L
-////
-////                index++
-////                if (index >= data.size) index = 0
-////                sendEmptyMessageDelayed(1, delayMillis)
-////            }
-////        }.sendEmptyMessage(1)
-//    }
-//
-//
-//    private fun showDefaultImg() {
-//        val sp = getSharedPreferences("banner", MODE_PRIVATE)
-//        val bannerData = sp.getStringSet("banner_paths", mutableSetOf())?.toList()
-//        if (bannerData.isNullOrEmpty()) {
-////            showInnerImage()
-//            return
-//        }
-//
-//        val msg: Message = Handler().obtainMessage()
-//        msg.obj = bannerData
-//        weakHandlerBannerData.sendMessage(msg)
-//        weakHandlerBannerData.sendEmptyMessageDelayed(1, 2000)
-////        var index = 0
-////        object : Handler(Looper.getMainLooper()) {
-////            override fun handleMessage(msg: Message) {
-////                if (isDestroyed) return
-////
-////                val activeIndex = index % bannerData.size
-////                Glide.with(this@SplashActivity)
-////                    .load(bannerData[activeIndex])
-////                    .into(viewBinding.banner)
-////
-////                index++
-////                if (index >= bannerData.size) index = 0
-////                sendEmptyMessageDelayed(1, 3000)
-////            }
-////        }.sendEmptyMessageDelayed(1, 2000)
-//    }
-//
-////    private fun showInnerImage() {
-////        val bannerData = arrayOf(
-////            R.mipmap.img_banner3,
-////            R.mipmap.img_banner2
-////        )
-////        var index = 0
-////        object : Handler(Looper.getMainLooper()) {
-////            override fun handleMessage(msg: Message) {
-////                if (isDestroyed) return
-////
-////                viewBinding.banner.setImageResource(bannerData[index % bannerData.size])
-////
-////                index++
-////                if (index >= bannerData.size) index = 0
-////                sendEmptyMessageDelayed(1, 3000)
-////            }
-////        }.sendEmptyMessageDelayed(1, 2000)
-////    }
-//
-////    /*
-////     * 登录获取token
-////     */
-////    private fun authLogin() {
-////        showLoading("加载中...")
-////        val disposable = ApiRepository.authOneLogin()
-////            .subscribe({ success ->
-////                dismissLoading()
-////                if (success) {
-//////                    jumpMainActivity()
-////                    queryAppVersion()
-////                }
-////            }, { throwable ->
-////                dismissLoading()
-////                showNetError(throwable)
-////            })
-////        addDisposable(disposable)
-////    }
-//
-//
-//    private fun authLogin() {
-//        showLoading("版本检测中...")
-//        val toDouble = DeviceUtils.getVersionName(this)//获取当前版本号
-//
-//        //    AIO_MANAGER("aio_manager","管控一体机"),
-//        //    AIO_CHEMICAL("aio_chemical","化学品一体机"),
-//        //    AIO_INFOBORD("aio_info bord","电子信息牌"),
-//        //    AIO_EXAM("aio_exam","学习考试一体机");
-//        RcLog.info("======当前设备信息${CommonUtils.getAndroidId(this)}")
-//        val disposable = ApiRepository.getCheck(CommonUtils.getAndroidId(this), "aio_exam", toDouble.toDouble())
-//            .subscribe({ data ->
-//                dismissLoading()
-//                if (!data.needUpgrade) {
-////                    startMainActivity()
-//                    initFaceEngine()
-//                } else {
-//                    //需要更新
-//                    if (data.appInfo != null) {
-//                        when {
-//                            data.appInfo!!.remark != null -> {
-//                                //同步进行更新
-//                                upDownloadManager(data!!.appInfo!!.remark)
-//
-//                            }
-//                            data!!.appInfo!!.url != null -> {
-//                                upDownloadManager(data.appInfo!!.url)
-//                            }
-//                            else -> {
-////                                // 启动定时任务
-////                                try {
-////                                    myHandler.stop()
-////                                } catch (e: Exception) {
-////
-////                                } finally {
-////                                    myHandler.start()
-////                                }
-//                                showToast("版本信息不不存在")
-//                            }
-//                        }
-//                    } else {
-//                        startMainActivity()
-//                    }
-//                }
-////                if (!data.needUpgrade) {
-////                    when {
-////                        data.appInfo.remark != null -> {
-////                            //同步进行更新
-////                            upDownloadManager(data.appInfo.remark)
-////                        }
-////                        data.appInfo.url != null -> {
-////                            upDownloadManager(data.appInfo.url)
-////                        }
-////                        else -> {
-////                            // 启动定时任务
-////                            try {
-////                                myHandler.stop()
-////                            } catch (e: Exception) {
-////
-////                            } finally {
-////                                myHandler.start()
-////                            }
-////                            showToast("版本信息不不存在")
-////                        }
-////                    }
-////                } else {
-////                    UiManager.switcher(this@SplashActivity, MainActivity::class.java)
-////                    finish()
-////                }
-//            }, { throwable ->
-//                dismissLoading()
-//                showNetError(throwable)
-////                // 启动定时任务
-////                try {
-////                    myHandler.stop()
-////                } catch (e: Exception) {
-////
-////                } finally {
-////                    myHandler.start()
-////                }
-//            })
-//        addDisposable(disposable)
-//    }
-//
-//    private fun upDownloadManager(downloadUrl: String) {
-//        ApkUpdater(this, BuildConfig.APPLICATION_ID, callback = object :
-//            ApkUpdater.DownloadCallback {
-//            override fun onProgress(progress: Int) {
-////                myHandler.stop()
-//                showLoading("检测到新版本,开始更新(${progress}%)")
-//            }
-//
-//            override fun onFailed(errMsg: String?) {
-//                dismissLoading()
-//                showToast("下载失败,请检查网络情况重新下载")
-//                // 启动定时任务
-////                try {
-////                    myHandler.stop()
-////                } catch (e: Exception) {
-////
-////                } finally {
-////                    myHandler.start()
-////                }
-//            }
-//
-//            override fun onSuccess(apkFile: String) {
-//                dismissLoading()
-//                startMainActivity()
-//            }
-//
-//        }).downloadApk(downloadUrl)
-//    }
-//
-//    private fun jumpMainActivity() {
-//        weakHandlerTwo.sendEmptyMessageDelayed(1, 200)
-////      object : Handler(Looper.getMainLooper()) {
-////            override fun handleMessage(msg: Message) {
-////                initFaceEngine()
-////            }
-////        }.sendEmptyMessageDelayed(1, 200)
-//    }
-//
-//    private fun queryAppVersion() {
-//        showLoading("版本检测中...")
-//        val disposable = ApiRepository.apkVersion(CommonUtils.getAndroidId(this))
-//            .subscribe({ data ->
-//                if (CommonUtils.stringParseInt(data.version) > DeviceUtils.getVersionCode(this)) {
-//                    // 有新版本
-//                    showLoading("检测到新版本,开始更新(0%)")
-//                    // 显示版本更新
-////                    downloadApk(data.apkFileUpload)
-//                } else {
-//                    // 没有新版本
-//                        RcLog.info("==进去了")
-//
-//                }
-//            }, { throwable ->
-//                dismissLoading()
-//                RcLog.info("==进1去了")
-//                showNetError(throwable)
-////                jumpMainActivity()
-//            })
-//        addDisposable(disposable)
-//    }
-//
-//    private fun downloadApk(downloadUrl: String) {
-//        callApkUpdateApi("2")
-//        ApkUpdater(this, BuildConfig.APPLICATION_ID, callback = object :
-//            ApkUpdater.DownloadCallback {
-//            override fun onProgress(progress: Int) {
-//                showLoading("检测到新版本,开始更新(${progress}%)")
-//            }
-//
-//            override fun onFailed(errMsg: String?) {
-//                dismissLoading()
-//                callApkUpdateApi("0")
-//                showToast("下载失败,请检查网络情况重新下载")
-//            }
-//
-//            override fun onSuccess(apkFile: String) {
-//                dismissLoading()
-//                callApkUpdateApi("1")
-//            }
-//
-//        }).downloadApk(downloadUrl)
-//    }
-//
-//    /*
-//     * state 0:升级失败; 1:升级成功; 2:升级中
-//     */
-//    private fun callApkUpdateApi(state: String) {
-//        val disposable = ApiRepository.onepcApkUpdate(CommonUtils.getAndroidId(this), state)
-//            .subscribe({ }, { })
-//        addDisposable(disposable)
-//    }
-//
-//    private fun startMainActivity() {
-//        startActivity(Intent(this, MainActivity::class.java))
-//        finish()
-//    }
-//
-//
-//    private fun initFaceEngine() {
-//        activeOnlineFaceEngine {
-//            startMainActivity()
-//        }
-//    }
-//
-//    private fun activeOnlineFaceEngine(callback: () -> Unit) {
-////        if (getActiveFileInfo()) {
-////            callback.invoke()
-////            return
-////        }
-//
-//        try {
-//            val disposable = Observable.create<Int> { emitter ->
-//                RcLog.info("[face]subscribe: getRuntimeABI() ${FaceEngine.getRuntimeABI()}")
-//                RcLog.info("[face]subscribe: getRuntimeABI() ${Constants.ArcFace.APP_ID}")
-//                RcLog.info("[face]subscribe: getRuntimeABI() ${Constants.ArcFace.SDK_KEY}")
-//
-//                val start = System.currentTimeMillis()
-//                val activeCode =
-//                    FaceEngine.activeOnline(
-//                        this,
-//                        Constants.ArcFace.APP_ID,
-//                        Constants.ArcFace.SDK_KEY
-//                    )
-//                RcLog.info("[face]subscribe cost: " + (System.currentTimeMillis() - start))
-//                emitter.onNext(activeCode)
-//            }.subscribeOn(Schedulers.io())
-//                .observeOn(AndroidSchedulers.mainThread())
-//                .subscribe({ activeCode ->
-//                    RcLog.info("[face]激活引擎 activeCode: $activeCode")
-//                    when (activeCode) {
-//                        // 激活引擎成功
-//                        ErrorInfo.MOK -> RcLog.info("[face]激活引擎成功")
-//                        // 引擎已激活,无需再次激活
-//                        ErrorInfo.MERR_ASF_ALREADY_ACTIVATED -> RcLog.info("[face]引擎已激活,无需再次激活")
-//                        // 引擎激活失败,错误码为 %d
-//                        else -> {
-//                            val message =
-//                                "[face] 引擎激活失败,错误码为 ${ArcSoftErrCode.decode(activeCode)}"
-//                            RcLog.warn(message)
-//                            showToast(message)
-//                        }
-//                    }
-//                    callback.invoke()
-//
-//                }, { throwable ->
-//                    throwable.printStackTrace()
-//                })
-//            addDisposable(disposable)
-//        } catch (e: Exception) {
-//            RcLog.info("[face]激活引擎 activeCode: 加载失败")
-//            val disposable = Observable.create<Int> { emitter ->
-//                RcLog.info("[face]subscribe: getRuntimeABI() ${FaceEngine.getRuntimeABI()}")
-//
-//                val start = System.currentTimeMillis()
-//                val activeCode =
-//                    FaceEngine.activeOnline(
-//                        this,
-//                        Constants.ArcFace.APP_ID,
-//                        Constants.ArcFace.SDK_KEY
-//                    )
-//                RcLog.info("[face]subscribe cost: " + (System.currentTimeMillis() - start))
-//                emitter.onNext(activeCode)
-//            }.subscribeOn(Schedulers.io())
-//                .observeOn(AndroidSchedulers.mainThread())
-//                .subscribe({ activeCode ->
-//                    RcLog.info("[face]激活引擎 activeCode: $activeCode")
-//                    when (activeCode) {
-//                        // 激活引擎成功
-//                        ErrorInfo.MOK -> RcLog.info("[face]激活引擎成功")
-//                        // 引擎已激活,无需再次激活
-//                        ErrorInfo.MERR_ASF_ALREADY_ACTIVATED -> RcLog.info("[face]引擎已激活,无需再次激活")
-//                        // 引擎激活失败,错误码为 %d
-//                        else -> {
-//                            val message =
-//                                "[face] 引擎激活失败,错误码为 ${ArcSoftErrCode.decode(activeCode)}"
-//                            RcLog.warn(message)
-//                            showToast(message)
-//                        }
-//                    }
-//                    callback.invoke()
-//
-//                }, { throwable ->
-//                    throwable.printStackTrace()
-//                })
-//            addDisposable(disposable)
-//        }
-//    }
-//
-//    private fun getActiveFileInfo(): Boolean {
-//        val activeFileInfo = ActiveFileInfo()
-//        val activeCode = FaceEngine.getActiveFileInfo(this, activeFileInfo)
-//        return if (ErrorInfo.MOK == activeCode) {
-//            RcLog.info("[face] FaceEngine 已经激活")
-//            RcLog.info("[face] appId:${activeFileInfo.appId}")
-//            RcLog.info("[face] sdkKey:${activeFileInfo.sdkKey}")
-//            RcLog.info("[face] platform:${activeFileInfo.platform}")
-//            RcLog.info("[face] sdkType:${activeFileInfo.sdkType}")
-//            RcLog.info("[face] sdkVersion:${activeFileInfo.sdkVersion}")
-//            RcLog.info("[face] fileVersion:${activeFileInfo.fileVersion}")
-//            RcLog.info("[face] startTime:${DateUtils.formatTimestamp(activeFileInfo.startTime)}")
-//            RcLog.info("[face] endTime:${DateUtils.formatTimestamp(activeFileInfo.endTime)}")
-//            true
-//        } else {
-//            RcLog.info("[face] getActiveFileInfo failed, code is  : $activeCode")
-//            false
-//        }
-//    }
-//
-//    // static + 弱引用  防止内存泄露
-//    class WeakReferenceHandler(obj: SplashActivity) : Handler(Looper.getMainLooper()) {
-//
-//        private val mRef: WeakReference<SplashActivity> = WeakReference(obj)
-//        var index = 0
-//        var datas: List<BannerImageBean>? = null
-//        override fun handleMessage(msg: Message) {
-//            datas = msg.obj as List<BannerImageBean>?
-//            mRef.get()?.run {
-//                if (isDestroyed) return
-//                val activeIndex = index % datas!!.size
-//                val delayMillis = if (true == mBannerMap[activeIndex]) {
-//                    var url = ""
-//                    if (datas!![activeIndex].imgUrl != null) {
-//                        url = if (datas!![activeIndex].imgUrl.startsWith("http")) {
-//                            datas!![activeIndex].imgUrl
-//                        } else {
-//                            HttpConfig.API_BASE_URL + datas!![activeIndex].imgUrl
-//                        }
-//                    }
-//                    Glide.with(this)
-////                        .load(datas!![activeIndex].imgUrl)
-//                        .load(url)
-//                        .into(viewBinding.banner)
-//
-//                    3000L
-//                } else 0L
-//                index++
-//                if (index >= datas!!.size) index = 0
-//                sendEmptyMessageDelayed(1, delayMillis)
-//            }
-//        }
-//
-//    }
-//
-//    // static + 弱引用  防止内存泄露
-//    class WeakReferenceHandlerTwo(obj: SplashActivity) : Handler(Looper.getMainLooper()) {
-//        private val mRef: WeakReference<SplashActivity> = WeakReference(obj)
-//        override fun handleMessage(msg: Message) {
-//            mRef.get()?.run {
-//                initFaceEngine()
-//            }
-//        }
-//
-//    }
-//
-//    // static + 弱引用  防止内存泄露
-//    class WeakReferenceHandlerBannerData(obj: SplashActivity) : Handler(Looper.getMainLooper()) {
-//        private val mRef: WeakReference<SplashActivity> = WeakReference(obj)
-//        var index = 0
-//        private var bannerData: List<String>? = null
-//        override fun handleMessage(msg: Message) {
-//            bannerData = msg.obj as List<String>
-//            mRef.get()?.run {
-//                if (isDestroyed) return
-//                val activeIndex = index % bannerData!!.size
-//                var url = ""
-//                if (bannerData!![activeIndex] != null) {
-//                    url = if (bannerData!![activeIndex].startsWith("http")) {
-//                        bannerData!![activeIndex]
-//                    } else {
-//                        HttpConfig.API_BASE_URL + bannerData!![activeIndex]
-//                    }
-//                }
-//                Glide.with(this)
-////                    .load(bannerData!![activeIndex])
-//                    .load(url)
-//                    .into(viewBinding.banner)
-//                index++
-//                if (index >= bannerData!!.size) index = 0
-//                sendEmptyMessageDelayed(1, 3000)
-//            }
-//        }
-//
-//    }
-//
-//    override fun onDestroy() {
-//        super.onDestroy()
-//        weakHandler.removeCallbacksAndMessages(null)
-//        weakHandlerTwo.removeCallbacksAndMessages(null)
-//        weakHandlerBannerData.removeCallbacksAndMessages(null)
-//        try {
-//            handler.removeCallbacks(runnable)
-//            handler.removeCallbacksAndMessages(null)
-//        } catch (e: Exception) {
-//        }
-//    }
-//}

+ 8 - 3
app/src/main/java/com/dlc/exam/ui/StartActivity.java

@@ -80,8 +80,13 @@ public class StartActivity extends RcBaseActivity<ActivityStartBinding> {
                         if (activeOnlineFaceEngine()) {
                             activeTimer.cancel();
                             activeTimer = null;
-                            finish();
-                            ActivityUtils.startActivity(MainActivity.class);
+                            binding.main.setOnClickListener(new View.OnClickListener() {
+                                @Override
+                                public void onClick(View v) {
+                                    finish();
+                                    ActivityUtils.startActivity(MainActivity.class);
+                                }
+                            });
                         } else {
                             activeTimer.start();
                         }
@@ -106,7 +111,7 @@ public class StartActivity extends RcBaseActivity<ActivityStartBinding> {
         ActiveFileInfo activeFileInfo = new ActiveFileInfo();
         int res = FaceEngine.getActiveFileInfo(this, activeFileInfo);
         if (res == ErrorInfo.MOK) {
-            LogUtils.d(activeFileInfo.toString());
+            LogUtils.json(activeFileInfo);
             return true;
         } else {
             int code = FaceEngine.activeOnline(this, Constants.ArcFace.APP_ID, Constants.ArcFace.SDK_KEY);

+ 1 - 1
app/src/main/java/com/dlc/exam/ui/learn/CourseChapterActivity.kt

@@ -104,7 +104,7 @@ class CourseChapterActivity : BaseCountDownActivity<ActivityCourseChapterBinding
         }
         // WebView处理
         else {
-            intent.setClass(this, LearnDetailWebActivity::class.java)
+            intent.setClass(this, LearnDetailLibOfficeActivity::class.java)
         }
         startActivityForResult(intent, 100)
     }

+ 292 - 0
app/src/main/java/com/dlc/exam/ui/learn/LearnDetailLibOfficeActivity.java

@@ -0,0 +1,292 @@
+package com.dlc.exam.ui.learn;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+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 android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.blankj.utilcode.util.LogUtils;
+import com.dlc.exam.common.CommonUtils;
+import com.dlc.exam.databinding.ActivityLearnDetailWebBinding;
+import com.dlc.exam.ui.common.BaseCountDownActivity;
+import com.dlc.exam.ui.learn.test.ClassTestActivity;
+import com.dlc.exam.ui.widget.JsInterface;
+import com.dlc.exam.ui.widget.MessageEvent;
+import com.rc.core.util.EscapeUnescape;
+import com.rc.httpcore.HttpConfig;
+import com.rc.httpcore.client.ApiRepository;
+import com.rc.httpcore.vo.request.ExamLearnReq;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import io.reactivex.disposables.Disposable;
+import okhttp3.HttpUrl;
+
+public class LearnDetailLibOfficeActivity extends BaseCountDownActivity<ActivityLearnDetailWebBinding> implements View.OnClickListener {
+
+    private ActivityLearnDetailWebBinding binding;
+    private LearnChapterBean learnChapterBean;
+    private WebView webView;
+    private boolean learnCompleted = false;// 是否已完成学习
+    private long learnTimeSecond = 0L;
+
+    @NonNull
+    @Override
+    protected ActivityLearnDetailWebBinding createViewBinding() {
+        return ActivityLearnDetailWebBinding.inflate(LayoutInflater.from(this));
+    }
+
+    @Override
+    protected void initViews(@Nullable Bundle savedInstanceState) {
+        super.initViews(savedInstanceState);
+
+        binding = getViewBinding();
+        Intent getIntent = getIntent();
+        if (null != getIntent && getIntent.hasExtra("Chapter")) {
+            learnChapterBean = getIntent.getParcelableExtra("Chapter");
+            boolean relearn = getIntent.getBooleanExtra("relearn", false);
+            if (null == learnChapterBean) {
+                finish();
+                return;
+            }
+            binding.back.setOnClickListener(this);
+            binding.titleText.setText(learnChapterBean.title);
+            // 是否完成学习
+            binding.learnCompleted.setVisibility(relearn ? View.GONE : View.VISIBLE);
+            binding.learnCompleted.setOnClickListener(this);
+            // 初始化WebView
+            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+            webView = new WebView(getApplicationContext());
+            webView.setLayoutParams(params);
+            binding.mainLL.addView(webView);
+            WebView.setWebContentsDebuggingEnabled(true);
+            WebSettings webSettings = webView.getSettings();
+            webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
+            webSettings.setSupportZoom(true);
+            webSettings.setLoadWithOverviewMode(true);
+            webSettings.setUseWideViewPort(true);
+            webSettings.setDomStorageEnabled(true);//DOM Storage
+            webSettings.setAllowFileAccessFromFileURLs(true);
+            webSettings.setAllowFileAccess(true);
+            webSettings.setAllowContentAccess(true);
+            webSettings.setAllowUniversalAccessFromFileURLs(true);
+            webSettings.setBuiltInZoomControls(true);
+            webSettings.setDefaultTextEncodingName("utf-8");
+            webSettings.setJavaScriptEnabled(true);//设置webview支持javascript脚本
+            webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_COMPATIBILITY_MODE);
+            webView.addJavascriptInterface(new JsInterface(), "Android");
+            webView.setWebChromeClient(webChromeClient);
+            webView.setWebViewClient(webViewClient);
+            webView.requestFocus();
+            // 富文本
+            if ("5".equals(learnChapterBean.type)) {
+                webView.loadDataWithBaseURL(null, EscapeUnescape.unescape(learnChapterBean.chapterData), "text/html", "utf-8", null);
+            } else {
+                String baseUrl = HttpConfig.Companion.getAPI_BASE_URL();
+                HttpUrl httpUrl = HttpUrl.get(baseUrl);
+                String libOfficeUrl = httpUrl.scheme() + "://" + httpUrl.host() + ":19999/";
+                String chapterData = learnChapterBean.chapterData;
+                if (!"http".startsWith(chapterData)) {
+                    chapterData = HttpConfig.Companion.getAPI_BASE_URL() + learnChapterBean.chapterData;
+                }
+                webView.loadUrl(libOfficeUrl + "file_to_images/" + chapterData);
+            }
+
+        } else {
+            finish();
+        }
+    }
+
+    private final WebViewClient webViewClient = new WebViewClient() {
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
+            LogUtils.d("Jayce", url);
+        }
+
+        @Override
+        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+            super.onReceivedError(view, request, error);
+
+            LogUtils.e("Jayce", error.getErrorCode(), error.getDescription());
+        }
+    };
+
+    private final WebChromeClient webChromeClient = new WebChromeClient() {
+        @Override
+        public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
+            if (ConsoleMessage.MessageLevel.ERROR == consoleMessage.messageLevel()) {
+                LogUtils.e("Jayce", consoleMessage.message(), consoleMessage.lineNumber(), consoleMessage.sourceId());
+            } else {
+                if (consoleMessage.message().startsWith("status")) {
+                    String[] statusArray = consoleMessage.message().split(" ", -1);
+                    if (statusArray.length > 1) {
+                        String code = statusArray[1];
+                        if ("200".equals(code)) {
+                            startLearn();
+                        } else if ("400".equals(code)) {
+                            Toast.makeText(LearnDetailLibOfficeActivity.this, "无法预览", Toast.LENGTH_LONG).show();
+                            finish();
+                        }
+                    }
+                }
+                LogUtils.d("Jayce", consoleMessage.message(), consoleMessage.lineNumber(), consoleMessage.sourceId());
+            }
+            return true;
+        }
+
+        @Override
+        public void onProgressChanged(WebView view, int newProgress) {
+            super.onProgressChanged(view, newProgress);
+            LogUtils.d("Jayce", "加载进度:" + newProgress);
+        }
+
+        @Override
+        public void onCloseWindow(WebView window) {
+            super.onCloseWindow(window);
+            String js = "javascript:objPreviewerDestroy()";
+            webView.evaluateJavascript(js, value -> {
+                LogUtils.d("Jayce", value);
+            });
+        }
+    };
+
+    /**
+     * 完成学习
+     */
+    private void finishLearn() {
+        showLoading("保存中...", false);
+        ExamLearnReq examLearnReq = new ExamLearnReq();
+        examLearnReq.chapterId = learnChapterBean.chapterId;
+        examLearnReq.courseId = learnChapterBean.courseId;
+        Disposable disposable = ApiRepository.INSTANCE.examLearnFinish(examLearnReq).subscribe(learnBonusBean -> {
+            dismissLoading();
+            LogUtils.json("Jayce", learnBonusBean);
+            learnCompleted = true;
+            new LearnCompletedDialog(LearnDetailLibOfficeActivity.this, learnBonusBean, false, learnChapterBean.assessStatus, () -> {
+                binding.learnCompleted.setEnabled(false);
+                // 课后考核
+                if (learnChapterBean.assessStatus) {
+                    Intent intent = new Intent(LearnDetailLibOfficeActivity.this, ClassTestActivity.class);
+                    intent.putExtra("chapterId", learnChapterBean.chapterId);
+                    startActivity(intent);
+                    setResult(RESULT_OK);
+                }
+                finish();
+                return null;
+            }).show();
+        }, throwable -> {
+            dismissLoading();
+            throwable.printStackTrace();
+            showNetError(throwable);
+        });
+        addDisposable(disposable);
+    }
+
+    private Handler cdHandler = new Handler(Looper.getMainLooper()) {
+        @Override
+        public void handleMessage(@NonNull Message msg) {
+            super.handleMessage(msg);
+            learnTimeSecond++;
+            binding.learnDuration.setText("已学习时长:" + CommonUtils.INSTANCE.formatLearnTime(learnTimeSecond));
+            sendEmptyMessageDelayed(1, 1000);
+            if (learnTimeSecond >= learnChapterBean.duration) {
+                binding.learnCompleted.setEnabled(true);
+            }
+        }
+    };
+
+    private volatile boolean isStartLearn = false;
+
+    /**
+     * 开始学习
+     */
+    private void startLearn() {
+        if (!isStartLearn) {
+            showLoading("加载中...", false);
+            ExamLearnReq examLearnReq = new ExamLearnReq();
+            examLearnReq.chapterId = learnChapterBean.chapterId;
+            examLearnReq.courseId = learnChapterBean.courseId;
+            Disposable disposable = ApiRepository.INSTANCE.examLearnStart(examLearnReq).subscribe(aBoolean -> {
+                isStartLearn = true;
+                dismissLoading();
+                learnTimeSecond = 0L;
+                cdHandler.sendEmptyMessage(1);
+
+            }, throwable -> {
+                dismissLoading();
+                throwable.printStackTrace();
+                showNetError(throwable);
+            });
+            addDisposable(disposable);
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        webView.onPause();
+        super.onPause();
+    }
+
+    @Override
+    protected void onResume() {
+        webView.onResume();
+        super.onResume();
+    }
+
+    @Override
+    protected void onDestroy() {
+        if (webView != null) {
+            webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
+            webView.clearHistory();
+            binding.mainLL.removeAllViewsInLayout();
+            webView.destroy();
+            webView = null;
+        }
+        cdHandler.removeMessages(1);
+        cdHandler.removeCallbacksAndMessages(null);
+        cdHandler = null;
+        super.onDestroy();
+    }
+
+    @Override
+    public void onBackPressed() {
+        if (learnCompleted) {
+            setResult(RESULT_OK);
+        }
+        super.onBackPressed();
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v.getId() == binding.back.getId()) {
+            onBackPressed();
+        }
+        // 完成学习
+        else if (v.getId() == binding.learnCompleted.getId()) {
+            learnTimeSecond = 0L;
+            cdHandler.removeMessages(1);
+            finishLearn();
+        }
+    }
+
+
+}

+ 26 - 1
app/src/main/res/layout/activity_learn_detail_web.xml

@@ -7,11 +7,36 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     tools:context=".ui.learn.LearnDetailWebActivity">
-
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:orientation="horizontal"
+        android:layout_height="wrap_content">
+        <Button
+            android:id="@+id/word"
+            android:layout_width="wrap_content"
+            android:text="word"
+            android:layout_height="wrap_content"/>
+        <Button
+            android:id="@+id/excel"
+            android:layout_width="wrap_content"
+            android:text="Excel"
+            android:layout_height="wrap_content"/>
+        <Button
+            android:id="@+id/ppt"
+            android:layout_width="wrap_content"
+            android:text="PPT"
+            android:layout_height="wrap_content"/>
+        <Button
+            android:id="@+id/pdf"
+            android:layout_width="wrap_content"
+            android:text="PDF"
+            android:layout_height="wrap_content"/>
+    </LinearLayout>
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/titleBar"
         android:layout_width="match_parent"
         android:layout_height="45dp"
+        android:visibility="gone"
         android:background="#349CFB">
 
         <TextView

+ 0 - 1
app/src/main/res/layout/activity_start.xml

@@ -9,7 +9,6 @@
     tools:context=".ui.StartActivity">
 
     <TextView
-        android:id="@+id/logo"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_centerInParent="true"