"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
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通讯
}
}
+ private var hasCheck = false
+
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
//判断指令是啥
//以下动作,需要延时执行,因为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)
}
/**
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
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)
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")
mFirstRepository.downloadPackage(mDownloadCallback)
}
if (downResult == null) {
- currentActionState.postValue(UpdateActionState.ERROR)
+ Log.d(TAG, "downResult is null...")
+ //currentActionState.postValue(UpdateActionState.ERROR)
} else {
downInfoResult.value = downResult
//下载成功以后,如果是强制升级的,直接走升级流程
}
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)
}
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 {
}
} catch (e: Exception) {
Log.e("e", e.toString())
+ currentActionState.postValue(UpdateActionState.ERROR)
}
}
}
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)
Log.d(TAG, "post install result..failed.")
mFirstRepository.reportInstallResult(false)
mFirstRepository.reportResult(versionRecord!!)
+ //删除文件
+ mFirstRepository.deletePackage()
}
}
} catch (e: Exception) {
Log.d(TAG, "onDownloaded...$extra")
//mCallback?.onDownloadSuccess()
//下载完就校验的,内部校验
- mCallback?.onVerify()
}
override fun onError(errCode: Int, extra: Bundle?) {
}
}) ?: 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)
override fun deletePackage() {
//删除flash_root下的
- val file = File(VersionInfoUtils.getFlashPath())
+ val file = File(VersionInfoUtils.getUpdatePackageFullPath())
if (file.exists()) {
file.delete()
}
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
initOkHttp()
}
if (otaInfo == null) {
+ callback?.onDownloadError(-1, "没有下载信息")
return null
}
val request: Request = Request.Builder().url(
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()
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
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
}
UpdateActionState.DOWNLOADING -> {
//暂停下载
- otaViewModel.pauseDownload()
+ //otaViewModel.pauseDownload()
+ //不支持暂停先
}
UpdateActionState.DOWNLOAD_PAUSE -> {
//去下载
otaInfo.observe(that, Observer {
if (it != null) {
updateText.text = getString(R.string.update_tips_text) + it.updateDesc
-
}
})
isTipsWifiConnect.observe(that, Observer {
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)
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
}
android:padding="10dp"
android:text="@string/check_has_update_text"
android:textColor="@color/white"
- android:textSize="20sp" />
+ android:textSize="18sp" />
</LinearLayout>
\ No newline at end of file
android:background="@color/grey"
android:gravity="center_horizontal"
android:orientation="vertical"
- android:padding="4dp">
+ android:padding="4dp"
+ android:paddingLeft="20dp"
+ android:paddingRight="20dp">
<TextView
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:gravity="center_vertical|center_horizontal"
- android:text="有新版本更新啦!"
+ android:text="@string/local_new_version_tips_title"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/white"
android:textIsSelectable="true" />
</ScrollView>
<View
- android:layout_width="200dp"
+ android:layout_width="match_parent"
android:layout_height="1px"
android:background="@color/white" />
android:text="@string/IFIA_btn_no"
android:textColor="@color/white" />
+ <Button
+ android:id="@+id/button_delete"
+ style="?android:attr/buttonBarButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/btn_delete_text"
+ android:textColor="@color/white"
+ android:visibility="gone" />
+
<Button
android:id="@+id/button_ok"
style="?android:attr/buttonBarButtonStyle"
<string name="app_name">ICFotaClient</string>
<string name="IFIA_btn_yes">是</string>
<string name="IFIA_btn_no">否</string>
+ <string name="btn_install_text">安装</string>
+ <string name="btn_cancel_text">取消</string>
+ <string name="btn_delete_text">删除</string>
<string name="pb_title_downloading">正在下载升级包</string>
<string name="check_has_update_text">检查是否有更新</string>
<string name="update_text">马上升级</string>
<string name="no_network_text">无法触及到服务器</string>
<string name="battery_level_tips_text">请确保电量50%以上</string>
- <string name="error_tips_text">资源准备失败,请重启尝试</string>
+ <string name="error_tips_text">资源准备失败,请重启尝试</string>
<string name="verify_package_text">正在校验升级包</string>
+ <string name="inject_update_seed_text">注入升级种子</string>
+ <string name="verify_error_text">校验失败</string>
<string name="last_version_text">已经是最新版本</string>
<string name="download_package">下载更新包</string>
<string name="try_to_downloading">正在玩命下载中…</string>
<string name="update_tips_text">更新说明:\n</string>
<string name="tips_wifi_connect">请连接WI-FI下载</string>
<string name="unsupport_pause_download">该服务器不支持暂停下载</string>
+ <string name="new_version_tips_title">有新版本更新啦!</string>
+ <string name="local_new_version_tips_title">检查到本地更新!</string>
+ <string name="local_update_desc_text">发现本地更新包,确定更新,或者删除.</string>
+ <string name="update_package_not_in_tips_text">安装文件不存在</string>
</resources>
\ No newline at end of file