AppVersionUtil.kt 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. package com.develop.common.utils
  2. import android.annotation.SuppressLint
  3. import android.app.Application
  4. import android.content.Context
  5. import android.net.Uri
  6. import android.os.PowerManager
  7. import android.provider.Settings
  8. import androidx.core.content.ContextCompat.getSystemService
  9. import com.azhon.appupdate.listener.OnDownloadListener
  10. import com.azhon.appupdate.util.LogUtil
  11. import com.blankj.utilcode.util.FileUtils
  12. import com.blankj.utilcode.util.ZipUtils
  13. import com.develop.base.ext.fromJson
  14. import com.develop.base.ext.globalApp
  15. import com.develop.base.util.FileKit
  16. import com.develop.base.util.GlobalToast
  17. import com.develop.base.util.MMkvUtils
  18. import com.develop.base.util.TopResumedAtyHolder
  19. import com.develop.common.R
  20. import com.develop.common.data_repo.FoodDataProvider
  21. import com.develop.common.data_repo.db.entity.DevRecipeCategory
  22. import com.develop.common.data_repo.db.entity.DevVersion
  23. import com.develop.common.data_repo.net.Api
  24. import com.develop.common.data_repo.net.converter.SerializationConverter.Companion.jsonDecoder
  25. import com.develop.common.data_repo.net.model.request.DeviceInfoBody
  26. import com.develop.common.data_repo.net.model.response.DevInfoResult
  27. import com.develop.common.data_repo.net.model.response.RecipeDataConfig
  28. import com.develop.common.dialog.CancelConfirmDialog
  29. import com.develop.common.dialog.CommonDialog
  30. import com.develop.common.dialog.RecipeUpdateDialog
  31. import com.develop.common.tag.SCREENSAVER
  32. import com.drake.net.Get
  33. import com.drake.net.Post
  34. import com.drake.net.component.Progress
  35. import com.drake.net.interfaces.ProgressListener
  36. import com.drake.net.utils.scopeNetLife
  37. import kotlinx.serialization.decodeFromString
  38. import org.greenrobot.eventbus.EventBus
  39. import java.io.File
  40. import java.util.*
  41. import kotlin.collections.ArrayList
  42. import kotlin.collections.HashMap
  43. object AppVersionUtil {
  44. fun checkRecipeUpdate(shoNoUpdateDialog: Boolean = false) {
  45. TopResumedAtyHolder.getCurrentActivity()?.apply {
  46. scopeNetLife {
  47. try {
  48. val result = Post<DevInfoResult>(Api.DEV_INFO) {
  49. body = DeviceInfoBody.genDeviceInfoBody()
  50. }.await()
  51. if (result.apkUpdate) {
  52. val commonDialog = CommonDialog()
  53. commonDialog.msg = getString(com.develop.common.R.string.update_msg)
  54. commonDialog.title = getString(com.develop.common.R.string.update)
  55. commonDialog.hasOKBtn = false
  56. val cancelConfirmDialog = CancelConfirmDialog()
  57. cancelConfirmDialog.title =
  58. getString(com.develop.common.R.string.update_title)
  59. cancelConfirmDialog.showDialog(
  60. supportFragmentManager,
  61. "cancelConfirmDialog"
  62. )
  63. cancelConfirmDialog.onDialogClickListener =
  64. object : CancelConfirmDialog.OnDialogClickListener {
  65. override fun onConfirm() {
  66. commonDialog.showDialog(supportFragmentManager, "commonDialog")
  67. UpdateUtil.updateApp(
  68. this@apply,
  69. result.apkUrl,
  70. object : OnDownloadListener {
  71. override fun cancel() {
  72. runOnUiThread {
  73. commonDialog.removeSelf()
  74. }
  75. }
  76. override fun done(apk: File) {
  77. GlobalToast.showToast(getString(R.string.finish_download))
  78. UpdateUtil.installPackage(this@apply, apk)
  79. commonDialog.updateProgress(getString(R.string.installing))
  80. }
  81. override fun downloading(max: Int, progress: Int) {
  82. runOnUiThread {
  83. commonDialog.updateProgress(
  84. "${
  85. String.format(
  86. "%.0f",
  87. ((progress.toFloat() / max.toFloat()) * 100f)
  88. )
  89. }%"
  90. )
  91. }
  92. }
  93. override fun error(e: Throwable) {
  94. GlobalToast.showToast(getString(R.string.download_fail))
  95. runOnUiThread {
  96. commonDialog.removeSelf()
  97. }
  98. }
  99. override fun start() {
  100. // GlobalToast.showToast(getString(com.develop.common.R.string.start_download))
  101. }
  102. })
  103. }
  104. override fun onCancel() {
  105. }
  106. }
  107. } else {
  108. val downloadDir = this@apply.externalCacheDir.toString()
  109. val downloadName = System.nanoTime().toString()
  110. val recipeUpdateTime = result.recipeUpdateTime
  111. val newRecipes = LinkedList(result.newRecipes)
  112. if (newRecipes.isEmpty() && shoNoUpdateDialog) {
  113. val dialog = RecipeUpdateDialog()
  114. dialog.onDialogClickListener =
  115. object : RecipeUpdateDialog.OnDialogClickListener {
  116. override fun onConfirm() {
  117. }
  118. override fun onCancel() {
  119. }
  120. }
  121. dialog.showNoUpdateTips(supportFragmentManager, "RECIPE_UPDATE_DIALOG")
  122. }
  123. if (newRecipes.isNotEmpty()) {
  124. val dialog = RecipeUpdateDialog()
  125. dialog.onDialogClickListener =
  126. object : RecipeUpdateDialog.OnDialogClickListener {
  127. override fun onConfirm() {
  128. updateRecipe = !updateRecipe
  129. EventBus.getDefault().post(NoScreenEvent(true))
  130. downloadRecipes(
  131. newRecipes,
  132. dialog,
  133. newRecipes.size.toLong(),
  134. downloadDir,
  135. downloadName,
  136. recipeUpdateTime
  137. )
  138. }
  139. override fun onCancel() {
  140. }
  141. }
  142. dialog.showUpdateTips(
  143. supportFragmentManager,
  144. "RECIPE_UPDATE_DIALOG",
  145. newRecipes.size.toLong()
  146. )
  147. }
  148. }
  149. } catch (e: java.lang.Exception) {
  150. e.printStackTrace()
  151. }
  152. }
  153. }
  154. }
  155. var updateRecipe = false
  156. @SuppressLint("InvalidWakeLockTag")
  157. private fun downloadRecipes(
  158. newRecipes: LinkedList<String>,
  159. recipeUpdateDialog: RecipeUpdateDialog,
  160. sum: Long,
  161. downloadDir: String,
  162. downloadName: String,
  163. recipeUpdateTime: Long?
  164. ) {
  165. //取消标识退出
  166. if (!updateRecipe) {
  167. return
  168. }
  169. //升级休眠
  170. val pm = globalApp().getSystemService(Application.POWER_SERVICE) as PowerManager
  171. val mWakeLock = pm.newWakeLock(
  172. PowerManager.SCREEN_BRIGHT_WAKE_LOCK or PowerManager.ON_AFTER_RELEASE or PowerManager.ACQUIRE_CAUSES_WAKEUP,
  173. "tag"
  174. );
  175. mWakeLock?.setReferenceCounted(false);
  176. mWakeLock?.acquire(10 * 60 * 1000L /*10 minutes*/)
  177. TopResumedAtyHolder.getCurrentActivity()?.apply {
  178. if (newRecipes.isEmpty()) {
  179. recipeUpdateDialog.removeSelf()
  180. showRecipesUpdateDialog(recipeUpdateTime)
  181. return
  182. }
  183. val recipeUrl = newRecipes.pop()
  184. val recipeNumber = recipeUrl.split("@")[0]
  185. val fileUrl = recipeUrl.split("@")[1]
  186. recipeUpdateDialog.showUpdating(supportFragmentManager, "", sum - newRecipes.size, sum)
  187. scopeNetLife {
  188. val result = Get<File>(fileUrl) {
  189. setDownloadFileName(downloadName)
  190. setDownloadDir(downloadDir)
  191. addDownloadListener(object : ProgressListener() {
  192. override fun onProgress(p: Progress) {
  193. LogUtil.d("dddddd", p.toString())
  194. }
  195. })
  196. }.await()
  197. if (!result.exists()) {
  198. downloadRecipes(
  199. newRecipes,
  200. recipeUpdateDialog,
  201. sum,
  202. downloadDir,
  203. downloadName,
  204. recipeUpdateTime
  205. )
  206. } else {
  207. prepareResource(result, recipeNumber)
  208. downloadRecipes(
  209. newRecipes,
  210. recipeUpdateDialog,
  211. sum,
  212. downloadDir,
  213. downloadName,
  214. recipeUpdateTime
  215. )
  216. }
  217. }
  218. }
  219. mWakeLock.release()
  220. }
  221. private fun prepareResource(file: File, recipeNumber: String) {
  222. try {
  223. val dst = ZipUtils.unzipFile(file, FoodDataProvider.getExtRecipeResourceDir())
  224. FileUtils.delete(file)
  225. if (dst.isNullOrEmpty()) {
  226. return
  227. }
  228. val jsonFile = FoodDataProvider.getResourceConfigJsonPath(recipeNumber)
  229. if (!jsonFile.exists()) {
  230. return
  231. }
  232. val jsonContent = FileKit.readFileToString(jsonFile)
  233. val contentData = jsonDecoder.decodeFromString<RecipeDataConfig>(jsonContent)
  234. contentData.resetAllCodes()
  235. FoodDataProvider.getDatabase().runInTransaction {
  236. FoodDataProvider.getDatabase().recipeDao().apply {
  237. deleteDevRecipeAccessorys(recipeNumber)
  238. deleteDevRecipeCookingSteps(recipeNumber)
  239. deleteDevRecipeFoods(recipeNumber)
  240. deleteDevRecipeNutritions(recipeNumber)
  241. deleteDevRecipeRelTags(recipeNumber)
  242. deleteDevRecipePortionSizes(recipeNumber)
  243. deleteRecipe(recipeNumber)
  244. insertDevAccessorys(contentData.devAccessorys)
  245. insertHotTags(contentData.devHotTags)
  246. insertDevPortraits(contentData.devPortraits)
  247. insertDevRecipeAccessorys(contentData.devRecipeAccessorys)
  248. val categorys = queryAllCategory()
  249. val categoryMap = HashMap<String, DevRecipeCategory>()
  250. for (category in categorys) {
  251. categoryMap[category.number + ":" + category.lang] = category
  252. }
  253. for (devRecipeCategory in contentData.devRecipeCategorys) {
  254. if (categoryMap.containsKey(devRecipeCategory.number + ":" + devRecipeCategory.lang)) {
  255. devRecipeCategory.code =
  256. categoryMap[devRecipeCategory.number + ":" + devRecipeCategory.lang]?.code.toString()
  257. }
  258. }
  259. insertDevRecipeCategorys(contentData.devRecipeCategorys)
  260. insertDevRecipeCookingSteps(contentData.devRecipeCookingSteps)
  261. insertDevRecipeFoods(contentData.devRecipeFoods)
  262. insertDevRecipeNutritions(contentData.devRecipeNutritions)
  263. insertDevRecipePortionSizes(contentData.devRecipePortionSizes)
  264. insertDevRecipeRelTags(contentData.devRecipeRelTags)
  265. insertDevRecipeTags(contentData.devRecipeTags)
  266. insertDevRecipes(contentData.devRecipes)
  267. }
  268. }
  269. } catch (e: Exception) {
  270. e.printStackTrace()
  271. }
  272. }
  273. private fun showRecipesUpdateDialog(recipeUpdateTime: Long?) {
  274. TopResumedAtyHolder.getCurrentActivity()?.apply {
  275. val minute = MMkvUtils.getInt(SCREENSAVER)
  276. if (minute != 0) {
  277. Settings.System.putInt(
  278. contentResolver,
  279. Settings.System.SCREEN_OFF_TIMEOUT,
  280. 1000 * 60 * minute
  281. )
  282. val uri: Uri = Settings.System
  283. .getUriFor(Settings.System.SCREEN_OFF_TIMEOUT)
  284. contentResolver.notifyChange(uri, null)
  285. }
  286. EventBus.getDefault().post(NoScreenEvent(false))
  287. RecipeUpdateDialog().apply {
  288. onDialogClickListener = object : RecipeUpdateDialog.OnDialogClickListener {
  289. override fun onConfirm() {
  290. val v = FoodDataProvider.getUserDatabase().devConfigDao().recipeVersion()
  291. ?: DevVersion(0, 0)
  292. v.recipeUpdateTime = recipeUpdateTime
  293. FoodDataProvider.getUserDatabase().devConfigDao().saveDevVersion(v)
  294. removeSelf()
  295. }
  296. override fun onCancel() {
  297. }
  298. }
  299. showSuccess(supportFragmentManager, "recipeUpdateDialog")
  300. }
  301. }
  302. }
  303. }
  304. class NoScreenEvent(var noScreen: Boolean)