Compare commits

...

6 Commits

18 changed files with 365 additions and 166 deletions

View File

@ -38,7 +38,7 @@
<!-- 允许应用程序快捷方式 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- 应用安装相关 -->
<uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" />
<!-- <uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" />-->
<!-- 前台服务权限-->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

View File

@ -335,11 +335,11 @@ public class Config {
}
// 更新安装列表是否开启的配置
// if (mNewApiSettingsEntity.getInstalledComplianceSwitch() != null) {
// PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(mNewApiSettingsEntity.getInstalledComplianceSwitch());
// } else {
// PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(false);
// }
if (mNewApiSettingsEntity.getInstalledComplianceSwitch() != null) {
PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(mNewApiSettingsEntity.getInstalledComplianceSwitch());
} else {
PackageHelper.INSTANCE.updateIsGetInstalledPackagesApiAgreedRequired(false);
}
// 更新包名监听是否开启
if (mNewApiSettingsEntity.isPackageObserveEnable()) {

View File

@ -7,6 +7,7 @@ import com.gh.download.PackageObserver
import com.gh.gamecenter.common.utils.NewFlatLogUtils
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.lightgame.utils.Utils
@ -75,11 +76,17 @@ object PackageChangeHelper : DefaultLifecycleObserver {
PackageRepository.addInstalledGame(packageName)
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
performInstallSuccessAction(packageName)
} else if (isUninstallPending && !isInstalled) {
pendingPackagePair = null
pendingGhId = null
// 从额外的包名白名单移除,下次启动时不再查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = false)
performUninstallSuccessAction(packageName)
} else if (isUpdatePending) {
val isUpdateValid = if (installedVersionName != pendingVersion) {
@ -95,23 +102,28 @@ object PackageChangeHelper : DefaultLifecycleObserver {
performUninstallSuccessAction(packageName)
performInstallSuccessAction(packageName)
}
// 添加到额外的包名白名单,下次启动同时查询此包的安装情况
PackageHelper.updateAdditionalWhiteListPackageName(packageName = packageName, isAdd = true)
}
}
}
fun addInstall(packageName: String) {
performInstallSuccessAction(packageName)
fun addInstall(packageName: String, cachedGameEntity: GameEntity? = null) {
performInstallSuccessAction(packageName, cachedGameEntity)
}
fun addUpdate(packageName: String) {
fun addUpdate(packageName: String, cachedGameEntity: GameEntity? = null) {
performUninstallSuccessAction(packageName)
performInstallSuccessAction(packageName)
performInstallSuccessAction(packageName, cachedGameEntity)
}
/**
* 对应包名安装成功后的操作,继承至 PackageChangeBroadcastObserver
*/
private fun performInstallSuccessAction(packageName: String, withLog: Boolean = true) {
private fun performInstallSuccessAction(packageName: String,
cachedGameEntity: GameEntity? = null,
withLog: Boolean = true) {
Utils.log(TAG, "安装了: $packageName 包名的程序")
val downloadEntity = DownloadManager.getInstance().getDownloadEntitySnapshotByPackageName(packageName)
val gameId = if (downloadEntity != null && downloadEntity.gameId != null) downloadEntity.gameId else ""
@ -128,7 +140,7 @@ object PackageChangeHelper : DefaultLifecycleObserver {
val versionName = PackageUtils.getVersionNameByPackageName(packageName)
val installEb = EBPackage(EBPackage.TYPE_INSTALLED, packageName, versionName)
PackageObserver.onPackageChanged(installEb)
PackageObserver.onPackageChanged(installEb, cachedGameEntity)
EventBus.getDefault().post(installEb)
}

View File

@ -17,12 +17,14 @@ import com.gh.common.prioritychain.RequestInstalledListPermissionHandler
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.utils.DialogHelper
import com.gh.gamecenter.common.utils.PermissionHelper
import com.gh.gamecenter.common.utils.PermissionHelper.isGetInstalledListPermissionDisabled
import com.gh.gamecenter.common.utils.SensorsBridge
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.common.utils.toJson
import com.gh.gamecenter.common.utils.toObject
import com.gh.gamecenter.core.GHThreadFactory
import com.gh.gamecenter.core.runOnUiThread
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.entity.WhitePackageListEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.SettingsEntity
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
@ -31,9 +33,8 @@ import com.halo.assistant.HaloApp
import com.lightgame.utils.Utils
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.*
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.util.HashMap
import java.util.concurrent.Executors
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
@ -42,6 +43,11 @@ object PackageHelper {
private const val TAG = "PackageHelper"
private const val SP_GET_INSTALLED_API_AGREED = "get_installed_api_agreed"
private const val SP_GET_INSTALLED_PERMISSION_REQUESTED = "get_installed_permission_requested"
private const val SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE = "user_used_get_installed_api_switch_package" // 用户是否使用过已安装应用列表获取开关的包
private const val SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST = "additional_whitelist_package_name_list" // 额外的白名单包名列表 (曾经更正为已安装的包名列表)
private const val UNKNOWN = -1
private const val UNSUPPORTED = 0
@ -52,11 +58,16 @@ object PackageHelper {
private var lastInstalledPackageListTime = 0L
private var cachedInstalledPackagesList: List<PackageInfo> = arrayListOf()
private var additionalWhiteListPackageNameSet: HashSet<String> = hashSetOf()
private var isGetInstalledPackagesApiAgreed = true // 用户是否已经同意使用已安装应用列表 API
private var isGetInstalledPackagesApiAgreedRequired = DISABLED // 需要用户手动授权才获取已安装应用列表的功能的开关
private var isGetInstalledPackagesApiAgreed = false // 用户是否已经同意使用已安装应用列表 API
private var isGetInstalledPackagesApiAgreedRequired = UNKNOWN // 需要用户手动授权才获取已安装应用列表的功能的开关
private var isGetInstalledPackagesPermissionSupported = UNKNOWN // 设备是否支持禁用获取已安装应用列表
private var reservedGameEntityMap = HashMap<String, GameEntity>() // 目前检查当前安装信息缺失的游戏 Entity
private val packageExecutor by lazy { Executors.newSingleThreadExecutor(GHThreadFactory("GH_PACKAGE_THREAD")) }
// 评论黑名单包名列表,避免用户安装了 Xposed Installer 这样的工具,也能在包含该安装包的游戏详情页评论
private var _commentPackageNameBlackList = arrayListOf<String>()
val commentPackageNameBlackList: ArrayList<String> = _commentPackageNameBlackList
@ -88,17 +99,51 @@ object PackageHelper {
}
}
/**
* 检查是否需要忽略已安装应用列表获取开关
*/
fun checkIfGetInstalledApiSwitchShouldBeIgnored(context: Context) {
val userHasUsedGetInstalledApiSwitchPackage = SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, false)
if (!userHasUsedGetInstalledApiSwitchPackage) {
val isSupportGetInstalledAppsPermission = isSupportGetInstalledAppsPermission(context)
if (!isSupportGetInstalledAppsPermission) {
onGetInstalledAppsListPermissionGranted()
} else if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
onGetInstalledAppsListPermissionGranted()
}
SPUtils.getBoolean(SP_USER_USED_GET_INSTALLED_API_SWITCH_PACKAGE, true)
}
}
/**
* 获取已安装的白名单列表(为了在没有已安装应用列表获取能力的时候也能正常判断更新、插件化)
*/
@SuppressLint("CheckResult")
fun getInstalledWhiteList() {
fun getInstalledWhiteList(additionalInstalledWhiteList: HashSet<String>) {
RetrofitManager.getInstance().newApi.installWhitelist
.subscribeOn(Schedulers.io())
.subscribe(object : BiResponse<WhitePackageListEntity>() {
override fun onSuccess(data: WhitePackageListEntity) {
val installedWhiteList = hashSetOf<String>()
if (additionalInstalledWhiteList.isNotEmpty()) {
installedWhiteList.addAll(additionalInstalledWhiteList)
}
data.data?.let {
addInstalledButMissingPackages(it)
installedWhiteList.addAll(it)
}
addInstalledButMissingPackages(installedWhiteList)
}
override fun onFailure(exception: Exception) {
super.onFailure(exception)
if (additionalInstalledWhiteList.isNotEmpty()) {
addInstalledButMissingPackages(additionalInstalledWhiteList)
}
}
})
@ -175,17 +220,28 @@ object PackageHelper {
return
}
Utils.log(TAG, "updateIsGetInstalledPackagesApiAgreedRequired 更新为 $isEnabled")
if (isEnabled) {
getInstalledWhiteList()
additionalWhiteListPackageNameSet = SPUtils.getString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST).toObject() ?: hashSetOf()
Utils.log(TAG, "updateIsGetInstalledPackagesApiAgreedRequired 额外的白名单为 $additionalWhiteListPackageNameSet")
getInstalledWhiteList(additionalWhiteListPackageNameSet)
_installedPackageApiSwitchStatusLiveData.postValue(true)
isGetInstalledPackagesApiAgreedRequired = ENABLED
} else {
isGetInstalledPackagesApiAgreedRequired = DISABLED
if (isSupportGetInstalledAppsPermission(HaloApp.getInstance())) {
GlobalPriorityChainHelper.queueNewHandler(RequestInstalledListPermissionHandler())
if (!SPUtils.getBoolean(SP_GET_INSTALLED_PERMISSION_REQUESTED, false)) {
SPUtils.setBoolean(SP_GET_INSTALLED_PERMISSION_REQUESTED, true)
GlobalPriorityChainHelper.queueNewHandler(RequestInstalledListPermissionHandler())
}
} else {
agreeOnGetInstalledPackagesApi()
// 临时启用 https://jira.shanqu.cc/browse/GHZSCY-5661
onGetInstalledAppsListPermissionGranted()
// initPackageRelatedData()
}
}
}
@ -226,7 +282,7 @@ object PackageHelper {
}
// 简单 debounce 过于频繁的获取已安装应用列表调用
if (System.currentTimeMillis() - lastInstalledPackageListTime < 3000 && cachedInstalledPackagesList.isNotEmpty()) {
if (System.currentTimeMillis() - lastInstalledPackageListTime < 20 * 1000 && cachedInstalledPackagesList.isNotEmpty()) {
Utils.log(TAG, "使用了缓存的已安装应用列表")
return cachedInstalledPackagesList
}
@ -237,7 +293,7 @@ object PackageHelper {
if (isSupportGetInstalledAppsPermission(context!!)) {
Utils.log(TAG, "当前设备支持限制获取已安装应用列表的功能")
// 当前设备是否支持禁用了获取已安装应用列表
if (!isGetInstalledListPermissionDisabled(context)) {
if (!PermissionHelper.isGetInstalledListPermissionDisabled(context)) {
Utils.log(TAG, "当前设备没有限制获取已安装应用列表的功能")
shouldGetNewInstalledPackagedList = true
} else {
@ -265,18 +321,10 @@ object PackageHelper {
resultClosure: (Boolean) -> Unit
) {
val globalOnPermissionGrantedClosure = {
agreeOnGetInstalledPackagesApi()
// 进行包名初始化相关的操作
PackageRepository.initData()
refreshLocalPackageList()
refreshList()
}
if (isSupportGetInstalledAppsPermission(activity)) {
// 若系统已经授予了获取应用列表的权限,直接进行授权成功回调
if (!isGetInstalledListPermissionDisabled(activity)) {
globalOnPermissionGrantedClosure.invoke()
if (!PermissionHelper.isGetInstalledListPermissionDisabled(activity)) {
onGetInstalledAppsListPermissionGranted()
resultClosure.invoke(true)
return
}
@ -288,7 +336,7 @@ object PackageHelper {
) { isGranted ->
if (isGranted) {
SensorsBridge.trackInstalledListPermissionsResult("成功")
globalOnPermissionGrantedClosure.invoke()
onGetInstalledAppsListPermissionGranted()
resultClosure.invoke(true)
trackInstalledListAfterDelay()
@ -315,7 +363,7 @@ object PackageHelper {
cancelText = "拒绝",
confirmClickCallback = {
SensorsBridge.trackInstalledListPermissionsCustomClick("开启")
globalOnPermissionGrantedClosure.invoke()
onGetInstalledAppsListPermissionGranted()
resultClosure.invoke(true)
trackInstalledListAfterDelay()
@ -332,6 +380,21 @@ object PackageHelper {
}
}
private fun onGetInstalledAppsListPermissionGranted() {
agreeOnGetInstalledPackagesApi()
// 进行包名初始化相关的操作
initPackageRelatedData()
}
/**
* 进行包名初始化相关的操作
*/
fun initPackageRelatedData() {
PackageRepository.initData()
refreshLocalPackageList()
refreshList()
}
/**
* 延迟5秒后上报已安装应用列表
*/
@ -346,6 +409,10 @@ object PackageHelper {
* 是否支持动态获取已安装应用列表权限
*/
fun isSupportGetInstalledAppsPermission(context: Context): Boolean {
// 临时禁用 https://jira.shanqu.cc/browse/GHZSCY-5661
isGetInstalledPackagesPermissionSupported = UNSUPPORTED
// 若存在缓存,直接返回缓存结果。
if (isGetInstalledPackagesPermissionSupported != UNKNOWN) {
return isGetInstalledPackagesPermissionSupported != UNSUPPORTED
@ -390,13 +457,20 @@ object PackageHelper {
val installedPackageNameSet: HashSet<String> = hashSetOf()
for (packageName in packageNameSet) {
if (!PackagesManager.isInstalled(packageName)
&& PackageUtils.getVersionNameByPackageName(packageName) != null
) {
val installedPkgNameExistInMemory = PackagesManager.isInstalled(packageName)
val packageNameInstalledOnDevice = PackageUtils.getVersionNameByPackageName(packageName) != null
if (!installedPkgNameExistInMemory && packageNameInstalledOnDevice) {
installedPackageNameSet.add(packageName)
}
if (!packageNameInstalledOnDevice) {
additionalWhiteListPackageNameSet.remove(packageName)
}
}
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toJson())
Utils.log(TAG, "addInstalledButMissingPackages 需要请求接口获取的包数量为 ${installedPackageNameSet.size}")
PackageRepository.addInstalledGames(
@ -405,22 +479,36 @@ object PackageHelper {
)
}
/**
* 更新额外的白名单包名列表
* @param packageName 包名
* @param isAdd 是否添加
*/
fun updateAdditionalWhiteListPackageName(packageName: String, isAdd: Boolean) {
val isUpdated = if (isAdd) {
additionalWhiteListPackageNameSet.add(packageName)
} else {
additionalWhiteListPackageNameSet.remove(packageName)
}
Utils.log(TAG, "updateAdditionalWhiteListPackageName 更新额外的白名单包名列表 $isAdd $packageName ,结果是 $isUpdated")
if (isUpdated) {
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toJson())
}
}
fun refreshWrongInstallStatus(packageNameSet: MutableSet<String>) {
runOnIoThread {
packageExecutor.execute {
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
val installedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (packageName in packageNameSet) {
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
if (!PackagesManager.isInstalled(packageName)
&& installedVersionName != null
) {
installedButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
if (PackagesManager.isInstalled(packageName)
&& installedVersionName == null) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
@ -430,21 +518,17 @@ object PackageHelper {
}
}
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已安装状态的包数量为 ${installedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}")
runOnUiThread {
if (installedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in installedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addInstall(packageName)
}
}
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in uninstalledButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUninstall(packageName)
additionalWhiteListPackageNameSet.remove(packageName)
}
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toString())
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
@ -456,46 +540,109 @@ object PackageHelper {
}
}
/**
* 在5.1系统手机使用PackageManager获取已安装应用容易发生Package manager has died异常
* https://stackoverflow.com/questions/13235793/transactiontoolargeeception-when-trying-tÏo-get-a-list-of-applications-installed/30062632#30062632
*/
fun refreshWrongInstallStatus(gameEntityList: ArrayList<GameEntity>) {
packageExecutor.execute {
Utils.log(TAG, "refreshWrongInstallStatus 检查安装状态异常的应用")
val installedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val uninstalledButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
val updatedButKeepingWrongStatusPackageNameSet: HashSet<String> = hashSetOf()
for (game in gameEntityList) {
for (apk in game.getApk()) {
val packageName = apk.packageName
val installedVersionName = PackageUtils.getVersionNameByPackageName(packageName)
if (!PackagesManager.isInstalled(packageName)
&& installedVersionName != null
) {
reservedGameEntityMap.put(packageName, game)
installedButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName == null
) {
uninstalledButKeepingWrongStatusPackageNameSet.add(packageName)
} else if (PackagesManager.isInstalled(packageName)
&& installedVersionName != null
&& !PackagesManager.isInstalledWithSpecificVersion(packageName, installedVersionName)
&& !PackagesManager.isCanUpdate(game.id, packageName, false)
) {
reservedGameEntityMap.put(packageName, game)
updatedButKeepingWrongStatusPackageNameSet.add(packageName)
}
}
}
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已安装状态的包数量为 ${installedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要更新已更新状态的包数量为 ${updatedButKeepingWrongStatusPackageNameSet.size}")
Utils.log(TAG, "refreshWrongInstallStatus 需要移除已安装的包数量为 ${uninstalledButKeepingWrongStatusPackageNameSet.size}")
runOnUiThread {
if (installedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in installedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addInstall(packageName, reservedGameEntityMap.remove(packageName))
additionalWhiteListPackageNameSet.add(packageName)
}
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toString())
}
if (uninstalledButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in uninstalledButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUninstall(packageName)
additionalWhiteListPackageNameSet.remove(packageName)
}
SPUtils.setString(SP_ADDITIONAL_WHITELIST_PACKAGE_NAME_LIST, additionalWhiteListPackageNameSet.toString())
}
if (updatedButKeepingWrongStatusPackageNameSet.isNotEmpty()) {
for (packageName in updatedButKeepingWrongStatusPackageNameSet) {
PackageChangeHelper.addUpdate(packageName, reservedGameEntityMap.remove(packageName))
}
}
}
}
}
private fun getInstalledPackagesInternal(context: Context, flags: Int): List<PackageInfo> {
Utils.log(TAG, "调用系统 API 获取已安装应用列表")
val pm = context.packageManager
try {
return pm.getInstalledPackages(flags)
return getInstalledPackageAlternative(context)
// return pm.getInstalledPackages(flags)
} catch (ignored: java.lang.Exception) {
//we don't care why it didn't succeed. We'll do it using an alternative way instead
// do nothing
}
// use fallback:
val process: Process
val result: MutableList<PackageInfo> = java.util.ArrayList()
var bufferedReader: BufferedReader? = null
try {
process = Runtime.getRuntime().exec("pm list packages")
bufferedReader = BufferedReader(InputStreamReader(process.inputStream))
var line: String
while ((bufferedReader.readLine().also { line = it }) != null) {
val packageName = line.substring(line.indexOf(':') + 1)
val packageInfo = pm.getPackageInfo(packageName, flags)
result.add(packageInfo)
}
process.waitFor()
} catch (e: java.lang.Exception) {
e.printStackTrace()
if (e is InterruptedException) {
Thread.currentThread().interrupt()
}
} finally {
if (bufferedReader != null) try {
bufferedReader.close()
} catch (e: IOException) {
e.printStackTrace()
return arrayListOf()
}
private fun getInstalledPackageAlternative(context: Context): ArrayList<PackageInfo> {
val packageManager = context.getPackageManager()
val packageList = arrayListOf<PackageInfo>()
var packagesArray: Array<String>? = null
var uid = android.os.Process.FIRST_APPLICATION_UID
while (uid <= android.os.Process.LAST_APPLICATION_UID) {
packagesArray = packageManager.getPackagesForUid(uid)
if (packagesArray != null && packagesArray.isNotEmpty()) {
for (packageName in packagesArray) {
try {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
if (packageInfo == null) {
break
}
packageList.add(packageInfo)
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
}
}
uid++
}
return result
return packageList
}
}

View File

@ -20,6 +20,7 @@ import com.gh.gamecenter.core.utils.ThirdPartyPackageHelper
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.GameDigestEntity
import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.utils.ConcernUtils
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.manager.PackagesManager
@ -55,7 +56,7 @@ object PackageObserver {
}
@JvmStatic
fun onPackageChanged(busFour: EBPackage) {
fun onPackageChanged(busFour: EBPackage, cachedGameEntity: GameEntity? = null) {
val application = HaloApp.getInstance().application
val packageName = busFour.packageName
val versionName = busFour.versionName
@ -99,7 +100,7 @@ object PackageObserver {
if (EBPackage.TYPE_INSTALLED == busFour.type) {
if (!busFour.isVGame) {
// 非畅玩游戏才执行下面的代码
mPackageViewModel.addInstalledGame(packageName)
mPackageViewModel.addInstalledGame(packageName, cachedGameEntity)
BrowserInstallHelper.onApkInstalled(mDownloadEntity?.path)
}

View File

@ -932,7 +932,7 @@ public class MainActivity extends BaseActivity {
Config.refreshVSettingEntity();
}
mPackageViewModel.checkData();
// mPackageViewModel.checkData();
deleteSimulatorGame();
}
}

View File

@ -116,6 +116,7 @@ class SplashScreenActivity : BaseActivity() {
}
} else {
cancelPreviousUpdateTask()
// PackageHelper.checkIfGetInstalledApiSwitchShouldBeIgnored(this)
launchMainActivity()
}
} else {
@ -167,10 +168,12 @@ class SplashScreenActivity : BaseActivity() {
if (isMalfunctioningHonorDevice) {
showHonorNotification()
mBaseHandler.postDelayed({
requestGetInstallListPermissionAndLaunchMainActivity()
launchMainActivity()
// requestGetInstallListPermissionAndLaunchMainActivity()
}, 100L)
} else {
requestGetInstallListPermissionAndLaunchMainActivity()
launchMainActivity()
// requestGetInstallListPermissionAndLaunchMainActivity()
}
} else {
DialogUtils.showPrivacyPolicyDisallowDialog(this) {
@ -196,17 +199,17 @@ class SplashScreenActivity : BaseActivity() {
}
// 尝试获取安装应用列表权限并启动首页(不在乎结果)
private fun requestGetInstallListPermissionAndLaunchMainActivity() {
if (PackageHelper.isSupportGetInstalledAppsPermission(this)
&& PermissionHelper.isGetInstalledListPermissionDisabled(this)
) {
PermissionHelper.requestGetInstalledAppsListPermission(this, true) {
launchMainActivity()
}
} else {
launchMainActivity()
}
}
// private fun requestGetInstallListPermissionAndLaunchMainActivity() {
// if (PackageHelper.isSupportGetInstalledAppsPermission(this)
// && PermissionHelper.isGetInstalledListPermissionDisabled(this)
// ) {
// PermissionHelper.requestGetInstalledAppsListPermission(this, true) {
// launchMainActivity()
// }
// } else {
// launchMainActivity()
// }
// }
// 删除更新后的光环助手包
private fun cancelPreviousUpdateTask() {

View File

@ -27,7 +27,6 @@ import com.gh.gamecenter.eventbus.EBPackage
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.feature.entity.GameInstall
import com.gh.gamecenter.manager.PackagesManager
import com.gh.gamecenter.packagehelper.PackageRepository
import com.gh.gamecenter.packagehelper.PackageViewModel
import com.lightgame.download.DataWatcher
import com.lightgame.download.DownloadEntity
@ -109,6 +108,11 @@ class NewInstalledGameFragment : ToolbarFragment() {
mPackageViewModel =
ViewModelProvider(this, PackageViewModel.Factory()).get(PackageViewModel::class.java)
if (mPackageViewModel?.getGameInstalledLiveData()?.value.isNullOrEmpty() == true) {
mInstallGameViewModel.initData(arrayListOf())
}
mPackageViewModel?.getGameInstalledLiveData()?.observe(
this
) { gameInstalls ->

View File

@ -52,10 +52,16 @@ class UpdatableGameFragment : LazyFragment() {
super.onFragmentFirstVisible()
mPackageViewModel = viewModelProvider(PackageViewModel.Factory())
if (mPackageViewModel?.getGameUpdateIncludeCurrentVersion()?.value.isNullOrEmpty() == true) {
mViewModel?.setUpdatableList(arrayListOf())
}
mPackageViewModel?.getGameUpdateIncludeCurrentVersion()
?.observeNonNull(viewLifecycleOwner) { updatableList ->
mViewModel?.setUpdatableList(updatableList)
}
mViewModel?.updatableData?.observe(viewLifecycleOwner) {
mAdapter?.submitList(it)
mBinding?.noDataContainer?.root?.goneIf(!it.isNullOrEmpty())

View File

@ -29,6 +29,7 @@ import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.entity.GamesCollectionDetailEntity
import com.gh.gamecenter.eventbus.EBUserFollow
import com.gh.gamecenter.feature.entity.CommentEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.qa.article.detail.CommentItemData
import com.gh.gamecenter.qa.comment.base.BaseCommentViewModel
@ -65,7 +66,7 @@ open class GameCollectionDetailViewModel(
var videoIsMuted = SPUtils.getBoolean(Constants.SP_VIDEO_PLAY_MUTE, true)
var isPostFirstOver = false
private var packageNameSet = hashSetOf<String>()
private var gameList: ArrayList<GameEntity>? = null
@SuppressLint("CheckResult")
fun getGameCollectionDetail() {
@ -131,14 +132,12 @@ open class GameCollectionDetailViewModel(
add(mResultLiveData.value!![i])
}
} else {
packageNameSet = hashSetOf()
gameList = arrayListOf<GameEntity>()
games?.forEach {
it.isAdData = adIconActive
add(CommentItemData(game = it))
it.getApk().forEach { apk ->
packageNameSet.add(apk.packageName)
}
gameList?.add(it)
}
refreshPackageStatus()
@ -169,8 +168,8 @@ open class GameCollectionDetailViewModel(
!isHandleTopComment && gameCollectionDetail != null && topCommentId.isNotBlank() && index == 0
fun refreshPackageStatus() {
if (packageNameSet.isNotEmpty()) {
PackageHelper.refreshWrongInstallStatus(packageNameSet)
if (!gameList.isNullOrEmpty()) {
PackageHelper.refreshWrongInstallStatus(gameList!!)
}
}

View File

@ -258,11 +258,9 @@ class GameDetailViewModel(
}
fun refreshWrongInstallStatus() {
val packageNameSet = hashSetOf<String>()
game?.getApk()?.forEach {
packageNameSet.add(it.packageName)
game?.let {
PackageHelper.refreshWrongInstallStatus(arrayListOf(it))
}
PackageHelper.refreshWrongInstallStatus(packageNameSet)
}
private fun replaceWithMirrorInfoIfNeeded(data: NewGameDetailEntity) {

View File

@ -34,7 +34,6 @@ import org.greenrobot.eventbus.EventBus
import org.json.JSONException
import org.json.JSONObject
import java.util.*
import kotlin.collections.HashSet
/**
* 该类存储的是已安装的所有游戏(助手后台已收录的)和所有更新(包括插件化)数据
@ -246,19 +245,9 @@ object PackageRepository {
}
for (game in validGames) {
if (gh_id == null || gh_id == game.id) {
gameInstalled.add(GameInstall.transformGameInstall(game, pkgName, isVGame))
mInstalledGameList.add(game)
val isCanPluggable = checkGamePlugin(game, pkgName)
val isCanUpdate = checkGameUpdate(game, isVGame)
addCurrentlyInstalledVersionIfValid(game)
if (!isNotifyUpdate && isCanUpdate || isCanPluggable) {
isNotifyUpdate = true
}
if (updateInstallStatus) {
EventBus.getDefault().post(EBPackage(EBPackage.TYPE_INSTALLED, pkgName, game.getApk().firstOrNull()?.version))
}
val shouldNotifyChanges = validateGameAndPostChanges(gh_id, game, pkgName, isVGame, updateInstallStatus)
if (!isNotifyUpdate && shouldNotifyChanges) {
isNotifyUpdate = true
}
}
}
@ -274,6 +263,33 @@ object PackageRepository {
}
}
/**
* 验证游戏并且更新数据
*/
private fun validateGameAndPostChanges(ghId: Any?,
game: GameEntity,
pkgName: String,
isVGame: Boolean,
updateInstallStatus: Boolean): Boolean {
if (ghId == null || ghId == game.id) {
gameInstalled.add(GameInstall.transformGameInstall(game, pkgName, isVGame))
mInstalledGameList.add(game)
val isCanPluggable = checkGamePlugin(game, pkgName)
val isCanUpdate = checkGameUpdate(game, isVGame)
addCurrentlyInstalledVersionIfValid(game)
if (updateInstallStatus) {
EventBus.getDefault().post(EBPackage(EBPackage.TYPE_INSTALLED, pkgName, game.getApk().firstOrNull()?.version))
}
if (isCanUpdate || isCanPluggable) {
return true
}
}
return false
}
/**
* 检查游戏更新
* @param game
@ -405,20 +421,38 @@ object PackageRepository {
/**
* 新增已安装的游戏
* @param pkgName 已安装的游戏包名
* @param cachedGameEntity 缓存的游戏实体,若存在免去再请求接口的过程
*/
fun addInstalledGame(pkgName: String, updateInstallStatus: Boolean = false) {
fun addInstalledGame(pkgName: String,
cachedGameEntity: GameEntity? = null) {
mInstalledPkgSet.add(pkgName)
notifyInstallPkgData()
val list = arrayListOf(pkgName)
if (cachedGameEntity != null) {
val ghId = PackageUtils.getMetaData(HaloApp.getInstance().application, pkgName, "gh_id")
val containsUpdate = validateGameAndPostChanges(
ghId = ghId,
game = cachedGameEntity,
pkgName = pkgName,
isVGame = false,
updateInstallStatus = false)
updateFilterPackage(list) {
loadInstalledGameDigestAndNotifyData(
filteredList = list,
onWorkerThreadOnly = true,
updateInstallStatus = updateInstallStatus
)
if (containsUpdate) {
notifyGameUpdateData()
}
notifyInstallPkgData()
} else {
val list = arrayListOf(pkgName)
updateFilterPackage(list) {
loadInstalledGameDigestAndNotifyData(
filteredList = list,
onWorkerThreadOnly = true,
updateInstallStatus = false
)
}
}
changeRecentVaPlayed()
}

View File

@ -5,6 +5,7 @@ import android.text.TextUtils
import androidx.lifecycle.*
import com.gh.gamecenter.feature.entity.GameInstall
import com.gh.gamecenter.entity.GameUpdateEntity
import com.gh.gamecenter.feature.entity.GameEntity
import com.halo.assistant.HaloApp
import kotlin.collections.set
@ -57,15 +58,15 @@ class PackageViewModel(
/**
* 新增一个已安装的游戏
* 只在收到安装广播时调用,不建议手动调用
* @param pkgName 包名
* @param cachedGameEntity 缓存的游戏实体
*/
fun addInstalledGame(pkgName: String?) {
if (!TextUtils.isEmpty(pkgName)) mRepository.addInstalledGame(pkgName!!)
fun addInstalledGame(pkgName: String?, cachedGameEntity: GameEntity? = null) {
if (!TextUtils.isEmpty(pkgName)) mRepository.addInstalledGame(pkgName!!, cachedGameEntity)
}
/**
* 卸载一个已安装的游戏
* 只在收到卸载广播时调用,不建议手动调用
*/
fun addUninstalledGame(pkgName: String?, isVGame: Boolean) {
if (!TextUtils.isEmpty(pkgName)) mRepository.addUninstalledGame(pkgName!!, isVGame)

View File

@ -74,12 +74,12 @@ public class PackageChangeBroadcastReceiver extends BroadcastReceiver {
String versionName = PackageUtils.getVersionNameByPackageName(packageName);
EBPackage installEb = new EBPackage(EBPackage.TYPE_INSTALLED, packageName, versionName);
if (PackageUtils.isAppOnForeground(context)) {
PackageObserver.onPackageChanged(installEb);
PackageObserver.onPackageChanged(installEb, null);
EventBus.getDefault().post(installEb);
} else {
// 处于后台运行的时候尝试延迟 100 ms 再触发 onPackageChanged (猜测是引起 ANR 的原因)
AppExecutor.getUiExecutor().executeWithDelay(() -> {
PackageObserver.onPackageChanged(installEb);
PackageObserver.onPackageChanged(installEb, null);
EventBus.getDefault().post(installEb);
}, 100);
}
@ -103,7 +103,7 @@ public class PackageChangeBroadcastReceiver extends BroadcastReceiver {
PackageHelper.refreshLocalPackageList();
EBPackage uninstallEb = new EBPackage(EBPackage.TYPE_UNINSTALLED, packageName, "");
PackageObserver.onPackageChanged(uninstallEb);
PackageObserver.onPackageChanged(uninstallEb, null);
EventBus.getDefault().post(uninstallEb);
if (webviewPackageName.equals(packageName)) {
SPUtils.remove(Constants.SP_WEBVIEW_ABI_LIST);
@ -120,7 +120,7 @@ public class PackageChangeBroadcastReceiver extends BroadcastReceiver {
EBPackage updateEb = new EBPackage(EBPackage.TYPE_REPLACED, packageName, versionName);
EventBus.getDefault().post(updateEb);
PackageObserver.onPackageChanged(updateEb);
PackageObserver.onPackageChanged(updateEb, null);
if (webviewPackageName.equals(packageName)) {
HaloApp.getInstance().getWebviewAbiList();
}

View File

@ -46,7 +46,7 @@ class SearchGameResultViewModel(
private var mAdPositionSet: HashSet<Int>? = null
private val mAdGameMap = ConcurrentHashMap<String, List<GameEntity>>()
private var mPackageNameSet = hashSetOf<String>()
private var mGameEntityList = arrayListOf<GameEntity>()
fun updateSearchKeyWithType(searchKey: String, searchType: String) {
mSearchKey = searchKey
@ -59,6 +59,7 @@ class SearchGameResultViewModel(
override fun mergeResultLiveData() {
mResultLiveData.addSource(mListLiveData) { list ->
mGameEntityList = ArrayList(list)
decorateListAndPost(list)
}
}
@ -71,15 +72,6 @@ class SearchGameResultViewModel(
}
)
mPackageNameSet = hashSetOf()
// 添加所有出现的游戏包名
list.forEach {
it.getApk().forEach { apk ->
mPackageNameSet.add(apk.packageName)
}
}
refreshWrongInstallStatus()
repository.getSearchSubject(mSearchKey, mPage)
@ -183,8 +175,8 @@ class SearchGameResultViewModel(
}
fun refreshWrongInstallStatus() {
if (mPackageNameSet.isNotEmpty()) {
PackageHelper.refreshWrongInstallStatus(mPackageNameSet)
if (mGameEntityList.isNotEmpty()) {
PackageHelper.refreshWrongInstallStatus(mGameEntityList)
}
}

View File

@ -269,9 +269,9 @@ class MainWrapperFragment : BaseBottomTabFragment<PieceBottomTabBinding>(), OnBa
private fun showInstallApiHintView(binding: FragmentMainBinding) {
val contentText = SpannableStringBuilder()
.color(R.color.text_theme.toColor(requireContext())) { append("您未授予已安装列表权限,可能") }
.color(R.color.secondary_red.toColor(requireContext())) { append("导致无法安装及更新") }
.color(R.color.text_theme.toColor(requireContext())) { append("建议开启权限!") }
.color(R.color.text_theme.toColor(requireContext())) { append("您未授予已安装列表权限,可能导致无法安装及更新建议开启权限!") }
// .color(R.color.secondary_red.toColor(requireContext())) { append("导致无法安装及更新") }
// .color(R.color.text_theme.toColor(requireContext())) { append("建议开启权限!") }
binding.installApiContainer.visibility = View.VISIBLE
binding.installApiContainer.setOnClickListener {

View File

@ -69,7 +69,6 @@ import com.gh.gamecenter.core.utils.SPUtils;
import com.gh.gamecenter.login.user.UserManager;
import com.gh.gamecenter.login.user.UserRepository;
import com.gh.gamecenter.oaid.OAIDHelper;
import com.gh.gamecenter.packagehelper.PackageRepository;
import com.gh.gamecenter.provider.FlavorProviderImp;
import com.gh.gamecenter.receiver.ActivitySkipReceiver;
import com.gh.gamecenter.receiver.DownloadReceiver;
@ -333,7 +332,7 @@ public class HaloApp extends MultiDexApplication {
com.gh.common.constant.Config.getGhzsSettings();
// 5 秒获取后台配置的获取应用列表限制接口结果超时后,回落到关闭状态
// PackageHelper.INSTANCE.fallbackInstalledPackageApiSwitchAfterTimeout(5000L);
PackageHelper.INSTANCE.fallbackInstalledPackageApiSwitchAfterTimeout(5000L);
String localTemporaryDeviceId = SPUtils.getString(Constants.SP_TEMPORARY_DEVICE_ID);
if (!TextUtils.isEmpty(localTemporaryDeviceId)) {
@ -353,9 +352,9 @@ public class HaloApp extends MultiDexApplication {
RegionSettingHelper.getRegionSetting();
PackageRepository.initData();
PackageHelper.refreshLocalPackageList();
PackageHelper.refreshList();
if (PackageHelper.INSTANCE.isGetInstalledPackagesApiAgreed()) {
PackageHelper.INSTANCE.initPackageRelatedData();
}
initReceiver();
initPackageChangesReceiver();

View File

@ -363,6 +363,9 @@ object PermissionHelper {
@JvmStatic
fun isGetInstalledListPermissionDisabled(context: Context): Boolean {
// 临时禁用 https://jira.shanqu.cc/browse/GHZSCY-5661
return false
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false
val permissionInfo: PermissionInfo?