diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 70a270edf3..2dba2904cb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -136,9 +136,14 @@ android:name="com.gh.gamecenter.MainActivity" android:configChanges="orientation|screenSize|keyboardHidden" android:launchMode="singleTask" + android:exported="true" android:screenOrientation="portrait" android:theme="@style/AppCompatTheme.APP" - android:windowSoftInputMode="stateAlwaysHidden|adjustResize" /> + android:windowSoftInputMode="stateAlwaysHidden|adjustResize" > + + + + { + VHelper.postOnInitialized(() -> { + if (VHelper.isInstalled(gamePackageName)) { + VHelper.launch(this, gamePackageName); + } else { + ToastUtils.showToast("应用已被卸载!"); + } + return null; + }); + }, 500); + break; case KEY_MARKET_DETAILS: redirectGameDetail(bundle.getString(KEY_DATA)); break; diff --git a/app/src/main/java/com/gh/vspace/VDownloadManagerAdapter.kt b/app/src/main/java/com/gh/vspace/VDownloadManagerAdapter.kt index 46b4c74d05..47464ef912 100644 --- a/app/src/main/java/com/gh/vspace/VDownloadManagerAdapter.kt +++ b/app/src/main/java/com/gh/vspace/VDownloadManagerAdapter.kt @@ -10,13 +10,11 @@ import android.widget.LinearLayout import android.widget.PopupWindow import android.widget.TextView import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView import com.gh.common.databind.BindingAdapters -import com.gh.gamecenter.feature.exposure.ExposureEvent -import com.gh.gamecenter.feature.exposure.ExposureSource import com.gh.common.exposure.IExposable import com.gh.common.util.NewFlatLogUtils -import com.gh.gamecenter.feature.view.DownloadButton import com.gh.download.DownloadManager import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R @@ -25,8 +23,8 @@ import com.gh.gamecenter.common.baselist.LoadType import com.gh.gamecenter.common.constant.Constants import com.gh.gamecenter.common.constant.ItemViewType import com.gh.gamecenter.common.utils.* -import com.gh.gamecenter.common.viewholder.FooterViewHolder import com.gh.gamecenter.common.view.DrawableView +import com.gh.gamecenter.common.viewholder.FooterViewHolder import com.gh.gamecenter.core.AppExecutor import com.gh.gamecenter.core.runOnIoThread import com.gh.gamecenter.core.utils.CurrentActivityHolder @@ -36,8 +34,13 @@ import com.gh.gamecenter.core.utils.ToastUtils import com.gh.gamecenter.databinding.ItemVgameDownloadManagerBinding import com.gh.gamecenter.databinding.PopupHistoryOptionBinding import com.gh.gamecenter.feature.entity.GameEntity +import com.gh.gamecenter.feature.exposure.ExposureEvent +import com.gh.gamecenter.feature.exposure.ExposureSource +import com.gh.gamecenter.feature.view.DownloadButton import com.gh.gamecenter.history.ManageOption import com.gh.gamecenter.manager.PackagesManager +import com.gh.vspace.menu.VDownLoadManagerItemMenuDialog +import com.gh.vspace.shortcut.ShortcutManager import com.lightgame.download.DownloadEntity import com.lightgame.download.DownloadStatus import com.lightgame.utils.Utils @@ -45,6 +48,7 @@ import org.json.JSONArray class VDownloadManagerAdapter( context: Context, + private val mFragmentManager: FragmentManager, private val mViewModel: VDownloadManagerViewModel, ) : ListAdapter(context), IExposable { @@ -56,6 +60,7 @@ class VDownloadManagerAdapter( private var mPopWindow: PopupWindow? = null private var mCurrentOption = ManageOption.OPTION_MANAGER private var mPopupBinding: PopupHistoryOptionBinding? = null + private var mItemMenuDialog: VDownLoadManagerItemMenuDialog? = null var selectItems = arrayListOf() @@ -187,37 +192,29 @@ class VDownloadManagerAdapter( if (autoPause) { holder.binding.downloadBtn.performClick() } - DialogHelper.showDialog( - holder.binding.root.context, - "删除游戏", - "单机类游戏被删除将可能导致本地存档、充值数据丢失,请确认后操作(网游类游戏删除不会影响游戏存档和充值数据)", - "再等等", - "删除", - { - if (autoPause) { - holder.binding.downloadBtn.performClick() - } - }, - { - runOnIoThread { - val apk = gameEntity.getApk().firstOrNull() - mViewModel.removeItem(apk?.url, apk?.packageName) - - AppExecutor.uiExecutor.executeWithDelay({ - mViewModel.load(LoadType.REFRESH) - }, 200) - } - }, - uiModificationCallback = { - it.cancelTv.setTextColor(R.color.theme_red.toColor(it.root.context)) - it.confirmTv.setTextColor(R.color.text_subtitle.toColor(it.root.context)) - }, - extraConfig = DialogHelper.Config(centerTitle = true) - )?.setOnCancelListener { - if (autoPause) { - holder.binding.downloadBtn.performClick() - } + //还在下载中的游戏直接弹出删除对话框 + if (!mViewModel.isTypeDownloaded()) { + showDelGameDialog(holder, autoPause, gameEntity) + return@setOnLongClickListener false } + //下载完成的在玩游戏才有菜单 + if (mItemMenuDialog == null) { + mItemMenuDialog = VDownLoadManagerItemMenuDialog() + } else { + mItemMenuDialog?.dismiss() + } + mItemMenuDialog?.onAddIconToLauncherClickListener = { + //添加到桌面 + addShortcutToLauncher(holder, gameEntity) + } + mItemMenuDialog?.onClearGameDataClickListener = { + //清除游戏数据 + showCLearGameDataDialog(holder, gameEntity) + } + mItemMenuDialog?.onDeleteGameClickListener = { + showDelGameDialog(holder, autoPause, gameEntity) + } + mItemMenuDialog?.show(mFragmentManager, null) return@setOnLongClickListener false } } @@ -228,6 +225,73 @@ class VDownloadManagerAdapter( } } + /** + * 显示添加图标到桌面的对话框 + */ + private fun addShortcutToLauncher(holder: VGameItemViewHolder, gameEntity: GameEntity) { + ShortcutManager.getInstance().tryCreateShortCut(holder.binding.root.context, gameEntity) + } + + /** + * 显示清除游戏数据对话框 + */ + private fun showCLearGameDataDialog(holder: VGameItemViewHolder, gameEntity: GameEntity) { + DialogHelper.showDialog( + holder.binding.root.context, + "提示", + "清除后游戏的所有记录都将被清空,无法恢复!您确定要清除吗?", + "确定", + "取消", + confirmClickCallback = { //清除游戏数据 + mViewModel.cleanGameData(gameEntity.getUniquePackageName()) + }, + extraConfig = DialogHelper.Config(centerTitle = true) + ) + } + + /** + * 显示删除游戏的对话框 + */ + private fun showDelGameDialog( + holder: VGameItemViewHolder, + autoPause: Boolean, + gameEntity: GameEntity + ) { + DialogHelper.showDialog( + holder.binding.root.context, + "删除游戏", + "单机类游戏被删除将可能导致本地存档、充值数据丢失,请确认后操作(网游类游戏删除不会影响游戏存档和充值数据)", + "再等等", + "删除", + { + if (autoPause) { + holder.binding.downloadBtn.performClick() + } + }, + { + //删除对应的桌面快捷方式 + ShortcutManager.getInstance().removeShortcut(holder.binding.root.context, gameEntity) + runOnIoThread { + val apk = gameEntity.getApk().firstOrNull() + mViewModel.removeItem(apk?.url, apk?.packageName) + + AppExecutor.uiExecutor.executeWithDelay({ + mViewModel.load(LoadType.REFRESH) + }, 200) + } + }, + uiModificationCallback = { + it.cancelTv.setTextColor(R.color.theme_red.toColor(it.root.context)) + it.confirmTv.setTextColor(R.color.text_subtitle.toColor(it.root.context)) + }, + extraConfig = DialogHelper.Config(centerTitle = true) + )?.setOnCancelListener { + if (autoPause) { + holder.binding.downloadBtn.performClick() + } + } + } + private fun showOptionWindow() { mPopupBinding = PopupHistoryOptionBinding.inflate(LayoutInflater.from(mContext)) mPopupBinding?.root?.isFocusable = true diff --git a/app/src/main/java/com/gh/vspace/VDownloadManagerFragment.kt b/app/src/main/java/com/gh/vspace/VDownloadManagerFragment.kt index da10742b94..6d036a1c22 100644 --- a/app/src/main/java/com/gh/vspace/VDownloadManagerFragment.kt +++ b/app/src/main/java/com/gh/vspace/VDownloadManagerFragment.kt @@ -27,6 +27,7 @@ class VDownloadManagerFragment : private val mAdapter by lazy { VDownloadManagerAdapter( requireContext(), + childFragmentManager, provideListViewModel() ) } diff --git a/app/src/main/java/com/gh/vspace/VDownloadManagerViewModel.kt b/app/src/main/java/com/gh/vspace/VDownloadManagerViewModel.kt index 5ee1926e01..7d669d2586 100644 --- a/app/src/main/java/com/gh/vspace/VDownloadManagerViewModel.kt +++ b/app/src/main/java/com/gh/vspace/VDownloadManagerViewModel.kt @@ -6,6 +6,7 @@ import com.gh.download.DownloadManager import com.gh.download.PackageObserver import com.gh.gamecenter.common.baselist.ListViewModel import com.gh.gamecenter.common.utils.toProperReadableSize +import com.gh.gamecenter.core.runOnIoThread import com.gh.gamecenter.core.runOnUiThread import com.gh.gamecenter.core.utils.NumberUtils import com.gh.gamecenter.core.utils.ToastUtils @@ -97,6 +98,12 @@ class VDownloadManagerViewModel(application: Application) : } } + fun cleanGameData(packageName: String?) { + runOnIoThread { + VHelper.cleanGameData(packageName) + } + } + @WorkerThread fun removeItem(url: String?, packageName: String?) { DownloadManager.getInstance().pause(url) diff --git a/app/src/main/java/com/gh/vspace/VHelper.kt b/app/src/main/java/com/gh/vspace/VHelper.kt index d983143b6f..9635ceccec 100644 --- a/app/src/main/java/com/gh/vspace/VHelper.kt +++ b/app/src/main/java/com/gh/vspace/VHelper.kt @@ -242,6 +242,15 @@ object VHelper { } } + @JvmStatic + fun postOnInitialized(callback: () -> Unit) { + if (mIsServiceConnected) { + callback() + } else { + mPendingAction = callback + } + } + private fun toastIfServiceConnectTimeout(timeout: Long = 3000L) { if (!mIsServiceConnected) { AppExecutor.uiExecutor.executeWithDelay({ @@ -616,6 +625,7 @@ object VHelper { /** * 启动应用 */ + @JvmStatic fun launch(context: Context, packageName: String) { Utils.log(LOG_TAG, "打开应用 $packageName") @@ -692,6 +702,31 @@ object VHelper { } } + /** + * 清除游戏数据 + */ + @JvmStatic + fun cleanGameData(packageName: String?) { + Utils.log(LOG_TAG, "清除游戏数据 $packageName") + if (packageName.isNullOrBlank()) return + val cleanGameDataClosure: () -> Unit = { + try { + val result = VirtualAppManager.get().cleanGameData(packageName) + if (result) { + updateInstalledList() + } + Utils.log(LOG_TAG, "清除游戏数据结果 -> $result") + } catch (e: Exception) { + ToastUtils.toast(e.localizedMessage ?: "") + } + } + if (mDelegateManager.isConnectAidlInterface) { + cleanGameDataClosure.invoke() + } else { + connectService(false, cleanGameDataClosure) + } + } + /** * 获取游戏最后打开的时间 * @return 最后打开的时间戳 diff --git a/app/src/main/java/com/gh/vspace/menu/VDownLoadManagerItemMenuDialog.kt b/app/src/main/java/com/gh/vspace/menu/VDownLoadManagerItemMenuDialog.kt new file mode 100644 index 0000000000..a0e8245152 --- /dev/null +++ b/app/src/main/java/com/gh/vspace/menu/VDownLoadManagerItemMenuDialog.kt @@ -0,0 +1,54 @@ +package com.gh.vspace.menu + +import android.os.Bundle +import android.view.View +import com.gh.gamecenter.R +import com.gh.gamecenter.common.base.fragment.BaseBottomDialogFragment +import com.gh.gamecenter.common.utils.setRootBackgroundDrawable +import com.gh.gamecenter.common.utils.toColor +import com.gh.gamecenter.common.utils.toDrawable +import com.gh.gamecenter.databinding.DialogGameDownloadManagerMenuBinding + +/** + * @author : liujiarui + * date : 2023/3/20 + * description : 畅玩游戏管理item菜单 + */ +class VDownLoadManagerItemMenuDialog : + BaseBottomDialogFragment() { + + var onAddIconToLauncherClickListener: (() -> Unit)? = null + var onClearGameDataClickListener: (() -> Unit)? = null + var onDeleteGameClickListener: (() -> Unit)? = null + + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mBinding.addIconToDesktopBtn.setOnClickListener { + dismissAllowingStateLoss() + onAddIconToLauncherClickListener?.invoke() + } + mBinding.clearGameDataBtn.setOnClickListener { + dismissAllowingStateLoss() + onClearGameDataClickListener?.invoke() + } + mBinding.uninstallGameBtn.setOnClickListener { + dismissAllowingStateLoss() + onDeleteGameClickListener?.invoke() + } + mBinding.cancelBtn.setOnClickListener { + dismissAllowingStateLoss() + } + } + + override fun onDarkModeChanged() { + super.onDarkModeChanged() + mBinding.run { + root.setRootBackgroundDrawable(R.drawable.background_shape_white_radius_12_top_only) + cancelBtn.background = R.drawable.bg_shape_f5_radius_999.toDrawable(requireContext()) + dialogTitleTv.setTextColor(R.color.text_title.toColor(requireContext())) + cancelBtn.setTextColor(R.color.text_subtitle.toColor(requireContext())) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/vspace/shortcut/ShortcutManager.kt b/app/src/main/java/com/gh/vspace/shortcut/ShortcutManager.kt new file mode 100644 index 0000000000..a472b8ca17 --- /dev/null +++ b/app/src/main/java/com/gh/vspace/shortcut/ShortcutManager.kt @@ -0,0 +1,206 @@ +package com.gh.vspace.shortcut + +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.Matrix +import androidx.core.content.pm.ShortcutInfoCompat +import androidx.core.content.pm.ShortcutManagerCompat +import androidx.core.graphics.drawable.IconCompat +import androidx.fragment.app.FragmentActivity +import com.gh.gamecenter.MainActivity +import com.gh.gamecenter.common.callback.BiCallback +import com.gh.gamecenter.common.constant.EntranceConsts +import com.gh.gamecenter.common.exposure.meta.MetaUtil +import com.gh.gamecenter.common.utils.ImageUtils +import com.gh.gamecenter.common.utils.PermissionHelper +import com.gh.gamecenter.core.runOnUiThread +import com.gh.gamecenter.core.utils.ToastUtils +import com.gh.gamecenter.feature.entity.GameEntity +import com.halo.assistant.HaloApp +import com.lg.vspace.VirtualAppManager +import com.muugi.shortcut.core.Executor +import com.muugi.shortcut.core.Shortcut +import com.muugi.shortcut.core.ShortcutAction + +/** + * @author : liujiarui + * date : 2023/3/20 + * description : 动态创建快捷方式管理类 + */ +class ShortcutManager private constructor() { + + private val mDelegateManager by lazy { VirtualAppManager.get() } + + private val mShortcutAction: ShortcutAction by lazy { + object : ShortcutAction() { + override fun showPermissionDialog(context: Context, check: Int, executor: Executor) { + runOnUiThread { + ShortcutPermissionDialog(context, executor).show() + } + } + + override fun onCreateAction( + requestPinShortcut: Boolean, + check: Int, + executor: Executor + ) { + if (requestPinShortcut) { + ToastUtils.showToast("桌面图标创建成功~") + } else { + ToastUtils.showToast("创建快捷方式失败") + } + } + + override fun onUpdateAction(updatePinShortcut: Boolean) { + if (updatePinShortcut) { + ToastUtils.showToast("桌面图标更新成功~") + } else { + ToastUtils.showToast("更新快捷方式失败") + } + } + } + } + + private val mCallback: Shortcut.Callback by lazy { + object : Shortcut.Callback { + override fun onAsyncCreate(id: String, label: String) { + //ToastUtils.showToast("桌面图标创建成功~") + } + } + } + + + /** + * 创建快捷方式 + */ + fun tryCreateShortCut(context: Context, gameEntity: GameEntity) { + val activity = context as? FragmentActivity ?: return + if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)) { + PermissionHelper.checkShortcutPermission(activity, + onGrantedCallback = { + createShortcut(context, gameEntity) + }, + onDeniedCallback = { + ShortcutPermissionDialog(context).show() + }) + } else { + ShortcutPermissionDialog(context).show() + } + } + + /** + * 创建快捷方式 + */ + private fun createShortcut(context: Context, gameEntity: GameEntity) { + val gameId = gameEntity.id + val gameName = gameEntity.name ?: "" + val gameIcon = gameEntity.icon ?: "" + val dynamicShortcuts = ShortcutManagerCompat.getShortcuts(context, ShortcutManagerCompat.FLAG_MATCH_PINNED) + val shortcutExists = dynamicShortcuts.find { it.id == gameId } + if (shortcutExists != null) { + ShortcutManagerCompat.enableShortcuts( + context, listOf(shortcutExists) + ) + ToastUtils.showToast("桌面图标已创建,无需重复!") + return + } + ImageUtils.getBitmap(gameIcon, object : BiCallback { + override fun onFirst(first: Bitmap) { + // 压缩图片 + val bitmap = compressImage(first) + val shortcutInfoIntent = getGameIntent(context, gameEntity) + shortcutInfoIntent.run { + val info = ShortcutInfoCompat.Builder(context, gameId) + .setIcon(IconCompat.createWithBitmap(bitmap)) + .setShortLabel(gameName) + //.setAlwaysBadged() // 设置图标角标为应用角标 + .setIntent(this) + .build() + // 创建快捷方式 + Shortcut.singleInstance.requestPinShortcut( + context = context, + shortcutInfoCompat = info, + updateIfExit = false, + fixHwOreo = true, + shortcutAction = mShortcutAction + ) + } + } + + override fun onSecond(second: Boolean) { + ToastUtils.showToast("创建快捷方式失败") + } + }) + } + + /** + * 动态删除快捷方式 + * 暂时只能在原生系统禁用快捷方式 + */ + fun removeShortcut(context: Context, gameEntity: GameEntity) { + val gameId = gameEntity.id + val gameName = gameEntity.name ?: "" + val dynamicShortcuts = ShortcutManagerCompat.getShortcuts(context, ShortcutManagerCompat.FLAG_MATCH_PINNED) + val shortcutExists = dynamicShortcuts.find { it.id == gameId } + if (shortcutExists != null) { + ShortcutManagerCompat.disableShortcuts( + context, listOf(gameId), "$gameName 已经卸载" + ) + ShortcutManagerCompat.removeLongLivedShortcuts(context, listOf(gameId)) + } + } + + /** + * 获取游戏快捷方式跳转Intent + * 直接启动游戏 + */ + private fun getIntent(gameEntity: GameEntity): Intent { + val intent = mDelegateManager.getStartGameIntent( + gameEntity.getUniquePackageName(), + gameEntity.id, + gameEntity.name ?: "unknown", + MetaUtil.getBase64EncodedAndroidId(), + HaloApp.getInstance().gid, + com.gh.gamecenter.BuildConfig.VERSION_NAME, + HaloApp.getInstance().channel + ) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + return intent + } + + /** + * 获取游戏快捷方式跳转Intent + * 先启动光环助手,然后跳转游戏 + */ + private fun getGameIntent(context: Context, gameEntity: GameEntity): Intent { + val intent = Intent(context, MainActivity::class.java) + intent.action = Intent.ACTION_VIEW + intent.putExtra(EntranceConsts.KEY_REQUIRE_REDIRECT, true) + intent.putExtra(EntranceConsts.KEY_TO, EntranceConsts.HOST_LAUNCH_VM_GAME) + intent.putExtra(EntranceConsts.KEY_GAME_PKG, gameEntity.getUniquePackageName()) + return intent + } + + // Bitmap尺寸超过300*300就压缩 + private fun compressImage(bitmap: Bitmap): Bitmap { + return if (bitmap.byteCount > 300 * 300 * 4) { + val width = bitmap.width.toFloat() + val height = bitmap.height.toFloat() + val matrix = Matrix() + val scaleWidth = 300 / width + val scaleHeight = 300 / height + matrix.postScale(scaleWidth, scaleHeight) + Bitmap.createBitmap(bitmap, 0, 0, width.toInt(), height.toInt(), matrix, true) + } else bitmap + } + + + companion object { + private val mShortcutManager = ShortcutManager() + fun getInstance(): ShortcutManager { + Shortcut.singleInstance.addShortcutCallback(mShortcutManager.mCallback) + return mShortcutManager + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/vspace/shortcut/ShortcutPermissionDialog.kt b/app/src/main/java/com/gh/vspace/shortcut/ShortcutPermissionDialog.kt new file mode 100644 index 0000000000..e9ae5b3d2c --- /dev/null +++ b/app/src/main/java/com/gh/vspace/shortcut/ShortcutPermissionDialog.kt @@ -0,0 +1,63 @@ +package com.gh.vspace.shortcut + +import android.app.Dialog +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.provider.Settings +import android.view.Window +import com.gh.common.util.DirectUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.databinding.DialogGameAddShortcutPermissionBinding +import com.muugi.shortcut.core.Executor + +/** + * @author : liujiarui + * date : 2023/3/20 + * description : 创建快捷方式权限弹窗 + */ +class ShortcutPermissionDialog( + context: Context, + private val mExecutor: Executor? = null +) : Dialog(context, R.style.DialogWindowTransparent) { + private lateinit var mBinding: DialogGameAddShortcutPermissionBinding + + override fun onCreate(savedInstanceState: Bundle?) { + requestWindowFeature(Window.FEATURE_NO_TITLE); + super.onCreate(savedInstanceState) + DialogGameAddShortcutPermissionBinding.inflate(layoutInflater).apply { + setContentView(root) + mBinding = this + } + initEvent() + } + + private fun initEvent() { + mBinding.closeContainer.setOnClickListener { + dismiss() + } + mBinding.goSettingTv.setOnClickListener { + jumpToSetting() + dismiss() + } + mBinding.serviceTv.setOnClickListener { + jumpToFeedback() + dismiss() + } + } + + private fun jumpToSetting() { + if (mExecutor != null) { + mExecutor.executeSetting() + return + } + val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + intent.data = Uri.parse("package:" + context.packageName) + context.startActivity(intent) + } + + private fun jumpToFeedback() { + DirectUtils.directToFeedback(context, "无法正常设置桌面快捷方式权限", hintType = "other") + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-xxhdpi/ic_game_add_shortcut_permission_content.webp b/app/src/main/res/drawable-xxhdpi/ic_game_add_shortcut_permission_content.webp new file mode 100644 index 0000000000..8e78493e32 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_game_add_shortcut_permission_content.webp differ diff --git a/app/src/main/res/layout/dialog_game_add_shortcut_permission.xml b/app/src/main/res/layout/dialog_game_add_shortcut_permission.xml new file mode 100644 index 0000000000..f1023eb94b --- /dev/null +++ b/app/src/main/res/layout/dialog_game_add_shortcut_permission.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_game_download_manager_menu.xml b/app/src/main/res/layout/dialog_game_download_manager_menu.xml new file mode 100644 index 0000000000..e34d4f13b2 --- /dev/null +++ b/app/src/main/res/layout/dialog_game_download_manager_menu.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/base/fragment/BaseBottomDialogFragment.kt b/module_common/src/main/java/com/gh/gamecenter/common/base/fragment/BaseBottomDialogFragment.kt new file mode 100644 index 0000000000..6b6a1f8c51 --- /dev/null +++ b/module_common/src/main/java/com/gh/gamecenter/common/base/fragment/BaseBottomDialogFragment.kt @@ -0,0 +1,61 @@ +package com.gh.gamecenter.common.base.fragment + +import android.app.Dialog +import android.os.Bundle +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.viewbinding.ViewBinding +import com.gh.gamecenter.common.R +import com.gh.gamecenter.common.utils.getSuperClassGenericType +import com.gh.gamecenter.core.utils.DisplayUtils + +/** + * @author : liujiarui + * date : 2023/3/20 + * description : 底部弹出dialog + */ +abstract class BaseBottomDialogFragment : BaseDialogFragment() { + + protected lateinit var mBinding: T + + private fun initViewBinding(inflater: LayoutInflater): T { + return this::class.java.getSuperClassGenericType().getMethod( + "inflate", + LayoutInflater::class.java, + ViewGroup::class.java, + Boolean::class.java + ).invoke(null, inflater, null, false) as T + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + initViewBinding(inflater).apply { mBinding = this } + return mBinding.root + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val createDialog = super.onCreateDialog(savedInstanceState) + createDialog.setCanceledOnTouchOutside(true) + val window = createDialog.window + window?.setGravity(Gravity.BOTTOM) + window?.setWindowAnimations(R.style.community_publication_animation) + return createDialog + } + + override fun onStart() { + super.onStart() + val width = if (isWidthMatchParent()) DisplayUtils.getScreenWidth() else { + dialog?.window?.attributes?.width ?: ViewGroup.LayoutParams.WRAP_CONTENT + } + val height = dialog?.window?.attributes?.height ?: ViewGroup.LayoutParams.WRAP_CONTENT + dialog?.window?.setLayout(width, height) + } + + /** + * 是否宽度撑满屏幕 + */ + protected fun isWidthMatchParent(): Boolean { + return true + } +} \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/constant/EntranceConsts.java b/module_common/src/main/java/com/gh/gamecenter/common/constant/EntranceConsts.java index 2b7713be0b..693b7d9ac7 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/constant/EntranceConsts.java +++ b/module_common/src/main/java/com/gh/gamecenter/common/constant/EntranceConsts.java @@ -68,6 +68,8 @@ public class EntranceConsts { public static final String HOST_GAME_RATING_DETAIL = "game_rating_detail"; public static final String HOST_HELP_AND_FEEDBACK = "help_and_feedback"; public static final String HOST_LAUNCH_SIMULATOR_GAME = "launch_simulator_game"; + + public static final String HOST_LAUNCH_VM_GAME = "launch_vm_game"; public static final String HOST_HELP_DETAIL = "help_detail"; public static final String HOST_GAME_COLLECTION_DETAIL = "game_collection_detail"; public static final String HOST_GAME_COLLECTION_SQUARE = "game_collection_square"; @@ -117,6 +119,8 @@ public class EntranceConsts { public static final String KEY_SEARCHKEY = "searchKey"; public static final String KEY_HINT = "hint"; public static final String KEY_GAME = "game"; + + public static final String KEY_GAME_PKG = "game_pkg"; public static final String KEY_GAME_ICON_URL = "gameIconUrl"; public static final String KEY_SHARECONTENT = "shareContent"; public static final String KEY_SUGGESTTYPE = "suggestType"; diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/Extensions.kt b/module_common/src/main/java/com/gh/gamecenter/common/utils/Extensions.kt index 2e0efd018c..01746bf438 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/utils/Extensions.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/Extensions.kt @@ -68,6 +68,7 @@ import okhttp3.MediaType import okhttp3.RequestBody import org.json.JSONArray import org.json.JSONObject +import java.lang.reflect.ParameterizedType import java.net.URI import java.util.* import java.util.concurrent.TimeUnit @@ -1492,4 +1493,31 @@ fun List.colorRGBToHSV(): FloatArray { fun Activity.getUniqueId(): String { return System.identityHashCode(this).toString() +} + +/** + * 通过反射,获得定义Class时声明的父类的范型参数的类型. + */ +fun Class<*>.getSuperClassGenericType(): Class { + return getSuperClassGenericType(0) +} + +/** + * 通过反射,获得定义Class时声明的父类的范型参数的类型. + * @param index 获取第几个范型参数的类型 + */ +@Suppress("UNCHECKED_CAST") +fun Class<*>.getSuperClassGenericType(index: Int): Class { + var cls: Class<*>? = this + var genType = cls?.genericSuperclass + while (genType !is ParameterizedType) { + cls = cls?.superclass + requireNotNull(cls) + genType = cls.genericSuperclass + } + val params = genType.actualTypeArguments + require(!(index >= params.size || index < 0)) + return if (params[index] !is Class<*>) { + throw IllegalArgumentException() + } else params[index] as Class } \ No newline at end of file diff --git a/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt b/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt index 7a83808a09..d3ca8346b9 100644 --- a/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt +++ b/module_common/src/main/java/com/gh/gamecenter/common/utils/PermissionHelper.kt @@ -342,4 +342,41 @@ object PermissionHelper { } } + /** + * 检查添加到桌面快捷方式权限 + */ + @SuppressLint("CheckResult") + @JvmStatic + fun checkShortcutPermission( + context: FragmentActivity, + onGrantedCallback: EmptyCallback, + onDeniedCallback: EmptyCallback + ) { + tryWithDefaultCatch { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + onGrantedCallback.onCallback() + return + } + val rxPermission = RxPermissions(context) + rxPermission + .requestEachCombined( + Manifest.permission.INSTALL_SHORTCUT, + Manifest.permission.UNINSTALL_SHORTCUT, + ) + .subscribe { permission -> + when { + permission.granted -> { + onGrantedCallback.onCallback() + } + permission.shouldShowRequestPermissionRationale -> { + // do nothing + } + else -> { + onDeniedCallback.onCallback() + } + } + } + } + } + } \ No newline at end of file diff --git a/module_lib/build.gradle b/module_lib/build.gradle index 84042c9450..e05a76fd6f 100644 --- a/module_lib/build.gradle +++ b/module_lib/build.gradle @@ -1,2 +1,3 @@ configurations.maybeCreate("default") -artifacts.add("default", file('quick_login_android_5.9.4.aar')) \ No newline at end of file +artifacts.add("default", file('quick_login_android_5.9.4.aar')) +artifacts.add("default", file('shortcut.aar')) \ No newline at end of file diff --git a/module_lib/shortcut.aar b/module_lib/shortcut.aar new file mode 100644 index 0000000000..7256765360 Binary files /dev/null and b/module_lib/shortcut.aar differ diff --git a/vspace-bridge b/vspace-bridge index 066641c478..b00d19b246 160000 --- a/vspace-bridge +++ b/vspace-bridge @@ -1 +1 @@ -Subproject commit 066641c4787a03366e8d490ac5b43cca4133d499 +Subproject commit b00d19b246fb06894fb840b3e4251dd71959629b