diff --git a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt index 7c5bd38bab..95df4144ce 100644 --- a/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt +++ b/app/src/main/java/com/gh/common/simulator/SimulatorDownloadManager.kt @@ -9,15 +9,19 @@ import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout import com.g00fy2.versioncompare.Version -import com.gh.gamecenter.core.AppExecutor.uiExecutor -import com.gh.gamecenter.common.constant.Constants -import com.gh.gamecenter.common.base.TrackableDialog -import com.gh.common.util.* import com.gh.common.util.LogUtils +import com.gh.common.util.PackageInstaller +import com.gh.common.util.PackageUtils import com.gh.download.DownloadManager import com.gh.gamecenter.R +import com.gh.gamecenter.common.base.TrackableDialog +import com.gh.gamecenter.common.constant.Constants import com.gh.gamecenter.common.utils.* -import com.gh.gamecenter.core.utils.* +import com.gh.gamecenter.core.AppExecutor.uiExecutor +import com.gh.gamecenter.core.utils.DisplayUtils +import com.gh.gamecenter.core.utils.MtaHelper +import com.gh.gamecenter.core.utils.SpeedUtils +import com.gh.gamecenter.core.utils.ToastUtils import com.gh.gamecenter.entity.ApkEntity import com.gh.gamecenter.entity.SimulatorEntity import com.gh.gamecenter.entity.TrackableEntity @@ -73,7 +77,7 @@ class SimulatorDownloadManager private constructor() { val fileName = downloadEntity.path.substring(downloadEntity.path.lastIndexOf('/') + 1).removeSuffix(".apk") val startTime = downloadEntity.getMetaExtra(Constants.SIMULATOR_DOWNLOAD_START_TIME) LogUtils.uploadSimulatorDownload("simulator_download_complete", fileName, simulator?.id, downloadEntity.name, gameId, locationStr, downloadType, startTime) - DownloadManager.getInstance().cancel(downloadEntity.url, false, true) + DownloadManager.getInstance().cancel(downloadEntity.url, false, true, false) val activity = mContextRef?.get() as? AppCompatActivity if (activity?.isFinishing == false) { downloadDialog?.dismiss() diff --git a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java index 96c15ce359..2012b6bfc2 100644 --- a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java +++ b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java @@ -297,8 +297,9 @@ public class DetailDownloadUtils { case uncertificated: case unqualified: case unavailable: - detailInitDownload(viewHolder, false); - break; + // TODO 检查不调用 detailInitDownload 会有什么影响 +// detailInitDownload(viewHolder, false); +// break; default: break; } diff --git a/app/src/main/java/com/gh/common/util/DownloadObserver.kt b/app/src/main/java/com/gh/common/util/DownloadObserver.kt index 4b6c65be44..4bb52dab5b 100644 --- a/app/src/main/java/com/gh/common/util/DownloadObserver.kt +++ b/app/src/main/java/com/gh/common/util/DownloadObserver.kt @@ -312,7 +312,7 @@ object DownloadObserver { override fun onConfirm() { val simulator = HaloApp.get(downloadEntity.name, true) as? SimulatorEntity ?: return - DownloadManager.getInstance().cancel(downloadEntity.url, true, true) + DownloadManager.getInstance().cancel(downloadEntity.url, true, true, false) SimulatorDownloadManager.getInstance() .showDownloadDialog(currentActivity, simulator, SimulatorDownloadManager.SimulatorLocation.SIMULATOR_GAME) } diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java index c85d1568e9..e69b047974 100644 --- a/app/src/main/java/com/gh/download/DownloadManager.java +++ b/app/src/main/java/com/gh/download/DownloadManager.java @@ -747,7 +747,7 @@ public class DownloadManager implements DownloadStatusListener { * 根据url取消下载,并删除已下载的文件 */ public void cancel(String url) { - cancel(url, true, false); + cancel(url, true, false, false); } /** @@ -755,7 +755,7 @@ public class DownloadManager implements DownloadStatusListener { * * @param automatic 是否是安装完自动删除 */ - public void cancel(String url, boolean isDeleteFile, boolean automatic) { + public void cancel(String url, boolean isDeleteFile, boolean automatic, boolean cancelSilently) { DownloadEntity entry = mDownloadDao.get(url); if (entry != null) { AppExecutor.getIoExecutor().execute(() -> { @@ -783,11 +783,15 @@ public class DownloadManager implements DownloadStatusListener { task.cancel(); // 改任务队列的状态 DataChanger.INSTANCE.getDownloadingTasks().remove(entry.getUrl()); - DataChanger.INSTANCE.notifyDataChanged(entry); + if (!cancelSilently) { + DataChanger.INSTANCE.notifyDataChanged(entry); + } } DataChanger.INSTANCE.getDownloadEntries().remove(entry.getUrl()); - DataChanger.INSTANCE.notifyDataChanged(entry); - DownloadStatusManager.getInstance().onTaskCancelled(entry); + if (!cancelSilently) { + DataChanger.INSTANCE.notifyDataChanged(entry); + DownloadStatusManager.getInstance().onTaskCancelled(entry); + } Utils.log(DownloadManager.class.getSimpleName(), "cancel"); }, 0); diff --git a/app/src/main/java/com/gh/download/PackageObserver.kt b/app/src/main/java/com/gh/download/PackageObserver.kt index b6d515980d..ab51b38e2c 100644 --- a/app/src/main/java/com/gh/download/PackageObserver.kt +++ b/app/src/main/java/com/gh/download/PackageObserver.kt @@ -103,7 +103,7 @@ object PackageObserver { // 畅玩游戏安装完成的同时直接删除文件 runOnIoThread { FileUtils.deleteFile(mDownloadEntity.path) } } else { - DownloadManager.getInstance().cancel(mDownloadEntity.url, false, true) + DownloadManager.getInstance().cancel(mDownloadEntity.url, false, true, false) } } if (sp.getBoolean(CONCERN_GAME_SP_KEY, true)) { //设置页面控制是否安装后自动关注 diff --git a/app/src/main/java/com/gh/gamecenter/entity/AppEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/AppEntity.kt index 65fd42ffc6..70b391b6fd 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/AppEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/AppEntity.kt @@ -31,6 +31,10 @@ data class AppEntity( * EVERY_TIME_OPEN(每次打开) */ var alert: String? = null, -) : Parcelable +) : Parcelable { + fun isAlertEveryTime() = alert == "EVERY_TIME_OPEN" + + fun isAlertOnceADay() = alert == "ONCE_A_DAY" +} diff --git a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt index a6cb36cefe..c4e5099c26 100644 --- a/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/home/HomeViewModel.kt @@ -68,6 +68,7 @@ class HomeViewModel(application: Application) : AndroidViewModel(application) { init { itemDataList.addSource(PackageRepository.gameUpdateLiveData) { initPlugin(it) + refreshRecentVGameIfNeeded() } itemDataList.addSource(DownloadManager.getInstance().downloadEntityLiveData) { refreshRecentVGameIfNeeded() diff --git a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java index 488465bb49..0b0403e01c 100644 --- a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java +++ b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java @@ -144,7 +144,7 @@ public class UpdateManager { } if (DownloadStatus.done.equals(downloadEntity.getStatus())) { - DownloadManager.getInstance().cancel(downloadEntity.getUrl(), false, true); + DownloadManager.getInstance().cancel(downloadEntity.getUrl(), false, true, false); if (downloadDialog != null) { try { downloadDialog.dismiss(); @@ -517,7 +517,7 @@ public class UpdateManager { } downloadEntity.setPackageName(mApplicationContext.getPackageName()); - DownloadManager.getInstance().cancel(appEntity.getUrl(), true, true); + DownloadManager.getInstance().cancel(appEntity.getUrl(), true, true, false); DownloadManager.getInstance().pauseAll(); AppExecutor.getUiExecutor().executeWithDelay(() -> { diff --git a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt index 9e3977741d..bd11cde67b 100644 --- a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt @@ -261,6 +261,7 @@ object PackageRepository { } else if (game.isVGame()) { // 畅玩游戏移除更新,避免死循环更新 removeUpdate(game.id) + return true } return false @@ -359,7 +360,7 @@ object PackageRepository { * 移除更新 * @param gameId 游戏 ID */ - private fun removeUpdate(gameId: String) { + fun removeUpdate(gameId: String) { gameUpdate.removeAll { it.id == gameId } } diff --git a/app/src/main/java/com/gh/vspace/VBackupHelper.kt b/app/src/main/java/com/gh/vspace/VBackupHelper.kt new file mode 100644 index 0000000000..65449fbbab --- /dev/null +++ b/app/src/main/java/com/gh/vspace/VBackupHelper.kt @@ -0,0 +1,77 @@ +package com.gh.vspace + +import android.content.Context +import android.os.Environment +import com.gh.download.DownloadManager +import com.gh.gamecenter.common.utils.isSmoothGame +import com.gh.gamecenter.core.runOnIoThread +import com.lightgame.download.DBHelper +import com.lightgame.download.DownloadStatus +import com.lightgame.utils.Utils +import java.io.File +import java.io.FileInputStream +import java.io.FileOutputStream +import java.nio.channels.FileChannel + +object VBackupHelper { + + fun recoverValidData(context: Context) { + runOnIoThread { + recoverFromBackupDb(context) + + val entityList = DownloadManager.getInstance().allDownloadEntity + + for (entity in entityList) { + if (!entity.isSmoothGame() || entity.status != DownloadStatus.done) { + DownloadManager.getInstance().cancel(entity.url) + } + } + } + } + + private fun recoverFromBackupDb(context: Context) { + try { + val rootDir: File = Environment.getExternalStorageDirectory() + if (rootDir.canWrite()) { + val appDB: File = context.getDatabasePath(DBHelper.DB_NAME) + val backupDBPath = String.format("/gh-files/%s.bak", DBHelper.DB_NAME) + val externalDB = File(rootDir, backupDBPath) + val src: FileChannel = FileInputStream(externalDB).channel + val dst: FileChannel = FileOutputStream(appDB).channel + dst.transferFrom(src, 0, src.size()) + src.close() + dst.close() + + externalDB.delete() + + Utils.log("Import Download DB Successful!") + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + /** + * 备份现有数据库到 SD 卡 + */ + fun backupDBToExternalStorage(context: Context) { + try { + val rootDir: File = Environment.getExternalStorageDirectory() + if (rootDir.canWrite()) { + val appDB: File = context.getDatabasePath(DBHelper.DB_NAME) + val externalDBPath = String.format("/gh-files/%s.bak", DBHelper.DB_NAME) + val externalDB = File(rootDir, externalDBPath) + val src: FileChannel = FileInputStream(appDB).channel + val dst: FileChannel = FileOutputStream(externalDB).channel + dst.transferFrom(src, 0, src.size()) + src.close() + dst.close() + + Utils.log("Export Download DB Successful!") + } + } catch (e: Exception) { + e.printStackTrace() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/vspace/VDownloadManagerWrapperFragment.kt b/app/src/main/java/com/gh/vspace/VDownloadManagerWrapperFragment.kt index 31475e91b0..459e7db978 100644 --- a/app/src/main/java/com/gh/vspace/VDownloadManagerWrapperFragment.kt +++ b/app/src/main/java/com/gh/vspace/VDownloadManagerWrapperFragment.kt @@ -27,7 +27,7 @@ class VDownloadManagerWrapperFragment: BaseLazyTabFragment() { super.onCreate(savedInstanceState) // 进入的时候再连接一遍服务,尽量保证能用 - VHelper.connectService() + VHelper.connectService(true) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/java/com/gh/vspace/VHelper.kt b/app/src/main/java/com/gh/vspace/VHelper.kt index c37358ab04..33c50eb316 100644 --- a/app/src/main/java/com/gh/vspace/VHelper.kt +++ b/app/src/main/java/com/gh/vspace/VHelper.kt @@ -29,6 +29,7 @@ import com.gh.gamecenter.core.runOnIoThread import com.gh.gamecenter.core.runOnUiThread import com.gh.gamecenter.core.utils.EmptyCallback import com.gh.gamecenter.core.utils.GsonUtils +import com.gh.gamecenter.core.utils.SPUtils import com.gh.gamecenter.core.utils.ToastUtils import com.gh.gamecenter.entity.* import com.gh.gamecenter.eventbus.EBPackage @@ -52,6 +53,7 @@ object VHelper { private const val LOG_TAG = "VSPACE" private const val KEY_LAST_PLAYED_TIME = "last_played_time" + private const val KEY_LAST_ALERT_UPDATE_URL = "last_alert_update_url" private val mDelegateManager by lazy { VirtualAppManager.get() } private var mInstalledInfoList: List = arrayListOf() @@ -89,7 +91,7 @@ object VHelper { if (config != null && PackageUtils.isInstalled(context, config.arch64?.packageName) ) { - connectService() + connectService(true) // 检查畅玩助手组件更新 checkVSpaceUpdate(config.arch64!!) @@ -100,13 +102,16 @@ object VHelper { /** * 连接服务 */ - fun connectService(callbackClosure: (() -> Unit)? = null) { + fun connectService(shouldCheckUpdate: Boolean = false, callbackClosure: (() -> Unit)? = null) { mDelegateManager.connectService(object : RemoteConnectListener { override fun onServiceConnectionSuccessed() { Utils.log(LOG_TAG, "V 服务连接成功") + mInstalledInfoList = getInstalledList() - PackageRepository.addInstalledGames(getInstalledPackageList(), true) + if (shouldCheckUpdate) { + checkUpdateViaPackageRepository() + } callbackClosure?.invoke() } @@ -211,10 +216,10 @@ object VHelper { PackageUtils.getVersionCodeByPackageName(vaConfig64?.packageName) // 检查更新 - val containsUpdate = - mUpdateEntity != null && installedSpaceVersionCode < mUpdateEntity!!.versionCode + val containsUpdate = shouldShowVSpaceUpdate(mUpdateEntity, installedSpaceVersionCode) if (containsUpdate) { + SPUtils.setString(KEY_LAST_ALERT_UPDATE_URL, mUpdateEntity!!.url ?: "") DialogHelper.showDialog( context = context, title = "服务工具更新提示", @@ -233,7 +238,7 @@ object VHelper { }, extraConfig = DialogHelper.Config(centerTitle = true), uiModificationCallback = { - if (mUpdateEntity!!.isForce) { + if (mUpdateEntity!!.isAlertEveryTime()) { it.confirmTv.visibility = View.GONE it.cancelTv.setTextColor(R.color.theme_font.toColor(context)) } @@ -283,7 +288,7 @@ object VHelper { try { list = mDelegateManager.installedGamesInfo - Utils.log(LOG_TAG, "已安装应用数量${list.size}") + Utils.log(LOG_TAG, "已安装应用数量${list.size}" + list) } catch (e: Exception) { Utils.log(LOG_TAG, "获取已安装应用数量异常 ${e.localizedMessage}") } @@ -313,7 +318,7 @@ object VHelper { if (mDelegateManager.isConnectAidlInterface) { checkClosure.invoke() } else { - connectService(checkClosure) + connectService(false, checkClosure) } } @@ -368,6 +373,8 @@ object VHelper { mInstallationLiveData.postValue(result.packageName) Utils.log(LOG_TAG, "安装新应用结果 -> " + result.status) + + VBackupHelper.backupDBToExternalStorage(HaloApp.getInstance()) } catch (e: Exception) { runOnUiThread { ToastUtils.toast(e.localizedMessage ?: "") @@ -380,7 +387,7 @@ object VHelper { if (mDelegateManager.isConnectAidlInterface) { installClosure.invoke() } else { - connectService(installClosure) + connectService(false, installClosure) } } @@ -464,7 +471,7 @@ object VHelper { if (mDelegateManager.isConnectAidlInterface) { uninstallClosure.invoke() } else { - connectService(uninstallClosure) + connectService(false, uninstallClosure) } } @@ -573,7 +580,7 @@ object VHelper { ) { Utils.log(LOG_TAG, "更新应用${originDownloadEntity.packageName}") - DownloadManager.getInstance().cancel(originDownloadEntity.url) + DownloadManager.getInstance().cancel(originDownloadEntity.url, false, false, true) if (updateEntity != null) { originDownloadEntity.url = updateEntity.url @@ -589,6 +596,8 @@ object VHelper { updateEntity.iconSubscript ) originDownloadEntity.addMetaExtra(Constants.APK_MD5, updateEntity.md5) + + PackageRepository.removeUpdate(updateEntity.id) } originDownloadEntity.isUpdate = true @@ -662,4 +671,48 @@ object VHelper { }) } + /** + * 通过 PackageRepository 检查更新 + */ + private fun checkUpdateViaPackageRepository() { + val rawInstalledPackageList = getInstalledPackageList() + val validInstalledPackageList = arrayListOf() + for (packageName in rawInstalledPackageList) { + if (getDownloadEntitySnapshotByPackageName(packageName) != null) { + validInstalledPackageList.add(packageName) + } + } + PackageRepository.addInstalledGames(validInstalledPackageList, true) + } + + /** + * 是否需要显示畅玩助手更新 + */ + private fun shouldShowVSpaceUpdate( + updateEntity: AppEntity?, + installedSpaceVersionCode: Int + ): Boolean { + if (updateEntity == null) return false + + val hasNewerVersion = installedSpaceVersionCode < updateEntity.versionCode + + if (!hasNewerVersion) return false + + if (updateEntity.isAlertEveryTime()) return true + + if (updateEntity.isAlertOnceADay() + && SPUtils.getString(KEY_LAST_ALERT_UPDATE_URL) != updateEntity.url + ) { + return true + } + + return false + } + + @JvmStatic + fun recoverVDataIfPossible() { + VBackupHelper.recoverValidData(HaloApp.getInstance()) + connectService() + } + } \ No newline at end of file