diff --git a/app/build.gradle b/app/build.gradle
index 1abf412b9..4ab6b7ff2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -175,8 +175,8 @@ android {
def Lombok = "1.18.10"
dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
- implementation fileTree(dir: 'aliyun-libs', include: ['*.jar','*.aar'])
+ implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+ implementation fileTree(dir: 'aliyun-libs', include: ['*.jar', '*.aar'])
testImplementation 'junit:junit:4.13.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
@@ -243,9 +243,9 @@ dependencies {
implementation 'com.huawei.hms:push:6.5.0.300'
//魅族推送
implementation 'com.meizu.flyme.internet:push-internal:4.1.0'
- //oppo推送需要
+ //oppo推送需要
implementation 'commons-codec:commons-codec:1.6'
-
+
api 'com.tencent.vasdolly:helper:3.0.3'
implementation "io.github.tencent:vap:2.0.24"
@@ -254,7 +254,7 @@ dependencies {
repositories {
flatDir {
- dirs 'aliyun-libs','com.huawei.agconnect'
+ dirs 'aliyun-libs', 'com.huawei.agconnect'
}
mavenCentral()
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e34584635..a5c9d01f9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -270,8 +270,8 @@
+ android:exported="true"
+ android:permission="com.push.permission.UPSTAGESERVICE" />
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/AppUpgradeHelper.java b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/AppUpgradeHelper.java
index 7d465a769..c7afc822b 100644
--- a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/AppUpgradeHelper.java
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/AppUpgradeHelper.java
@@ -2,13 +2,16 @@ package com.tongdaxing.erban.upgrade;
import android.annotation.SuppressLint;
-import com.trello.rxlifecycle3.android.ActivityEvent;
-import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;
import com.mango.core.upgrade.bean.NewestVersionInfo;
import com.mango.core.upgrade.bean.UpgradeCache;
import com.mango.core.upgrade.model.UpgradeModel;
import com.mango.core.utils.ActivityUtil;
+import com.mango.moshen.R;
+import com.mango.xchat_android_library.utils.JavaUtil;
import com.mango.xchat_android_library.utils.SingleToastUtil;
+import com.tongdaxing.erban.upgrade.manager.DownloadManager;
+import com.trello.rxlifecycle3.android.ActivityEvent;
+import com.trello.rxlifecycle3.components.support.RxAppCompatActivity;
/**
* @author jack
@@ -18,9 +21,8 @@ import com.mango.xchat_android_library.utils.SingleToastUtil;
public class AppUpgradeHelper {
/**
- *
* @param isUserAuto ture 表示,是用户主动发起的请求,比如设置页点更新
- * @param isPush ture 表示是后台推送
+ * @param isPush ture 表示是后台推送
*/
@SuppressLint("CheckResult")
public static void checkAppUpgrade(RxAppCompatActivity activity, boolean isUserAuto,
@@ -73,10 +75,17 @@ public class AppUpgradeHelper {
}
//如果是强更,一定要弹窗
if (forceUpdate || needShow) {
- AppUpdateDialog appUpdateDialog = new AppUpdateDialog();
- appUpdateDialog.setNewestVersionInfo(newestVersionInfo);
- appUpdateDialog.show(activity.getSupportFragmentManager());
- UpgradeModel.get().setHasShowDialog(true);
+ DownloadManager manager = new DownloadManager.Builder(activity)
+ .apkUrl(newestVersionInfo.getUpdateDownloadLink())
+ .apkName("magic_v" + newestVersionInfo.getUpdateVersion() + ".apk")
+ .apkMD5(newestVersionInfo.getUpdateFileMd5())
+ .apkVersionName(newestVersionInfo.getUpdateVersion())
+ .smallIcon(R.mipmap.app_logo)
+ .forcedUpgrade(forceUpdate)
+ .apkVersionCode(Integer.MAX_VALUE)
+ .apkDescription(newestVersionInfo.getUpdateVersionDesc())
+ .build();
+ manager.download();
}
}
} else {
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/base/BaseHttpDownloadManager.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/base/BaseHttpDownloadManager.kt
new file mode 100644
index 000000000..1d58583b2
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/base/BaseHttpDownloadManager.kt
@@ -0,0 +1,34 @@
+package com.tongdaxing.erban.upgrade.base
+
+import com.tongdaxing.erban.upgrade.base.bean.DownloadStatus
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.base
+ * FileName: BaseHttpDownloadManager
+ * CreateDate: 2022/4/7 on 10:24
+ * Desc:
+ *
+ * @author azhon
+ */
+
+abstract class BaseHttpDownloadManager {
+ /**
+ * download apk from apkUrl
+ *
+ * @param apkUrl
+ * @param apkName
+ */
+ abstract fun download(apkUrl: String, apkName: String): Flow
+
+ /**
+ * cancel download apk
+ */
+ abstract fun cancel()
+
+ /**
+ * release memory
+ */
+ abstract fun release()
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/base/bean/DownloadStatus.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/base/bean/DownloadStatus.kt
new file mode 100644
index 000000000..524f5abff
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/base/bean/DownloadStatus.kt
@@ -0,0 +1,28 @@
+package com.tongdaxing.erban.upgrade.base.bean
+
+import java.io.File
+
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.base.bean
+ * FileName: DownloadStatus
+ * CreateDate: 2022/4/14 on 11:18
+ * Desc:
+ *
+ * @author azhon
+ */
+
+
+sealed class DownloadStatus {
+
+ object Start : DownloadStatus()
+
+ data class Downloading(val max: Int, val progress: Int) : DownloadStatus()
+
+ class Done(val apk: File) : DownloadStatus()
+
+ object Cancel : DownloadStatus()
+
+ data class Error(val e: Throwable) : DownloadStatus()
+}
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/config/AppUpdateFileProvider.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/config/AppUpdateFileProvider.kt
new file mode 100644
index 000000000..0a173ee5e
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/config/AppUpdateFileProvider.kt
@@ -0,0 +1,16 @@
+package com.tongdaxing.erban.upgrade.config
+
+import androidx.core.content.FileProvider
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.config
+ * FileName: AppUpdateFileProvider
+ * CreateDate: 2022/4/7 on 10:30
+ * Desc:
+ *
+ * @author azhon
+ */
+
+
+class AppUpdateFileProvider : FileProvider()
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/config/Constant.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/config/Constant.kt
new file mode 100644
index 000000000..426b63f59
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/config/Constant.kt
@@ -0,0 +1,59 @@
+package com.tongdaxing.erban.upgrade.config
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.config
+ * FileName: Constant
+ * CreateDate: 2022/4/7 on 10:28
+ * Desc:
+ *
+ * @author azhon
+ */
+
+object Constant {
+
+ /**
+ * Http timeout(ms)
+ */
+ const val HTTP_TIME_OUT = 30_000
+
+ /**
+ * Logcat tag
+ */
+ const val TAG = "AppUpdate."
+
+ /**
+ * Apk file extension
+ */
+ const val APK_SUFFIX = ".apk"
+
+ /**
+ * Coroutine Name
+ */
+ const val COROUTINE_NAME = "app-update-coroutine"
+
+ /**
+ * Notification channel id
+ */
+ const val DEFAULT_CHANNEL_ID = "appUpdate"
+
+ /**
+ * Notification id
+ */
+ const val DEFAULT_NOTIFY_ID = 1011
+
+ /**
+ * Notification channel name
+ */
+ const val DEFAULT_CHANNEL_NAME = "AppUpdate"
+
+ /**
+ * Compat Android N file uri
+ */
+ var AUTHORITIES: String? = null
+
+ /**
+ * Apk path
+ */
+ var APK_PATH = "/storage/emulated/0/Android/data/%s/cache"
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/LifecycleCallbacksAdapter.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/LifecycleCallbacksAdapter.kt
new file mode 100644
index 000000000..e897b2ef8
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/LifecycleCallbacksAdapter.kt
@@ -0,0 +1,40 @@
+package com.tongdaxing.erban.upgrade.listener
+
+import android.app.Activity
+import android.app.Application
+import android.os.Bundle
+
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.listener
+ * FileName: LifecycleCallbacksAdapter
+ * CreateDate: 2022/4/8 on 11:26
+ * Desc:
+ *
+ * @author azhon
+ */
+
+abstract class LifecycleCallbacksAdapter : Application.ActivityLifecycleCallbacks {
+
+ override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
+ }
+
+ override fun onActivityStarted(activity: Activity) {
+ }
+
+ override fun onActivityResumed(activity: Activity) {
+ }
+
+ override fun onActivityPaused(activity: Activity) {
+ }
+
+ override fun onActivityStopped(activity: Activity) {
+ }
+
+ override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
+ }
+
+ override fun onActivityDestroyed(activity: Activity) {
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/OnButtonClickListener.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/OnButtonClickListener.kt
new file mode 100644
index 000000000..95283d9a0
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/OnButtonClickListener.kt
@@ -0,0 +1,28 @@
+package com.tongdaxing.erban.upgrade.listener
+
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.listener
+ * FileName: OnButtonClickListener
+ * CreateDate: 2022/4/7 on 15:56
+ * Desc:
+ *
+ * @author azhon
+ */
+
+interface OnButtonClickListener {
+ companion object {
+ /**
+ * click update button
+ */
+ const val UPDATE = 0
+
+ /**
+ * click cancel button
+ */
+ const val CANCEL = 1
+ }
+
+ fun onButtonClick(id: Int)
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/OnDownloadListener.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/OnDownloadListener.kt
new file mode 100644
index 000000000..94a245210
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/OnDownloadListener.kt
@@ -0,0 +1,43 @@
+package com.tongdaxing.erban.upgrade.listener
+
+import java.io.File
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.listener
+ * FileName: OnDownloadListener
+ * CreateDate: 2022/4/7 on 10:27
+ * Desc:
+ *
+ * @author azhon
+ */
+
+interface OnDownloadListener {
+ /**
+ * start download
+ */
+ fun start()
+
+ /**
+ *
+ * @param max file length
+ * @param progress downloaded file size
+ */
+ fun downloading(max: Int, progress: Int)
+
+ /**
+ * @param apk
+ */
+ fun done(apk: File)
+
+ /**
+ * cancel download
+ */
+ fun cancel()
+
+ /**
+ *
+ * @param e
+ */
+ fun error(e: Throwable)
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/OnDownloadListenerAdapter.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/OnDownloadListenerAdapter.kt
new file mode 100644
index 000000000..34eaf6c09
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/listener/OnDownloadListenerAdapter.kt
@@ -0,0 +1,31 @@
+package com.tongdaxing.erban.upgrade.listener
+
+import java.io.File
+
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.listener
+ * FileName: OnDownloadListenerAdapter
+ * CreateDate: 2022/4/8 on 10:58
+ * Desc:
+ *
+ * @author azhon
+ */
+
+abstract class OnDownloadListenerAdapter : OnDownloadListener {
+ override fun start() {
+ }
+
+ override fun downloading(max: Int, progress: Int) {
+ }
+
+ override fun done(apk: File) {
+ }
+
+ override fun cancel() {
+ }
+
+ override fun error(e: Throwable) {
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/manager/DownloadManager.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/manager/DownloadManager.kt
new file mode 100644
index 000000000..eb6ebcca5
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/manager/DownloadManager.kt
@@ -0,0 +1,441 @@
+package com.tongdaxing.erban.upgrade.manager
+
+import android.app.Activity
+import android.app.Application
+import android.app.NotificationChannel
+import android.content.Intent
+import android.widget.Toast
+import com.mango.moshen.R
+import com.tongdaxing.erban.upgrade.base.BaseHttpDownloadManager
+import com.tongdaxing.erban.upgrade.config.Constant
+import com.tongdaxing.erban.upgrade.listener.LifecycleCallbacksAdapter
+import com.tongdaxing.erban.upgrade.listener.OnButtonClickListener
+import com.tongdaxing.erban.upgrade.listener.OnDownloadListener
+import com.tongdaxing.erban.upgrade.service.DownloadService
+import com.tongdaxing.erban.upgrade.util.ApkUtil
+import com.tongdaxing.erban.upgrade.util.LogUtil
+import com.tongdaxing.erban.upgrade.view.UpdateDialogActivity
+import java.io.Serializable
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.manager
+ * FileName: DownloadManager
+ * CreateDate: 2022/4/7 on 10:36
+ * Desc:
+ *
+ * @author azhon
+ */
+class DownloadManager private constructor(builder: Builder) : Serializable {
+
+ companion object {
+ private const val TAG = "DownloadManager"
+ private var instance: DownloadManager? = null
+
+ fun getInstance(builder: Builder? = null): DownloadManager? {
+ if (instance != null && builder != null) {
+ instance!!.release()
+ }
+ if (instance == null) {
+ if (builder == null) return null
+ instance = DownloadManager(builder)
+ }
+ return instance!!
+ }
+ }
+
+ var application: Application = builder.application
+ var contextClsName: String = builder.contextClsName
+ var downloadState: Boolean = false
+ var apkUrl: String
+ var apkName: String
+ var apkVersionCode: Int
+ var apkVersionName: String
+ var downloadPath: String
+ var showNewerToast: Boolean
+ var smallIcon: Int
+ var apkDescription: String
+ var apkSize: String
+ var apkMD5: String
+ var httpManager: BaseHttpDownloadManager?
+ var notificationChannel: NotificationChannel?
+ var onDownloadListeners: MutableList
+ var onButtonClickListener: OnButtonClickListener?
+ var showNotification: Boolean
+ var jumpInstallPage: Boolean
+ var showBgdToast: Boolean
+ var forcedUpgrade: Boolean
+ var notifyId: Int
+ var dialogImage: Int
+ var dialogButtonColor: Int
+ var dialogButtonTextColor: Int
+ var dialogProgressBarColor: Int
+
+
+ init {
+ apkUrl = builder.apkUrl
+ apkName = builder.apkName
+ apkVersionCode = builder.apkVersionCode
+ apkVersionName = builder.apkVersionName
+ downloadPath =
+ builder.downloadPath ?: String.format(Constant.APK_PATH, application.packageName)
+ showNewerToast = builder.showNewerToast
+ smallIcon = builder.smallIcon
+ apkDescription = builder.apkDescription
+ apkSize = builder.apkSize
+ apkMD5 = builder.apkMD5
+ httpManager = builder.httpManager
+ notificationChannel = builder.notificationChannel
+ onDownloadListeners = builder.onDownloadListeners
+ onButtonClickListener = builder.onButtonClickListener
+ showNotification = builder.showNotification
+ jumpInstallPage = builder.jumpInstallPage
+ showBgdToast = builder.showBgdToast
+ forcedUpgrade = builder.forcedUpgrade
+ notifyId = builder.notifyId
+ dialogImage = builder.dialogImage
+ dialogButtonColor = builder.dialogButtonColor
+ dialogButtonTextColor = builder.dialogButtonTextColor
+ dialogProgressBarColor = builder.dialogProgressBarColor
+ // Fix memory leak
+ application.registerActivityLifecycleCallbacks(object : LifecycleCallbacksAdapter() {
+ override fun onActivityDestroyed(activity: Activity) {
+ super.onActivityDestroyed(activity)
+ if (contextClsName == activity.javaClass.name) {
+ clearListener()
+ }
+ }
+ })
+ }
+
+ /**
+ * Start download
+ */
+ fun download() {
+ if (!checkParams()) {
+ return
+ }
+ if (checkVersionCode()) {
+ application.startService(Intent(application, DownloadService::class.java))
+ } else {
+ if (apkVersionCode > ApkUtil.getVersionCode(application)) {
+ application.startActivity(
+ Intent(application, UpdateDialogActivity::class.java)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ )
+ } else {
+ if (showNewerToast) {
+ Toast.makeText(application, R.string.latest_version, Toast.LENGTH_SHORT).show()
+ }
+ LogUtil.d(TAG, application.resources.getString(R.string.latest_version))
+ }
+ }
+
+ }
+
+ private fun checkParams(): Boolean {
+ if (apkUrl.isEmpty()) {
+ LogUtil.e(TAG, "apkUrl can not be empty!")
+ return false
+ }
+ if (apkName.isEmpty()) {
+ LogUtil.e(TAG, "apkName can not be empty!")
+ return false
+ }
+ if (!apkName.endsWith(Constant.APK_SUFFIX)) {
+ LogUtil.e(TAG, "apkName must endsWith .apk!")
+ return false
+ }
+ if (smallIcon == -1) {
+ LogUtil.e(TAG, "smallIcon can not be empty!");
+ return false
+ }
+ Constant.AUTHORITIES = "${application.packageName}.fileProvider"
+ return true
+ }
+
+ /**
+ * Check the set apkVersionCode if it is not the default then use the built-in dialog
+ * If it is the default value Int.MIN_VALUE, directly start the service download
+ */
+ private fun checkVersionCode(): Boolean {
+ if (apkVersionCode == Int.MIN_VALUE) {
+ return true
+ }
+ if (apkDescription.isEmpty()) {
+ LogUtil.e(TAG, "apkDescription can not be empty!")
+ }
+ return false
+ }
+
+ fun cancel() {
+ httpManager?.cancel()
+ }
+
+ /**
+ * release objects
+ */
+ internal fun release() {
+ httpManager?.release()
+ clearListener()
+ instance = null
+ }
+
+ private fun clearListener() {
+ onButtonClickListener = null
+ onDownloadListeners.clear()
+ }
+
+ class Builder constructor(activity: Activity) {
+
+ /**
+ * library context
+ */
+ internal var application: Application = activity.application
+
+ /**
+ * Fix the memory leak caused by Activity destroy
+ */
+ internal var contextClsName: String = activity.javaClass.name
+
+ /**
+ * Apk download url
+ */
+ internal var apkUrl = ""
+
+ /**
+ * Apk file name on disk
+ */
+ internal var apkName = ""
+
+ /**
+ * The apk versionCode that needs to be downloaded
+ */
+ internal var apkVersionCode = Int.MIN_VALUE
+
+ /**
+ * The versionName of the dialog reality
+ */
+ internal var apkVersionName = ""
+
+ /**
+ * The file path where the Apk is saved
+ * eg: /storage/emulated/0/Android/data/ your packageName /cache
+ */
+ internal var downloadPath = application.externalCacheDir?.path
+
+ /**
+ * whether to tip to user "Currently the latest version!"
+ */
+ internal var showNewerToast = false
+
+ /**
+ * Notification icon resource
+ */
+ internal var smallIcon = -1
+
+ /**
+ * New version description information
+ */
+ internal var apkDescription = ""
+
+ /**
+ * Apk Size,Unit MB
+ */
+ internal var apkSize = ""
+
+ /**
+ * Apk md5 file verification(32-bit) verification repeated download
+ */
+ internal var apkMD5 = ""
+
+ /**
+ * Apk download manager
+ */
+ internal var httpManager: BaseHttpDownloadManager? = null
+
+ /**
+ * The following are unimportant filed
+ */
+
+ /**
+ * adapter above Android O notification
+ */
+ internal var notificationChannel: NotificationChannel? = null
+
+ /**
+ * download listeners
+ */
+ internal var onDownloadListeners = mutableListOf()
+
+ /**
+ * dialog button click listener
+ */
+ internal var onButtonClickListener: OnButtonClickListener? = null
+
+ /**
+ * Whether to show the progress of the notification
+ */
+ internal var showNotification = true
+
+ /**
+ * Whether the installation page will pop up automatically after the download is complete
+ */
+ internal var jumpInstallPage = true
+
+ /**
+ * Does the download start tip "Downloading a new version in the background..."
+ */
+ internal var showBgdToast = true
+
+ /**
+ * Whether to force an upgrade
+ */
+ internal var forcedUpgrade = false
+
+ /**
+ * Notification id
+ */
+ internal var notifyId = Constant.DEFAULT_NOTIFY_ID
+
+ /**
+ * dialog background Image resource
+ */
+ internal var dialogImage = -1
+
+ /**
+ * dialog button background color
+ */
+ internal var dialogButtonColor = -1
+
+ /**
+ * dialog button text color
+ */
+ internal var dialogButtonTextColor = -1
+
+ /**
+ * dialog progress bar color and progress-text color
+ */
+ internal var dialogProgressBarColor = -1
+
+
+ fun apkUrl(apkUrl: String): Builder {
+ this.apkUrl = apkUrl
+ return this
+ }
+
+ fun apkName(apkName: String): Builder {
+ this.apkName = apkName
+ return this
+ }
+
+ fun apkVersionCode(apkVersionCode: Int): Builder {
+ this.apkVersionCode = apkVersionCode
+ return this
+ }
+
+ fun apkVersionName(apkVersionName: String): Builder {
+ this.apkVersionName = apkVersionName
+ return this
+ }
+
+ fun showNewerToast(showNewerToast: Boolean): Builder {
+ this.showNewerToast = showNewerToast
+ return this
+ }
+
+ fun smallIcon(smallIcon: Int): Builder {
+ this.smallIcon = smallIcon
+ return this
+ }
+
+ fun apkDescription(apkDescription: String): Builder {
+ this.apkDescription = apkDescription
+ return this
+ }
+
+ fun apkSize(apkSize: String): Builder {
+ this.apkSize = apkSize
+ return this
+ }
+
+ fun apkMD5(apkMD5: String): Builder {
+ this.apkMD5 = apkMD5
+ return this
+ }
+
+ fun httpManager(httpManager: BaseHttpDownloadManager): Builder {
+ this.httpManager = httpManager
+ return this
+ }
+
+ fun notificationChannel(notificationChannel: NotificationChannel): Builder {
+ this.notificationChannel = notificationChannel
+ return this
+ }
+
+ fun onButtonClickListener(onButtonClickListener: OnButtonClickListener): Builder {
+ this.onButtonClickListener = onButtonClickListener
+ return this
+ }
+
+ fun onDownloadListener(onDownloadListener: OnDownloadListener): Builder {
+ this.onDownloadListeners.add(onDownloadListener)
+ return this
+ }
+
+ fun showNotification(showNotification: Boolean): Builder {
+ this.showNotification = showNotification
+ return this
+ }
+
+ fun jumpInstallPage(jumpInstallPage: Boolean): Builder {
+ this.jumpInstallPage = jumpInstallPage
+ return this
+ }
+
+ fun showBgdToast(showBgdToast: Boolean): Builder {
+ this.showBgdToast = showBgdToast
+ return this
+ }
+
+ fun forcedUpgrade(forcedUpgrade: Boolean): Builder {
+ this.forcedUpgrade = forcedUpgrade
+ return this
+ }
+
+ fun notifyId(notifyId: Int): Builder {
+ this.notifyId = notifyId
+ return this
+ }
+
+ fun dialogImage(dialogImage: Int): Builder {
+ this.dialogImage = dialogImage
+ return this
+ }
+
+ fun dialogButtonColor(dialogButtonColor: Int): Builder {
+ this.dialogButtonColor = dialogButtonColor
+ return this
+ }
+
+ fun dialogButtonTextColor(dialogButtonTextColor: Int): Builder {
+ this.dialogButtonTextColor = dialogButtonTextColor
+ return this
+ }
+
+ fun dialogProgressBarColor(dialogProgressBarColor: Int): Builder {
+ this.dialogProgressBarColor = dialogProgressBarColor
+ return this
+ }
+
+ fun enableLog(enable: Boolean): Builder {
+ LogUtil.enable(enable)
+ return this
+ }
+
+ fun build(): DownloadManager {
+ return getInstance(this)!!
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/manager/HttpDownloadManager.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/manager/HttpDownloadManager.kt
new file mode 100644
index 000000000..b3bc754cd
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/manager/HttpDownloadManager.kt
@@ -0,0 +1,135 @@
+package com.tongdaxing.erban.upgrade.manager
+
+import com.tongdaxing.erban.upgrade.base.BaseHttpDownloadManager
+import com.tongdaxing.erban.upgrade.base.bean.DownloadStatus
+import com.tongdaxing.erban.upgrade.config.Constant
+import com.tongdaxing.erban.upgrade.util.LogUtil
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.*
+import java.io.File
+import java.io.FileOutputStream
+import java.net.HttpURLConnection
+import java.net.SocketTimeoutException
+import java.net.URL
+import java.security.SecureRandom
+import java.security.cert.X509Certificate
+import javax.net.ssl.HttpsURLConnection
+import javax.net.ssl.SSLContext
+import javax.net.ssl.TrustManager
+import javax.net.ssl.X509TrustManager
+
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.manager
+ * FileName: HttpDownloadManager
+ * CreateDate: 2022/4/7 on 14:29
+ * Desc:
+ *
+ * @author azhon
+ */
+
+@Suppress("BlockingMethodInNonBlockingContext")
+class HttpDownloadManager(private val path: String) : BaseHttpDownloadManager() {
+ companion object {
+ private const val TAG = "HttpDownloadManager"
+ }
+
+ private var shutdown: Boolean = false
+
+ override fun download(apkUrl: String, apkName: String): Flow {
+ trustAllHosts()
+ shutdown = false
+ File(path, apkName).let {
+ if (it.exists()) it.delete()
+ }
+ return flow {
+ emit(DownloadStatus.Start)
+ connectToDownload(apkUrl, apkName, this)
+ }.catch {
+ emit(DownloadStatus.Error(it))
+ }.flowOn(Dispatchers.IO)
+ }
+
+ private suspend fun connectToDownload(
+ apkUrl: String, apkName: String, flow: FlowCollector
+ ) {
+ val con = URL(apkUrl).openConnection() as HttpURLConnection
+ con.apply {
+ requestMethod = "GET"
+ readTimeout = Constant.HTTP_TIME_OUT
+ connectTimeout = Constant.HTTP_TIME_OUT
+ setRequestProperty("Accept-Encoding", "identity")
+ }
+ if (con.responseCode == HttpURLConnection.HTTP_OK) {
+ val inStream = con.inputStream
+ val length = con.contentLength
+ var len: Int
+ var progress = 0
+ val buffer = ByteArray(1024 * 2)
+ val file = File(path, apkName)
+ FileOutputStream(file).use { out ->
+ while (inStream.read(buffer).also { len = it } != -1 && !shutdown) {
+ out.write(buffer, 0, len)
+ progress += len
+ flow.emit(DownloadStatus.Downloading(length, progress))
+ }
+ out.flush()
+ }
+ inStream.close()
+ if (shutdown) {
+ flow.emit(DownloadStatus.Cancel)
+ } else {
+ flow.emit(DownloadStatus.Done(file))
+ }
+ } else if (con.responseCode == HttpURLConnection.HTTP_MOVED_PERM
+ || con.responseCode == HttpURLConnection.HTTP_MOVED_TEMP
+ ) {
+ con.disconnect()
+ val locationUrl = con.getHeaderField("Location")
+ LogUtil.d(
+ TAG,
+ "The current url is the redirect Url, the redirected url is $locationUrl"
+ )
+ connectToDownload(locationUrl, apkName, flow)
+ } else {
+ val e = SocketTimeoutException("Error: Http response code = ${con.responseCode}")
+ flow.emit(DownloadStatus.Error(e))
+ }
+ con.disconnect()
+ }
+
+ /**
+ * fix https url (SSLHandshakeException) exception
+ */
+ private fun trustAllHosts() {
+ val manager: TrustManager = object : X509TrustManager {
+ override fun getAcceptedIssuers(): Array {
+ return arrayOf()
+ }
+
+ override fun checkClientTrusted(chain: Array?, authType: String?) {
+ LogUtil.d(TAG, "checkClientTrusted")
+ }
+
+ override fun checkServerTrusted(chain: Array?, authType: String?) {
+ LogUtil.d(TAG, "checkServerTrusted")
+ }
+ }
+ try {
+ val sslContext = SSLContext.getInstance("TLS")
+ sslContext.init(null, arrayOf(manager), SecureRandom())
+ HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.socketFactory)
+ } catch (e: Exception) {
+ LogUtil.e(TAG, "trustAllHosts error: $e")
+ }
+ }
+
+ override fun cancel() {
+ shutdown = true
+ }
+
+ override fun release() {
+ cancel()
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/service/DownloadService.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/service/DownloadService.kt
new file mode 100644
index 000000000..5546f78fc
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/service/DownloadService.kt
@@ -0,0 +1,188 @@
+package com.tongdaxing.erban.upgrade.service
+
+import android.app.Service
+import android.content.Intent
+import android.os.Build
+import android.os.IBinder
+import android.widget.Toast
+import com.mango.moshen.R
+import com.tongdaxing.erban.upgrade.base.bean.DownloadStatus
+import com.tongdaxing.erban.upgrade.config.Constant
+import com.tongdaxing.erban.upgrade.listener.OnDownloadListener
+import com.tongdaxing.erban.upgrade.manager.DownloadManager
+import com.tongdaxing.erban.upgrade.manager.HttpDownloadManager
+import com.tongdaxing.erban.upgrade.util.ApkUtil
+import com.tongdaxing.erban.upgrade.util.FileUtil
+import com.tongdaxing.erban.upgrade.util.LogUtil
+import com.tongdaxing.erban.upgrade.util.NotificationUtil
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.collect
+import java.io.File
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.service
+ * FileName: DownloadService
+ * CreateDate: 2022/4/7 on 11:42
+ * Desc:
+ *
+ * @author azhon
+ */
+
+class DownloadService : Service(), OnDownloadListener {
+ companion object {
+ private const val TAG = "DownloadService"
+ }
+
+ private lateinit var manager: DownloadManager
+ private var lastProgress = 0
+
+ override fun onBind(intent: Intent?): IBinder? = null
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ if (intent == null) {
+ return START_NOT_STICKY
+ }
+ init()
+ return super.onStartCommand(intent, flags, startId)
+ }
+
+ private fun init() {
+ val tempManager = DownloadManager.getInstance()
+ if (tempManager == null) {
+ LogUtil.e(TAG, "An exception occurred by DownloadManager=null,please check your code!")
+ return
+ }
+ manager = tempManager
+ FileUtil.createDirDirectory(manager.downloadPath)
+
+ val enable = NotificationUtil.notificationEnable(this@DownloadService)
+ LogUtil.d(
+ TAG,
+ if (enable) "Notification switch status: opened" else " Notification switch status: closed"
+ )
+ if (checkApkMd5()) {
+ LogUtil.d(TAG, "Apk already exist and install it directly.")
+ //install apk
+ done(File(manager.downloadPath, manager.apkName))
+ } else {
+ LogUtil.d(TAG, "Apk don't exist will start download.")
+ download()
+ }
+ }
+
+ /**
+ * Check whether the Apk has been downloaded, don't download again
+ */
+ private fun checkApkMd5(): Boolean {
+ val file = File(manager.downloadPath, manager.apkName)
+ if (file.exists()) {
+ return FileUtil.md5(file).equals(manager.apkMD5, ignoreCase = true)
+ }
+ return false
+ }
+
+ @Synchronized
+ private fun download() {
+ if (manager.downloadState) {
+ LogUtil.e(TAG, "Currently downloading, please download again!")
+ return
+ }
+ if (manager.httpManager == null) {
+ manager.httpManager = HttpDownloadManager(manager.downloadPath)
+ }
+ GlobalScope.launch(Dispatchers.Main + CoroutineName(Constant.COROUTINE_NAME)) {
+ manager.httpManager!!.download(manager.apkUrl, manager.apkName)
+ .collect {
+ when (it) {
+ is DownloadStatus.Start -> start()
+ is DownloadStatus.Downloading -> downloading(it.max, it.progress)
+ is DownloadStatus.Done -> done(it.apk)
+ is DownloadStatus.Cancel -> this@DownloadService.cancel()
+ is DownloadStatus.Error -> error(it.e)
+ }
+ }
+ }
+ manager.downloadState = true
+ }
+
+ override fun start() {
+ LogUtil.i(TAG, "download start")
+ if (manager.showBgdToast) {
+ Toast.makeText(this, R.string.background_downloading, Toast.LENGTH_SHORT).show()
+ }
+ if (manager.showNotification) {
+ NotificationUtil.showNotification(
+ this@DownloadService, manager.smallIcon,
+ resources.getString(R.string.start_download),
+ resources.getString(R.string.start_download_hint)
+ )
+ }
+ manager.onDownloadListeners.forEach { it.start() }
+ }
+
+ override fun downloading(max: Int, progress: Int) {
+ if (manager.showNotification) {
+ val curr = (progress / max.toDouble() * 100.0).toInt()
+ if (curr == lastProgress) return
+ LogUtil.i(TAG, "downloading max: $max --- progress: $progress")
+ lastProgress = curr
+ val content = if (curr < 0) "" else "$curr%"
+ NotificationUtil.showProgressNotification(
+ this@DownloadService, manager.smallIcon,
+ resources.getString(R.string.start_downloading),
+ content, if (max == -1) -1 else 100, curr
+ )
+ }
+ manager.onDownloadListeners.forEach { it.downloading(max, progress) }
+ }
+
+ override fun done(apk: File) {
+ LogUtil.d(TAG, "apk downloaded to ${apk.path}")
+ manager.downloadState = false
+ //If it is android Q (api=29) and above, (showNotification=false) will also send a
+ // download completion notification
+ if (manager.showNotification || Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ NotificationUtil.showDoneNotification(
+ this@DownloadService, manager.smallIcon,
+ resources.getString(R.string.download_completed),
+ resources.getString(R.string.click_hint),
+ Constant.AUTHORITIES!!, apk
+ )
+ }
+ if (manager.jumpInstallPage) {
+ ApkUtil.installApk(this@DownloadService, Constant.AUTHORITIES!!, apk)
+ }
+ manager.onDownloadListeners.forEach { it.done(apk) }
+
+ // release objects
+ releaseResources()
+ }
+
+ override fun cancel() {
+ LogUtil.i(TAG, "download cancel")
+ manager.downloadState = false
+ if (manager.showNotification) {
+ NotificationUtil.cancelNotification(this@DownloadService)
+ }
+ manager.onDownloadListeners.forEach { it.cancel() }
+ }
+
+ override fun error(e: Throwable) {
+ LogUtil.e(TAG, "download error: $e")
+ manager.downloadState = false
+ if (manager.showNotification) {
+ NotificationUtil.showErrorNotification(
+ this@DownloadService, manager.smallIcon,
+ resources.getString(R.string.download_error),
+ resources.getString(R.string.continue_downloading),
+ )
+ }
+ manager.onDownloadListeners.forEach { it.error(e) }
+ }
+
+ private fun releaseResources() {
+ manager.release()
+ stopSelf()
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/ApkUtil.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/ApkUtil.kt
new file mode 100644
index 000000000..15c6e0450
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/ApkUtil.kt
@@ -0,0 +1,82 @@
+package com.tongdaxing.erban.upgrade.util
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import androidx.core.content.FileProvider
+import java.io.File
+
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.util
+ * FileName: ApkUtil
+ * CreateDate: 2022/4/7 on 17:02
+ * Desc:
+ *
+ * @author azhon
+ */
+
+class ApkUtil {
+ companion object {
+ /**
+ * install package form file
+ */
+ fun installApk(context: Context, authorities: String, apk: File) {
+ context.startActivity(createInstallIntent(context, authorities, apk))
+ }
+
+ fun createInstallIntent(context: Context, authorities: String, apk: File): Intent {
+ val intent = Intent().apply {
+ action = Intent.ACTION_VIEW
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ addCategory(Intent.CATEGORY_DEFAULT)
+ }
+ val uri: Uri
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ uri = FileProvider.getUriForFile(context, authorities, apk)
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ } else {
+ uri = Uri.fromFile(apk)
+ }
+ intent.setDataAndType(uri, "application/vnd.android.package-archive")
+ return intent
+ }
+
+ fun getVersionCode(context: Context): Long {
+ val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ packageInfo.longVersionCode
+ } else {
+ return packageInfo.versionCode.toLong()
+ }
+ }
+
+ fun deleteOldApk(context: Context, oldApkPath: String): Boolean {
+ val curVersionCode = getVersionCode(context)
+ try {
+ val apk = File(oldApkPath)
+ if (apk.exists()) {
+ val oldVersionCode = getVersionCodeByPath(context, oldApkPath)
+ if (curVersionCode > oldVersionCode) {
+ return apk.delete()
+ }
+ }
+ } catch (e: Exception) {
+ }
+ return false
+ }
+
+ private fun getVersionCodeByPath(context: Context, path: String): Long {
+ val packageInfo =
+ context.packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES)
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ packageInfo?.longVersionCode ?: 1
+ } else {
+ return packageInfo?.versionCode?.toLong() ?: 1
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/DensityUtil.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/DensityUtil.kt
new file mode 100644
index 000000000..7edc5b07e
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/DensityUtil.kt
@@ -0,0 +1,23 @@
+package com.tongdaxing.erban.upgrade.util
+
+import android.content.Context
+
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.util
+ * FileName: DensityUtil
+ * CreateDate: 2022/4/7 on 17:52
+ * Desc:
+ *
+ * @author azhon
+ */
+
+class DensityUtil {
+ companion object {
+ fun dip2px(context: Context, dpValue: Float): Float {
+ val scale = context.resources.displayMetrics.density
+ return dpValue * scale + 0.5f
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/FileUtil.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/FileUtil.kt
new file mode 100644
index 000000000..c16d3f5ea
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/FileUtil.kt
@@ -0,0 +1,47 @@
+package com.tongdaxing.erban.upgrade.util
+
+import java.io.File
+import java.io.FileInputStream
+import java.math.BigInteger
+import java.security.MessageDigest
+import java.util.*
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.util
+ * FileName: FileUtil
+ * CreateDate: 2022/4/7 on 11:52
+ * Desc:
+ *
+ * @author azhon
+ */
+
+class FileUtil {
+ companion object {
+ fun createDirDirectory(path: String) {
+ File(path).let {
+ if (!it.exists()) {
+ it.mkdirs()
+ }
+ }
+ }
+
+ fun md5(file: File): String {
+ try {
+ val buffer = ByteArray(1024)
+ var len: Int
+ val digest = MessageDigest.getInstance("MD5")
+ val inStream = FileInputStream(file)
+ while (inStream.read(buffer).also { len = it } != -1) {
+ digest.update(buffer, 0, len)
+ }
+ inStream.close()
+ val bigInt = BigInteger(1, digest.digest())
+ return bigInt.toString(16).toUpperCase(Locale.ROOT)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ return ""
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/LogUtil.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/LogUtil.kt
new file mode 100644
index 000000000..32e20d4e8
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/LogUtil.kt
@@ -0,0 +1,39 @@
+package com.tongdaxing.erban.upgrade.util
+
+import android.util.Log
+import com.tongdaxing.erban.upgrade.config.Constant
+
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.util
+ * FileName: LogUtil
+ * CreateDate: 2022/4/7 on 11:23
+ * Desc:
+ *
+ * @author azhon
+ */
+
+class LogUtil {
+
+ companion object {
+ var b = true
+
+ fun enable(enable: Boolean) {
+ b = enable
+ }
+
+ fun e(tag: String, msg: String) {
+ if (b) Log.e(Constant.TAG + tag, msg)
+ }
+
+ fun d(tag: String, msg: String) {
+ if (b) Log.d(Constant.TAG + tag, msg)
+ }
+
+ fun i(tag: String, msg: String) {
+ if (b) Log.i(Constant.TAG + tag, msg)
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/NotificationUtil.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/NotificationUtil.kt
new file mode 100644
index 000000000..7f65c8dda
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/util/NotificationUtil.kt
@@ -0,0 +1,163 @@
+package com.tongdaxing.erban.upgrade.util
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import androidx.annotation.RequiresApi
+import androidx.core.app.NotificationCompat
+import androidx.core.app.NotificationManagerCompat
+import com.tongdaxing.erban.upgrade.config.Constant
+import com.tongdaxing.erban.upgrade.manager.DownloadManager
+import com.tongdaxing.erban.upgrade.service.DownloadService
+import java.io.File
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.util
+ * FileName: NotificationUtil
+ * CreateDate: 2022/4/7 on 13:36
+ * Desc:
+ *
+ * @author azhon
+ */
+class NotificationUtil {
+ companion object {
+
+ fun notificationEnable(context: Context): Boolean {
+ return NotificationManagerCompat.from(context).areNotificationsEnabled()
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.O)
+ private fun getNotificationChannelId(): String {
+ val channel = DownloadManager.getInstance()?.notificationChannel
+ return if (channel == null) {
+ Constant.DEFAULT_CHANNEL_ID
+ } else {
+ channel.id
+ }
+ }
+
+ private fun builderNotification(
+ context: Context, icon: Int, title: String, content: String
+ ): NotificationCompat.Builder {
+ var channelId = ""
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ channelId = getNotificationChannelId()
+ }
+ return NotificationCompat.Builder(context, channelId)
+ .setSmallIcon(icon)
+ .setContentTitle(title)
+ .setWhen(System.currentTimeMillis())
+ .setContentText(content)
+ .setAutoCancel(false)
+ .setOngoing(true)
+ }
+
+ fun showNotification(context: Context, icon: Int, title: String, content: String) {
+ val manager =
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ afterO(manager)
+ }
+ val notify = builderNotification(context, icon, title, content)
+ .setDefaults(Notification.DEFAULT_SOUND)
+ .build()
+ manager.notify(
+ DownloadManager.getInstance()?.notifyId ?: Constant.DEFAULT_NOTIFY_ID,
+ notify
+ )
+ }
+
+ /**
+ * send a downloading Notification
+ */
+ fun showProgressNotification(
+ context: Context, icon: Int, title: String, content: String, max: Int, progress: Int
+ ) {
+ val manager =
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ val notify = builderNotification(context, icon, title, content)
+ .setProgress(max, progress, max == -1).build()
+ manager.notify(
+ DownloadManager.getInstance()?.notifyId ?: Constant.DEFAULT_NOTIFY_ID,
+ notify
+ )
+ }
+
+ /**
+ * send a downloaded Notification
+ */
+ fun showDoneNotification(
+ context: Context, icon: Int, title: String, content: String,
+ authorities: String, apk: File
+ ) {
+ val manager =
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ manager.cancel(DownloadManager.getInstance()?.notifyId ?: Constant.DEFAULT_NOTIFY_ID)
+ val intent = ApkUtil.createInstallIntent(context, authorities, apk)
+ val pi = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ val notify = builderNotification(context, icon, title, content)
+ .setContentIntent(pi)
+ .build()
+ notify.flags = notify.flags or Notification.FLAG_AUTO_CANCEL
+ manager.notify(
+ DownloadManager.getInstance()?.notifyId ?: Constant.DEFAULT_NOTIFY_ID,
+ notify
+ )
+ }
+
+ /**
+ * send a error Notification
+ */
+ fun showErrorNotification(
+ context: Context, icon: Int, title: String, content: String
+ ) {
+ val manager =
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ afterO(manager)
+ }
+ val intent = Intent(context, DownloadService::class.java)
+ val pi = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
+ val notify = builderNotification(context, icon, title, content)
+ .setAutoCancel(true)
+ .setOngoing(false)
+ .setContentIntent(pi)
+ .setDefaults(Notification.DEFAULT_SOUND)
+ .build()
+ manager.notify(
+ DownloadManager.getInstance()?.notifyId ?: Constant.DEFAULT_NOTIFY_ID,
+ notify
+ )
+ }
+
+ /**
+ * cancel Notification by id
+ */
+ fun cancelNotification(context: Context) {
+ val manager =
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ manager.cancel(DownloadManager.getInstance()?.notifyId ?: Constant.DEFAULT_NOTIFY_ID)
+
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.O)
+ private fun afterO(manager: NotificationManager) {
+ var channel = DownloadManager.getInstance()?.notificationChannel
+ if (channel == null) {
+ channel = NotificationChannel(
+ Constant.DEFAULT_CHANNEL_ID, Constant.DEFAULT_CHANNEL_NAME,
+ NotificationManager.IMPORTANCE_LOW
+ ).apply {
+ enableLights(true)
+ setShowBadge(true)
+ }
+ }
+ manager.createNotificationChannel(channel)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/view/NumberProgressBar.java b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/view/NumberProgressBar.java
new file mode 100644
index 000000000..4f6a3fa4a
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/view/NumberProgressBar.java
@@ -0,0 +1,479 @@
+package com.tongdaxing.erban.upgrade.view;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.mango.moshen.R;
+
+
+/**
+ * Created by daimajia on 14-4-30.
+ *
+ */
+public class NumberProgressBar extends View {
+
+ private int mMaxProgress = 100;
+
+ /**
+ * Current progress, can not exceed the max progress.
+ */
+ private int mCurrentProgress = 0;
+
+ /**
+ * The progress area bar color.
+ */
+ private int mReachedBarColor;
+
+ /**
+ * The bar unreached area color.
+ */
+ private int mUnreachedBarColor;
+
+ /**
+ * The progress text color.
+ */
+ private int mTextColor;
+
+ /**
+ * The progress text size.
+ */
+ private float mTextSize;
+
+ /**
+ * The height of the reached area.
+ */
+ private float mReachedBarHeight;
+
+ /**
+ * The height of the unreached area.
+ */
+ private float mUnreachedBarHeight;
+
+ /**
+ * The suffix of the number.
+ */
+ private String mSuffix = "%";
+
+ /**
+ * The prefix.
+ */
+ private String mPrefix = "";
+
+
+ private final int default_text_color = Color.rgb(255, 137, 91);
+ private final int default_reached_color = Color.rgb(255, 137, 91);
+ private final int default_unreached_color = Color.rgb(204, 204, 204);
+ private final float default_progress_text_offset;
+ private final float default_text_size;
+
+ /**
+ * For save and restore instance of progressbar.
+ */
+ private static final String INSTANCE_STATE = "saved_instance";
+ private static final String INSTANCE_TEXT_COLOR = "text_color";
+ private static final String INSTANCE_TEXT_SIZE = "text_size";
+ private static final String INSTANCE_REACHED_BAR_HEIGHT = "reached_bar_height";
+ private static final String INSTANCE_REACHED_BAR_COLOR = "reached_bar_color";
+ private static final String INSTANCE_UNREACHED_BAR_HEIGHT = "unreached_bar_height";
+ private static final String INSTANCE_UNREACHED_BAR_COLOR = "unreached_bar_color";
+ private static final String INSTANCE_MAX = "max";
+ private static final String INSTANCE_PROGRESS = "progress";
+ private static final String INSTANCE_SUFFIX = "suffix";
+ private static final String INSTANCE_PREFIX = "prefix";
+ private static final String INSTANCE_TEXT_VISIBILITY = "text_visibility";
+
+ private static final int PROGRESS_TEXT_VISIBLE = 0;
+
+
+ /**
+ * The width of the text that to be drawn.
+ */
+ private float mDrawTextWidth;
+
+ /**
+ * The drawn text start.
+ */
+ private float mDrawTextStart;
+
+ /**
+ * The drawn text end.
+ */
+ private float mDrawTextEnd;
+
+ /**
+ * The text that to be drawn in onDraw().
+ */
+ private String mCurrentDrawText;
+
+ /**
+ * The Paint of the reached area.
+ */
+ private Paint mReachedBarPaint;
+ /**
+ * The Paint of the unreached area.
+ */
+ private Paint mUnreachedBarPaint;
+ /**
+ * The Paint of the progress text.
+ */
+ private Paint mTextPaint;
+
+ /**
+ * Unreached bar area to draw rect.
+ */
+ private RectF mUnreachedRectF = new RectF(0, 0, 0, 0);
+ /**
+ * Reached bar area rect.
+ */
+ private RectF mReachedRectF = new RectF(0, 0, 0, 0);
+
+ /**
+ * The progress text offset.
+ */
+ private float mOffset;
+
+ /**
+ * Determine if need to draw unreached area.
+ */
+ private boolean mDrawUnreachedBar = true;
+
+ private boolean mDrawReachedBar = true;
+
+ private boolean mIfDrawText = true;
+
+ public enum ProgressTextVisibility {
+ Visible, Invisible
+ }
+
+ public NumberProgressBar(Context context) {
+ this(context, null);
+ }
+
+ public NumberProgressBar(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NumberProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ mReachedBarHeight = dp2px(1.5f);
+ mUnreachedBarHeight = dp2px(1.0f);
+ default_text_size = sp2px(10);
+ default_progress_text_offset = dp2px(3.0f);
+
+ //load styled attributes.
+ final TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.NumberProgressBar,
+ defStyleAttr, 0);
+
+ mReachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_reached_color, default_reached_color);
+ mUnreachedBarColor = attributes.getColor(R.styleable.NumberProgressBar_progress_unreached_color, default_unreached_color);
+ mTextColor = attributes.getColor(R.styleable.NumberProgressBar_progress_text_color, default_text_color);
+ mTextSize = attributes.getDimension(R.styleable.NumberProgressBar_progress_text_size, default_text_size);
+ attributes.recycle();
+ initializePainters();
+ }
+
+ @Override
+ protected int getSuggestedMinimumWidth() {
+ return (int) mTextSize;
+ }
+
+ @Override
+ protected int getSuggestedMinimumHeight() {
+ return Math.max((int) mTextSize, Math.max((int) mReachedBarHeight, (int) mUnreachedBarHeight));
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(measure(widthMeasureSpec, true), measure(heightMeasureSpec, false));
+ }
+
+ private int measure(int measureSpec, boolean isWidth) {
+ int result;
+ int mode = MeasureSpec.getMode(measureSpec);
+ int size = MeasureSpec.getSize(measureSpec);
+ int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom();
+ if (mode == MeasureSpec.EXACTLY) {
+ result = size;
+ } else {
+ result = isWidth ? getSuggestedMinimumWidth() : getSuggestedMinimumHeight();
+ result += padding;
+ if (mode == MeasureSpec.AT_MOST) {
+ if (isWidth) {
+ result = Math.max(result, size);
+ } else {
+ result = Math.min(result, size);
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mIfDrawText) {
+ calculateDrawRectF();
+ } else {
+ calculateDrawRectFWithoutProgressText();
+ }
+
+ if (mDrawReachedBar) {
+ canvas.drawRect(mReachedRectF, mReachedBarPaint);
+ }
+
+ if (mDrawUnreachedBar) {
+ canvas.drawRect(mUnreachedRectF, mUnreachedBarPaint);
+ }
+
+ if (mIfDrawText)
+ canvas.drawText(mCurrentDrawText, mDrawTextStart, mDrawTextEnd, mTextPaint);
+ }
+
+ private void initializePainters() {
+ mReachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mReachedBarPaint.setColor(mReachedBarColor);
+
+ mUnreachedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mUnreachedBarPaint.setColor(mUnreachedBarColor);
+
+ mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mTextPaint.setColor(mTextColor);
+ mTextPaint.setTextSize(mTextSize);
+ }
+
+
+ private void calculateDrawRectFWithoutProgressText() {
+ mReachedRectF.left = getPaddingLeft();
+ mReachedRectF.top = getHeight() / 2.0f - mReachedBarHeight / 2.0f;
+ mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight()) / (getMax() * 1.0f) * getProgress() + getPaddingLeft();
+ mReachedRectF.bottom = getHeight() / 2.0f + mReachedBarHeight / 2.0f;
+
+ mUnreachedRectF.left = mReachedRectF.right;
+ mUnreachedRectF.right = getWidth() - getPaddingRight();
+ mUnreachedRectF.top = getHeight() / 2.0f + -mUnreachedBarHeight / 2.0f;
+ mUnreachedRectF.bottom = getHeight() / 2.0f + mUnreachedBarHeight / 2.0f;
+ }
+
+ private void calculateDrawRectF() {
+
+ mCurrentDrawText = String.format("%d", getProgress() * 100 / getMax());
+ mCurrentDrawText = mPrefix + mCurrentDrawText + mSuffix;
+ mDrawTextWidth = mTextPaint.measureText(mCurrentDrawText);
+
+ if (getProgress() == 0) {
+ mDrawReachedBar = false;
+ mDrawTextStart = getPaddingLeft();
+ } else {
+ mDrawReachedBar = true;
+ mReachedRectF.left = getPaddingLeft();
+ mReachedRectF.top = getHeight() / 2.0f - mReachedBarHeight / 2.0f;
+ mReachedRectF.right = (getWidth() - getPaddingLeft() - getPaddingRight()) / (getMax() * 1.0f) * getProgress() - mOffset + getPaddingLeft();
+ mReachedRectF.bottom = getHeight() / 2.0f + mReachedBarHeight / 2.0f;
+ mDrawTextStart = (mReachedRectF.right + mOffset);
+ }
+
+ mDrawTextEnd = (int) ((getHeight() / 2.0f) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2.0f));
+
+ if ((mDrawTextStart + mDrawTextWidth) >= getWidth() - getPaddingRight()) {
+ mDrawTextStart = getWidth() - getPaddingRight() - mDrawTextWidth;
+ mReachedRectF.right = mDrawTextStart - mOffset;
+ }
+
+ float unreachedBarStart = mDrawTextStart + mDrawTextWidth + mOffset;
+ if (unreachedBarStart >= getWidth() - getPaddingRight()) {
+ mDrawUnreachedBar = false;
+ } else {
+ mDrawUnreachedBar = true;
+ mUnreachedRectF.left = unreachedBarStart;
+ mUnreachedRectF.right = getWidth() - getPaddingRight();
+ mUnreachedRectF.top = getHeight() / 2.0f + -mUnreachedBarHeight / 2.0f;
+ mUnreachedRectF.bottom = getHeight() / 2.0f + mUnreachedBarHeight / 2.0f;
+ }
+ }
+
+ /**
+ * Get progress text color.
+ *
+ * @return progress text color.
+ */
+ public int getTextColor() {
+ return mTextColor;
+ }
+
+ /**
+ * Get progress text size.
+ *
+ * @return progress text size.
+ */
+ public float getProgressTextSize() {
+ return mTextSize;
+ }
+
+ public int getUnreachedBarColor() {
+ return mUnreachedBarColor;
+ }
+
+ public int getReachedBarColor() {
+ return mReachedBarColor;
+ }
+
+ public int getProgress() {
+ return mCurrentProgress;
+ }
+
+ public int getMax() {
+ return mMaxProgress;
+ }
+
+ public float getReachedBarHeight() {
+ return mReachedBarHeight;
+ }
+
+ public float getUnreachedBarHeight() {
+ return mUnreachedBarHeight;
+ }
+
+ public void setProgressTextSize(float textSize) {
+ this.mTextSize = textSize;
+ mTextPaint.setTextSize(mTextSize);
+ invalidate();
+ }
+
+ public void setProgressTextColor(int textColor) {
+ this.mTextColor = textColor;
+ mTextPaint.setColor(mTextColor);
+ invalidate();
+ }
+
+ public void setUnreachedBarColor(int barColor) {
+ this.mUnreachedBarColor = barColor;
+ mUnreachedBarPaint.setColor(mUnreachedBarColor);
+ invalidate();
+ }
+
+ public void setReachedBarColor(int progressColor) {
+ this.mReachedBarColor = progressColor;
+ mReachedBarPaint.setColor(mReachedBarColor);
+ invalidate();
+ }
+
+ public void setReachedBarHeight(float height) {
+ mReachedBarHeight = height;
+ }
+
+ public void setUnreachedBarHeight(float height) {
+ mUnreachedBarHeight = height;
+ }
+
+ public void setMax(int maxProgress) {
+ if (maxProgress > 0) {
+ this.mMaxProgress = maxProgress;
+ invalidate();
+ }
+ }
+
+ public void setSuffix(String suffix) {
+ if (suffix == null) {
+ mSuffix = "";
+ } else {
+ mSuffix = suffix;
+ }
+ }
+
+ public String getSuffix() {
+ return mSuffix;
+ }
+
+ public void setPrefix(String prefix) {
+ if (prefix == null)
+ mPrefix = "";
+ else {
+ mPrefix = prefix;
+ }
+ }
+
+ public String getPrefix() {
+ return mPrefix;
+ }
+
+ public void incrementProgressBy(int by) {
+ if (by > 0) {
+ setProgress(getProgress() + by);
+ }
+ }
+
+ public void setProgress(int progress) {
+ if (progress <= getMax() && progress >= 0) {
+ this.mCurrentProgress = progress;
+ invalidate();
+ }
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());
+ bundle.putInt(INSTANCE_TEXT_COLOR, getTextColor());
+ bundle.putFloat(INSTANCE_TEXT_SIZE, getProgressTextSize());
+ bundle.putFloat(INSTANCE_REACHED_BAR_HEIGHT, getReachedBarHeight());
+ bundle.putFloat(INSTANCE_UNREACHED_BAR_HEIGHT, getUnreachedBarHeight());
+ bundle.putInt(INSTANCE_REACHED_BAR_COLOR, getReachedBarColor());
+ bundle.putInt(INSTANCE_UNREACHED_BAR_COLOR, getUnreachedBarColor());
+ bundle.putInt(INSTANCE_MAX, getMax());
+ bundle.putInt(INSTANCE_PROGRESS, getProgress());
+ bundle.putString(INSTANCE_SUFFIX, getSuffix());
+ bundle.putString(INSTANCE_PREFIX, getPrefix());
+ bundle.putBoolean(INSTANCE_TEXT_VISIBILITY, getProgressTextVisibility());
+ return bundle;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (state instanceof Bundle) {
+ final Bundle bundle = (Bundle) state;
+ mTextColor = bundle.getInt(INSTANCE_TEXT_COLOR);
+ mTextSize = bundle.getFloat(INSTANCE_TEXT_SIZE);
+ mReachedBarHeight = bundle.getFloat(INSTANCE_REACHED_BAR_HEIGHT);
+ mUnreachedBarHeight = bundle.getFloat(INSTANCE_UNREACHED_BAR_HEIGHT);
+ mReachedBarColor = bundle.getInt(INSTANCE_REACHED_BAR_COLOR);
+ mUnreachedBarColor = bundle.getInt(INSTANCE_UNREACHED_BAR_COLOR);
+ initializePainters();
+ setMax(bundle.getInt(INSTANCE_MAX));
+ setProgress(bundle.getInt(INSTANCE_PROGRESS));
+ setPrefix(bundle.getString(INSTANCE_PREFIX));
+ setSuffix(bundle.getString(INSTANCE_SUFFIX));
+ setProgressTextVisibility(bundle.getBoolean(INSTANCE_TEXT_VISIBILITY) ? ProgressTextVisibility.Visible : ProgressTextVisibility.Invisible);
+ super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));
+ return;
+ }
+ super.onRestoreInstanceState(state);
+ }
+
+ public float dp2px(float dp) {
+ final float scale = getResources().getDisplayMetrics().density;
+ return dp * scale + 0.5f;
+ }
+
+ public float sp2px(float sp) {
+ final float scale = getResources().getDisplayMetrics().scaledDensity;
+ return sp * scale;
+ }
+
+ public void setProgressTextVisibility(ProgressTextVisibility visibility) {
+ mIfDrawText = visibility == ProgressTextVisibility.Visible;
+ invalidate();
+ }
+
+ public boolean getProgressTextVisibility() {
+ return mIfDrawText;
+ }
+
+}
diff --git a/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/view/UpdateDialogActivity.kt b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/view/UpdateDialogActivity.kt
new file mode 100644
index 000000000..92bb71c4c
--- /dev/null
+++ b/app/src/module_upgrade_app/java/com/tongdaxing/erban/upgrade/view/UpdateDialogActivity.kt
@@ -0,0 +1,197 @@
+package com.tongdaxing.erban.upgrade.view
+
+import android.content.Intent
+import android.graphics.drawable.GradientDrawable
+import android.graphics.drawable.StateListDrawable
+import android.os.Bundle
+import android.view.Gravity
+import android.view.View
+import android.view.WindowManager
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+import com.mango.moshen.R
+import com.tongdaxing.erban.upgrade.config.Constant
+import com.tongdaxing.erban.upgrade.listener.OnButtonClickListener
+import com.tongdaxing.erban.upgrade.listener.OnDownloadListenerAdapter
+import com.tongdaxing.erban.upgrade.manager.DownloadManager
+import com.tongdaxing.erban.upgrade.service.DownloadService
+import com.tongdaxing.erban.upgrade.util.ApkUtil
+import com.tongdaxing.erban.upgrade.util.DensityUtil
+import com.tongdaxing.erban.upgrade.util.LogUtil
+import java.io.File
+
+
+/**
+ * ProjectName: AppUpdate
+ * PackageName: com.tongdaxing.erban.upgrade.view
+ * FileName: UpdateDialogActivity
+ * CreateDate: 2022/4/7 on 17:40
+ * Desc:
+ *
+ * @author azhon
+ */
+
+class UpdateDialogActivity : AppCompatActivity(), View.OnClickListener {
+
+ private val install = 0x45
+ private val error = 0x46
+ private lateinit var manager: DownloadManager
+ private lateinit var apk: File
+ private lateinit var progressBar: NumberProgressBar
+ private lateinit var btnUpdate: Button
+
+ companion object {
+ private const val TAG = "UpdateDialogActivity"
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ overridePendingTransition(0, 0)
+ title = ""
+ setContentView(R.layout.dialog_update)
+ init()
+ }
+
+ private fun init() {
+ val tempManager = DownloadManager.getInstance()
+ if (tempManager == null) {
+ LogUtil.e(TAG, "An exception occurred by DownloadManager=null,please check your code!")
+ return
+ }
+ manager = tempManager
+ if (manager.forcedUpgrade) {
+ manager.onDownloadListeners.add(listenerAdapter)
+ }
+ setWindowSize()
+ initView()
+ }
+
+ private fun initView() {
+ val ibClose = findViewById(R.id.ib_close)
+ val vLine = findViewById(R.id.line)
+ val ivBg = findViewById(R.id.iv_bg)
+ val tvTitle = findViewById(R.id.tv_title)
+ val tvSize = findViewById(R.id.tv_size)
+ val tvDescription = findViewById(R.id.tv_description)
+ progressBar = findViewById(R.id.np_bar)
+ btnUpdate = findViewById(R.id.btn_update)
+ progressBar.visibility = if (manager.forcedUpgrade) View.VISIBLE else View.GONE
+ btnUpdate.tag = 0
+ btnUpdate.setOnClickListener(this)
+ ibClose.setOnClickListener(this)
+ if (manager.dialogImage != -1) {
+ ivBg.setBackgroundResource(manager.dialogImage)
+ }
+ if (manager.dialogButtonTextColor != -1) {
+ btnUpdate.setTextColor(manager.dialogButtonTextColor)
+ }
+ if (manager.dialogProgressBarColor != -1) {
+ progressBar.reachedBarColor = manager.dialogProgressBarColor
+ progressBar.setProgressTextColor(manager.dialogProgressBarColor)
+ }
+ if (manager.dialogButtonColor != -1) {
+ val colorDrawable = GradientDrawable().apply {
+ setColor(manager.dialogButtonColor)
+ cornerRadius = DensityUtil.dip2px(this@UpdateDialogActivity, 3f)
+ }
+ val drawable = StateListDrawable().apply {
+ addState(intArrayOf(android.R.attr.state_pressed), colorDrawable)
+ addState(IntArray(0), colorDrawable)
+ }
+ btnUpdate.background = drawable
+ }
+ if (manager.forcedUpgrade) {
+ vLine.visibility = View.GONE
+ ibClose.visibility = View.GONE
+ }
+ if (manager.apkVersionName.isNotEmpty()) {
+ tvTitle.text =
+ String.format(resources.getString(R.string.dialog_new), manager.apkVersionName)
+ }
+ if (manager.apkSize.isNotEmpty()) {
+ tvSize.text =
+ String.format(resources.getString(R.string.dialog_new_size), manager.apkSize)
+ tvSize.visibility = View.VISIBLE
+ }
+ tvDescription.text = manager.apkDescription
+ }
+
+ private fun setWindowSize() {
+ val attributes = window.attributes
+ attributes.width = (resources.displayMetrics.widthPixels * 0.75f).toInt()
+ attributes.height = WindowManager.LayoutParams.WRAP_CONTENT
+ attributes.gravity = Gravity.CENTER
+ window.attributes = attributes
+ }
+
+ override fun onClick(v: View?) {
+ when (v?.id) {
+ R.id.ib_close -> {
+ if (!manager.forcedUpgrade) {
+ finish()
+ }
+ manager.onButtonClickListener?.onButtonClick(OnButtonClickListener.CANCEL)
+ }
+ R.id.btn_update -> {
+ if (btnUpdate.tag == install) {
+ ApkUtil.installApk(this, Constant.AUTHORITIES!!, apk)
+ return
+ }
+ if (manager.forcedUpgrade) {
+ btnUpdate.isEnabled = false
+ btnUpdate.text = resources.getString(R.string.background_downloading)
+ } else {
+ finish()
+ }
+ manager.onButtonClickListener?.onButtonClick(OnButtonClickListener.UPDATE)
+ startService(Intent(this, DownloadService::class.java))
+ }
+ }
+ }
+
+ override fun onBackPressed() {
+ if (manager.forcedUpgrade) return
+ super.onBackPressed()
+ }
+
+ override fun finish() {
+ super.finish()
+ overridePendingTransition(0, 0)
+ }
+
+ private val listenerAdapter: OnDownloadListenerAdapter = object : OnDownloadListenerAdapter() {
+ override fun start() {
+ btnUpdate.isEnabled = false
+ btnUpdate.text = resources.getString(R.string.background_downloading)
+ }
+
+ override fun downloading(max: Int, progress: Int) {
+ if (max != -1) {
+ val curr = (progress / max.toDouble() * 100.0).toInt()
+ progressBar.progress = curr
+ } else {
+ progressBar.visibility = View.GONE
+ }
+ }
+
+ override fun done(apk: File) {
+ this@UpdateDialogActivity.apk = apk
+ btnUpdate.tag = install
+ btnUpdate.isEnabled = true
+ btnUpdate.text = resources.getString(R.string.click_hint)
+ }
+
+ override fun error(e: Throwable) {
+ btnUpdate.tag = error
+ btnUpdate.isEnabled = true
+ btnUpdate.text = resources.getString(R.string.continue_downloading)
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ manager.onDownloadListeners.remove(listenerAdapter)
+ }
+}
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/res/drawable/bg_button.xml b/app/src/module_upgrade_app/res/drawable/bg_button.xml
new file mode 100644
index 000000000..ffb9ab3c4
--- /dev/null
+++ b/app/src/module_upgrade_app/res/drawable/bg_button.xml
@@ -0,0 +1,15 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/res/drawable/bg_white_radius_6.xml b/app/src/module_upgrade_app/res/drawable/bg_white_radius_6.xml
new file mode 100644
index 000000000..1d9623652
--- /dev/null
+++ b/app/src/module_upgrade_app/res/drawable/bg_white_radius_6.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/res/drawable/ic_dialog_close.png b/app/src/module_upgrade_app/res/drawable/ic_dialog_close.png
new file mode 100644
index 000000000..03315a3ad
Binary files /dev/null and b/app/src/module_upgrade_app/res/drawable/ic_dialog_close.png differ
diff --git a/app/src/module_upgrade_app/res/drawable/ic_dialog_default.png b/app/src/module_upgrade_app/res/drawable/ic_dialog_default.png
new file mode 100644
index 000000000..2b036c811
Binary files /dev/null and b/app/src/module_upgrade_app/res/drawable/ic_dialog_default.png differ
diff --git a/app/src/module_upgrade_app/res/layout/dialog_update.xml b/app/src/module_upgrade_app/res/layout/dialog_update.xml
new file mode 100644
index 000000000..013d30c29
--- /dev/null
+++ b/app/src/module_upgrade_app/res/layout/dialog_update.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/res/values/strings.xml b/app/src/module_upgrade_app/res/values/strings.xml
index 1bbee5f2c..307e99e8c 100644
--- a/app/src/module_upgrade_app/res/values/strings.xml
+++ b/app/src/module_upgrade_app/res/values/strings.xml
@@ -3,4 +3,16 @@
·正在更新%s·
版本更新
VERSION UPDATE
+ 当前已是最新版本!
+ 开始下载
+ 可稍后查看下载进度
+ 正在下载新版本
+ 下载完成
+ 点击进行安装
+ 下载出错
+ 点击继续下载
+ 正在后台下载新版本…
+ 发现新版本%s可以下载啦!
+ 新版本大小:%s
+ 升级
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/res/values/styles.xml b/app/src/module_upgrade_app/res/values/styles.xml
new file mode 100644
index 000000000..6ea75ba64
--- /dev/null
+++ b/app/src/module_upgrade_app/res/values/styles.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/module_upgrade_app/res/xml/app_update_file.xml b/app/src/module_upgrade_app/res/xml/app_update_file.xml
new file mode 100644
index 000000000..66a8776a4
--- /dev/null
+++ b/app/src/module_upgrade_app/res/xml/app_update_file.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index a5171729f..9b23118b6 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -25,5 +25,5 @@ only_arm64=true
channel_file=channel.txt
-version_name=5.5.0
-version_code=550
\ No newline at end of file
+version_name=5.3.0
+version_code=500
\ No newline at end of file