Bladeren bron

feat 远程更新优化

robin 4 jaren geleden
bovenliggende
commit
76f1eaeb5d

+ 3 - 2
app/src/main/AndroidManifest.xml

@@ -27,7 +27,9 @@
         <activity android:name=".view.MainActivity" />
         <activity
             android:name=".view.PreferenceActivity"
-            android:label="@string/preference"
+            android:theme="@style/ActivityTransparent" />
+        <activity
+            android:name=".view.UpdateActivity"
             android:theme="@style/ActivityTransparent" />
 
         <provider
@@ -39,7 +41,6 @@
                 android:name="com.doverfuelingsolutions.issp.data.GlobalDataInitializer"
                 android:value="androidx.startup" />
         </provider>
-
         <provider
             android:name="androidx.core.content.FileProvider"
             android:authorities="${applicationId}.provider"

+ 16 - 0
app/src/main/java/com/doverfuelingsolutions/issp/utils/NetworkUtil.kt

@@ -0,0 +1,16 @@
+package com.doverfuelingsolutions.issp.utils
+
+import android.content.Context
+import android.net.ConnectivityManager
+
+object NetworkUtil {
+
+    /**
+     * Indicate if the network is available
+     */
+    fun isAvailable(context: Context) : Boolean {
+        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+        val activeNetworkInfo = connectivityManager.activeNetworkInfo
+        return activeNetworkInfo?.isAvailable ?: false
+    }
+}

+ 4 - 0
app/src/main/java/com/doverfuelingsolutions/issp/utils/download/DownloadAction.kt

@@ -65,4 +65,8 @@ class DownloadAction(
             }
         }
     }
+
+    fun stop() {
+        downloadManager.remove(downloadId)
+    }
 }

+ 2 - 87
app/src/main/java/com/doverfuelingsolutions/issp/view/PreferenceActivity.kt

@@ -1,17 +1,11 @@
 package com.doverfuelingsolutions.issp.view
 
 import android.app.Activity
-import android.app.DownloadManager
 import android.content.Context
 import android.content.Intent
-import android.net.Uri
 import android.os.Bundle
-import android.os.Environment
 import android.view.View
-import android.widget.Button
-import android.widget.TextView
 import androidx.appcompat.app.AppCompatActivity
-import androidx.core.content.FileProvider
 import androidx.databinding.DataBindingUtil
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
@@ -19,21 +13,16 @@ import androidx.lifecycle.lifecycleScope
 import com.doverfuelingsolutions.issp.R
 import com.doverfuelingsolutions.issp.api.FuelInfoApi
 import com.doverfuelingsolutions.issp.api.SystemApi
-import com.doverfuelingsolutions.issp.api.WayneApiConfig
 import com.doverfuelingsolutions.issp.databinding.ActivityPreferenceBinding
-import com.doverfuelingsolutions.issp.utils.WindowUtil
 import com.doverfuelingsolutions.issp.utils.AppUtil
 import com.doverfuelingsolutions.issp.utils.DFSToastUtil
 import com.doverfuelingsolutions.issp.utils.StringUtil
-import com.doverfuelingsolutions.issp.utils.download.DownloadAction
+import com.doverfuelingsolutions.issp.utils.WindowUtil
 import com.doverfuelingsolutions.issp.utils.log.DFSLog
 import com.doverfuelingsolutions.issp.utils.sp.SPKeys
 import com.doverfuelingsolutions.issp.utils.sp.SPUtil
 import com.doverfuelingsolutions.issp.view.fragment.FragmentPreference
-import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.moos.library.CircleProgressView
 import kotlinx.coroutines.launch
-import java.io.File
 
 class PreferenceActivity : AppCompatActivity(),
     View.OnClickListener {
@@ -169,81 +158,7 @@ class PreferenceActivity : AppCompatActivity(),
                 return@launch
             }
 
-            val dialogView = View.inflate(this@PreferenceActivity, R.layout.layout_version_update, null).apply {
-                findViewById<TextView>(R.id.versionTitle).text = StringUtil.get(R.string.new_version, remoteVersion.version)
-                findViewById<TextView>(R.id.versionInfo).text = StringUtil.get(R.string.new_version, remoteVersion.info)
-            }
-            val progressView = dialogView.findViewById<CircleProgressView>(R.id.progressView)
-//            val loadingTip = dialogView.findViewById<TextView>(R.id.loadingTip).apply {
-//                text = StringUtil.get(R.string.in_download)
-//            }
-            val dialog = MaterialAlertDialogBuilder(this@PreferenceActivity)
-                .setTitle(R.string.find_new_version)
-                .setView(dialogView)
-                .setCancelable(false)
-                .show()
-            dialog.window?.let { WindowUtil.setFullscreen(it) }
-            val actionButton = dialogView.findViewById<Button>(R.id.close)
-            actionButton.setOnClickListener { dialog.dismiss() }
-
-            // TODO 下载中途断网,下载失败,下载完成但是未成功安装,成功安装后怎么删除
-            // 准备下载
-            val localName = "update/${remoteVersion.name}"
-            val downloadAction = DownloadAction(
-                this@PreferenceActivity,
-                Uri.parse("${WayneApiConfig.HOST_ASSETS}/isspt/${remoteVersion.name}"),
-                localName)
-            downloadAction.start { status, size, total ->
-                lifecycleScope.launch {
-                    when (status) {
-                        // 下载中
-                        DownloadManager.STATUS_RUNNING -> {
-//                            val percentage = (size.toDouble() * 10000 / total).toInt().toDouble() / 100
-//                            loadingTip.text = StringUtil.get(R.string.download_progress, percentage)
-                            progressView.progress = size.toFloat() * 100 / total
-                        }
-                        // 下载结束
-                        DownloadManager.STATUS_SUCCESSFUL -> {
-//                            loadingTip.text = StringUtil.get(R.string.download_done)
-                            actionButton.visibility = View.VISIBLE
-
-                            // 安装应用
-                            getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.let { folder ->
-                                val file = File("${folder.absolutePath}/$localName")
-                                if (!file.isFile) {
-                                    DFSToastUtil.fail(R.string.cant_find_local_file)
-                                    dialog.dismiss()
-                                    return@let
-                                }
-                                // 先删掉其他APK
-                                file.parentFile?.list()?.forEach {
-                                    File(it).let { f ->
-                                        if (f.absolutePath != file.absolutePath && f.isFile && f.name.endsWith("apk")) {
-                                            f.delete()
-                                        }
-                                    }
-                                }
-                                val fileUri = FileProvider.getUriForFile(
-                                    this@PreferenceActivity,
-                                    "$packageName.provider",
-                                    file
-                                )
-                                Intent(Intent.ACTION_VIEW).let { intent ->
-                                    intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
-                                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
-                                    intent.setDataAndType(fileUri, "application/vnd.android.package-archive")
-                                    this@PreferenceActivity.startActivity(intent)
-                                }
-                            }
-                        }
-                        // 下载失败
-                        DownloadManager.STATUS_FAILED -> {
-//                            loadingTip.text = StringUtil.get(R.string.download_fail)
-                            actionButton.visibility = View.VISIBLE
-                        }
-                    }
-                }
-            }
+            UpdateActivity.start(this@PreferenceActivity, remoteVersion.version, remoteVersion.name, remoteVersion.info)
         }
     }
 

+ 183 - 0
app/src/main/java/com/doverfuelingsolutions/issp/view/UpdateActivity.kt

@@ -0,0 +1,183 @@
+package com.doverfuelingsolutions.issp.view
+
+import android.app.DownloadManager
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Bundle
+import android.os.Environment
+import android.view.View
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.FileProvider
+import androidx.databinding.DataBindingUtil
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.lifecycleScope
+import com.doverfuelingsolutions.issp.R
+import com.doverfuelingsolutions.issp.api.WayneApiConfig
+import com.doverfuelingsolutions.issp.databinding.ActivityUpdateBinding
+import com.doverfuelingsolutions.issp.utils.DFSToastUtil
+import com.doverfuelingsolutions.issp.utils.NetworkUtil
+import com.doverfuelingsolutions.issp.utils.StringUtil
+import com.doverfuelingsolutions.issp.utils.WindowUtil
+import com.doverfuelingsolutions.issp.utils.download.DownloadAction
+import kotlinx.coroutines.launch
+import java.io.File
+
+class UpdateActivity : AppCompatActivity(),
+    View.OnClickListener{
+
+    companion object {
+
+        fun start(context: Context, version: String, remoteFileName: String, description: String) {
+            Intent(context, UpdateActivity::class.java).let {
+                it.putExtra("version", version)
+                it.putExtra("remoteFileName", remoteFileName)
+                it.putExtra("description", description)
+
+                context.startActivity(it)
+            }
+        }
+    }
+
+    private val binding: ActivityUpdateBinding by lazy {
+        DataBindingUtil.setContentView(this, R.layout.activity_update)
+    }
+    private val viewModel: UpdateViewModel by viewModels()
+
+    private var remoteFileName = ""
+    private var localFileName = ""
+    private var downloadAction: DownloadAction? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        supportActionBar?.hide()
+
+        binding.lifecycleOwner = this
+        binding.viewModel = viewModel
+        binding.handler = this
+
+        viewModel.version.value = intent.getStringExtra("version") ?: ""
+        viewModel.versionDescription.value = intent.getStringExtra("description") ?: ""
+        intent.getStringExtra("remoteFileName").let {
+            if (it.isNullOrBlank()) {
+                DFSToastUtil.fail(R.string.invalid_version_file)
+                finish()
+                return
+            }
+
+            remoteFileName = it
+            download()
+        }
+
+        viewModel.progress.observe(this, {
+            binding.progressView.progress = it
+        })
+    }
+
+    override fun onResume() {
+        super.onResume()
+
+        WindowUtil.setFullscreen(this)
+    }
+
+    override fun onClick(v: View?) {
+        when (v) {
+            binding.buttonRetry -> {
+                downloadAction?.stop()
+                download()
+            }
+            binding.reInstall -> {
+                installApk()
+            }
+            binding.buttonCancel -> {
+                downloadAction?.stop()
+                finish()
+            }
+        }
+    }
+
+    private fun download() {
+        viewModel.isCancel.value = false
+        viewModel.isRetry.value = false
+        viewModel.isRetry.value = false
+
+        localFileName = "update/$remoteFileName"
+        downloadAction = DownloadAction(
+            this,
+            Uri.parse("${WayneApiConfig.HOST_ASSETS}/isspt/$remoteFileName"),
+            localFileName)
+        downloadAction?.start { status, size, total ->
+            lifecycleScope.launch {
+                when (status) {
+                    DownloadManager.STATUS_RUNNING -> {
+                        viewModel.errorText.value = ""
+                        viewModel.progress.value = size.toFloat() * 100 / total
+                    }
+                    DownloadManager.STATUS_SUCCESSFUL -> {
+                        viewModel.errorText.value = ""
+                        viewModel.progress.value = 100f
+                        viewModel.isCancel.value = true
+                        viewModel.isDownloaded.value = true
+
+                        installApk()
+                    }
+                    DownloadManager.STATUS_FAILED -> {
+                        viewModel.isCancel.value = true
+                        viewModel.isRetry.value = true
+                        viewModel.errorText.value = StringUtil.get(R.string.download_fail)
+                        downloadAction?.stop()
+                    }
+                    DownloadManager.STATUS_PAUSED -> {
+                        viewModel.isCancel.value = true
+                        if (NetworkUtil.isAvailable(this@UpdateActivity)) {
+                            viewModel.errorText.value = StringUtil.get(R.string.download_pause_no_network)
+                        } else {
+                            viewModel.errorText.value = StringUtil.get(R.string.download_pause)
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private fun installApk() {
+        getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.let { folder ->
+            val file = File("${folder.absolutePath}/$localFileName")
+            if (!file.isFile) {
+                DFSToastUtil.fail(R.string.cant_find_local_file)
+                finish()
+                return@let
+            }
+
+            // 先删掉其他APK
+            file.parentFile?.list()?.forEach {
+                File(it).let { f ->
+                    if (f.absolutePath != file.absolutePath && f.isFile && f.name.endsWith("apk")) {
+                        f.delete()
+                    }
+                }
+            }
+
+            // 安装
+            val fileUri = FileProvider.getUriForFile(this, "$packageName.provider", file)
+            Intent(Intent.ACTION_VIEW).let { intent ->
+                intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+                intent.setDataAndType(fileUri, "application/vnd.android.package-archive")
+                this.startActivity(intent)
+            }
+        }
+    }
+
+    class UpdateViewModel : ViewModel() {
+        val version = MutableLiveData("1.0.0")
+        val versionDescription = MutableLiveData("")
+        val progress = MutableLiveData(0f)
+        val isDownloaded = MutableLiveData(false)
+        val isCancel = MutableLiveData(false)
+        val isRetry = MutableLiveData(false)
+        val errorText = MutableLiveData("")
+    }
+}

+ 1 - 1
app/src/main/res/layout/activity_preference.xml

@@ -15,7 +15,7 @@
         android:layout_width="800dp"
         android:layout_height="1600dp"
         android:layout_gravity="center"
-        android:background="@color/white"
+        android:background="@drawable/border_gray"
         android:elevation="60dp"
         android:orientation="vertical"
         android:paddingVertical="40dp"

+ 113 - 0
app/src/main/res/layout/activity_update.xml

@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <data>
+
+        <variable
+            name="viewModel"
+            type="com.doverfuelingsolutions.issp.view.UpdateActivity.UpdateViewModel" />
+
+        <variable
+            name="handler"
+            type="com.doverfuelingsolutions.issp.view.UpdateActivity" />
+
+        <import type="android.view.View" />
+    </data>
+
+    <LinearLayout
+        style="@style/wrap"
+        android:layout_gravity="center"
+        android:background="@drawable/border_gray"
+        android:elevation="60dp"
+        android:gravity="center_horizontal"
+        android:minWidth="500dp"
+        android:orientation="vertical"
+        android:paddingHorizontal="40dp"
+        android:paddingVertical="80dp">
+
+        <com.moos.library.CircleProgressView
+            android:id="@+id/progressView"
+            android:layout_width="240dp"
+            android:layout_height="240dp"
+            app:circleBroken="true"
+            app:end_color="@color/colorPrimary"
+            app:end_progress="100"
+            app:isTracked="true"
+            app:progressDuration="300"
+            app:progressTextVisibility="false"
+            app:start_color="@color/colorSecondary"
+            app:start_progress="0"
+            app:track_width="26dp" />
+
+        <TextView
+            android:id="@+id/progressText"
+            style="@style/wrap"
+            android:text="@{@string/download_progress(viewModel.progress), default=@string/download_progress}"
+            android:textColor="@color/colorPrimaryVariant"
+            android:textSize="18sp" />
+
+        <TextView
+            android:id="@+id/errorText"
+            style="@style/wrap"
+            android:text="@{viewModel.errorText, default=@string/download_fail}"
+            android:layout_marginTop="40dp"
+            android:textColor="@color/colorRed"
+            android:textSize="20sp" />
+
+        <TextView
+            android:id="@+id/versionTitle"
+            style="@style/wrap"
+            android:layout_gravity="start"
+            android:layout_marginTop="60dp"
+            android:text="@{@string/new_version(viewModel.version), default=@string/new_version}"
+            android:textColor="@color/color333"
+            android:textSize="24sp" />
+
+        <TextView
+            android:id="@+id/versionInfo"
+            style="@style/wrap"
+            android:layout_gravity="start"
+            android:layout_marginTop="20dp"
+            android:text="@{viewModel.versionDescription, default=@string/new_version}"
+            android:textColor="@color/color666"
+            android:textSize="18sp" />
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="100dp"
+            android:orientation="horizontal">
+
+            <Button
+                android:id="@+id/buttonRetry"
+                style="@style/Widget.MaterialComponents.Button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="12dp"
+                android:onClick="@{handler}"
+                android:text="@string/retry"
+                android:visibility="@{viewModel.isRetry ? View.VISIBLE : View.GONE}" />
+
+            <Button
+                android:id="@+id/reInstall"
+                style="@style/Widget.MaterialComponents.Button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="12dp"
+                android:onClick="@{handler}"
+                android:text="@string/reinstall"
+                android:visibility="@{viewModel.isDownloaded ? View.VISIBLE : View.GONE}" />
+
+            <Button
+                android:id="@+id/buttonCancel"
+                style="@style/Widget.MaterialComponents.Button.TextButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="12dp"
+                android:onClick="@{handler}"
+                android:text="@string/cancel_update"
+                android:visibility="@{viewModel.isCancel ? View.VISIBLE : View.GONE}" />
+        </LinearLayout>
+    </LinearLayout>
+</layout>

+ 0 - 48
app/src/main/res/layout/layout_version_update.xml

@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    style="@style/wrap"
-    android:gravity="center_horizontal"
-    android:minWidth="300dp"
-    android:orientation="vertical"
-    android:paddingHorizontal="40dp"
-    android:paddingVertical="80dp">
-
-    <com.moos.library.CircleProgressView
-        android:id="@+id/progressView"
-        android:layout_width="240dp"
-        android:layout_height="240dp"
-        app:circleBroken="true"
-        app:end_color="@color/colorPrimary"
-        app:end_progress="60"
-        app:isTracked="true"
-        app:progressTextVisibility="false"
-        app:start_color="@color/colorSecondary"
-        app:start_progress="0"
-        app:track_width="26dp" />
-
-    <TextView
-        android:id="@+id/versionTitle"
-        style="@style/wrap"
-        android:layout_gravity="start"
-        android:layout_marginTop="80dp"
-        android:text="@string/new_version"
-        android:textSize="24sp" />
-
-    <TextView
-        android:id="@+id/versionInfo"
-        style="@style/wrap"
-        android:layout_gravity="start"
-        android:layout_marginTop="20dp"
-        android:text="@string/new_version"
-        android:textSize="18sp" />
-
-    <Button
-        android:id="@+id/close"
-        style="@style/Widget.MaterialComponents.Button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="100dp"
-        android:text="@string/click_close"
-        android:visibility="gone" />
-</LinearLayout>

+ 2 - 0
app/src/main/res/values/colors.xml

@@ -13,6 +13,7 @@
 
     <color name="colorLight">#E7F8FC</color>
     <color name="colorYellow">#FF5722</color>
+    <color name="colorRed">#FF3C2E</color>
     <color name="colorGreen">#2BBF32</color>
     <color name="colorTransparent">#00000000</color>
 
@@ -21,6 +22,7 @@
     <color name="white">#FFFFFFFF</color>
     <color name="color333">#333</color>
     <color name="color555">#555</color>
+    <color name="color666">#666</color>
     <color name="color777">#777</color>
     <color name="color999">#999</color>
     <color name="colorBBB">#bbb</color>

+ 7 - 0
app/src/main/res/values/strings.xml

@@ -35,6 +35,7 @@
     <string name="data_null">数据为空</string>
     <string name="fail_request">请求失败</string>
     <string name="network_error">网络异常</string>
+    <string name="network_none">暂无网络</string>
 
 
     <string name="fail_operate">操作失败</string>
@@ -147,9 +148,15 @@
     <string name="in_download">下载中</string>
     <string name="download_done">下载已完成</string>
     <string name="download_fail">下载失败,请在网络畅通的情况下重试</string>
+    <string name="download_pause_no_network">设备无网络链接,下载已暂时停止</string>
+    <string name="download_pause">下载已暂时停止,请检查网络是否正常</string>
     <string name="download_progress">已下载:%1$s%%</string>
     <string name="click_close">点击关闭</string>
+    <string name="cancel_update">取消升级</string>
     <string name="cant_find_local_file">未找到本地文件</string>
+    <string name="reinstall">重新安装</string>
+    <string name="retry">重新尝试</string>
+    <string name="invalid_version_file">错误的远程版本文件</string>
 
     <!-- Fusion -->
     <string name="fusion_in_connect">正在连接 Fusion…</string>

+ 1 - 0
app/src/main/res/values/styles.xml

@@ -6,6 +6,7 @@
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowFullscreen">true</item>
+        <item name="android:windowActionBar">false</item>
     </style>
 
     <style name="match">