From: TrillGates Date: Wed, 3 Feb 2021 10:36:54 +0000 (+0800) Subject: add local update check. X-Git-Url: http://git.snicker.com.cn/sitemap.xml?a=commitdiff_plain;h=dc1312d7e03c09618eda13adb3aed360edeca640;p=icfotaclient.git add local update check. --- diff --git a/app/FotaBrand8541e/debug/FotaBrand8541e_V1_202101251756_debug.apk b/app/FotaBrand8541e/debug/FotaBrand8541e_V1_202101251756_debug.apk deleted file mode 100644 index 1c87ee8..0000000 Binary files a/app/FotaBrand8541e/debug/FotaBrand8541e_V1_202101251756_debug.apk and /dev/null differ diff --git a/app/FotaBrand8541e/release/FotaBrand8541e_V1_202102031807_release.apk b/app/FotaBrand8541e/release/FotaBrand8541e_V1_202102031807_release.apk new file mode 100644 index 0000000..9688da4 Binary files /dev/null and b/app/FotaBrand8541e/release/FotaBrand8541e_V1_202102031807_release.apk differ diff --git a/app/FotaBrand8541e/debug/output-metadata.json b/app/FotaBrand8541e/release/output-metadata.json similarity index 67% rename from app/FotaBrand8541e/debug/output-metadata.json rename to app/FotaBrand8541e/release/output-metadata.json index 25d61d3..2b7bdab 100644 --- a/app/FotaBrand8541e/debug/output-metadata.json +++ b/app/FotaBrand8541e/release/output-metadata.json @@ -5,14 +5,14 @@ "kind": "Directory" }, "applicationId": "com.ic.icfotaclient", - "variantName": "processFotaBrand8541eDebugResources", + "variantName": "processFotaBrand8541eReleaseResources", "elements": [ { "type": "SINGLE", "filters": [], "versionCode": 1, "versionName": "1.0", - "outputFile": "FotaBrand8541e_V1_202101252023_debug.apk" + "outputFile": "FotaBrand8541e_V1_202102031807_release.apk" } ] } \ No newline at end of file diff --git a/app/src/main/java/com/ic/icfotaclient/presenter/OtaService.kt b/app/src/main/java/com/ic/icfotaclient/presenter/OtaService.kt index 1c8a8d3..54aa9b1 100644 --- a/app/src/main/java/com/ic/icfotaclient/presenter/OtaService.kt +++ b/app/src/main/java/com/ic/icfotaclient/presenter/OtaService.kt @@ -5,14 +5,13 @@ import android.content.Intent import android.os.IBinder import android.text.TextUtils import android.util.Log +import android.widget.Toast import androidx.lifecycle.* import com.ic.icfotaclient.App import com.ic.icfotaclient.IOtaCheckCallback import com.ic.icfotaclient.IOtaCheckService -import com.ic.icfotaclient.utils.Constants -import com.ic.icfotaclient.utils.OtaViewModelCreator -import com.ic.icfotaclient.utils.VersionCheckFrom -import com.ic.icfotaclient.utils.VersionInfoUtils +import com.ic.icfotaclient.R +import com.ic.icfotaclient.utils.* /** * 这个是专门给远程使用的,如果远程需要知道是否有更新的内容,可以通过AIDL通讯 @@ -71,6 +70,8 @@ class OtaService : Service(), ViewModelStoreOwner, LifecycleOwner { } } + private var hasCheck = false + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { //判断指令是啥 @@ -86,28 +87,53 @@ class OtaService : Service(), ViewModelStoreOwner, LifecycleOwner { //以下动作,需要延时执行,因为IMEI号,网络这些还没准备好 //检查网络,如果网络okay了,就去检查版本更新 //如果网络不okay,那么就等待网络连接的广播,在连接的广播里去检查更新 - App.sHandler.postDelayed({ - checkVersion(VersionCheckFrom.BOOT_CHECK) - }, Constants.TIME_DELAY_BOOT) - //如果已经更新了,那么通知一下服务器 - otaViewModel?.checkHasUpdated() + doCheck() } Constants.CMD_ACTION_NET_WORK_CONNECTED -> { //去检查更新 - otaViewModel?.checkHasUpdated() + doCheck() } } return super.onStartCommand(intent, flags, startId) } - private fun checkVersion(from: VersionCheckFrom) { - val checkNetWork = otaViewModel?.checkNetWork() - Log.d(TAG, "checkNetWork == > $checkNetWork") - if (checkNetWork == true) { - //连接上了,那么就去检查更新 - otaViewModel?.checkUpdate(from) + private fun doCheck() { + if (hasCheck) { + Log.d(TAG, "has checked..") + return } + hasCheck = true + App.sHandler.postDelayed({ + checkVersion(VersionCheckFrom.BOOT_CHECK) + }, Constants.TIME_DELAY_BOOT) + OtaViewModelCreator.getOtaViewModel(object : OtaViewModelCreator.OnViewModelInitListener { + override fun onViewModelInit(otaViewModel: OtaViewModel?) { + //如果已经更新了,那么通知一下服务器 + otaViewModel?.checkHasUpdated() + otaViewModel?.currentActionState?.observe(this@OtaService, Observer { + when (it) { + UpdateActionState.VERIFY_ERROR -> { + Toast.makeText( + App.sContext, App.sContext.getString(R.string.verify_error_text), + Toast.LENGTH_SHORT + ).show() + } + UpdateActionState.VERIFY -> { + Toast.makeText( + App.sContext, App.sContext.getString(R.string.verify_package_text), + Toast.LENGTH_SHORT + ).show() + } + } + }) + } + }) + } + + private fun checkVersion(from: VersionCheckFrom) { + //连接上了,那么就去检查更新 + otaViewModel?.checkUpdate(from) } /** diff --git a/app/src/main/java/com/ic/icfotaclient/presenter/OtaViewModel.kt b/app/src/main/java/com/ic/icfotaclient/presenter/OtaViewModel.kt index 3352323..acc139d 100644 --- a/app/src/main/java/com/ic/icfotaclient/presenter/OtaViewModel.kt +++ b/app/src/main/java/com/ic/icfotaclient/presenter/OtaViewModel.kt @@ -4,6 +4,8 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.os.BatteryManager +import android.os.Handler +import android.os.Looper import android.os.RecoverySystem import android.text.TextUtils import android.util.Log @@ -92,8 +94,96 @@ class OtaViewModel : ViewModel() { Log.d(TAG, "checking....") return } + //检查是否有本地更新 + if (hasLocalUpdateZip()) { + Log.d(TAG, "tips local update zip.") + return + } + checkRemote(from) + } + + /** + * 检查本地是否有升级包 + */ + private fun hasLocalUpdateZip(): Boolean { + val file = File(VersionInfoUtils.getLocalUpdateZip()) + Log.d(TAG, "file is == > ${file.path}") + if (file.exists()) { + //弹窗询问用户是否进行升级 + showLocalUpdateTips() + return true + } + return false + } + + /** + * 展示本地安装和提示框 + */ + private fun showLocalUpdateTips() { + val manager = App.sContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager + val layoutParams = WindowManager.LayoutParams() + layoutParams.gravity = Gravity.CENTER + layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT + layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT + layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT + layoutParams.alpha = 1.0f + layoutParams.packageName = App.sContext.getPackageName() + layoutParams.buttonBrightness = 1f + layoutParams.windowAnimations = android.R.style.Animation_Dialog + val view: View = + View.inflate(App.sContext, R.layout.dialog_tips, null) + val descText: TextView = view.findViewById(R.id.description) + val deleteBtn: TextView = view.findViewById(R.id.button_delete) + deleteBtn.visibility = View.VISIBLE + val cancelBtn: TextView = view.findViewById(R.id.button_cancel) + cancelBtn.text = App.sContext.getString(R.string.btn_cancel_text) + val installBtn: TextView = view.findViewById(R.id.button_ok) + installBtn.text = App.sContext.getString(R.string.btn_install_text) + descText.text = App.sContext.getString(R.string.local_update_desc_text) + installBtn.setOnClickListener { + //进行安装 + val file = File(VersionInfoUtils.getLocalUpdateZip()) + if (file.exists()) { + downInfoResult.postValue(DownloadInfo(file.path, file.length())) + this.install() + } else { + Toast.makeText( + App.sContext, + App.sContext.getString(R.string.update_package_not_in_tips_text), + Toast.LENGTH_SHORT + ).show() + } + descText.text = "正在拆解升级包..." + installBtn.visibility = View.GONE + cancelBtn.visibility = View.GONE + deleteBtn.visibility = View.GONE + Handler(Looper.getMainLooper()).postDelayed({ + manager.removeView(view) + }, 3000) + } + deleteBtn.setOnClickListener { + //删除 + viewModelScope.launch { + withContext(Dispatchers.IO) { + val file = File(VersionInfoUtils.getLocalUpdateZip()) + if (file.exists()) { + file.delete() + } + } + } + manager.removeView(view) + } + cancelBtn.setOnClickListener { + //取消 + manager.removeView(view) + } + manager.addView(view, layoutParams) + } + + private fun checkRemote(from: VersionCheckFrom) { if (!checkNetWork()) { - currentActionState.value = UpdateActionState.NO_NETWORK + currentActionState.postValue(UpdateActionState.NO_NETWORK) + Log.d(TAG, "no network...") return } currentActionState.postValue(UpdateActionState.CHECKING) @@ -101,7 +191,15 @@ class OtaViewModel : ViewModel() { try { //检查更新 val result: OtaInfo? = withContext(Dispatchers.IO) { - mFirstRepository.checkHasNewVersion() + val checkHasNewVersion = mFirstRepository.checkHasNewVersion() + if (checkHasNewVersion != null) { + //干掉复制文件的地方,给下载位置 + val file = File(VersionInfoUtils.getUpdatePackageFullPath()) + if (file.exists()) { + file.delete() + } + } + checkHasNewVersion } //结果 Log.d(TAG, "check result ==> $result") @@ -179,7 +277,8 @@ class OtaViewModel : ViewModel() { mFirstRepository.downloadPackage(mDownloadCallback) } if (downResult == null) { - currentActionState.postValue(UpdateActionState.ERROR) + Log.d(TAG, "downResult is null...") + //currentActionState.postValue(UpdateActionState.ERROR) } else { downInfoResult.value = downResult //下载成功以后,如果是强制升级的,直接走升级流程 @@ -210,13 +309,18 @@ class OtaViewModel : ViewModel() { } override fun onDownloadError(errorCode: Int, msg: String) { - Toast.makeText(App.sContext, "errorCode:$errorCode", Toast.LENGTH_LONG).show() + // Toast.makeText(App.sContext, "errorCode:$errorCode", Toast.LENGTH_LONG).show() Log.d(TAG, "onDownloadError -- > $errorCode == > $msg") if (errorCode == 0) { //停止下载了,修改UI为继续下载 currentActionState.postValue(UpdateActionState.DOWNLOAD_PAUSE) } else { - Toast.makeText(App.sContext, "error:$errorCode", Toast.LENGTH_LONG).show() + //Toast.makeText(App.sContext, "error:$errorCode", Toast.LENGTH_LONG).show() + //这里就是子线程 + val file = File(VersionInfoUtils.getUpdatePackageFullPath()) + if (file.exists()) { + file.delete() + } //其他错误,都提示用户重启 currentActionState.postValue(UpdateActionState.ERROR) } @@ -311,32 +415,45 @@ class OtaViewModel : ViewModel() { level * 100f / scale.toFloat() } Log.d(TAG, "batteryPct == > $batteryPct") + //进行电量检查 if (batteryPct!! >= 50.0f) { - Log.d(TAG, "otaInfo.value!!.versionCode == > " + otaInfo.value!!.versionCode) - Log.d(TAG, "save target update version.") + currentActionState.postValue(UpdateActionState.UPDATING) //保存一个SP值,升级完了检查,用于通知服务器更新成功了. - val sharePreference = SPUtil.getSharePreference() - sharePreference.edit() - .putString(SPUtil.KEY_TARGET_VERSION_CODE, otaInfo.value!!.versionCode) - .apply() //这里后面要改成我们自己的升级,而不是apk的升级方式 withContext(Dispatchers.IO) { - //进行电量检查 val path = downInfoResult.value!!.path; + Log.d(TAG, "install path is == > $path") //val path = "/data/media/0/sl8541e_1h10_oversea-ota-04210.zip" val tempFile = File(path) Log.d(TAG, "tempFile.exists() == > ${tempFile.exists()}") - Log.d(TAG, "install path is == > $path") + if (otaInfo.value != null) { + Log.d( + TAG, + "otaInfo.value!!.versionCode == > " + otaInfo.value!!.versionCode + ) + val sharePreference = SPUtil.getSharePreference() + sharePreference.edit() + .putString( + SPUtil.KEY_TARGET_VERSION_CODE, + otaInfo.value!!.versionCode + ) + .apply() + } + + Log.d(TAG, "save target update version.") //先验证,再安装 try { RecoverySystem.verifyPackage(File(path), null, null) Log.d(TAG, "verifyPackageFinished...") - RecoverySystem.installPackage( - App.sContext, - File(path) - ) + RecoverySystem.installPackage(App.sContext, File(path)) } catch (e: Exception) { e.printStackTrace() + currentActionState.postValue(UpdateActionState.VERIFY_ERROR) + //删除文件 + val file = File(path) + if (file.exists()) { + file.delete() + } } } } else { @@ -346,6 +463,7 @@ class OtaViewModel : ViewModel() { } } catch (e: Exception) { Log.e("e", e.toString()) + currentActionState.postValue(UpdateActionState.ERROR) } } } @@ -360,10 +478,11 @@ class OtaViewModel : ViewModel() { val systemVersion = VersionInfoUtils.getSystemVersion() Log.d(TAG, "system version code is == > $systemVersion") Log.d(TAG, "versionRecord code is == > $versionRecord") - if (TextUtils.isEmpty(versionRecord)) { + if (!TextUtils.isEmpty(versionRecord)) { if (versionRecord == systemVersion) { try { viewModelScope.launch { + Toast.makeText(App.sContext, "升级成功!", Toast.LENGTH_SHORT).show() withContext(Dispatchers.IO) { Log.d(TAG, "post install result..success.") mFirstRepository.reportInstallResult(true) @@ -382,6 +501,8 @@ class OtaViewModel : ViewModel() { Log.d(TAG, "post install result..failed.") mFirstRepository.reportInstallResult(false) mFirstRepository.reportResult(versionRecord!!) + //删除文件 + mFirstRepository.deletePackage() } } } catch (e: Exception) { diff --git a/app/src/main/java/com/ic/icfotaclient/repository/CarOtaRepository.kt b/app/src/main/java/com/ic/icfotaclient/repository/CarOtaRepository.kt index 801067b..377bd0e 100644 --- a/app/src/main/java/com/ic/icfotaclient/repository/CarOtaRepository.kt +++ b/app/src/main/java/com/ic/icfotaclient/repository/CarOtaRepository.kt @@ -59,7 +59,6 @@ class CarOtaRepository : AbstractOtaRepository() { Log.d(TAG, "onDownloaded...$extra") //mCallback?.onDownloadSuccess() //下载完就校验的,内部校验 - mCallback?.onVerify() } override fun onError(errCode: Int, extra: Bundle?) { @@ -72,9 +71,10 @@ class CarOtaRepository : AbstractOtaRepository() { } }) ?: return null + mCallback?.onVerify() //复制到对应的位置 val sourceFile = download.file - val targetFile = VersionInfoUtils.getFlashPath() + val targetFile = VersionInfoUtils.getUpdatePackageFullPath() Log.d(TAG, "download == > $sourceFile") try { val fis = FileInputStream(sourceFile) diff --git a/app/src/main/java/com/ic/icfotaclient/repository/ICOtaRepository.kt b/app/src/main/java/com/ic/icfotaclient/repository/ICOtaRepository.kt index 5a02dd1..21b4d44 100644 --- a/app/src/main/java/com/ic/icfotaclient/repository/ICOtaRepository.kt +++ b/app/src/main/java/com/ic/icfotaclient/repository/ICOtaRepository.kt @@ -77,7 +77,7 @@ class ICOtaRepository : AbstractOtaRepository() { override fun deletePackage() { //删除flash_root下的 - val file = File(VersionInfoUtils.getFlashPath()) + val file = File(VersionInfoUtils.getUpdatePackageFullPath()) if (file.exists()) { file.delete() } diff --git a/app/src/main/java/com/ic/icfotaclient/utils/ICOtaApiUtils.kt b/app/src/main/java/com/ic/icfotaclient/utils/ICOtaApiUtils.kt index ab031cf..034f572 100644 --- a/app/src/main/java/com/ic/icfotaclient/utils/ICOtaApiUtils.kt +++ b/app/src/main/java/com/ic/icfotaclient/utils/ICOtaApiUtils.kt @@ -10,8 +10,6 @@ import com.ic.icfotaclient.bean.OtaInfo import com.ic.icfotaclient.repository.IOtaRepositoryCallback import okhttp3.OkHttpClient import okhttp3.Request -import java.io.BufferedInputStream -import java.io.BufferedOutputStream import java.io.FileOutputStream import java.net.HttpURLConnection import java.net.URI @@ -154,6 +152,7 @@ object ICOtaApiUtils { initOkHttp() } if (otaInfo == null) { + callback?.onDownloadError(-1, "没有下载信息") return null } val request: Request = Request.Builder().url( @@ -163,31 +162,35 @@ object ICOtaApiUtils { val total = otaInfo!!.OtaPackageLength val response = okHttpClient?.newCall(request)?.execute() if (response?.code() == HttpURLConnection.HTTP_OK) { - val inputStream = response.body()?.byteStream() - val outPutStream = FileOutputStream(VersionInfoUtils.getFlashPath()) - val bis = BufferedInputStream(inputStream) - val bos = BufferedOutputStream(outPutStream) - val buf = ByteArray(1024) - var len: Int - var current = 0; - while (true) { - len = bis.read(buf) - if (len == -1) break; - current += len; - bos.write(buf, 0, len) - callback?.onDownloadProgressChange(current.toLong(), total.toLong()) + try { + val fis = response.body()?.byteStream() + val fos = FileOutputStream(VersionInfoUtils.getUpdatePackageFullPath()) + val buf = ByteArray(1024) + var len: Int + var current = 0 + while (fis?.read(buf).also { + len = it!! + } != -1) { + fos.write(buf, 0, len) + current += len + callback?.onDownloadProgressChange(current.toLong(), total.toLong()) + } + fis?.close() + fos.close() + } catch (e: Exception) { + e.printStackTrace() + callback?.onDownloadError(-4, "下载中出错") } - inputStream?.close() - outPutStream.close() //校验文件下载是否正确 callback?.onVerify() - val checkMd5 = MD5.checkMd5(otaInfo!!.md5sum, VersionInfoUtils.getFlashPath()) + val checkMd5 = MD5.checkMd5(otaInfo!!.md5sum, VersionInfoUtils.getUpdatePackageFullPath()) Log.d(TAG, "checkMd5 =+++= > $checkMd5") if (!checkMd5) { callback?.onDownloadError(-5, "校验失败") + return null } callback?.onDownloadSuccess() - return DownloadInfo(VersionInfoUtils.getFlashPath(), total.toLong()) + return DownloadInfo(VersionInfoUtils.getUpdatePackageFullPath(), total.toLong()) } } catch (e: Exception) { e.printStackTrace() diff --git a/app/src/main/java/com/ic/icfotaclient/utils/UpdateActionState.kt b/app/src/main/java/com/ic/icfotaclient/utils/UpdateActionState.kt index 557f71e..8c18aee 100644 --- a/app/src/main/java/com/ic/icfotaclient/utils/UpdateActionState.kt +++ b/app/src/main/java/com/ic/icfotaclient/utils/UpdateActionState.kt @@ -12,4 +12,6 @@ enum class UpdateActionState { NO_NETWORK,/*显示无网络,isEnable=false*/ ERROR,/*恢复默认,显示检查更新 isEnable=false*/ BATTERY_LEVEL_NOT_ENOUGH,/*电池电量不足50%,isEnable=false*/ + UPDATING,/*显示:注入升级种子,isEnable=false*/ + VERIFY_ERROR/*显示:校验出错,isEnable=false*/ } \ No newline at end of file diff --git a/app/src/main/java/com/ic/icfotaclient/utils/VersionInfoUtils.kt b/app/src/main/java/com/ic/icfotaclient/utils/VersionInfoUtils.kt index 1f07ae6..a66599c 100644 --- a/app/src/main/java/com/ic/icfotaclient/utils/VersionInfoUtils.kt +++ b/app/src/main/java/com/ic/icfotaclient/utils/VersionInfoUtils.kt @@ -84,14 +84,22 @@ object VersionInfoUtils { var DATA_ROOT = "/data/media/0" private const val updateFileName = "update_pkg" + private const val localUpdateFileName = "update_pkg.zip" - fun getFlashPath(): String { + fun getLocalUpdateZip(): String { + //移动到对应的位置上 + // if (getMultiUserState()) { + flash_root = DATA_ROOT + // } + return flash_root + File.separator + localUpdateFileName + } + + fun getUpdatePackageFullPath(): String { //移动到对应的位置上 if (getMultiUserState()) { flash_root = DATA_ROOT } - return flash_root + File.separator + updateFileName } } \ No newline at end of file diff --git a/app/src/main/java/com/ic/icfotaclient/view/SystemUpdateActivity.kt b/app/src/main/java/com/ic/icfotaclient/view/SystemUpdateActivity.kt index fc0e662..1fd851f 100644 --- a/app/src/main/java/com/ic/icfotaclient/view/SystemUpdateActivity.kt +++ b/app/src/main/java/com/ic/icfotaclient/view/SystemUpdateActivity.kt @@ -64,7 +64,8 @@ class SystemUpdateActivity : AppCompatActivity() { } UpdateActionState.DOWNLOADING -> { //暂停下载 - otaViewModel.pauseDownload() + //otaViewModel.pauseDownload() + //不支持暂停先 } UpdateActionState.DOWNLOAD_PAUSE -> { //去下载 @@ -91,7 +92,6 @@ class SystemUpdateActivity : AppCompatActivity() { otaInfo.observe(that, Observer { if (it != null) { updateText.text = getString(R.string.update_tips_text) + it.updateDesc - } }) isTipsWifiConnect.observe(that, Observer { @@ -121,8 +121,8 @@ class SystemUpdateActivity : AppCompatActivity() { checkUpdate.isEnabled = false } UpdateActionState.DOWNLOADING -> { - checkUpdate.text = getString(R.string.pause_download_text) - checkUpdate.isEnabled = true + checkUpdate.text = getString(R.string.try_to_downloading) + checkUpdate.isEnabled = false } UpdateActionState.DOWNLOAD_PAUSE -> { checkUpdate.text = getString(R.string.continue_download_text) @@ -148,6 +148,14 @@ class SystemUpdateActivity : AppCompatActivity() { checkUpdate.text = getString(R.string.verify_package_text) checkUpdate.isEnabled = false } + UpdateActionState.UPDATING -> { + checkUpdate.text = getString(R.string.inject_update_seed_text) + checkUpdate.isEnabled = false + } + UpdateActionState.VERIFY_ERROR -> { + checkUpdate.text = getString(R.string.verify_error_text) + checkUpdate.isEnabled = false + } else -> { //NONE } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b94e12d..af9c491 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -80,6 +80,6 @@ android:padding="10dp" android:text="@string/check_has_update_text" android:textColor="@color/white" - android:textSize="20sp" /> + android:textSize="18sp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_tips.xml b/app/src/main/res/layout/dialog_tips.xml index 0039973..61eb176 100644 --- a/app/src/main/res/layout/dialog_tips.xml +++ b/app/src/main/res/layout/dialog_tips.xml @@ -5,7 +5,9 @@ android:background="@color/grey" android:gravity="center_horizontal" android:orientation="vertical" - android:padding="4dp"> + android:padding="4dp" + android:paddingLeft="20dp" + android:paddingRight="20dp"> @@ -38,7 +40,7 @@ @@ -58,6 +60,16 @@ android:text="@string/IFIA_btn_no" android:textColor="@color/white" /> +