diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4ec2e80671..75316f157c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -515,9 +515,6 @@
android:name=".qa.answer.draft.AnswerDraftActivity"
android:screenOrientation="portrait" />
-
-
())
+ private val mXapkUnzipThreadMap = Collections.synchronizedMap(HashMap())
// 按并行解压
@JvmStatic
@@ -45,23 +45,24 @@ object XapkInstaller : IUnzipListener {
private var startTime = 0L
private fun unzipXapkFile(downloadEntity: DownloadEntity) {
- startTime = System.currentTimeMillis()
- val thread = Thread(Runnable {
- ZipHelper.unzipXapk(downloadEntity, this)
- })
- thread.start()
-
- mXapkUnzipThreadMap[downloadEntity.path] = thread
+ if (mXapkUnzipThreadMap[downloadEntity.path] == null) {
+ startTime = System.currentTimeMillis()
+ val xapkUnzipThread = XapkUnzipThread(downloadEntity, this)
+ xapkUnzipThread.start()
+ mXapkUnzipThreadMap[downloadEntity.path] = xapkUnzipThread
+ } else {
+ debugOnly {
+ Utils.log("unzip", "重复解压,该文件解压已在队列中")
+ }
+ }
}
override fun onProgress(downloadEntity: DownloadEntity, unzipPath: String, unzipSize: Long, unzipProgress: Long) {
AppExecutor.uiExecutor.execute {
val df = DecimalFormat("#.0")
var percent = 0.0
- // 有时会产生 “,0” 的数据导致 parseDouble 抛出异常
- try {
+ tryCatchInRelease {
percent = df.format((unzipSize.toFloat() / unzipProgress) * 100).toDouble()
- } catch (ignore: NumberFormatException) {
}
downloadEntity.meta[XAPK_UNZIP_PERCENT] = percent.toString()
downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.UNZIPPING.name
@@ -82,13 +83,27 @@ object XapkInstaller : IUnzipListener {
}
// update download database
- // todo 更新页面需要注意线程切换问题
debugOnly {
Utils.log("unzip", "onNext->$unzipPath")
}
}
+ /**
+ * 取消解压回调
+ *
+ * 取消后的表现与下载完成一致
+ */
+ override fun onCancel(downloadEntity: DownloadEntity) {
+ mXapkUnzipThreadMap.remove(downloadEntity.path)
+
+ AppExecutor.uiExecutor.execute {
+ downloadEntity.meta[XAPK_UNZIP_PERCENT] = "0.0"
+ downloadEntity.meta[XAPK_UNZIP_STATUS] = XapkUnzipStatus.CANCEL.name
+ DataChanger.notifyDataChanged(downloadEntity)
+ }
+ }
+
override fun onFailure(downloadEntity: DownloadEntity, exception: Exception) {
mXapkUnzipThreadMap.remove(downloadEntity.path)
@@ -123,15 +138,15 @@ object XapkInstaller : IUnzipListener {
}
}
- // todo 取消解压
+ @JvmStatic
fun cancelUnzipTask(zipPath: String) {
- mXapkUnzipThreadMap[zipPath]?.interrupt()
- // todo 取消解压还需要通知页面更新
+ mXapkUnzipThreadMap[zipPath]?.canceled = true
}
}
enum class XapkUnzipStatus(status: String) {
UNZIPPING("unzipping"),
SUCCESS("success"),
+ CANCEL("cancel"),
FAILURE("failure");
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/common/util/ZipHelper.kt b/app/src/main/java/com/gh/common/xapk/XapkUnzipThread.kt
similarity index 70%
rename from app/src/main/java/com/gh/common/util/ZipHelper.kt
rename to app/src/main/java/com/gh/common/xapk/XapkUnzipThread.kt
index 7313319f83..b7fc922d30 100644
--- a/app/src/main/java/com/gh/common/util/ZipHelper.kt
+++ b/app/src/main/java/com/gh/common/xapk/XapkUnzipThread.kt
@@ -1,6 +1,8 @@
-package com.gh.common.util
+package com.gh.common.xapk
import android.os.Environment
+import com.gh.common.util.getExtension
+import com.gh.common.util.throwException
import com.gh.gamecenter.BuildConfig
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadEntity
@@ -9,16 +11,17 @@ import com.lightgame.utils.Utils
import java.io.File
import java.util.zip.ZipFile
-object ZipHelper {
- private const val DEFAULT_BUFFER_SIZE = 1024 * 1024
+class XapkUnzipThread(private var mDownloadEntity: DownloadEntity,
+ private var mUnzipListener: IXapkUnzipListener) : Thread() {
- // todo apk包存放路径/命名等问题...
- // todo apk 解压过慢,目前已知的影响因数(BufferSize,进度回调的同步操作)
- // 目前已知的情况时xapk只会有一个apk包,obb资源包的数量时不固定的
- fun unzipXapk(downloadEntity: DownloadEntity, listener: IUnzipListener) {
+ private val mDefaultBufferSize = 1024 * 1024
+
+ var canceled = false
+
+ override fun run() {
+ super.run()
try {
- // todo check file type???
- val path = downloadEntity.path
+ val path = mDownloadEntity.path
val unzipSize = getUnzipSize(path)
val msg = FileUtils.isCanDownload(HaloApp.getInstance().application, unzipSize)
@@ -37,7 +40,8 @@ object ZipHelper {
File(absolutePath + File.separator + zipEntry.name)
} else if (zipEntry.name.getExtension() == XapkInstaller.PACKAGE_EXTENSION_NAME) {
// apk文件名称 = xapk文件名+本身的文件名称
- File(FileUtils.getDownloadPath(HaloApp.getInstance().application, xapkFile.nameWithoutExtension + "_" + zipEntry.name))
+ val fileName = xapkFile.nameWithoutExtension + "_" + zipEntry.name
+ File(FileUtils.getDownloadPath(HaloApp.getInstance().application, fileName))
} else continue // 暂时只需要解压xpk/obb文件
if (zipEntry.isDirectory) {
@@ -59,49 +63,45 @@ object ZipHelper {
throwException("unzip create file failure", !outputFile.createNewFile())
} else {
unzipProgress += zipEntry.size
- listener.onProgress(downloadEntity, outputFile.path, unzipProgress, unzipSize)
- listener.onNext(downloadEntity, outputFile.path)
+ mUnzipListener.onProgress(mDownloadEntity, outputFile.path, unzipProgress, unzipSize)
+ mUnzipListener.onNext(mDownloadEntity, outputFile.path)
continue
}
// unzip
zip.getInputStream(zipEntry).use { input ->
outputFile.outputStream().use { output ->
- val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
+ val buffer = ByteArray(mDefaultBufferSize)
var bytes = input.read(buffer)
while (bytes >= 0) {
output.write(buffer, 0, bytes)
unzipProgress += bytes
bytes = input.read(buffer)
- listener.onProgress(downloadEntity, outputFile.path, unzipProgress, unzipSize)
+ if (canceled) {
+ mUnzipListener.onCancel(mDownloadEntity)
+ return
+ } else {
+ mUnzipListener.onProgress(mDownloadEntity, outputFile.path, unzipProgress, unzipSize)
+ }
+
}
}
}
- listener.onNext(downloadEntity, outputFile.path)
+ mUnzipListener.onNext(mDownloadEntity, outputFile.path)
}
}
- listener.onSuccess(downloadEntity)
+ mUnzipListener.onSuccess(mDownloadEntity)
} catch (e: Exception) {
if (BuildConfig.DEBUG) throw e
- listener.onFailure(downloadEntity, e)
+ mUnzipListener.onFailure(mDownloadEntity, e)
}
}
- fun getUnzipSize(path: String): Long {
+ private fun getUnzipSize(path: String): Long {
var totalSize = 0L
for (entry in ZipFile(File(path)).entries()) {
totalSize += entry.size
}
return totalSize
}
-}
-
-interface IUnzipListener {
- fun onProgress(downloadEntity: DownloadEntity, unzipPath: String, unzipSize: Long, unzipProgress: Long)
-
- fun onNext(downloadEntity: DownloadEntity, unzipPath: String)
-
- fun onFailure(downloadEntity: DownloadEntity, exception: Exception)
-
- fun onSuccess(downloadEntity: DownloadEntity)
}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java
index 3b1ff2c130..a807334a3b 100644
--- a/app/src/main/java/com/gh/download/DownloadManager.java
+++ b/app/src/main/java/com/gh/download/DownloadManager.java
@@ -29,7 +29,7 @@ import com.gh.common.util.MD5Utils;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.SPUtils;
-import com.gh.common.util.XapkInstaller;
+import com.gh.common.xapk.XapkInstaller;
import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.entity.ApkEntity;
import com.gh.gamecenter.entity.GameEntity;
diff --git a/app/src/main/java/com/gh/gamecenter/XapkTestActivity.kt b/app/src/main/java/com/gh/gamecenter/XapkTestActivity.kt
deleted file mode 100644
index 470e91dc87..0000000000
--- a/app/src/main/java/com/gh/gamecenter/XapkTestActivity.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.gh.gamecenter
-
-import android.app.Activity
-import android.content.Intent
-import android.util.Log
-import android.view.View
-import com.gh.base.BaseActivity
-import com.gh.common.util.XapkInstaller
-import com.lightgame.download.DownloadEntity
-
-class XapkTestActivity : BaseActivity() {
-
- override fun getLayoutId(): Int {
- return R.layout.activity_test_xapk
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
- if (resultCode != Activity.RESULT_OK || data == null) return
- val filePath = data.data?.path ?: return
- Log.e("MainActivity", filePath)
- unZipFile(filePath)
- }
-
- fun onSelectListener(view: View) {
- val getContentIntent = Intent(Intent.ACTION_GET_CONTENT)
- getContentIntent.type = "*/*"
- getContentIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
- startActivityForResult(Intent.createChooser(getContentIntent, ""), REQUEST_CODE_GET_FILES)
- }
-
- private fun unZipFile(path: String) {
- val downloadEntity = DownloadEntity()
- downloadEntity.path = path
- downloadEntity.meta = hashMapOf()
- XapkInstaller.install(downloadEntity)
- }
-
- companion object {
- const val REQUEST_CODE_GET_FILES: Int = 112
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java
index 9fb640bbb4..ab7946001b 100644
--- a/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java
+++ b/app/src/main/java/com/gh/gamecenter/adapter/viewholder/DetailViewHolder.java
@@ -28,7 +28,7 @@ import com.gh.common.util.PackageUtils;
import com.gh.common.util.PermissionHelper;
import com.gh.common.util.ReservationHelper;
import com.gh.common.util.StringUtils;
-import com.gh.common.util.XapkInstaller;
+import com.gh.common.xapk.XapkInstaller;
import com.gh.common.view.DownloadProgressBar;
import com.gh.download.DownloadManager;
import com.gh.download.dialog.DownloadDialog;
diff --git a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java
index 9e36ebf953..24437dda8c 100644
--- a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java
+++ b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragment.java
@@ -7,12 +7,19 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.DefaultItemAnimator;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
import com.gh.base.fragment.BaseFragment;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.NetworkUtils;
import com.gh.common.util.PackageUtils;
import com.gh.common.view.RecyclerViewExtended;
+import com.gh.common.xapk.XapkInstaller;
+import com.gh.common.xapk.XapkUnzipStatus;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.MainActivity;
@@ -32,10 +39,6 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
-import androidx.core.content.ContextCompat;
-import androidx.recyclerview.widget.DefaultItemAnimator;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.OnClick;
@@ -72,12 +75,20 @@ public class GameDownloadFragment extends BaseFragment implements View.OnClickLi
private DataWatcher dataWatcher = new DataWatcher() {
@Override
public void onDataChanged(DownloadEntity downloadEntity) {
+ Integer location = adapter.getLocation(downloadEntity.getUrl());
+
+ String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
+ if (XapkUnzipStatus.UNZIPPING.name().equals(xapkStatus)) {
+ adapter.notifyItemChanged(location + 1);
+ return;
+ }
+
if (downloadEntity.getStatus().equals(DownloadStatus.downloading)
|| downloadEntity.getStatus().equals(DownloadStatus.pause)
|| downloadEntity.getStatus().equals(DownloadStatus.waiting)) {
adapter.notifyItemChanged(adapter.getBase());
}
- Integer location = adapter.getLocation(downloadEntity.getUrl());
+
if (location != null) {
if (!"pause".equals(adapter.getStatusMap().get(downloadEntity.getUrl()))) {
if (downloadEntity.getStatus().equals(DownloadStatus.done)) {
diff --git a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java
index 6652c0d3b4..7ebbf355e6 100644
--- a/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java
+++ b/app/src/main/java/com/gh/gamecenter/download/GameDownloadFragmentAdapter.java
@@ -1,9 +1,6 @@
package com.gh.gamecenter.download;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Message;
import android.text.TextUtils;
@@ -17,7 +14,6 @@ import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-import com.gh.common.util.BitmapUtils;
import com.gh.common.util.DataUtils;
import com.gh.common.util.DialogUtils;
import com.gh.common.util.ImageUtils;
@@ -26,6 +22,8 @@ import com.gh.common.util.PackageInstaller;
import com.gh.common.util.PackageUtils;
import com.gh.common.util.PlatformUtils;
import com.gh.common.util.SpeedUtils;
+import com.gh.common.xapk.XapkInstaller;
+import com.gh.common.xapk.XapkUnzipStatus;
import com.gh.download.DownloadManager;
import com.gh.gamecenter.R;
import com.gh.gamecenter.adapter.viewholder.DownloadHeadViewHolder;
@@ -40,8 +38,6 @@ import com.lightgame.download.FileUtils;
import com.lightgame.utils.Utils;
import org.greenrobot.eventbus.EventBus;
-import org.json.JSONException;
-import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
@@ -116,26 +112,7 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
downloadEntity = downloadingList.get(position - doneList.size() - 2);
}
String icon = downloadEntity.getIcon();
- if (!TextUtils.isEmpty(icon) && icon.contains("KuaiChuanIcon")) { // 来自快传的apk
- try {
- JSONObject jsonObject = new JSONObject(icon);
- String apkPath = jsonObject.getString("KuaiChuanIcon");
- android.content.pm.PackageManager pm = mContext.getPackageManager();
- PackageInfo info = pm.getPackageArchiveInfo(apkPath,
- android.content.pm.PackageManager.GET_ACTIVITIES);
- if (info != null) {
- ApplicationInfo appInfo = info.applicationInfo;
- appInfo.sourceDir = apkPath;
- appInfo.publicSourceDir = apkPath;
- Bitmap bitmap = BitmapUtils.drawableToBitmap(appInfo.loadIcon(pm), true);
- viewHolder.dmIcon.setImageBitmap(bitmap);
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
-
- } else if (!TextUtils.isEmpty(icon)) {
-// viewHolder.dmIcon.setImageURI(icon);
+ if (!TextUtils.isEmpty(icon)) {
ImageUtils.display(viewHolder.dmIcon, icon);
} else {
ImageUtils.display(viewHolder.dmIcon, R.mipmap.logo);
@@ -176,7 +153,17 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
viewHolder.dmDownloads.setText("下载完成");
viewHolder.dmDelete.setVisibility(View.VISIBLE);
viewHolder.dmStartorpause.setTextColor(Color.WHITE);
- if (downloadEntity.isPluggable()
+
+ String xapkStatus = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_STATUS);
+
+ if (XapkUnzipStatus.UNZIPPING.name().equals(xapkStatus)) {
+ viewHolder.dmStartorpause.setText("取消");
+ viewHolder.dmStartorpause.setBackgroundResource(R.drawable.download_button_normal_style);
+
+ String percent = downloadEntity.getMeta().get(XapkInstaller.XAPK_UNZIP_PERCENT);
+ viewHolder.dmProgressbar.setProgress((int) (Float.parseFloat(percent == null ? "0" : percent) * 10));
+ viewHolder.dmSpeed.setText((percent + "%"));
+ } else if (downloadEntity.isPluggable()
&& PackagesManager.INSTANCE.isInstalled(downloadEntity.getPackageName())) {
viewHolder.dmStartorpause.setText("安装");
viewHolder.dmStartorpause.setBackgroundResource(R.drawable.download_button_pluggable_style);
@@ -336,7 +323,9 @@ class GameDownloadFragmentAdapter extends BaseRecyclerAdapter {
, "安装包数据校验失败,无法完成下载,建议删除任务重新下载"
, "知道了", null, null, null);
break;
-
+ case "取消":
+ XapkInstaller.cancelUnzipTask(downloadEntity.getPath());
+ break;
}
// DataUtils.onMtaEvent(HaloApp.getInstance().getApplication(), "下载管理", "游戏下载", str);
diff --git a/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java b/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java
index c019fa61c8..8c4c8330d6 100644
--- a/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java
+++ b/app/src/main/java/com/gh/gamecenter/fragment/SearchToolbarFragment.java
@@ -27,12 +27,10 @@ import com.gh.common.util.DisplayUtils;
import com.gh.common.util.EntranceUtils;
import com.gh.common.util.MtaHelper;
import com.gh.download.DownloadManager;
-import com.gh.gamecenter.BuildConfig;
import com.gh.gamecenter.DownloadManagerActivity;
import com.gh.gamecenter.MessageActivity;
import com.gh.gamecenter.R;
import com.gh.gamecenter.SearchActivity;
-import com.gh.gamecenter.XapkTestActivity;
import com.gh.gamecenter.entity.GameUpdateEntity;
import com.gh.gamecenter.eventbus.EBDownloadStatus;
import com.gh.gamecenter.eventbus.EBReuse;
@@ -252,12 +250,6 @@ public class SearchToolbarFragment extends BaseLazyFragment implements View.OnCl
startActivity(intent);
break;
case R.id.actionbar_notification:
- // todo test
- if (BuildConfig.DEBUG) {
- startActivity(new Intent(getContext(), XapkTestActivity.class));
- return;
- }
-
DataUtils.onEvent(getActivity(), "主页", "消息图标");
MtaHelper.onEvent("首页_点击", "顶栏", "消息中心");
DataCollectionUtils.uploadClick(getActivity(), "消息图标", "主页");
diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/video/TopVideoView.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/video/TopVideoView.kt
index 4daeffad0c..48d30987b5 100644
--- a/app/src/main/java/com/gh/gamecenter/gamedetail/video/TopVideoView.kt
+++ b/app/src/main/java/com/gh/gamecenter/gamedetail/video/TopVideoView.kt
@@ -15,7 +15,6 @@ import com.gh.common.constant.Constants
import com.gh.common.observer.MuteCallback
import com.gh.common.observer.VolumeObserver
import com.gh.common.util.*
-import com.gh.download.DownloadManager
import com.gh.gamecenter.R
import com.gh.gamecenter.entity.GameDetailEntity
import com.gh.gamecenter.gamedetail.GameDetailViewModel