From 0f194a80bb4d1a9fc48498125b1b7aa003f73c02 Mon Sep 17 00:00:00 2001 From: lyr <15622190878@163.com> Date: Thu, 28 Oct 2021 17:09:08 +0800 Subject: [PATCH 01/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=B8=B8=E6=88=8F?= =?UTF-8?q?=E6=90=9C=E7=B4=A2=E9=A1=B5=E9=9D=A2=E5=88=97=E8=A1=A8=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E8=B6=8A=E7=95=8C=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt | 4 ++-- .../java/com/gh/gamecenter/search/SearchGameResultAdapter.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt index 88a82a4656..685c5d693a 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameIndexAdapter.kt @@ -416,7 +416,7 @@ class SearchGameIndexAdapter(context: Context, for (key in positionAndPackageMap.keys) { if (key.contains(download.packageName) && key.contains(download.gameId)) { val position = positionAndPackageMap[key] - if (position != null && mEntityList != null && mEntityList[position].game != null && position < mEntityList.size) { + if (position != null && mEntityList != null && position < mEntityList.size && mEntityList[position].game != null) { mEntityList[position].game!!.getEntryMap()[download.platform] = download notifyItemChanged(position) } @@ -428,7 +428,7 @@ class SearchGameIndexAdapter(context: Context, for (key in positionAndPackageMap.keys) { if (key.contains(status.packageName) && key.contains(status.gameId)) { val position = positionAndPackageMap[key] - if (position != null && mEntityList != null && mEntityList[position].game != null && position < mEntityList.size) { + if (position != null && mEntityList != null && position < mEntityList.size && mEntityList[position].game != null) { mEntityList[position].game!!.getEntryMap().remove(status.platform) notifyItemChanged(position) } diff --git a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt index 28ff1b3f3f..efc4f03b14 100644 --- a/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/search/SearchGameResultAdapter.kt @@ -435,7 +435,7 @@ class SearchGameResultAdapter(context: Context, for (key in positionAndPackageMap.keys) { if (key.contains(download.packageName) && key.contains(download.gameId)) { val position = positionAndPackageMap[key] - if (position != null && mEntityList != null && mEntityList[position].game != null && position < mEntityList.size) { + if (position != null && mEntityList != null && position < mEntityList.size && mEntityList[position].game != null) { mEntityList[position].game!!.getEntryMap()[download.platform] = download notifyItemChanged(position) } @@ -447,7 +447,7 @@ class SearchGameResultAdapter(context: Context, for (key in positionAndPackageMap.keys) { if (key.contains(status.packageName) && key.contains(status.gameId)) { val position = positionAndPackageMap[key] - if (position != null && mEntityList != null && mEntityList[position].game != null && position < mEntityList.size) { + if (position != null && mEntityList != null && position < mEntityList.size && mEntityList[position].game != null) { mEntityList[position].game!!.getEntryMap().remove(status.platform) notifyItemChanged(position) } From 783227656087075934fb39829eae937d51d7618e Mon Sep 17 00:00:00 2001 From: juntao Date: Thu, 28 Oct 2021 17:25:37 +0800 Subject: [PATCH 02/26] =?UTF-8?q?=E4=B8=BA=E5=90=8E=E7=BB=AD=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=8F=90=E4=BE=9B=E5=BD=93=E5=89=8D=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E7=9A=84=E7=89=88=E6=9C=AC=E5=92=8C=E6=B8=A0=E9=81=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/gh/gamecenter/MainActivity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index b896b4d1a2..4fd1baefe3 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -221,6 +221,9 @@ public class MainActivity extends BaseActivity { getPluginUpdate(); mSp.edit().putBoolean("isNewFirstLaunchV" + PackageUtils.getGhVersionName(), false).apply(); + // 记录曾安装过的版本 + 渠道 + SPUtils.setString("installedVersionV" + PackageUtils.getGhVersionName(), HaloApp.getInstance().getChannel()); + checkDevice(); // 根据设备信息判断用户是否是新用户 } From d3fab1aa73b4c7ca59d19876e390bc6b593e184d Mon Sep 17 00:00:00 2001 From: juntao Date: Thu, 28 Oct 2021 17:40:18 +0800 Subject: [PATCH 03/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9F=A5=E7=9C=8B?= =?UTF-8?q?=E5=A4=A7=E5=9B=BE=E4=BC=A0=E5=85=A5=E6=95=B0=E7=BB=84=E4=B8=BA?= =?UTF-8?q?=E7=A9=BA=E6=97=B6=E7=9A=84=E9=97=AA=E9=80=80=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gh/gamecenter/ImageViewerActivity.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt b/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt index 2b2d0f3b67..3867ae5b3a 100644 --- a/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/ImageViewerActivity.kt @@ -128,13 +128,19 @@ class ImageViewerActivity : BaseActivity(), OnPageChangeListener { mUrlList = ArrayList() mUrlList?.add(image) } else { - mUrlList = it.getStringArrayList(KEY_URL_LIST) + mUrlList = it.getStringArrayList(KEY_URL_LIST) ?: arrayListOf() mInitialPosition = it.getInt(KEY_CURRENT, 0) } mShowSaveBtn = it.getBoolean(KEY_SHOW_SAVE) mUseEnterAndExitAnimation = it.getBoolean(KEY_USE_ENTER_AND_EXIT_ANIMATION) mAnswerEntity = it.getParcelable(AnswerEntity::class.java.name) } + + if (mUrlList?.isEmpty() == true) { + ToastUtils.toast("无法查看大图") + finish() + } + mSavePicBtn.visibleIf(mShowSaveBtn) mArticleDetailBtn.visibleIf(mAnswerEntity != null) mIndicatorMask.goneIf(mUrlList?.size == 1) From 913bcdeeb271135eef2aaa38cdae17816f9b4b63 Mon Sep 17 00:00:00 2001 From: juntao Date: Thu, 28 Oct 2021 17:52:43 +0800 Subject: [PATCH 04/26] =?UTF-8?q?=E6=8D=95=E6=8A=93=E5=8D=B8=E8=BD=BD?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E6=97=B6=E5=81=B6=E5=8F=91=E7=9A=84=E9=97=AA?= =?UTF-8?q?=E9=80=80=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gh/gamecenter/packagehelper/PackageRepository.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) 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 89e0ff45af..50786ee7ff 100644 --- a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt @@ -345,10 +345,13 @@ object PackageRepository { fun uninstalledGame(pkgName: String) { // TODO 检查为什么会有两个相同的包名添加到 mInstalledPkgList 里 mInstalledPkgList.removeAll { it == pkgName } - val iterator = currentVersionList.iterator() - while (iterator.hasNext()) { - if (iterator.next().packageName == pkgName) { - iterator.remove() + // 尝试从临时的当前版本列表里移除已卸载的条目 + tryCatchInRelease { + val iterator = currentVersionList.iterator() + while (iterator.hasNext()) { + if (iterator.next().packageName == pkgName) { + iterator.remove() + } } } notifyInstallPkgData() From 9a1f3b0fe3c7f0f894e949c0427f3dba00508601 Mon Sep 17 00:00:00 2001 From: juntao Date: Fri, 29 Oct 2021 11:01:16 +0800 Subject: [PATCH 05/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E7=B3=BB?= =?UTF-8?q?=E5=88=97=E9=97=AA=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 跳转用户详情参数有误造成的闪退 2. 标记更新已读红点时的闪退 3. 5.0 以下设备点击更新按钮的闪退 4. 横向列表专题点击时偶发的闪退 5. 首页滑动顶部 BANNER 偶发的闪退 --- app/src/main/java/com/gh/common/util/DirectUtils.kt | 8 ++++---- app/src/main/java/com/gh/download/DownloadManager.java | 1 + .../com/gh/gamecenter/download/UpdatableGameAdapter.kt | 5 ++++- .../com/gh/gamecenter/download/UpdatableGameViewModel.kt | 2 ++ .../game/horizontal/GameHorizontalSlideAdapter.kt | 3 ++- .../gh/gamecenter/home/slide/HomeSlideListViewHolder.kt | 3 ++- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/gh/common/util/DirectUtils.kt b/app/src/main/java/com/gh/common/util/DirectUtils.kt index c90bfd057b..53f3d5a2f7 100644 --- a/app/src/main/java/com/gh/common/util/DirectUtils.kt +++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt @@ -505,9 +505,9 @@ object DirectUtils { @JvmStatic fun directToHomeActivity( context: Context, - userId: String?, - type: String = "", - position: Int, + userId: String? = "", + type: String? = "", + position: Int? = 0, entrance: String? = null, path: String? = null ) { @@ -519,7 +519,7 @@ object DirectUtils { bundle.putString(KEY_ENTRANCE, BaseActivity.mergeEntranceAndPath(entrance, path)) bundle.putString(KEY_PATH, path) bundle.putString(KEY_TYPE, UserHistoryViewModel.TYPE.fromValue(type).value) - bundle.putInt(KEY_POSITION, position) + bundle.putInt(KEY_POSITION, position ?: 0) jumpActivity(context, bundle) } diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java index 01d7d9bd3f..c3557ef903 100644 --- a/app/src/main/java/com/gh/download/DownloadManager.java +++ b/app/src/main/java/com/gh/download/DownloadManager.java @@ -1041,6 +1041,7 @@ public class DownloadManager implements DownloadStatusListener { ArrayList updates = PackageRepository.INSTANCE.getGameUpdate(); for (GameUpdateEntity update : updates) { + if (update == null) continue; String mark = update.getId() + update.getPackageName(); if (!mUpdateMarks.contains(mark)) { mUpdateMarks.add(mark); diff --git a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameAdapter.kt b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameAdapter.kt index ad953d615c..4045f0e31d 100644 --- a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameAdapter.kt @@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat import androidx.core.view.setPadding import androidx.fragment.app.FragmentActivity import androidx.recyclerview.widget.RecyclerView +import com.gh.base.CurrentActivityHolder import com.gh.common.exposure.ExposureEvent import com.gh.common.exposure.ExposureEvent.Companion.createEvent import com.gh.common.exposure.ExposureSource @@ -338,7 +339,9 @@ class UpdatableGameAdapter(private var mViewModel: UpdatableGameViewModel) : updateBtn.setOnClickListener { val str: String = updateBtn.text.toString() if ("更新" == str || str.contains("化")) { - (updateBtn.context as FragmentActivity).checkStoragePermissionBeforeAction { + // 这里用 CurrentActivity 不用 view.context 的原因是 + // view.context 在 5.0 以下设备会使用 TintContextWrapper 包一层导致类型转换异常 + (CurrentActivityHolder.getCurrentActivity() as? FragmentActivity)?.checkStoragePermissionBeforeAction { DialogUtils.checkDownload( updateBtn.context, update.size diff --git a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt index cf0dc15cc1..853dfce5a6 100644 --- a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt @@ -64,6 +64,8 @@ class UpdatableGameViewModel( mRawUpdatableList.clear() for (update in updatableList) { + // 有闪退日志说这个 update 实体可能为空,实在看不原因 :( + if (update == null) continue // 筛选仅下载管理出现的插件化更新 if (update.isShowPlugin(PluginLocation.only_index)) { val platform = diff --git a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt index d8c2644ba3..f33fd72764 100644 --- a/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/horizontal/GameHorizontalSlideAdapter.kt @@ -5,6 +5,7 @@ import android.view.ViewGroup import com.gh.common.exposure.ExposureEvent import com.gh.common.util.StringUtils import com.gh.common.util.dip2px +import com.gh.common.util.safelyGetInRelease import com.gh.gamecenter.GameDetailActivity import com.gh.gamecenter.R import com.gh.gamecenter.databinding.GameHorizontalItemBinding @@ -62,7 +63,7 @@ class GameHorizontalSlideAdapter(context: Context, } holder.setRemarkView(mSubjectEntity, gameEntity) holder.itemView.setOnClickListener { - val exposureEvent = exposureEventList?.get(position) + val exposureEvent = exposureEventList?.safelyGetInRelease(position) if (exposureEvent != null) { GameDetailActivity.startGameDetailActivity(mContext, gameEntity, StringUtils.buildString("(游戏-专题:", mSubjectEntity.name, "-列表[", (position + 1).toString(), "])"), exposureEvent) diff --git a/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt index 0ee49dc962..b5394ada52 100644 --- a/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt @@ -13,6 +13,7 @@ import com.gh.base.BaseRecyclerViewHolder import com.gh.common.exposure.ExposureSource import com.gh.common.util.MtaHelper import com.gh.common.util.hexStringToIntColor +import com.gh.common.util.safelyGetInRelease import com.gh.common.util.throwExceptionInDebug import com.gh.common.view.DrawableView import com.gh.common.view.FixLinearLayoutManager @@ -140,7 +141,7 @@ class HomeSlideListViewHolder( val currentColor = slideList[currentPosition].placeholderColor.hexStringToIntColor() - val nextColor = slideList[nextPosition].placeholderColor.hexStringToIntColor() + val nextColor = slideList.safelyGetInRelease(nextPosition)?.placeholderColor?.hexStringToIntColor() ?: currentColor val colorInBetween = ColorUtils.blendARGB(currentColor, nextColor, positionOffset) From 36bc35a7e34b373f32b9db232355089ce5becc85 Mon Sep 17 00:00:00 2001 From: juntao Date: Fri, 29 Oct 2021 11:13:46 +0800 Subject: [PATCH 06/26] =?UTF-8?q?=E7=89=88=E6=9C=AC=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=87=B3=205.3.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index c53f0c9846..480c8c6bdb 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,8 +7,8 @@ ext { targetSdkVersion = 26 // application info (每个大版本之间的 versionCode 增加 20) - versionCode = 410 - versionName = "5.3.0" + versionCode = 411 + versionName = "5.3.1" applicationId = "com.gh.gamecenter" // AndroidX From 63b88383a46fd5b38ea33ff666b0a459cf31c12f Mon Sep 17 00:00:00 2001 From: jack <1484288157@qq.com> Date: Fri, 29 Oct 2021 14:59:55 +0800 Subject: [PATCH 07/26] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=9C=AA=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E8=AF=84=E8=AE=BA=E6=97=B6=E4=B8=80=E9=94=AE=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E5=BC=B9=E7=AA=97=E5=BC=B9=E8=B5=B7=E9=94=AE=E7=9B=98?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=E6=94=B6=E8=B5=B7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt index c7d13f0532..d38e4880d3 100644 --- a/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/qa/comment/NewCommentFragment.kt @@ -357,6 +357,7 @@ open class NewCommentFragment : ListFragment override fun onClick(view: View) { when (view.id) { R.id.answer_comment_send_btn -> if (!ClickUtils.isFastDoubleClick(R.id.answer_comment_send_btn, 5000)) { + Util_System_Keyboard.hideSoftKeyboard(requireActivity()) ifLogin(getLoginEntrance()) { showRegulationTestDialogIfNeeded { postComment() From 25ce3ccdc9c64bbded8e01a5bbcf016468fdd566 Mon Sep 17 00:00:00 2001 From: juntao Date: Mon, 1 Nov 2021 11:24:43 +0800 Subject: [PATCH 08/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E9=97=AA=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 修复游戏详情页回到顶部的闪退 2. 尝试修复获取游戏更新时偶发的闪退 --- .../java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt | 4 +++- .../java/com/gh/gamecenter/packagehelper/PackageRepository.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt index 9797143edd..c5cdefcb82 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/desc/DescFragment.kt @@ -224,7 +224,9 @@ class DescFragment : BaseFragment(), IScrollable { } override fun scrollToTop() { - mRecyclerView.scrollToPosition(0) + if (::mRecyclerView.isInitialized) { + mRecyclerView.scrollToPosition(0) + } } } \ No newline at end of file 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 50786ee7ff..f907168bdb 100644 --- a/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt +++ b/app/src/main/java/com/gh/gamecenter/packagehelper/PackageRepository.kt @@ -82,7 +82,7 @@ object PackageRepository { mInstalledPkgList.addAll(list) notifyInstallPkgData() - loadInstalledGameDigestAndNotifyData(list, true) + loadInstalledGameDigestAndNotifyData(list) loadGhzsUpdate() } } From 3e8923f34a6b067eb9e48122469085e681ca13d2 Mon Sep 17 00:00:00 2001 From: juntao Date: Fri, 24 Sep 2021 17:29:39 +0800 Subject: [PATCH 09/26] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=AE=9E=E5=90=8D?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E4=BC=98=E5=8C=96=E7=AC=AC=E4=B8=89=E6=9C=9F?= =?UTF-8?q?=20https://git.ghzs.com/pm/halo-app-issues/-/issues/1572?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gh/common/constant/Constants.java | 3 + .../gh/common/dialog/CertificationDialog.kt | 5 +- .../gh/common/util/DetailDownloadUtils.java | 4 + .../java/com/gh/common/util/DirectUtils.kt | 2 +- .../com/gh/common/util/DownloadObserver.kt | 53 +---- .../java/com/gh/common/util/ErrorHelper.kt | 1 + .../java/com/gh/common/util/NewLogUtils.kt | 70 ++++++ .../com/gh/common/util/PackageInstaller.kt | 91 ++++++-- .../java/com/gh/common/util/RealNameHelper.kt | 95 ++++++++- .../java/com/gh/gamecenter/MainActivity.java | 2 + .../java/com/gh/gamecenter/ShellActivity.kt | 5 +- .../com/gh/gamecenter/entity/IdCardEntity.kt | 3 +- .../forum/moderator/ApplyModeratorFragment.kt | 10 +- .../personal/PersonalFunctionAdapter.kt | 3 +- .../retrofit/service/ApiService.java | 6 + .../gh/gamecenter/user/UserRepository.java | 16 +- .../fragment/user/RealNameInfoFragment.kt | 201 ++++++++++++++++++ .../fragment/user/RealNameInfoViewModel.kt | 120 +++++++++++ .../fragment/user/UserInfoFragment.java | 4 +- .../bg_userinfo_verified_success.9.png | Bin 35086 -> 39933 bytes .../drawable/button_round_2496ff_alpha_40.xml | 9 + .../main/res/layout/fragment_real_name.xml | 184 ++++++++++++++++ 22 files changed, 802 insertions(+), 85 deletions(-) create mode 100644 app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt create mode 100644 app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoViewModel.kt create mode 100644 app/src/main/res/drawable/button_round_2496ff_alpha_40.xml create mode 100644 app/src/main/res/layout/fragment_real_name.xml diff --git a/app/src/main/java/com/gh/common/constant/Constants.java b/app/src/main/java/com/gh/common/constant/Constants.java index ee79ea18c0..ec594c84ee 100644 --- a/app/src/main/java/com/gh/common/constant/Constants.java +++ b/app/src/main/java/com/gh/common/constant/Constants.java @@ -76,6 +76,9 @@ public class Constants { public static final String SP_IMEI = "imei"; public static final String SP_ANDROID_ID = "android_id"; + // 安装类型 + public static final String SP_INSTALL_TYPE = "install_type"; + public static final String LAST_INSTALL_GAME = "last_install_game"; //引导设置 “通知管理” 引导弹窗 diff --git a/app/src/main/java/com/gh/common/dialog/CertificationDialog.kt b/app/src/main/java/com/gh/common/dialog/CertificationDialog.kt index 0fd890b775..c2eb189505 100644 --- a/app/src/main/java/com/gh/common/dialog/CertificationDialog.kt +++ b/app/src/main/java/com/gh/common/dialog/CertificationDialog.kt @@ -19,12 +19,11 @@ import com.gh.common.avoidcallback.Callback import com.gh.common.constant.Constants import com.gh.common.util.* import com.gh.gamecenter.R -import com.gh.gamecenter.UserInfoEditActivity +import com.gh.gamecenter.ShellActivity import com.gh.gamecenter.entity.AuthDialogEntity import com.gh.gamecenter.entity.AuthDialogLevel import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.manager.UserManager -import com.gh.gamecenter.user.UserViewModel import com.google.gson.reflect.TypeToken import com.halo.assistant.fragment.user.UserInfoEditFragment import com.lightgame.utils.AppManager @@ -130,7 +129,7 @@ class CertificationDialog(context: Context, private val authDialogEntity: AuthDi val currentActivity = AppManager.getInstance().currentActivity() ?: return AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity) - .startForResult(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD), object : Callback { + .startForResult(ShellActivity.getIntent(context, ShellActivity.Type.REAL_NAME_INFO, null), object : Callback { override fun onActivityResult(resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && data != null) { val isAuthSuccess = data.getBooleanExtra(UserInfoEditFragment.AUTH_SUCCESS, false) 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 214c0e0f70..721fb46345 100644 --- a/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java +++ b/app/src/main/java/com/gh/common/util/DetailDownloadUtils.java @@ -82,6 +82,8 @@ public class DetailDownloadUtils { viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.PLUGIN); } else if (viewHolder.context.getString(R.string.launch).equals(status)) { viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.LAUNCH_OR_OPEN); + } else if (viewHolder.context.getString(R.string.install).equals(status)) { + viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.INSTALL_NORMAL); } else { viewHolder.mDownloadPb.setDownloadType(DownloadProgressBar.DownloadType.NORMAL); } @@ -95,6 +97,8 @@ public class DetailDownloadUtils { downloadText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : "-" + downloadAddWord); } else if (viewHolder.context.getString(R.string.attempt).equals(status)) { downloadText = status + getDownloadSizeText(viewHolder); + } else if (viewHolder.context.getString(R.string.install).equals(status)) { + downloadText = viewHolder.context.getString(R.string.install); } else { downloadText = status + (TextUtils.isEmpty(downloadAddWord) ? "" : downloadAddWord) + getDownloadSizeText(viewHolder); } diff --git a/app/src/main/java/com/gh/common/util/DirectUtils.kt b/app/src/main/java/com/gh/common/util/DirectUtils.kt index 53f3d5a2f7..ca525ff0cf 100644 --- a/app/src/main/java/com/gh/common/util/DirectUtils.kt +++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt @@ -290,7 +290,7 @@ object DirectUtils { } "authentication" -> { - context.startActivity(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD)) + context.startActivity(ShellActivity.getIntent(context, ShellActivity.Type.REAL_NAME_INFO, null)) } "user_background" -> { 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 9b3194e05a..318aacda3c 100644 --- a/app/src/main/java/com/gh/common/util/DownloadObserver.kt +++ b/app/src/main/java/com/gh/common/util/DownloadObserver.kt @@ -13,10 +13,7 @@ import com.gh.common.util.EnergyTaskHelper.postEnergyTask import com.gh.common.xapk.XapkInstaller import com.gh.download.DownloadDataHelper import com.gh.download.DownloadManager -import com.gh.gamecenter.BuildConfig -import com.gh.gamecenter.R -import com.gh.gamecenter.SuggestionActivity -import com.gh.gamecenter.UserInfoEditActivity +import com.gh.gamecenter.* import com.gh.gamecenter.entity.GameEntity import com.gh.gamecenter.entity.SimpleGameEntity import com.gh.gamecenter.entity.SimulatorEntity @@ -104,59 +101,15 @@ object DownloadObserver { DownloadDataHelper.uploadRedirectEvent(downloadEntity) } else if (DownloadStatus.unqualified == downloadEntity.status) { // 未成年 - val currentActivity = CurrentActivityHolder.getCurrentActivity() - if (currentActivity == null) { - ToastUtils.toast("为保护未成年身心健康成长,根据相关政策要求,该游戏不对未成年人开放下载") - } else { - NewLogUtils.logCertificationHintDialogTrigger(true) - DialogHelper.showDialog( - currentActivity, - title = "实名提示", - content = "为保护未成年身心健康成长,根据相关政策要求,该游戏不对未成年人开放下载", - confirmText = "知道了", - cancelText = "", - confirmClickCallback = { -// NewLogUtils.logCertificationHintDialogTrigger(true) - } - ) - } - DownloadManager.getInstance(HaloApp.getInstance()).addInvisiblePendingTask(downloadEntity) + RealNameHelper.showRealNameUnqualifiedDialog(downloadEntity) // 删除任务 downloadEntity.status = DownloadStatus.cancel downloadManager.cancel(downloadEntity.url) } else if (DownloadStatus.uncertificated == downloadEntity.status) { // 未实名 - NewLogUtils.logCertificationTrigger(downloadEntity.gameId, downloadEntity.name) + RealNameHelper.showRealNameUncertificatedDialog(downloadEntity) - val currentActivity = CurrentActivityHolder.getCurrentActivity() - if (currentActivity == null) { - ToastUtils.toast("为保护未成年身心健康成长,根据相关政策要求,该游戏不对未成年人开放下载") - } else { - NewLogUtils.logCertificationHintDialogAppearance() - DialogHelper.showDialog( - currentActivity, - title = "实名提示", - content = "为保护未成年身心健康成长,根据相关政策要求,该游戏不对未成年人开放下载\n" + - "如需下载,请前往实名认证", - confirmText = "前往实名认证", - cancelText = "取消", - confirmClickCallback = { - currentActivity.startActivity( - UserInfoEditActivity.getIntent( - currentActivity, - UserViewModel.TYPE_ID_CARD, - true - ) - ) - NewLogUtils.logCertificationHintDialogOptionsClicked("前往实名认证") - }, - cancelClickCallback = { - NewLogUtils.logCertificationHintDialogOptionsClicked("取消") - } - ) - } - DownloadManager.getInstance(HaloApp.getInstance()).addInvisiblePendingTask(downloadEntity) // 删除任务 downloadEntity.status = DownloadStatus.cancel downloadManager.cancel(downloadEntity.url) diff --git a/app/src/main/java/com/gh/common/util/ErrorHelper.kt b/app/src/main/java/com/gh/common/util/ErrorHelper.kt index 5eb6d4e9ba..5b4a1ef15c 100644 --- a/app/src/main/java/com/gh/common/util/ErrorHelper.kt +++ b/app/src/main/java/com/gh/common/util/ErrorHelper.kt @@ -133,6 +133,7 @@ object ErrorHelper { 403022 -> Utils.toast(context, "不能回复自己") 403056 -> Utils.toast(context, "发布失败,字数已达上限") 403111 -> Utils.toast(context, "提交失败,评论违规") + 403119 -> Utils.toast(context, "不能重复修改实名") 400001 -> Utils.toast(context, "字数超过500或者未填写原因") 403102 -> Utils.toast(context, "你已经举报过该内容了哦") 403115 -> Utils.toast(context, "请求太频繁了,稍微休息一下") diff --git a/app/src/main/java/com/gh/common/util/NewLogUtils.kt b/app/src/main/java/com/gh/common/util/NewLogUtils.kt index cb03b1dc8a..9d12c262a9 100644 --- a/app/src/main/java/com/gh/common/util/NewLogUtils.kt +++ b/app/src/main/java/com/gh/common/util/NewLogUtils.kt @@ -133,6 +133,76 @@ object NewLogUtils { log(json, "event", false) } + // 触发实名认证 + fun logCertificationTrigger(gameId: String, gameName: String) { + val json = json { + "event" to "verification_trigger" + "game_id" to gameId + "game_name" to gameName + "timestamp" to System.currentTimeMillis() / 1000 + parseAndPutMeta().invoke(this) + } + log(json, "event", false) + } + + // 触发实名认证的来源 (下载触发或用户手动触发) + fun logCertificationTriggerType(isForced: Boolean) { + val json = json { + "event" to "verification_page" + "trigger" to if (isForced) "实名认证流程" else "" + "timestamp" to System.currentTimeMillis() / 1000 + parseAndPutMeta().invoke(this) + } + log(json, "event", false) + } + + /** + * 记录实名认证结果 + * @param result 0 失败, 1 成功但未成年 2 成功且成年 + */ + fun logCertificationResult(isForced: Boolean, result: Int) { + val json = json { + "event" to "verification_finished" + "trigger" to if (isForced) "实名认证流程" else "" + "result" to result + "timestamp" to System.currentTimeMillis() / 1000 + parseAndPutMeta().invoke(this) + } + log(json, "event", false) + } + + // 实名弹窗弹出(含前往实名认证选项) + fun logCertificationHintDialogAppearance() { + val json = json { + "event" to "verification_pop_a_show" + "timestamp" to System.currentTimeMillis() / 1000 + parseAndPutMeta().invoke(this) + } + log(json, "event", false) + } + + // 实名弹窗(含前往实名认证选项) 选项点击 + fun logCertificationHintDialogOptionsClicked(text: String) { + val json = json { + "event" to "verification_pop_a_click" + "timestamp" to System.currentTimeMillis() / 1000 + "button" to text + parseAndPutMeta().invoke(this) + } + log(json, "event", false) + } + + // 实名弹窗弹出(不含前往实名认证选项) + fun logCertificationHintDialogTrigger(isForced: Boolean) { + val json = json { + "event" to "verification_pop_b_show" + "timestamp" to System.currentTimeMillis() / 1000 + "trigger" to if (isForced) "实名认证流程" else "" + parseAndPutMeta().invoke(this) + } + log(json, "event", false) + } + // 游戏详情点击顶部标签 fun logGameDetailTagClick(gameId: String, gameName: String, tagId: String, tagName: String) { val json = json { diff --git a/app/src/main/java/com/gh/common/util/PackageInstaller.kt b/app/src/main/java/com/gh/common/util/PackageInstaller.kt index 3a23b350d1..6454adeb52 100644 --- a/app/src/main/java/com/gh/common/util/PackageInstaller.kt +++ b/app/src/main/java/com/gh/common/util/PackageInstaller.kt @@ -1,5 +1,6 @@ package com.gh.common.util +import android.annotation.SuppressLint import android.app.Activity import android.content.Context import android.content.Intent @@ -7,16 +8,23 @@ import android.net.Uri import android.os.Build import androidx.appcompat.app.AppCompatActivity import androidx.core.content.FileProvider +import com.gh.base.CurrentActivityHolder import com.gh.common.constant.Constants import com.gh.common.dialog.InstallPermissionDialogFragment import com.gh.common.xapk.XapkInstaller +import com.gh.download.DownloadManager import com.gh.download.server.BrowserInstallHelper import com.gh.gamecenter.BuildConfig +import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.RetrofitManager import com.halo.assistant.HaloApp import com.lightgame.download.DownloadEntity import com.lightgame.download.FileUtils -import com.lightgame.utils.AppManager import com.lightgame.utils.Utils +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import okhttp3.ResponseBody +import retrofit2.HttpException import java.io.File object PackageInstaller { @@ -41,7 +49,7 @@ object PackageInstaller { val pkgPath = downloadEntity.path val isXapk = XapkInstaller.XAPK_EXTENSION_NAME == pkgPath.getExtension() - val currentActivity = AppManager.getInstance().currentActivity() ?: return + val currentActivity = CurrentActivityHolder.getCurrentActivity() ?: return // TODO 此处可能遇到 activity 是 WXEntryActivity // TODO 当 activity 全部出栈,但是应用还在下载游戏,下载完会唤不起安装! @@ -71,16 +79,27 @@ object PackageInstaller { try { // 判断是否需要使用浏览器来进行安装 if (BrowserInstallHelper.isUseBrowserToInstallEnabled() - && BrowserInstallHelper.shouldUseBrowserToInstall()) { + && BrowserInstallHelper.shouldUseBrowserToInstall() + ) { BrowserInstallHelper.downloadFile(pkgPath) return } if (PackageUtils.isCanLaunchSetup(context, pkgPath)) { + val app = HaloApp.getInstance() + HaloApp.put(Constants.LAST_INSTALL_GAME, pkgPath) - val installIntent = getInstallIntent(context, pkgPath) - context.startActivity(installIntent) + val downloadEntity = + DownloadManager.getInstance(app).allDownloadEntity.firstOrNull { + it.path == pkgPath + } + if (downloadEntity != null) { + showCertificateDialogIfNeededBeforeInstall(app, downloadEntity, pkgPath) + } else { + val installIntent = getInstallIntent(context, pkgPath) + context.startActivity(installIntent) + } } else { if (isPluggin) { DialogHelper.showPluginDialog(context) { @@ -98,6 +117,49 @@ object PackageInstaller { } } + @SuppressLint("CheckResult") + fun showCertificateDialogIfNeededBeforeInstall(context: Context, downloadEntity: DownloadEntity, pkgPath: String) { + val isOverwrite = LunchType.UPDATE.name == SPUtils.getString(Constants.SP_INSTALL_TYPE) + val hashMap = hashMapOf(Pair("url", downloadEntity.url), Pair("overwrite", isOverwrite)) + RetrofitManager.getInstance(context).api.postCertificationCheck(hashMap.toRequestBody()) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onSuccess(data: ResponseBody) { + val installIntent = getInstallIntent(context, pkgPath) + context.startActivity(installIntent) + } + + override fun onFailure(exception: Exception) { + super.onFailure(exception) + + if (exception is HttpException) { + val resultString = + (exception as HttpException).response().errorBody() + ?.string() + // 未实名 + when { + resultString?.contains("403117") == true -> { + RealNameHelper.showRealNameUncertificatedDialog( + downloadEntity + ) + } + resultString?.contains("403118") == true -> { + RealNameHelper.showRealNameUnqualifiedDialog( + downloadEntity + ) + } + resultString?.contains("400004") == true -> { + ToastUtils.toast("安装服务异常,缺少参数") + } + } + } else { + ToastUtils.toast("安装服务异常,${exception.localizedMessage}请稍候再试") + } + } + }) + } + /** * 获取启动安装意图 * @@ -107,11 +169,12 @@ object PackageInstaller { @JvmStatic fun getInstallIntent(context: Context, path: String): Intent { var uri = Uri.fromFile(File(path)) - val installIntent = if (BrowserInstallHelper.isUseBrowserToInstallEnabledWithPackageMatched()) { - Intent(Intent.ACTION_INSTALL_PACKAGE) - } else { - Intent(Intent.ACTION_VIEW) - } + val installIntent = + if (BrowserInstallHelper.isUseBrowserToInstallEnabledWithPackageMatched()) { + Intent(Intent.ACTION_INSTALL_PACKAGE) + } else { + Intent(Intent.ACTION_VIEW) + } if ("smartisan" == Build.MANUFACTURER) { installIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } @@ -129,7 +192,8 @@ object PackageInstaller { } installIntent.setDataAndType(uri, "application/vnd.android.package-archive") } - InstallUtils.getInstance(context).addInstall(PackageUtils.getPackageNameByPath(context, path)) + InstallUtils.getInstance(context) + .addInstall(PackageUtils.getPackageNameByPath(context, path)) return installIntent } @@ -163,7 +227,10 @@ object PackageInstaller { @JvmStatic fun getDownloadPathWithId(id: String, format: String?): String { - return FileUtils.getDownloadPath(HaloApp.getInstance().application, id + "." + getFileSuffixByFormat(format)) + return FileUtils.getDownloadPath( + HaloApp.getInstance().application, + id + "." + getFileSuffixByFormat(format) + ) } private fun getFileSuffixByFormat(format: String?): String { diff --git a/app/src/main/java/com/gh/common/util/RealNameHelper.kt b/app/src/main/java/com/gh/common/util/RealNameHelper.kt index 52778ce87f..b15d4e0bc9 100644 --- a/app/src/main/java/com/gh/common/util/RealNameHelper.kt +++ b/app/src/main/java/com/gh/common/util/RealNameHelper.kt @@ -1,17 +1,104 @@ package com.gh.common.util import android.content.Context -import com.gh.gamecenter.UserInfoEditActivity +import com.gh.base.CurrentActivityHolder +import com.gh.download.DownloadManager +import com.gh.gamecenter.ShellActivity import com.gh.gamecenter.entity.GameEntity -import com.gh.gamecenter.manager.UserManager -import com.gh.gamecenter.user.UserViewModel -import java.util.* +import com.halo.assistant.HaloApp +import com.lightgame.download.DownloadEntity +import com.lightgame.download.DownloadStatus object RealNameHelper { + var pendingInstallPkgPath = "" + @JvmStatic fun checkIfAuth(context: Context, gameEntity: GameEntity, callback: EmptyCallback) { callback.onCallback() } + /** + * 弹未成年人不能下载游戏弹窗 + */ + fun showRealNameUnqualifiedDialog(downloadEntity: DownloadEntity) { + + val contentText = if (downloadEntity.status == DownloadStatus.done) { + "为保护未成年身心健康成长\n" + "根据相关政策要求,该游戏不对未成年人开放" + } else { + "为保护未成年身心健康成长\n" + "根据相关政策要求,该游戏不对未成年人开放下载" + } + + val currentActivity = CurrentActivityHolder.getCurrentActivity() + if (currentActivity == null) { + ToastUtils.toast("为保护未成年身心健康成长,根据相关政策要求,该游戏不对未成年人开放") + } else { + NewLogUtils.logCertificationHintDialogTrigger(true) + DialogHelper.showDialog( + currentActivity, + title = "实名提示", + content = contentText, + confirmText = "知道了", + cancelText = "", + confirmClickCallback = { +// NewLogUtils.logCertificationHintDialogTrigger(true) + } + ) + } + if (downloadEntity.status != DownloadStatus.done) { + DownloadManager.getInstance(HaloApp.getInstance()) + .addInvisiblePendingTask(downloadEntity) + } + } + + /** + * 弹需要实名弹窗 + */ + fun showRealNameUncertificatedDialog(downloadEntity: DownloadEntity) { + NewLogUtils.logCertificationTrigger(downloadEntity.gameId, downloadEntity.name) + + val contentText = if (downloadEntity.status == DownloadStatus.done) { + "为保护未成年身心健康成长\n" + "根据相关政策要求,该游戏不对未成年人开放\n" + "如需完成安装,请前往实名认证" + } else { + "为保护未成年身心健康成长\n" + "根据相关政策要求,该游戏不对未成年人开放下载\n" + "如需下载,请前往实名认证" + } + + val currentActivity = CurrentActivityHolder.getCurrentActivity() + if (currentActivity == null) { + ToastUtils.toast("为保护未成年身心健康成长,根据相关政策要求,该游戏不对未成年人开放") + } else { + NewLogUtils.logCertificationHintDialogAppearance() + DialogHelper.showDialog( + currentActivity, + title = "实名提示", + content = contentText, + confirmText = "前往实名认证", + cancelText = "取消", + confirmClickCallback = { + currentActivity.startActivity( + ShellActivity.getIntent( + currentActivity, + ShellActivity.Type.REAL_NAME_INFO + ).apply { + putExtra(EntranceUtils.KEY_IS_FORCED_TO_CERTICIFICE, true) + } + ) + if (downloadEntity.status == DownloadStatus.done) { + pendingInstallPkgPath = downloadEntity.path + } + NewLogUtils.logCertificationHintDialogOptionsClicked("前往实名认证") + }, + cancelClickCallback = { + NewLogUtils.logCertificationHintDialogOptionsClicked("取消") + } + ) + } + + if (downloadEntity.status != DownloadStatus.done) { + DownloadManager.getInstance(HaloApp.getInstance()) + .addInvisiblePendingTask(downloadEntity) + } + + } + } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index 4fd1baefe3..c8c5706b16 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -224,6 +224,8 @@ public class MainActivity extends BaseActivity { // 记录曾安装过的版本 + 渠道 SPUtils.setString("installedVersionV" + PackageUtils.getGhVersionName(), HaloApp.getInstance().getChannel()); + SPUtils.setString(Constants.SP_INSTALL_TYPE, lunchType.name()); + checkDevice(); // 根据设备信息判断用户是否是新用户 } diff --git a/app/src/main/java/com/gh/gamecenter/ShellActivity.kt b/app/src/main/java/com/gh/gamecenter/ShellActivity.kt index e78f1c75dd..2484e64853 100644 --- a/app/src/main/java/com/gh/gamecenter/ShellActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/ShellActivity.kt @@ -9,6 +9,7 @@ import com.gh.base.fragment.BaseFragment import com.gh.common.util.EntranceUtils import com.gh.gamecenter.amway.AmwaySuccessFragment import com.halo.assistant.fragment.SwitchInstallMethodFragment +import com.halo.assistant.fragment.user.RealNameInfoFragment /** * ShellActivity 用来包裹那些几乎没有交互且运营也不会想要知道页面访问量的静态 fragment (如安利墙的评论提交成功页面) @@ -30,6 +31,7 @@ class ShellActivity : ToolBarActivity() { when (intentType) { Type.AMWAY_SUCCESS -> startFragment(AmwaySuccessFragment().with(bundle)) Type.SWITCH_INSTALL_METHOD -> startFragment(SwitchInstallMethodFragment()) + Type.REAL_NAME_INFO -> startFragment(RealNameInfoFragment().with(bundle)) } } @@ -54,7 +56,8 @@ class ShellActivity : ToolBarActivity() { enum class Type(val value: String) { AMWAY_SUCCESS("amway_success"), - SWITCH_INSTALL_METHOD("switch_install_method"); + SWITCH_INSTALL_METHOD("switch_install_method"), + REAL_NAME_INFO("real_name_info"); companion object { fun fromString(typeString: String): Type { diff --git a/app/src/main/java/com/gh/gamecenter/entity/IdCardEntity.kt b/app/src/main/java/com/gh/gamecenter/entity/IdCardEntity.kt index 61bec2d6e7..d36427fd57 100644 --- a/app/src/main/java/com/gh/gamecenter/entity/IdCardEntity.kt +++ b/app/src/main/java/com/gh/gamecenter/entity/IdCardEntity.kt @@ -5,5 +5,6 @@ import androidx.room.Entity @Entity data class IdCardEntity( var id: String? = null, - var name: String? = null + var name: String? = null, + var revise: Boolean? = false, ) \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorFragment.kt b/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorFragment.kt index 9ddc3dc55b..7e8e9936d4 100644 --- a/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/forum/moderator/ApplyModeratorFragment.kt @@ -13,14 +13,13 @@ import com.gh.common.avoidcallback.Callback import com.gh.common.dialog.ApplyModeratorDialogFragment import com.gh.common.util.* import com.gh.gamecenter.R -import com.gh.gamecenter.UserInfoEditActivity +import com.gh.gamecenter.ShellActivity import com.gh.gamecenter.databinding.FragmentApplyModeratorBinding import com.gh.gamecenter.entity.ApplyModeratorStatusEntity import com.gh.gamecenter.entity.ApplyModeratorTaskEntity import com.gh.gamecenter.forum.detail.ForumDetailActivity import com.gh.gamecenter.manager.UserManager import com.gh.gamecenter.normal.NormalFragment -import com.gh.gamecenter.user.UserViewModel import com.lightgame.utils.AppManager import com.lightgame.utils.Utils @@ -102,13 +101,10 @@ class ApplyModeratorFragment : NormalFragment() { val currentActivity = AppManager.getInstance().currentActivity() AvoidOnResultManager.getInstance(currentActivity as AppCompatActivity) .startForResult( - UserInfoEditActivity.getIntent( - context, - UserViewModel.TYPE_ID_CARD - ), object : + ShellActivity.getIntent(requireContext(), ShellActivity.Type.REAL_NAME_INFO, null), object : Callback { override fun onActivityResult(resultCode: Int, data: Intent?) { - + Utils.log(resultCode) } }) } diff --git a/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt b/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt index 9d8152caf4..7d6d0f39db 100644 --- a/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/personal/PersonalFunctionAdapter.kt @@ -26,7 +26,6 @@ import com.gh.gamecenter.mygame.MyGameActivity import com.gh.gamecenter.qa.myqa.MyAskActivity import com.gh.gamecenter.security.SecurityActivity import com.gh.gamecenter.simulatorgame.SimulatorGameActivity -import com.gh.gamecenter.user.UserViewModel import com.gh.gamecenter.video.videomanager.VideoManagerActivity import com.halo.assistant.HaloApp import com.lightgame.adapter.BaseRecyclerAdapter @@ -192,7 +191,7 @@ class PersonalFunctionAdapter(val context: Context, val groupName: String, var m } } "实名认证" -> { - context.startActivity(UserInfoEditActivity.getIntent(context, UserViewModel.TYPE_ID_CARD)) + context.startActivity(ShellActivity.getIntent(context, ShellActivity.Type.REAL_NAME_INFO, null)) } "微信提醒" -> { MtaHelper.onEvent("我的光环", "设置微信提醒") diff --git a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java index efcad0cd1f..09feb30e53 100644 --- a/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java +++ b/app/src/main/java/com/gh/gamecenter/retrofit/service/ApiService.java @@ -170,6 +170,12 @@ public interface ApiService { @POST("certification") Single postCertification(@Body RequestBody body); + /** + * 检查实名认证接口 + */ + @POST("./certification:check") + Single postCertificationCheck(@Body RequestBody body); + /** * 获取新闻详情 */ diff --git a/app/src/main/java/com/gh/gamecenter/user/UserRepository.java b/app/src/main/java/com/gh/gamecenter/user/UserRepository.java index 2540b3b8d5..1c6673c81e 100644 --- a/app/src/main/java/com/gh/gamecenter/user/UserRepository.java +++ b/app/src/main/java/com/gh/gamecenter/user/UserRepository.java @@ -8,6 +8,7 @@ import android.preference.PreferenceManager; import android.text.TextUtils; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.lifecycle.LiveData; import androidx.lifecycle.MediatorLiveData; @@ -152,6 +153,8 @@ public class UserRepository { // 通知页面更新 EventBus.getDefault().post(new EBReuse(PersonalFragment.LOGOUT_TAG)); + + DataUtils.getDeviceCertification(HaloApp.getInstance().getGid()); } public LiveData> getLoginUserInfo() { @@ -568,13 +571,22 @@ public class UserRepository { } } - private void cacheAndNotifyUserInfo(UserInfoEntity userInfoEntity, boolean isEditUserInfo) { + public void cacheAndNotifyUserInfo(UserInfoEntity userInfoEntity, boolean isEditUserInfo) { setUserManagerData(null, userInfoEntity); mCacheUserInfoEntity = userInfoEntity; mLoginObsResponseUserInfo.postValue(new ApiResponse<>(userInfoEntity)); - if (isEditUserInfo) mEditObsResponseUserInfo.postValue(new ApiResponse<>(userInfoEntity)); + if (isEditUserInfo) { + mEditObsResponseUserInfo.postValue(new ApiResponse<>(userInfoEntity)); + } else { + DataUtils.getDeviceCertification(HaloApp.getInstance().getGid()); + } + } + + @Nullable + public UserInfoEntity getCacheUserInfoEntity() { + return mCacheUserInfoEntity; } private void cacheAndNotifyLoginToken(LoginTokenEntity loginTokenEntity) { diff --git a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt new file mode 100644 index 0000000000..098af6fee8 --- /dev/null +++ b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt @@ -0,0 +1,201 @@ +package com.halo.assistant.fragment.user + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import android.text.InputType +import android.text.TextUtils +import android.view.View +import androidx.constraintlayout.widget.ConstraintSet +import androidx.core.widget.doOnTextChanged +import androidx.fragment.app.viewModels +import com.gh.common.util.* +import com.gh.common.view.CustomLinkMovementMethod +import com.gh.gamecenter.R +import com.gh.gamecenter.ShellActivity +import com.gh.gamecenter.databinding.FragmentRealNameBinding +import com.gh.gamecenter.normal.NormalFragment +import org.json.JSONObject + +class RealNameInfoFragment : NormalFragment() { + + private var mIsForcedToCertificate: Boolean = false + private val mViewModel: RealNameInfoViewModel by viewModels() + + private val mBinding: FragmentRealNameBinding by lazy { + FragmentRealNameBinding.inflate( + layoutInflater + ) + } + + override fun getLayoutId(): Int = 0 + override fun getInflatedLayout(): View = mBinding.root + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + mIsForcedToCertificate = + arguments?.getBoolean(EntranceUtils.KEY_IS_FORCED_TO_CERTICIFICE) ?: false + + mBinding.toolbar.normalTitle.text = "实名认证" + mBinding.toolbar.normalToolbar.setNavigationOnClickListener { requireActivity().finish() } + + if (mIsForcedToCertificate || !isRealNameInfoExist()) { + initEditingView() + mViewModel.certificateResultLiveData.observeNonNull(viewLifecycleOwner) { + requireActivity().setResult( + Activity.RESULT_OK, + Intent().putExtra(UserInfoEditFragment.AUTH_SUCCESS, true) + ) + requireActivity().finish() + } + } else { + initDisplayOnlyView() + } + } + + private fun isRealNameInfoExist(): Boolean { + val userInfoEntity = mViewModel.getUserInfo() + return if (userInfoEntity != null) { + val idCard = userInfoEntity.idCard + if (idCard != null && !TextUtils.isEmpty(idCard.name)) { + true + } else { + NewLogUtils.logCertificationTriggerType(mIsForcedToCertificate) + false + } + } else { + NewLogUtils.logCertificationTriggerType(mIsForcedToCertificate) + false + } + } + + private fun initEditingView() { + val bodyString = + "为响应《国家新闻出版署关于防止未成年沉迷网络游戏的通知》,请认真填写您的身份信息。您提供的证件信息将受到严格保护,仅用于用户实名制认证,不会用作其他用途,请放心填写。前往了解更多信息>>" + mBinding.bodyTv.text = + SpanBuilder(bodyString) + .click( + bodyString.length - "前往了解更多信息>>".length, + bodyString.length, + R.color.theme_font + ) { + DirectUtils.directToWebView( + requireContext(), + "https://resource.ghzs.com/page/privacy_policies/Identity_information.html", + "(实名认证)" + ) + } + .build() + mBinding.bodyTv.movementMethod = CustomLinkMovementMethod.getInstance() + + val hintString = "特别说明:由于部分用户之前的实名信息不正确或认证失败,可能需要重新认证,请提交真实的信息进行认证即可。部分游戏仅对成年用户进行开放" + mBinding.hintTv.text = + SpanBuilder(hintString) + .bold(0, 5) + .build() + + mBinding.nameEt.filters = arrayOf(TextHelper.getFilter(20, "最多20个字")) + mBinding.idCardEt.filters = arrayOf(TextHelper.getFilter(18, "身份证号码最长18位")) + + mBinding.nameEt.doOnTextChanged { _, _, _, _ -> + updateSubmitBtn() + } + mBinding.idCardEt.doOnTextChanged { _, _, _, _ -> + updateSubmitBtn() + } + } + + private fun initDisplayOnlyView() { + val userInfoEntity = mViewModel.getUserInfo() + + mBinding.badgeContainer.visibility = View.VISIBLE + mBinding.run { + val set = ConstraintSet() + set.run { + clone(infoContainer) + clear(R.id.nameTv, ConstraintSet.TOP) + connect( + R.id.nameTv, + ConstraintSet.TOP, + R.id.badgeContainer, + ConstraintSet.BOTTOM, + 14F.dip2px() + ) + applyTo(infoContainer) + } + } + mBinding.submitBtn.visibility = View.GONE + mBinding.reEditInfoBtn.visibleIf(userInfoEntity?.idCard?.revise == false) + mBinding.nameEt.inputType = InputType.TYPE_NULL + mBinding.idCardEt.inputType = InputType.TYPE_NULL + + val idCard = userInfoEntity?.idCard + val sb = StringBuilder(idCard?.name?.substring(0, 1) ?: "") + for (i in 0 until idCard?.name!!.length - 1) { + sb.append("*") + } + mBinding.nameEt.setText(sb.toString()) + mBinding.idCardEt.setText( + idCard.id?.replace( + "(\\d)\\d{16}([0-9,x-y])".toRegex(), + "$1****************$2" + ) + ) + + mBinding.reEditInfoBtn.setOnClickListener { + startActivity( + ShellActivity.getIntent(requireContext(), ShellActivity.Type.REAL_NAME_INFO).apply { + putExtra(EntranceUtils.KEY_IS_FORCED_TO_CERTICIFICE, true) + } + ) + requireActivity().finish() + } + } + + private fun updateSubmitBtn() { + val validationPair = + isInputValid(mBinding.nameEt.text.toString(), mBinding.idCardEt.text.toString()) + + mBinding.submitBtn.isEnabled = validationPair.first + if (validationPair.first) { + mBinding.submitBtn.background = R.drawable.button_round_2496ff.toDrawable() + mBinding.submitBtn.setOnClickListener { + val o = JSONObject() + o.put("id", mBinding.idCardEt.text.toString()) + o.put("name", mBinding.nameEt.text.toString()) + mViewModel.postCertification(o.toString(), mIsForcedToCertificate) + } + } else { + mBinding.submitBtn.background = R.drawable.button_round_2496ff_alpha_40.toDrawable() + } + mBinding.errorHintTv.text = validationPair.second + } + + private fun isInputValid(name: String, idCard: String): Pair { + if (TextUtils.isEmpty(name)) { + return Pair(false, "请输入姓名") + } + if (TextUtils.isEmpty(idCard)) { + return Pair(false, "请输入身份证号码") + } + if (name.length < 2) { + return Pair(false, "姓名至少2个汉字") + } + val nameRegex = Regex("[\\u4e00-\\u9fa5]+") + if (!name.matches(nameRegex)) { + return Pair(false, "姓名无效,请重新输入") + } + if (idCard.length < 18) { + return Pair(false, "必须使用18位的身份证号码") + } + val idCardRegex = + Regex("^[1-9]\\d{5}([1-9]\\d{3})(0\\d|1[0-2])([0-2]\\d|3[0-1])\\d{3}[\\dXx]$") + if (!idCard.matches(idCardRegex)) { + return Pair(false, "身份证无效,请重新输入") + } + + return Pair(true, "") + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoViewModel.kt b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoViewModel.kt new file mode 100644 index 0000000000..02098f9ddc --- /dev/null +++ b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoViewModel.kt @@ -0,0 +1,120 @@ +package com.halo.assistant.fragment.user + +import android.annotation.SuppressLint +import android.app.Application +import android.text.TextUtils +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import com.gh.common.constant.Constants +import com.gh.common.util.* +import com.gh.common.util.GsonUtils.fromJson +import com.gh.common.util.GsonUtils.toJson +import com.gh.download.DownloadManager +import com.gh.gamecenter.entity.IdCardEntity +import com.gh.gamecenter.entity.UserInfoEntity +import com.gh.gamecenter.manager.UserManager +import com.gh.gamecenter.retrofit.BiResponse +import com.gh.gamecenter.retrofit.RetrofitManager +import com.gh.gamecenter.user.UserRepository +import com.halo.assistant.HaloApp +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import okhttp3.MediaType +import okhttp3.RequestBody +import okhttp3.ResponseBody +import org.json.JSONObject +import retrofit2.HttpException + +class RealNameInfoViewModel(application: Application) : AndroidViewModel(application) { + + val certificateResultLiveData = MutableLiveData() + + fun getUserInfo(): UserInfoEntity? { + var userInfoEntity = UserManager.getInstance().userInfoEntity + val certificationOnlyInfoEntity: UserInfoEntity? + val deviceCertificationInfoString = + SPUtils.getString(Constants.SP_DEVICE_CERTIFICATION_PREFIX + HaloApp.getInstance().gid) + if (!TextUtils.isEmpty(deviceCertificationInfoString)) { + certificationOnlyInfoEntity = deviceCertificationInfoString.toObject() + if (userInfoEntity?.idCard == null && certificationOnlyInfoEntity != null) { + userInfoEntity = certificationOnlyInfoEntity + } + + userInfoEntity?.idCard?.revise = certificationOnlyInfoEntity?.idCard?.revise + } + + return userInfoEntity + } + + @SuppressLint("CheckResult") + fun postCertification(content: String, isForced: Boolean) { + val userInfoEntity = UserInfoEntity() + val idCardEntity = fromJson(content, IdCardEntity::class.java) + userInfoEntity.idCard = idCardEntity + val body = RequestBody.create( + MediaType.parse("application/json"), toJson(userInfoEntity) + ) + RetrofitManager.getInstance(HaloApp.getInstance()).api.postCertification(body) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : BiResponse() { + override fun onFailure(exception: Exception) { + ErrorHelper.handleError( + HaloApp.getInstance(), + (exception as? HttpException)?.response()?.errorBody()?.string() + ) + NewLogUtils.logCertificationResult(isForced, 0) + } + + override fun onSuccess(data: ResponseBody?) { + val cachedUserInfo = + UserRepository.getInstance(getApplication()).cacheUserInfoEntity + + // 登录状态下更新实名认证信息 + if (cachedUserInfo != null) { + cachedUserInfo.idCard = content.toObject() + UserRepository.getInstance(getApplication()) + .cacheAndNotifyUserInfo(cachedUserInfo, true) + } + + tryWithDefaultCatch { + val `object` = JSONObject(data?.string() ?: "") + val isUnQualified = `object`.getBoolean("minor") + var qualifyInt = 1 + if (!isUnQualified) { + qualifyInt = 2 + } + NewLogUtils.logCertificationResult(isForced, qualifyInt) + } + + DataUtils.getDeviceCertification(HaloApp.getInstance().gid) + + certificateResultLiveData.postValue(true) + + // 安装因为实名延迟的游戏 + resumeInstallationIfNeeded() + // 重启因为实名认证而处于等待中的任务 + DownloadManager.getInstance(HaloApp.getInstance()) + .resumeAllInvisiblePendingTask() + } + }) + } + + /** + * 安装因为实名延迟的游戏 + */ + private fun resumeInstallationIfNeeded() { + val pendingInstallation = RealNameHelper.pendingInstallPkgPath + if (pendingInstallation.isNotEmpty()) { + val pendingDownloadEntity = + DownloadManager.getInstance(HaloApp.getInstance()).allDownloadEntity.firstOrNull { + it.path == pendingInstallation + } + + PackageInstaller.install(HaloApp.getInstance(), pendingDownloadEntity) + RealNameHelper.pendingInstallPkgPath = "" + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/halo/assistant/fragment/user/UserInfoFragment.java b/app/src/main/java/com/halo/assistant/fragment/user/UserInfoFragment.java index 5631c8b2d8..6c4d2dedc2 100644 --- a/app/src/main/java/com/halo/assistant/fragment/user/UserInfoFragment.java +++ b/app/src/main/java/com/halo/assistant/fragment/user/UserInfoFragment.java @@ -11,9 +11,9 @@ import com.gh.common.util.ImageUtils; import com.gh.common.util.MtaHelper; import com.gh.gamecenter.R; import com.gh.gamecenter.SelectUserIconActivity; +import com.gh.gamecenter.ShellActivity; import com.gh.gamecenter.UserInfoEditActivity; import com.gh.gamecenter.UserRegionActivity; -import com.gh.gamecenter.WebActivity; import com.gh.gamecenter.entity.IdCardEntity; import com.gh.gamecenter.entity.UserInfoEntity; import com.gh.gamecenter.normal.NormalFragment; @@ -159,7 +159,7 @@ public class UserInfoFragment extends NormalFragment { break; case R.id.userinfo_verify_rl: MtaHelper.onEvent("个人主页详情", "个人中心", "实名认证"); - startActivity(UserInfoEditActivity.getIntent(getContext(), UserViewModel.TYPE_ID_CARD)); + startActivity(ShellActivity.getIntent(getContext(), ShellActivity.Type.REAL_NAME_INFO, null)); break; case R.id.userinfo_introduce_rl: MtaHelper.onEvent("个人主页详情", "个人中心", "个性签名"); diff --git a/app/src/main/res/drawable-xhdpi/bg_userinfo_verified_success.9.png b/app/src/main/res/drawable-xhdpi/bg_userinfo_verified_success.9.png index 4994be456b09cc5a9303ad291bf49ba50f01b6d5..a8401fa3fd52e2ca564b45a1c71e3b7a34b03a2c 100644 GIT binary patch literal 39933 zcmZs@c|4Ts8$WIqB$0+rmYEEm8AHSo*=uagV&6&|%BbXInNUm^Dm5KVGtZ0>6=LL2 zl4+4-IpxIQ)G<=YR*Z@)Cs~T*cl&%kzwhh&$M>IjmF8LQ`@XLCcH#K>P}ElIu2xV` zP@_@Z0~8bxbntz}Dkbn|yROm}1qHSO&D|yFWaxN*yWl}jFz)1UW^RO;qber7NzYV%kdyirQ)B)q)4>nu8+V;`OH}%E*sgFx9 z{_aZI#*~|fx79d|)l^oce5l#ET-m$v^Pp4r-CKv#BDxP(-YxK0 zUh}!DW=Y!qqjFDU;g9s2zOxoSv+}^3cMDF*($c4ce7D8#eQ|O*@l{LZwg<0gt12gF zJNLZS-+e7{>3#R!{pm+$*X~~K?%uV3xy`Tf)L!3zwjY`Gto-@C{PvrOrHtax#IR&egO`O!h??8xHI`GxO+jqYKI-;dwCyLq{% z{C3Ef#lp$Nk;e472OAqt%~*6!hw zugCP2<@fpxKYe2x>X)`JbfqNDR-S#M-`9uyp6G^Y%!qIcP{iIvi(ipD?<7Eldc0H5 z*nK>R%MqukQs};FxdnvyVNQ&ZJPvdW$HTvh&L9*z6L=SI`HI9Os)~Q59v@prj zDGFA6#)ivH{^ZqCv!QPcvP7Zh&YISj!Ofmz>>0;5{hHQyCwft=OW(c*$lo9hv<`c+$EV(r=8bXb)T}YnfVDyR0#1 zquRdw8*N%GJ>_fRgXP2Nd#Wl57E6K~DcD`f`Ppa_QV#yuH5E9OF32-g99EF~=dZ!{ zAjC#GWK)`CledG2K*LadVU^NHGR9Mk)JjHZ%h-prtf1%LgLFbLtzJR}zH=N_Cf|}7 zV0rWyxxiZxVvCRP#v0Kitco>eIflk0#4wNKC{m9+7{!i+_c^oC;h&VI)``AM{T7mv zKeOye6=gunvEev!#R)UDHY%*d@D-d3LGDNrw|c=yX7CN#&KtCYG*ay5!TLL=dPQdK z%Mg6CVScviN6XsTm4{ke_3`I7;~h`D!6c>C9h zbY)c3djlbF#-?|9czfkyH*&gm`{P<~zIM%G>#-=SdC1(~f!9FEiwX$Y1EbHUo!4Xu zaIM{`>9Q^co?{a}9%Aa9QlZ5a87^tGfNLRq^lLpY>`Q$jDWmxc)6NUXTg__frR5I1 z2a`rMQ#7T^XP8K}oim*>|+w^+>?eV>{` zUEQbZh3L66&Jq;-=K>65&-HQY!PGN^@E~Iz!GAMk;lCY4ijDjGlg+)jGgi+ggVR~4 zcTv}>cI{l+RJ;n(8fZq$t-<#N0L~xMj8;HDK1NCr*H`SE3@DOLG z3-8Uu@@6_6Hwcv`hw-Y7v?^Wh&J6UAOrTzkW$2yHDjXb;pGSXex7hB+w#?*)4={RQ;N-3N12*iGCf9>SopQo9k#v(r#N) zjb==xBll)*wVqu{F_f)xgCLC`SISnpajEZ#gnY>FsP!)}C;#XEdM}pnb@1!!}(AP4*fwG4C^oR$%@sN}YFZY

n_^L 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 qkdTmo + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_real_name.xml b/app/src/main/res/layout/fragment_real_name.xml new file mode 100644 index 0000000000..d2477e14e3 --- /dev/null +++ b/app/src/main/res/layout/fragment_real_name.xml @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 1478b5947973fa0c49ffeb49525155229fd6d529 Mon Sep 17 00:00:00 2001 From: chenjuntao Date: Mon, 1 Nov 2021 15:08:06 +0800 Subject: [PATCH 10/26] =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E5=8F=8A=E5=A4=84=E7=90=86=E8=A6=81=E6=B1=82?= =?UTF-8?q?=20https://git.ghzs.com/pm/halo-app-issues/-/issues/1605?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gh/common/util/DataUtils.java | 2 +- .../java/com/gh/common/util/DirectUtils.kt | 1 - .../com/gh/common/util/DownloadObserver.kt | 2 - .../java/com/gh/common/util/ErrorHelper.kt | 2 +- .../java/com/gh/common/util/NewLogUtils.kt | 70 ------------------- .../com/gh/common/util/PackageInstaller.kt | 8 +-- .../java/com/gh/download/DownloadManager.java | 9 +++ dependencies.gradle | 4 +- libraries/LGLibrary | 2 +- 9 files changed, 18 insertions(+), 82 deletions(-) diff --git a/app/src/main/java/com/gh/common/util/DataUtils.java b/app/src/main/java/com/gh/common/util/DataUtils.java index a4acfab466..c7aa2b056a 100644 --- a/app/src/main/java/com/gh/common/util/DataUtils.java +++ b/app/src/main/java/com/gh/common/util/DataUtils.java @@ -194,7 +194,7 @@ public class DataUtils { * 获取应用 gid 绑定的实名信息 */ @SuppressLint("CheckResult") - private static void getDeviceCertification(String gid) { + public static void getDeviceCertification(String gid) { RetrofitManager.getInstance(HaloApp.getInstance()) .getApi() .getCertification() diff --git a/app/src/main/java/com/gh/common/util/DirectUtils.kt b/app/src/main/java/com/gh/common/util/DirectUtils.kt index ca525ff0cf..4d69ca035b 100644 --- a/app/src/main/java/com/gh/common/util/DirectUtils.kt +++ b/app/src/main/java/com/gh/common/util/DirectUtils.kt @@ -60,7 +60,6 @@ import com.gh.gamecenter.servers.GameServersActivity import com.gh.gamecenter.subject.SubjectActivity import com.gh.gamecenter.suggest.SuggestType import com.gh.gamecenter.tag.TagsActivity -import com.gh.gamecenter.user.UserViewModel import com.gh.gamecenter.video.data.VideoDataActivity import com.gh.gamecenter.video.detail.VideoDetailActivity import com.gh.gamecenter.video.detail.VideoDetailContainerViewModel 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 318aacda3c..6e0b3b0aea 100644 --- a/app/src/main/java/com/gh/common/util/DownloadObserver.kt +++ b/app/src/main/java/com/gh/common/util/DownloadObserver.kt @@ -3,7 +3,6 @@ package com.gh.common.util import android.os.Build import android.preference.PreferenceManager import com.gh.base.BaseActivity -import com.gh.base.CurrentActivityHolder import com.gh.common.constant.Constants import com.gh.common.exposure.ExposureUtils import com.gh.common.exposure.meta.MetaUtil @@ -23,7 +22,6 @@ import com.gh.gamecenter.retrofit.Response import com.gh.gamecenter.retrofit.RetrofitManager import com.gh.gamecenter.setting.GameDownloadSettingFragment.Companion.AUTO_INSTALL_SP_KEY import com.gh.gamecenter.suggest.SuggestType -import com.gh.gamecenter.user.UserViewModel import com.halo.assistant.HaloApp import com.lightgame.download.DataWatcher import com.lightgame.download.DownloadEntity diff --git a/app/src/main/java/com/gh/common/util/ErrorHelper.kt b/app/src/main/java/com/gh/common/util/ErrorHelper.kt index 5b4a1ef15c..2a9ed4927c 100644 --- a/app/src/main/java/com/gh/common/util/ErrorHelper.kt +++ b/app/src/main/java/com/gh/common/util/ErrorHelper.kt @@ -133,10 +133,10 @@ object ErrorHelper { 403022 -> Utils.toast(context, "不能回复自己") 403056 -> Utils.toast(context, "发布失败,字数已达上限") 403111 -> Utils.toast(context, "提交失败,评论违规") - 403119 -> Utils.toast(context, "不能重复修改实名") 400001 -> Utils.toast(context, "字数超过500或者未填写原因") 403102 -> Utils.toast(context, "你已经举报过该内容了哦") 403115 -> Utils.toast(context, "请求太频繁了,稍微休息一下") + 403119 -> Utils.toast(context, "不能重复修改实名") 403020 -> if (showHighPriorityHint) { DialogHelper.showDialog( diff --git a/app/src/main/java/com/gh/common/util/NewLogUtils.kt b/app/src/main/java/com/gh/common/util/NewLogUtils.kt index 9d12c262a9..cb03b1dc8a 100644 --- a/app/src/main/java/com/gh/common/util/NewLogUtils.kt +++ b/app/src/main/java/com/gh/common/util/NewLogUtils.kt @@ -133,76 +133,6 @@ object NewLogUtils { log(json, "event", false) } - // 触发实名认证 - fun logCertificationTrigger(gameId: String, gameName: String) { - val json = json { - "event" to "verification_trigger" - "game_id" to gameId - "game_name" to gameName - "timestamp" to System.currentTimeMillis() / 1000 - parseAndPutMeta().invoke(this) - } - log(json, "event", false) - } - - // 触发实名认证的来源 (下载触发或用户手动触发) - fun logCertificationTriggerType(isForced: Boolean) { - val json = json { - "event" to "verification_page" - "trigger" to if (isForced) "实名认证流程" else "" - "timestamp" to System.currentTimeMillis() / 1000 - parseAndPutMeta().invoke(this) - } - log(json, "event", false) - } - - /** - * 记录实名认证结果 - * @param result 0 失败, 1 成功但未成年 2 成功且成年 - */ - fun logCertificationResult(isForced: Boolean, result: Int) { - val json = json { - "event" to "verification_finished" - "trigger" to if (isForced) "实名认证流程" else "" - "result" to result - "timestamp" to System.currentTimeMillis() / 1000 - parseAndPutMeta().invoke(this) - } - log(json, "event", false) - } - - // 实名弹窗弹出(含前往实名认证选项) - fun logCertificationHintDialogAppearance() { - val json = json { - "event" to "verification_pop_a_show" - "timestamp" to System.currentTimeMillis() / 1000 - parseAndPutMeta().invoke(this) - } - log(json, "event", false) - } - - // 实名弹窗(含前往实名认证选项) 选项点击 - fun logCertificationHintDialogOptionsClicked(text: String) { - val json = json { - "event" to "verification_pop_a_click" - "timestamp" to System.currentTimeMillis() / 1000 - "button" to text - parseAndPutMeta().invoke(this) - } - log(json, "event", false) - } - - // 实名弹窗弹出(不含前往实名认证选项) - fun logCertificationHintDialogTrigger(isForced: Boolean) { - val json = json { - "event" to "verification_pop_b_show" - "timestamp" to System.currentTimeMillis() / 1000 - "trigger" to if (isForced) "实名认证流程" else "" - parseAndPutMeta().invoke(this) - } - log(json, "event", false) - } - // 游戏详情点击顶部标签 fun logGameDetailTagClick(gameId: String, gameName: String, tagId: String, tagName: String) { val json = json { diff --git a/app/src/main/java/com/gh/common/util/PackageInstaller.kt b/app/src/main/java/com/gh/common/util/PackageInstaller.kt index 6454adeb52..67e8d4cbae 100644 --- a/app/src/main/java/com/gh/common/util/PackageInstaller.kt +++ b/app/src/main/java/com/gh/common/util/PackageInstaller.kt @@ -94,12 +94,12 @@ object PackageInstaller { DownloadManager.getInstance(app).allDownloadEntity.firstOrNull { it.path == pkgPath } - if (downloadEntity != null) { - showCertificateDialogIfNeededBeforeInstall(app, downloadEntity, pkgPath) - } else { +// if (downloadEntity != null) { +// showCertificateDialogIfNeededBeforeInstall(app, downloadEntity, pkgPath) +// } else { val installIntent = getInstallIntent(context, pkgPath) context.startActivity(installIntent) - } +// } } else { if (isPluggin) { DialogHelper.showPluginDialog(context) { diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java index c3557ef903..aa69dfd7c2 100644 --- a/app/src/main/java/com/gh/download/DownloadManager.java +++ b/app/src/main/java/com/gh/download/DownloadManager.java @@ -27,6 +27,7 @@ import com.gh.common.util.DialogUtils; import com.gh.common.util.ExtensionsKt; import com.gh.common.util.GsonUtils; import com.gh.common.util.HomePluggableHelper; +import com.gh.common.util.LunchType; import com.gh.common.util.NetworkUtils; import com.gh.common.util.PackageInstaller; import com.gh.common.util.PackageUtils; @@ -1125,6 +1126,13 @@ public class DownloadManager implements DownloadStatusListener { * 更新下载请求头的相关信息 */ public static void updateDownloadMetaMap() { + String isOverwrite; + if (LunchType.UPDATE.name().equals(SPUtils.getString(Constants.SP_INSTALL_TYPE))) { + isOverwrite = "true"; + } else { + isOverwrite = "false"; + } + HashMap map = new HashMap<>(); map.put(HttpDnsManager.APP_VERSION, BuildConfig.VERSION_NAME); map.put(HttpDnsManager.CHANNEL, HaloApp.getInstance().getChannel()); @@ -1133,6 +1141,7 @@ public class DownloadManager implements DownloadStatusListener { map.put(HttpDnsManager.USER_ID, UserManager.getInstance().getUserId()); map.put(HttpDnsManager.IMEI, MetaUtil.getBase64EncodedIMEI()); map.put(HttpDnsManager.TOKEN, UserManager.getInstance().getToken()); + map.put(HttpDnsManager.IS_OVERWRITE, isOverwrite); HttpDnsManager.metaMap = map; } diff --git a/dependencies.gradle b/dependencies.gradle index 480c8c6bdb..cf9269238c 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,8 +7,8 @@ ext { targetSdkVersion = 26 // application info (每个大版本之间的 versionCode 增加 20) - versionCode = 411 - versionName = "5.3.1" + versionCode = 412 + versionName = "5.3.2" applicationId = "com.gh.gamecenter" // AndroidX diff --git a/libraries/LGLibrary b/libraries/LGLibrary index fffe52891c..7b7d13d471 160000 --- a/libraries/LGLibrary +++ b/libraries/LGLibrary @@ -1 +1 @@ -Subproject commit fffe52891cd80daf50a422df1933c5ec3aec6b51 +Subproject commit 7b7d13d47190581c24ae5f89b02a2d7e78ccde7f From 44aebc39ea599f2d54e398dd2b1560f86f5c8fc4 Mon Sep 17 00:00:00 2001 From: juntao Date: Fri, 5 Nov 2021 09:58:42 +0800 Subject: [PATCH 11/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AE=9E=E5=90=8D?= =?UTF-8?q?=E8=BA=AB=E4=BB=BD=E8=AF=81=E5=8F=B7=E6=97=A0=E6=B3=95=E8=BE=93?= =?UTF-8?q?=E5=85=A5=20X=20=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/fragment_real_name.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/res/layout/fragment_real_name.xml b/app/src/main/res/layout/fragment_real_name.xml index d2477e14e3..4336b327f5 100644 --- a/app/src/main/res/layout/fragment_real_name.xml +++ b/app/src/main/res/layout/fragment_real_name.xml @@ -126,9 +126,8 @@ android:layout_height="40dp" android:layout_marginTop="12dp" android:background="@drawable/bg_shape_fa_radius_2" - android:digits="0123456789X" + android:digits="0123456789xX" android:hint="请输入本人真实身份证号码" - android:inputType="number" android:padding="8dp" android:singleLine="true" android:textColor="@color/text_333333" From 96a19eb5ee58687e94f184e5ea6bb1227111ebe6 Mon Sep 17 00:00:00 2001 From: juntao Date: Fri, 5 Nov 2021 11:05:26 +0800 Subject: [PATCH 12/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E9=97=AA=E9=80=80=201.=20=E9=83=A8=E5=88=865.0=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=90=AF=E5=8A=A8=E8=AF=BB=E5=8F=96=E9=94=99=E8=AF=AF?= =?UTF-8?q?abi=E9=80=A0=E6=88=90=E9=97=AA=E9=80=80=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=202.=20=E9=83=A8=E5=88=86=E5=8D=8E=E4=B8=BA=E9=B8=BF?= =?UTF-8?q?=E8=92=99=E8=AE=BE=E5=A4=87=E8=AF=BB=E5=8F=96=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E9=97=AA=E9=80=80=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 6 +++++- .../main/java/com/gh/common/constant/Constants.java | 3 +++ app/src/main/java/com/gh/common/util/LoginHelper.kt | 10 ++++++++++ app/src/main/java/com/gh/gamecenter/MainActivity.java | 4 +--- dependencies.gradle | 2 +- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b160dad573..d42e98113b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -47,7 +47,11 @@ android { ndk { // 如果不添加 `arm64` 调用系统的 PackageManager 的方法读取安装包信息的时候会出现 native 层闪退,草 - abiFilters "armeabi-v7a", "arm64-v8a", "x86" + // 添加了 `arm64` 以后部分 5.0 的设备会报用错 so 的问题, + // couldn't find DSO to load: libimagepipeline.so caused by: dlopen failed: "/data/data/com.gh.gamecenter/lib-main/libimagepipeline.so" is 64-bit instead of 32-bit result: 0 + // 以 OPPO R7PLUS 为例,明明设备是骁龙 615,ARMv8-64 bit 的设备却不支持 arm64 的 abi + // 惊了 + abiFilters "armeabi-v7a", "x86" } renderscriptTargetApi 18 diff --git a/app/src/main/java/com/gh/common/constant/Constants.java b/app/src/main/java/com/gh/common/constant/Constants.java index ec594c84ee..a9f59127e5 100644 --- a/app/src/main/java/com/gh/common/constant/Constants.java +++ b/app/src/main/java/com/gh/common/constant/Constants.java @@ -207,6 +207,9 @@ public class Constants { // 新分类2.0引导 public static final String SP_SHOW_CATEGORY_GUIDE = "show_category_guide"; + // 用户是否需要 weibo x86 so + public static final String SP_USER_NEED_WEIBO_X86_SO = "user_need_weibo_x86_so"; + // 内容视频播放选项 public static final String SP_CONTENT_VIDEO_OPTION = "content_video_option"; diff --git a/app/src/main/java/com/gh/common/util/LoginHelper.kt b/app/src/main/java/com/gh/common/util/LoginHelper.kt index 9dc9806805..07e9585186 100644 --- a/app/src/main/java/com/gh/common/util/LoginHelper.kt +++ b/app/src/main/java/com/gh/common/util/LoginHelper.kt @@ -3,6 +3,7 @@ package com.gh.common.util import android.app.Activity import android.content.Intent import com.gh.common.constant.Config +import com.gh.common.constant.Constants import com.gh.gamecenter.R import com.gh.gamecenter.user.LoginTag import com.halo.assistant.HaloApp @@ -169,6 +170,15 @@ object LoginHelper { // 微博登录 @JvmStatic fun loginWithWeibo(loginCallback: LoginCallback, context: Activity) { + + tryWithDefaultCatch { + if (SPUtils.getBoolean(Constants.SP_USER_NEED_WEIBO_X86_SO)) { + SentryHelper.onEvent( + "weibo_sdk_login_error", + "exception_digest", "no_x86_so"); + } + } + mWBAPI = WBAPIFactory.createWBAPI(context) //初始化微博分享 mLoginCallback = WeakReference(loginCallback) mWBAPI.registerApp( diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index c8c5706b16..bc155af834 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -1010,9 +1010,7 @@ public class MainActivity extends BaseActivity { // 所以 x86 的 AS 模拟器/ Genymotion 会初始化失败,但实测部分硬性需要提供 x86 SO 的模拟器 (如雷电) 却又能正常使用 // 这里加个简单日志,看看到底有没有(有多少)真实设备出现初始化失败的问题 if (!BuildConfig.DEBUG) { - SentryHelper.INSTANCE.onEvent( - "weibo_sdk_init_error", - "exception_digest", e.getLocalizedMessage()); + SPUtils.setBoolean(Constants.SP_USER_NEED_WEIBO_X86_SO, true); e.printStackTrace(); } } diff --git a/dependencies.gradle b/dependencies.gradle index cf9269238c..a0a7fa3ff4 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -100,7 +100,7 @@ ext { skeleton = "1.1.1" shimmerlayout = "2.1.0" mta = "6.7.9" - romChecker = "1.0.2" + romChecker = "1.0.3" oss = "2.9.2" toolargetool = "0.3.0" chart = "3.1.0" From 9982ebea9e83dcea63a347f75be2e4c29b194b62 Mon Sep 17 00:00:00 2001 From: juntao Date: Fri, 5 Nov 2021 11:07:34 +0800 Subject: [PATCH 13/26] =?UTF-8?q?=E7=89=88=E6=9C=AC=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=88=B0=205.3.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index a0a7fa3ff4..1178e9bc3f 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,8 +7,8 @@ ext { targetSdkVersion = 26 // application info (每个大版本之间的 versionCode 增加 20) - versionCode = 412 - versionName = "5.3.2" + versionCode = 413 + versionName = "5.3.3" applicationId = "com.gh.gamecenter" // AndroidX From fa2fb66f44f12a601c457e29e8d9375e90a76946 Mon Sep 17 00:00:00 2001 From: juntao Date: Fri, 5 Nov 2021 11:12:16 +0800 Subject: [PATCH 14/26] =?UTF-8?q?=E5=8F=96=E6=B6=88=E5=AE=9E=E5=90=8D?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E8=BA=AB=E4=BB=BD=E8=AF=81=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/fragment_real_name.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/res/layout/fragment_real_name.xml b/app/src/main/res/layout/fragment_real_name.xml index 4336b327f5..370b4d21d8 100644 --- a/app/src/main/res/layout/fragment_real_name.xml +++ b/app/src/main/res/layout/fragment_real_name.xml @@ -126,7 +126,6 @@ android:layout_height="40dp" android:layout_marginTop="12dp" android:background="@drawable/bg_shape_fa_radius_2" - android:digits="0123456789xX" android:hint="请输入本人真实身份证号码" android:padding="8dp" android:singleLine="true" From 4086fcdb30c09893b0614fe6508759ead144a70f Mon Sep 17 00:00:00 2001 From: juntao Date: Mon, 8 Nov 2021 11:56:58 +0800 Subject: [PATCH 15/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=BF=AB=E9=80=9F=E8=B7=B3=E8=BD=AC=E9=A1=B5=E9=9D=A2=E5=8F=AF?= =?UTF-8?q?=E4=BB=A5=E8=B7=B3=E8=BF=87=E5=BC=BA=E6=9B=B4=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gh/gamecenter/manager/UpdateManager.java | 100 +++++++++++------- 1 file changed, 63 insertions(+), 37 deletions(-) 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 f914863adc..bd03b0ba80 100644 --- a/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java +++ b/app/src/main/java/com/gh/gamecenter/manager/UpdateManager.java @@ -1,5 +1,6 @@ package com.gh.gamecenter.manager; +import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.SharedPreferences; @@ -18,6 +19,7 @@ import android.widget.TextView; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.app.NotificationManagerCompat; +import com.gh.base.CurrentActivityHolder; import com.gh.common.AppExecutor; import com.gh.common.constant.Constants; import com.gh.common.exposure.ExposureEvent; @@ -64,6 +66,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import retrofit2.HttpException; +// 吐了,这个祖传的类,代码写得不是一般的糟糕,还不敢随便改 : ( /** * Created by LGT on 2016/12/8. * 助手更新 工具类 @@ -76,6 +79,7 @@ public class UpdateManager { private final static String ONCE_ONLY_SECOND_OPEN = "ONCE_ONLY_SECOND_OPEN"; private Context mContext; + private Context mApplicationContext; private SharedPreferences mSp; @@ -140,7 +144,7 @@ public class UpdateManager { } if (DownloadStatus.done.equals(downloadEntity.getStatus())) { - DownloadManager.getInstance(mContext).cancel(downloadEntity.getUrl(), false, true); + DownloadManager.getInstance(mApplicationContext).cancel(downloadEntity.getUrl(), false, true); if (downloadDialog != null) { try { downloadDialog.dismiss(); @@ -152,13 +156,13 @@ public class UpdateManager { AppExecutor.getUiExecutor().executeWithDelay(() -> exitApp(), 1000); } } else if (DownloadStatus.neterror.equals(downloadEntity.getStatus())) { - Utils.toast(mContext, "网络错误,请稍后重试"); + Utils.toast(mApplicationContext, "网络错误,请稍后重试"); } else if (DownloadStatus.timeout.equals(downloadEntity.getStatus())) { - Utils.toast(mContext, "请求超时,请稍后重试"); + Utils.toast(mApplicationContext, "请求超时,请稍后重试"); } else if (DownloadStatus.notfound.equals(downloadEntity.getStatus())) { - Utils.toast(mContext, "下载链接异常,请稍后重试"); + Utils.toast(mApplicationContext, "下载链接异常,请稍后重试"); } else if (DownloadStatus.hijack.equals(downloadEntity.getStatus())) { - Utils.toast(mContext, "网络劫持,请稍后重试"); + Utils.toast(mApplicationContext, "网络劫持,请稍后重试"); } } else { if (downloadEntity.getSize() != lastUpdateFileSize) { @@ -186,7 +190,8 @@ public class UpdateManager { private UpdateManager(Context context) { mContext = context; - mSp = PreferenceManager.getDefaultSharedPreferences(mContext); + mApplicationContext = context.getApplicationContext(); + mSp = PreferenceManager.getDefaultSharedPreferences(mApplicationContext); this.isShowDownload = false; this.isChecking = false; @@ -209,7 +214,7 @@ public class UpdateManager { loadingDialog = DialogUtils.showWaitDialog(mContext, "检查更新中..."); } String channel = HaloApp.getInstance().getChannel(); - RetrofitManager.getInstance(mContext).getApi().getUpdate(PackageUtils.getGhVersionName(), PackageUtils.getGhVersionCode(), channel) + RetrofitManager.getInstance(mApplicationContext).getApi().getUpdate(PackageUtils.getGhVersionName(), PackageUtils.getGhVersionCode(), channel) .map(appEntity -> { boolean isShowUpdateDialog = false; @@ -261,7 +266,7 @@ public class UpdateManager { if (!appEntity.isForce() && isAutoCheck && !isUpdateFileDownloaded(response) - && NetworkUtils.isWifiConnected(mContext)) { + && NetworkUtils.isWifiConnected(mApplicationContext)) { createUpdate(response, true); } else { showUpdateDialog(response); @@ -273,7 +278,7 @@ public class UpdateManager { handler.sendMessage(message); } } else if (!isAutoCheck) { - Utils.toast(mContext, "已是最新版本"); + Utils.toast(mApplicationContext, "已是最新版本"); if (handler != null) { handler.sendEmptyMessage(1); } @@ -293,11 +298,11 @@ public class UpdateManager { handler.sendEmptyMessage(1); } if (e != null && (e.code() == 304 || e.code() == 404)) { - Utils.toast(mContext, "您的光环助手已是最新版本"); + Utils.toast(mApplicationContext, "您的光环助手已是最新版本"); return; } - Utils.toast(mContext, "检查更新失败"); + Utils.toast(mApplicationContext, "检查更新失败"); } invokeDismissCallback(); @@ -307,7 +312,9 @@ public class UpdateManager { // 显示助手有更新提示框 private void showUpdateDialog(final String md5) { - updateDialog = new Dialog(mContext); + Context context = getValidContext(); + + updateDialog = new Dialog(context); updateDialog.setOnDismissListener(dialog -> { invokeDismissCallback(); }); @@ -316,7 +323,8 @@ public class UpdateManager { window.setBackgroundDrawableResource(android.R.color.transparent); } - View view = View.inflate(mContext, R.layout.app_update_hint_dialog, null); + View view = View.inflate(context, R.layout.app_update_hint_dialog, null); + cancelUpdateTextView = view.findViewById(R.id.cancel); downloadedHintView = view.findViewById(R.id.downloadedHint); confirmTextView = view.findViewById(R.id.confirm); @@ -331,7 +339,7 @@ public class UpdateManager { R.color.theme_font, false, () -> { - DirectUtils.directToExternalBrowser(mContext, appEntity.getSpareLink()); + DirectUtils.directToExternalBrowser(context, appEntity.getSpareLink()); return null; }) .build(); @@ -340,7 +348,7 @@ public class UpdateManager { externalTextTv.setVisibility(View.VISIBLE); } - if (NetworkUtils.isWifiConnected(mContext)) { + if (NetworkUtils.isWifiConnected(context)) { if (!isUpdateFileDownloaded(md5)) { updateUpdateDialogView(false); createUpdate(md5, true); @@ -376,11 +384,11 @@ public class UpdateManager { } else if (isUpdateFileDownloaded(md5) && !appEntity.isForce()) { updateDialog.dismiss(); } - String path = FileUtils.getDownloadPath(mContext, "光环助手V" + appEntity.getVersion() + "_" + md5 + ".apk"); + String path = FileUtils.getDownloadPath(context, "光环助手V" + appEntity.getVersion() + "_" + md5 + ".apk"); // 产品不接受显示下载完成文案从立即更新变为立即安装,所以文案为立即更新时一律不执行安装 if (isUpdateFileDownloaded(md5) && confirmTextView.getText() != "立即更新") { - DataLogUtils.uploadUpgradeLog(mContext, "install"); //上传更新安装数据 - PackageInstaller.install(mContext, false, path); + DataLogUtils.uploadUpgradeLog(context, "install"); //上传更新安装数据 + PackageInstaller.install(context, false, path); } else { MtaHelper.onEvent("软件更新", "下载开始"); @@ -396,20 +404,22 @@ public class UpdateManager { updateDialog.setContentView(view); updateDialog.show(); - DataLogUtils.uploadUpgradeLog(mContext, "notice"); //上传更新通知弹窗数据 + DataLogUtils.uploadUpgradeLog(context, "notice"); //上传更新通知弹窗数据 } private void exitApp() { - NotificationManagerCompat.from(HaloApp.getInstance().getApplication()).cancelAll(); + NotificationManagerCompat.from(mApplicationContext).cancelAll(); AppManager.getInstance().finishAllActivity(); } private void showDownloadDialog(String md5) { - if (NetworkUtils.isMobileConnected(mContext)) { - Utils.toast(mContext, "当前使用移动数据进行下载"); + Context context = getValidContext(); + + if (NetworkUtils.isMobileConnected(context)) { + Utils.toast(context, "当前使用移动数据进行下载"); } - downloadDialog = new Dialog(mContext); + downloadDialog = new Dialog(context); downloadDialog.setOnDismissListener(dialog -> { invokeDismissCallback(); }); @@ -418,7 +428,7 @@ public class UpdateManager { window.setBackgroundDrawableResource(android.R.color.transparent); } - View view = View.inflate(mContext, R.layout.app_updating_dialog, null); + View view = View.inflate(context, R.layout.app_updating_dialog, null); app_pb_progress = view.findViewById(R.id.progress); appProgressSize = view.findViewById(R.id.size); @@ -428,7 +438,7 @@ public class UpdateManager { appProgressFilling = view.findViewById(R.id.progress_filling); view.findViewById(R.id.app_tv_cancel).setOnClickListener(v -> { - DownloadManager.getInstance(mContext).cancel(appEntity.getUrl()); + DownloadManager.getInstance(context).cancel(appEntity.getUrl()); if (appEntity.isForce()) { exitApp(); } else { @@ -437,11 +447,11 @@ public class UpdateManager { }); downloadDialog.setOnDismissListener(dialog -> { - DownloadManager.getInstance(mContext).removeObserver(dataWatcher); + DownloadManager.getInstance(context).removeObserver(dataWatcher); isShowDownload = false; }); - int dialogWidth = mContext.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(60); + int dialogWidth = context.getResources().getDisplayMetrics().widthPixels - DisplayUtils.dip2px(60); downloadDialog.setCanceledOnTouchOutside(false); downloadDialog.setCancelable(false); downloadDialog.closeOptionsMenu(); @@ -456,20 +466,20 @@ public class UpdateManager { } private void createUpdate(String md5, boolean isSilentUpdate) { - DownloadManager.getInstance(mContext).addObserver(dataWatcher); + DownloadManager.getInstance(mApplicationContext).addObserver(dataWatcher); boolean shouldCancelPreviousDownload = true; // 是否应该取消旧更新任务 // 在部分设备上取消正在进行中的旧下载任务再创建新下载任务有机率造成新下载任务依然带有 "静默更新" 标签导致无法唤起安装 // 所以这里对当前静默更新任务正在进行中的时候就不用删旧任务,直接改 meta 标签 if (!isSilentUpdate - && DownloadManager.getInstance(mContext).isTaskDownloading(appEntity.getUrl())) { + && DownloadManager.getInstance(mApplicationContext).isTaskDownloading(appEntity.getUrl())) { try { DownloadEntity entity = DataChanger.INSTANCE.getDownloadEntries().get(appEntity.getUrl()); if (entity != null) { ExtensionsKt.addMetaExtra(entity, Constants.EXTRA_DOWNLOAD_TYPE, "不再是静默更新"); - DownloadManager.getInstance(mContext).updateDownloadEntity(entity); - DownloadManager.getInstance(mContext).resume(entity, false); + DownloadManager.getInstance(mApplicationContext).updateDownloadEntity(entity); + DownloadManager.getInstance(mApplicationContext).resume(entity, false); shouldCancelPreviousDownload = false; } @@ -482,7 +492,7 @@ public class UpdateManager { // 预下载完成或者还没进行预下载的都进这里,先删掉旧的下载文件再进行下载 if (shouldCancelPreviousDownload) { - String path = FileUtils.getDownloadPath(mContext, "光环助手V" + appEntity.getVersion() + "_" + md5 + ".apk"); + String path = FileUtils.getDownloadPath(mApplicationContext, "光环助手V" + appEntity.getVersion() + "_" + md5 + ".apk"); File file = new File(path); if (file.exists() && file.delete()) { Utils.log(file.getName() + " file delete success."); @@ -506,18 +516,34 @@ public class UpdateManager { ExtensionsKt.addMetaExtra(downloadEntity, Constants.EXTRA_DOWNLOAD_TYPE, Constants.SILENT_UPDATE); } - downloadEntity.setPackageName(mContext.getPackageName()); - DownloadManager.getInstance(mContext).cancel(appEntity.getUrl(), true, true); - DownloadManager.getInstance(mContext).pauseAll(); + downloadEntity.setPackageName(mApplicationContext.getPackageName()); + DownloadManager.getInstance(mApplicationContext).cancel(appEntity.getUrl(), true, true); + DownloadManager.getInstance(mApplicationContext).pauseAll(); AppExecutor.getUiExecutor().executeWithDelay(() -> { - DownloadManager.getInstance(mContext).add(downloadEntity); + DownloadManager.getInstance(mApplicationContext).add(downloadEntity); }, 200); } } + /** + * 尽量获取有效的 activity context + */ + private Context getValidContext() { + Context context = mContext; + + Activity currentActivity = CurrentActivityHolder.getCurrentActivity(); + if (currentActivity != null + && mContext != currentActivity + && !currentActivity.isFinishing()) { + context = currentActivity; + } + + return context; + } + private boolean isUpdateFileDownloaded(String md5) { - String path = FileUtils.getDownloadPath(mContext, "光环助手V" + appEntity.getVersion() + "_" + md5 + ".apk"); + String path = FileUtils.getDownloadPath(mApplicationContext, "光环助手V" + appEntity.getVersion() + "_" + md5 + ".apk"); File file = new File(path); return file.exists() && file.length() == SPUtils.getLong(Constants.LAST_GHZS_UPDATE_FILE_SIZE, 0); From 1dc2e661d1c2e3af04db69352c530c2aafd5cc82 Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 10:13:17 +0800 Subject: [PATCH 16/26] =?UTF-8?q?=20=E4=BF=AE=E5=A4=8D=E8=BF=9B=E5=85=A5?= =?UTF-8?q?=E6=B8=B8=E6=88=8F=E8=AF=A6=E6=83=85=E9=A1=B5=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E9=9D=9E=E6=B4=BB=E8=B7=83=20tab=20=E4=B9=9F=E4=BC=9A=E8=A2=AB?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E5=88=9D=E5=A7=8B=E5=8C=96=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gamedetail/GameDetailFragment.kt | 20 ++----- .../gamedetail/fuli/FuLiFragment.kt | 48 +++++++++-------- .../gamedetail/rating/RatingFragment.kt | 53 +++++++++++-------- 3 files changed, 59 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt index 4274987738..0d16f9a647 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/GameDetailFragment.kt @@ -18,13 +18,12 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentStatePagerAdapter import androidx.lifecycle.Observer -import androidx.viewpager.widget.PagerAdapter import butterknife.BindView import butterknife.OnClick import com.ethanhua.skeleton.Skeleton import com.ethanhua.skeleton.ViewSkeletonScreen +import com.gh.base.adapter.FragmentAdapter import com.gh.base.fragment.BaseFragment_TabLayout import com.gh.common.constant.Config import com.gh.common.constant.Constants @@ -759,20 +758,7 @@ class GameDetailFragment : NormalFragment() { mTabContainer.goneIf(tabTitleList.size == 1) mToolbarGapView.goneIf(tabTitleList.size == 1) -// mViewPager.adapter = FragmentAdapter(childFragmentManager, fragmentsList, tabTitleList) - mViewPager.adapter = object : FragmentStatePagerAdapter(childFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - override fun getItem(position: Int) = fragmentsList[position] - - override fun getCount() = fragmentsList.size - - override fun getItemPosition(`object`: Any) = PagerAdapter.POSITION_NONE - - override fun getPageTitle(position: Int): CharSequence? { - return if (tabTitleList.size > position) { - tabTitleList[position] - } else super.getPageTitle(position) - } - } + mViewPager.adapter = FragmentAdapter(childFragmentManager, fragmentsList, tabTitleList) mViewPager.doOnPageSelected { logTabClick(it) } @@ -1440,7 +1426,7 @@ class GameDetailFragment : NormalFragment() { && System.currentTimeMillis() - mTabClickEvent.first < 300 ) { val fragment = fragmentsList[mViewPager.currentItem] - if (fragment is IScrollable) { + if (fragment is IScrollable && fragment.isAdded) { fragment.scrollToTop() } } else { diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/FuLiFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/FuLiFragment.kt index 280c5ac63b..5f3ffd3df4 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/FuLiFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/fuli/FuLiFragment.kt @@ -1,7 +1,6 @@ package com.gh.gamecenter.gamedetail.fuli import android.content.Intent -import android.os.Bundle import android.view.View import androidx.core.content.ContextCompat import androidx.lifecycle.Observer @@ -9,7 +8,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.ethanhua.skeleton.Skeleton import com.ethanhua.skeleton.ViewSkeletonScreen -import com.gh.base.fragment.BaseFragment +import com.gh.base.fragment.LazyFragment import com.gh.common.iinterface.IScrollable import com.gh.common.util.* import com.gh.gamecenter.LibaoDetailActivity @@ -29,7 +28,7 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode -class FuLiFragment : BaseFragment(), IScrollable { +class FuLiFragment : LazyFragment(), IScrollable { private val mRecyclerView by bindView(R.id.fm_fuli_rv) @@ -45,24 +44,21 @@ class FuLiFragment : BaseFragment(), IScrollable { private var isCanShowKaiFuHint: Boolean = false private var shouldScroolToLibao: Boolean = false - private var indexHeight = 0 - private lateinit var mViewSkeletonScreen: ViewSkeletonScreen override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) - val detailEntity = mFuLiViewModel?.unifiedGameDetail?.game if (requestCode == GAME_DETAIL_LIBAO_REQUEST) { mAdapter!!.notifyDataSetChanged() } } - override fun getLayoutId(): Int { + override fun getRealLayoutId(): Int { return R.layout.fragment_fuli } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) + override fun onFragmentFirstVisible() { + super.onFragmentFirstVisible() val gameEntity = arguments?.getParcelable(GameEntity.TAG) as? GameEntity val gameDetailFactory = GameDetailViewModel.Factory(HaloApp.getInstance().application, gameEntity?.id, gameEntity) @@ -99,8 +95,25 @@ class FuLiFragment : BaseFragment(), IScrollable { } } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun onFragmentResume() { + super.onFragmentResume() + startPageTime = System.currentTimeMillis() + } + + override fun onFragmentPause() { + super.onFragmentPause() + + val stayTime = (System.currentTimeMillis() - startPageTime) / 1000 + NewLogUtils.logGameDetailTabOrCommentDetailPause( + "jump_game_detail_special_area_tab", + stayTime, + mGameDetailViewModel?.game?.id ?: "", + mGameDetailViewModel?.game?.gameType ?: "" + ) + } + + override fun initRealView() { + super.initRealView() mViewSkeletonScreen = Skeleton.bind(game_detail_skeleton).shimmer(false).load(R.layout.fragment_gamedongtai_skeleton).show() mAdapter = FuLiAdapter(requireContext(), this, mFuLiViewModel, mEntrance) @@ -176,8 +189,7 @@ class FuLiFragment : BaseFragment(), IScrollable { } } - - override fun onListClick(view: View?, position: Int, data: LIST) { + override fun onListClick(view: View?, position: Int, data: Any?) { when (view?.id) { R.id.gamedetail_libao_item -> { val liBao = data as LibaoEntity @@ -200,14 +212,4 @@ class FuLiFragment : BaseFragment(), IScrollable { mRecyclerView.scrollToPosition(0) } - override fun onPause() { - super.onPause() - val stayTime = (System.currentTimeMillis() - startPageTime) / 1000 - NewLogUtils.logGameDetailTabOrCommentDetailPause( - "jump_game_detail_special_area_tab", - stayTime, - mGameDetailViewModel?.game?.id ?: "", - mGameDetailViewModel?.game?.gameType ?: "" - ) - } } \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingFragment.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingFragment.kt index 59517ae6ad..ae8feb32d6 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/RatingFragment.kt @@ -2,7 +2,6 @@ package com.gh.gamecenter.gamedetail.rating import android.app.Activity import android.content.Intent -import android.os.Bundle import android.text.method.LinkMovementMethod import android.view.View import android.widget.ProgressBar @@ -17,7 +16,7 @@ import com.gh.common.util.* import com.gh.common.view.VerticalItemDecoration import com.gh.gamecenter.R import com.gh.gamecenter.WebActivity -import com.gh.gamecenter.baselist.ListFragment +import com.gh.gamecenter.baselist.LazyListFragment import com.gh.gamecenter.baselist.LoadStatus import com.gh.gamecenter.baselist.LoadType import com.gh.gamecenter.entity.GameEntity @@ -32,7 +31,7 @@ import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode -class RatingFragment : ListFragment(), IScrollable { +class RatingFragment : LazyListFragment(), IScrollable { private var mAdapter: RatingAdapter? = null @@ -40,9 +39,9 @@ class RatingFragment : ListFragment(), IScrollab private var mRatingType: RatingViewModel.RatingType? = null - override fun getLayoutId(): Int { + override fun getRealLayoutId(): Int { return if (mRatingType == RatingViewModel.RatingType.RATING) { - super.getLayoutId() + R.layout.fragment_list_base } else { R.layout.fragment_list_fold_rating } @@ -83,10 +82,31 @@ class RatingFragment : ListFragment(), IScrollab return false } - override fun onCreate(savedInstanceState: Bundle?) { + override fun onFragmentResume() { + super.onFragmentResume() + + startPageTime = System.currentTimeMillis() + } + + override fun onFragmentPause() { + super.onFragmentPause() + + val game = arguments?.getParcelable(GameEntity.TAG) + val stayTime = (System.currentTimeMillis() - startPageTime) / 1000 + NewLogUtils.logGameDetailTabOrCommentDetailPause( + "jump_game_detail_comment_tab", + stayTime, + game?.id ?: "", + game?.gameType ?: "" + ) + } + + override fun onFragmentFirstVisible() { mRatingType = arguments?.getSerializable(EntranceUtils.KEY_LOCATION) as? RatingViewModel.RatingType - ?: RatingViewModel.RatingType.RATING - super.onCreate(savedInstanceState) + ?: RatingViewModel.RatingType.RATING + + super.onFragmentFirstVisible() + mSkipGameComment = arguments?.getBoolean(EntranceUtils.KEY_SKIP_GAME_COMMENT) mListRv.setPadding(20F.dip2px(), 0, 20F.dip2px(), 0) mListRefresh?.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.transparent)) @@ -97,8 +117,9 @@ class RatingFragment : ListFragment(), IScrollab }) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) + override fun initRealView() { + super.initRealView() + if (mRatingType == RatingViewModel.RatingType.FOLD_RATING) { val foldRatingReasonTv = requireView().findViewById(R.id.foldRatingReasonTv) val text = "折叠原因:因违反《光环助手评论规则》被管理员折叠" @@ -189,18 +210,6 @@ class RatingFragment : ListFragment(), IScrollab mListRv?.scrollToPosition(0) } - override fun onPause() { - super.onPause() - val game = arguments?.getParcelable(GameEntity.TAG) - val stayTime = (System.currentTimeMillis() - startPageTime) / 1000 - NewLogUtils.logGameDetailTabOrCommentDetailPause( - "jump_game_detail_comment_tab", - stayTime, - game?.id ?: "", - game?.gameType ?: "" - ) - } - companion object { @BindingAdapter("setRatingScore") @JvmStatic From 5d5c8dfddb1daa9b88fa16db633472d398f5741e Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 10:17:01 +0800 Subject: [PATCH 17/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=E8=BD=AE=E6=92=AD=E5=9B=BE=E5=88=B7=E6=96=B0=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=96=B0=E6=B8=90=E5=8F=98=E9=A2=9C=E8=89=B2=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E8=B6=8A=E7=95=8C=E9=97=AA=E9=80=80=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt b/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt index b5394ada52..94e584ac07 100644 --- a/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt +++ b/app/src/main/java/com/gh/gamecenter/home/slide/HomeSlideListViewHolder.kt @@ -140,7 +140,7 @@ class HomeSlideListViewHolder( val nextPosition = adapter.getActualPosition(position + 1) val currentColor = - slideList[currentPosition].placeholderColor.hexStringToIntColor() + slideList.safelyGetInRelease(currentPosition)?.placeholderColor?.hexStringToIntColor() ?: Color.WHITE val nextColor = slideList.safelyGetInRelease(nextPosition)?.placeholderColor?.hexStringToIntColor() ?: currentColor val colorInBetween = From edd8b861448fd5633a6b4a7ab956f351866ae13b Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 10:37:16 +0800 Subject: [PATCH 18/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=A1=B5=E9=9D=A2=E5=81=B6=E5=8F=91=E7=9A=84?= =?UTF-8?q?=E6=95=B0=E7=BB=84=E8=B6=8A=E7=95=8C=E9=97=AA=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gh/gamecenter/download/UpdatableGameFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameFragment.kt b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameFragment.kt index 7dfab6da2f..b6bbb42da5 100644 --- a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameFragment.kt @@ -1,13 +1,13 @@ package com.gh.gamecenter.download import android.view.View -import androidx.recyclerview.widget.LinearLayoutManager import com.gh.base.fragment.LazyFragment import com.gh.common.exposure.ExposureListener import com.gh.common.util.EntranceUtils import com.gh.common.util.goneIf import com.gh.common.util.observeNonNull import com.gh.common.util.viewModelProvider +import com.gh.common.view.FixLinearLayoutManager import com.gh.gamecenter.MainActivity import com.gh.gamecenter.R import com.gh.gamecenter.databinding.FragmentGameUpdatableBinding @@ -59,7 +59,7 @@ class UpdatableGameFragment : LazyFragment() { noDataContainer.reuseNodataSkipTvBtn.setOnClickListener { MainActivity.skipToMainActivity(activity, MainWrapperFragment.INDEX_HOME) } - recyclerView.layoutManager = LinearLayoutManager(requireContext()) + recyclerView.layoutManager = FixLinearLayoutManager(requireContext()) recyclerView.adapter = mAdapter.also { recyclerView.addOnScrollListener(ExposureListener(this@UpdatableGameFragment, it)) } From 92eece62891c83940cf19fe3451847c794aa7258 Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 10:38:16 +0800 Subject: [PATCH 19/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8E=92=E8=A1=8C?= =?UTF-8?q?=E6=A6=9C=E5=88=97=E8=A1=A8=E7=82=B9=E5=87=BB=E6=95=B0=E7=BB=84?= =?UTF-8?q?=E8=B6=8A=E7=95=8C=E9=97=AA=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/gh/gamecenter/game/rank/RankAdapter.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/gh/gamecenter/game/rank/RankAdapter.kt b/app/src/main/java/com/gh/gamecenter/game/rank/RankAdapter.kt index f58da9dfda..2a15b60d22 100644 --- a/app/src/main/java/com/gh/gamecenter/game/rank/RankAdapter.kt +++ b/app/src/main/java/com/gh/gamecenter/game/rank/RankAdapter.kt @@ -20,7 +20,7 @@ import com.gh.gamecenter.entity.TagStyleEntity import com.gh.gamecenter.eventbus.EBDownloadStatus import com.lightgame.adapter.BaseRecyclerAdapter import com.lightgame.download.DownloadEntity -import java.util.HashMap +import java.util.* class RankAdapter( context: Context, @@ -148,7 +148,7 @@ class RankAdapter( } val entrance = "(专题合集-排行榜:$columnName)" - val exposureEvent = exposureEventList?.get(exposureOffset + position) + val exposureEvent = exposureEventList?.safelyGetInRelease(exposureOffset + position) root.setOnClickListener { if (exposureEvent != null) { GameDetailActivity.startGameDetailActivity( From 82d79028de461178c24c2c8b6fd3280a729185e7 Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 10:40:57 +0800 Subject: [PATCH 20/26] =?UTF-8?q?=E6=8D=95=E6=8A=93=E9=83=A8=E5=88=86?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=BD=91=E9=A1=B5=E4=B8=8D=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E5=AE=89=E5=85=A8=E6=B5=8F=E8=A7=88=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E7=9A=84=E9=97=AA=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../game/upload/GameResourcePolicyDialogFragment.kt | 9 +++++++-- .../gamedetail/rating/edit/RatingEditActivity.kt | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt b/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt index e670db7d1c..56a3fc162d 100644 --- a/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/game/upload/GameResourcePolicyDialogFragment.kt @@ -5,12 +5,15 @@ import android.content.DialogInterface import android.os.Build import android.os.Bundle import android.view.* -import android.webkit.* +import android.webkit.WebSettings +import android.webkit.WebView +import android.webkit.WebViewClient import android.widget.TextView import com.gh.base.fragment.BaseDialogFragment import com.gh.common.DefaultJsApi import com.gh.common.util.MtaHelper import com.gh.common.util.dip2px +import com.gh.common.util.tryWithDefaultCatch import com.gh.common.view.dsbridge.DWebView import com.gh.gamecenter.BuildConfig import com.gh.gamecenter.R @@ -37,7 +40,9 @@ class GameResourcePolicyDialogFragment : BaseDialogFragment() { } // 避免提示网页有害信息不能访问 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - settings?.safeBrowsingEnabled = false + tryWithDefaultCatch { + settings?.safeBrowsingEnabled = false + } } DWebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG || "internal" == BuildConfig.FLAVOR) diff --git a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt index 3dd8194f26..2016d02f86 100644 --- a/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt +++ b/app/src/main/java/com/gh/gamecenter/gamedetail/rating/edit/RatingEditActivity.kt @@ -150,7 +150,9 @@ class RatingEditActivity : ToolBarActivity(), KeyboardHeightObserver { } // 避免提示网页有害信息不能访问 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - settings.safeBrowsingEnabled = false + tryWithDefaultCatch { + settings.safeBrowsingEnabled = false + } } DWebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG || "internal" == BuildConfig.FLAVOR) From d6a341337a0b1b201c4f9f98a4a827ae35e8e068 Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 10:46:17 +0800 Subject: [PATCH 21/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E8=B7=B3=E8=BD=AC=E9=80=9A=E7=9F=A5=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E9=A1=B5=E9=9D=A2=E7=9A=84=E9=97=AA=E9=80=80=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gh/common/dialog/NotificationHintDialogFragment.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/gh/common/dialog/NotificationHintDialogFragment.kt b/app/src/main/java/com/gh/common/dialog/NotificationHintDialogFragment.kt index c5667d02e1..9201a62d1c 100644 --- a/app/src/main/java/com/gh/common/dialog/NotificationHintDialogFragment.kt +++ b/app/src/main/java/com/gh/common/dialog/NotificationHintDialogFragment.kt @@ -1,6 +1,7 @@ package com.gh.common.dialog import android.annotation.SuppressLint +import android.content.ActivityNotFoundException import android.content.Intent import android.os.Build import android.os.Bundle @@ -73,7 +74,11 @@ class NotificationHintDialogFragment : BaseTrackableDialogFragment() { val intent = Intent() intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID) - startActivity(intent) + try { + startActivity(intent) + } catch (e: ActivityNotFoundException) { + PermissionHelper.toPermissionSetting(requireActivity()) + } } else { PermissionHelper.toPermissionSetting(requireActivity()) } From 760aa6f8f660b862bb623af08a96b4ba3202e1d1 Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 10:58:47 +0800 Subject: [PATCH 22/26] =?UTF-8?q?=E5=81=9C=E7=94=A8=E5=9B=A0=E6=9C=AA?= =?UTF-8?q?=E6=AD=A3=E7=A1=AE=E5=88=9D=E5=A7=8B=E5=8C=96=E5=B7=B2=E5=A4=B1?= =?UTF-8?q?=E6=95=88=E7=9A=84=20WorkManager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/gh/download/DownloadManager.java | 4 ++-- app/src/main/java/com/gh/download/DownloadWorkManager.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/gh/download/DownloadManager.java b/app/src/main/java/com/gh/download/DownloadManager.java index aa69dfd7c2..6428240fe1 100644 --- a/app/src/main/java/com/gh/download/DownloadManager.java +++ b/app/src/main/java/com/gh/download/DownloadManager.java @@ -119,7 +119,7 @@ public class DownloadManager implements DownloadStatusListener { downloadingMap.put(entity.getUrl(), entity); - DownloadWorkManager.addWorker(); +// DownloadWorkManager.addWorker(); } @Override @@ -143,7 +143,7 @@ public class DownloadManager implements DownloadStatusListener { mDownloadedGameIdAndPackageNameDao.add(entity.getGameId() + entity.getPackageName()); if (downloadingMap.isEmpty()) { - DownloadWorkManager.cancelWorker(); +// DownloadWorkManager.cancelWorker(); } } diff --git a/app/src/main/java/com/gh/download/DownloadWorkManager.kt b/app/src/main/java/com/gh/download/DownloadWorkManager.kt index cd734214b3..18ff96b85a 100644 --- a/app/src/main/java/com/gh/download/DownloadWorkManager.kt +++ b/app/src/main/java/com/gh/download/DownloadWorkManager.kt @@ -29,7 +29,7 @@ object DownloadWorkManager { @JvmStatic fun cancelWorker() { - tryWithDefaultCatch { WorkManager.getInstance().cancelAllWorkByTag(TAG_DOWNLOAD) } +// tryWithDefaultCatch { WorkManager.getInstance().cancelAllWorkByTag(TAG_DOWNLOAD) } } } \ No newline at end of file From a5f5bd8828e90a207dc09ec8684a742eee0b600e Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 11:21:40 +0800 Subject: [PATCH 23/26] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=80=9A=E7=94=A8=E5=88=97=E8=A1=A8=E6=95=B0=E6=8D=AE=E5=8F=98?= =?UTF-8?q?=E6=9B=B4=E5=81=B6=E5=8F=91=E7=9A=84=E8=B6=8A=E7=95=8C=E9=97=AA?= =?UTF-8?q?=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gh/gamecenter/baselist/ListAdapter.java | 69 +++++++++++-------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/gh/gamecenter/baselist/ListAdapter.java b/app/src/main/java/com/gh/gamecenter/baselist/ListAdapter.java index a30e95d50b..d2140c0f1b 100644 --- a/app/src/main/java/com/gh/gamecenter/baselist/ListAdapter.java +++ b/app/src/main/java/com/gh/gamecenter/baselist/ListAdapter.java @@ -52,42 +52,51 @@ public abstract class ListAdapter extends BaseRecyclerAdapter { ArrayList updateDataCopy = new ArrayList<>(updateData); ListExecutor.getWorkerExecutor().execute(() -> { - DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() { - @Override - public int getOldListSize() { - return mEntityList == null ? 0 : mEntityList.size(); - } + try { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() { + @Override + public int getOldListSize() { + return mEntityList == null ? 0 : mEntityList.size(); + } - @Override - public int getNewListSize() { - return updateDataCopy.size(); - } + @Override + public int getNewListSize() { + return updateDataCopy.size(); + } - @Override - public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { - if (oldItemPosition >= mEntityList.size()) return false; - if (newItemPosition >= updateDataCopy.size()) return false; + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + if (oldItemPosition >= mEntityList.size()) return false; + if (newItemPosition >= updateDataCopy.size()) return false; - DataType oldItem = ExtensionsKt.safelyGetInRelease(mEntityList, oldItemPosition); - DataType newItem = ExtensionsKt.safelyGetInRelease(updateDataCopy, newItemPosition); - return ListAdapter.this.areItemsTheSame(oldItem, newItem); - } + DataType oldItem = ExtensionsKt.safelyGetInRelease(mEntityList, oldItemPosition); + DataType newItem = ExtensionsKt.safelyGetInRelease(updateDataCopy, newItemPosition); + return ListAdapter.this.areItemsTheSame(oldItem, newItem); + } - @Override - public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { - if (oldItemPosition >= mEntityList.size()) return false; - if (newItemPosition >= updateDataCopy.size()) return false; + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + if (oldItemPosition >= mEntityList.size()) return false; + if (newItemPosition >= updateDataCopy.size()) return false; - DataType oldItem = ExtensionsKt.safelyGetInRelease(mEntityList, oldItemPosition); - DataType newItem = ExtensionsKt.safelyGetInRelease(updateDataCopy, newItemPosition); - return ListAdapter.this.areContentsTheSame(oldItem, newItem); - } - }); + DataType oldItem = ExtensionsKt.safelyGetInRelease(mEntityList, oldItemPosition); + DataType newItem = ExtensionsKt.safelyGetInRelease(updateDataCopy, newItemPosition); + return ListAdapter.this.areContentsTheSame(oldItem, newItem); + } + }); - ListExecutor.getUiExecutor().execute(() -> { - mEntityList = new ArrayList<>(updateDataCopy); - diffResult.dispatchUpdatesTo(ListAdapter.this); - }); + ListExecutor.getUiExecutor().execute(() -> { + mEntityList = new ArrayList<>(updateDataCopy); + diffResult.dispatchUpdatesTo(ListAdapter.this); + }); + } catch (ArrayIndexOutOfBoundsException exception) { + // 新旧数据比较的时候数组越界了(大概是别处修改了数据源 :( ),直接 notifyDataSetChanged + ListExecutor.getUiExecutor().execute(() -> { + exception.printStackTrace(); + mEntityList = new ArrayList<>(updateData); + notifyDataSetChanged(); + }); + } }); } From 328d200a78a5eedaff6ae7a611957f92ed7e7167 Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 11:36:53 +0800 Subject: [PATCH 24/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E6=B8=B8?= =?UTF-8?q?=E6=88=8F=E5=8F=AF=E6=9B=B4=E6=96=B0=E6=97=B6=E7=82=B9=E5=87=BB?= =?UTF-8?q?=E5=85=A8=E9=83=A8=E6=9B=B4=E6=96=B0=E6=8C=89=E9=92=AE=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=E7=9A=84=E9=97=AA=E9=80=80=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/gh/gamecenter/download/UpdatableGameViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt index 853dfce5a6..ec5971b472 100644 --- a/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt +++ b/app/src/main/java/com/gh/gamecenter/download/UpdatableGameViewModel.kt @@ -536,7 +536,8 @@ class UpdatableGameViewModel( * 全部更新 (版本匹配的我的版本) */ fun updateAllMatchedVersionValidUpdate() { - for (update in mCachedMatchedVersionValidUpdateList) { + val updateList = ArrayList(mCachedMatchedVersionValidUpdateList) + for (update in updateList) { update(update, false) } } From df2d5a93a0c7eff29359f77f7609c9d1dd192ddc Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 11:49:33 +0800 Subject: [PATCH 25/26] =?UTF-8?q?=E5=8E=BB=E9=99=A4=E5=AE=9E=E5=90=8D?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E7=9A=84=E8=BE=93=E5=85=A5=E9=99=90=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../halo/assistant/fragment/user/RealNameInfoFragment.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt index 098af6fee8..b000aca5e4 100644 --- a/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt +++ b/app/src/main/java/com/halo/assistant/fragment/user/RealNameInfoFragment.kt @@ -179,13 +179,6 @@ class RealNameInfoFragment : NormalFragment() { if (TextUtils.isEmpty(idCard)) { return Pair(false, "请输入身份证号码") } - if (name.length < 2) { - return Pair(false, "姓名至少2个汉字") - } - val nameRegex = Regex("[\\u4e00-\\u9fa5]+") - if (!name.matches(nameRegex)) { - return Pair(false, "姓名无效,请重新输入") - } if (idCard.length < 18) { return Pair(false, "必须使用18位的身份证号码") } From 844c028b7b843ac1b249b7ce2206732d0044850d Mon Sep 17 00:00:00 2001 From: juntao Date: Tue, 9 Nov 2021 14:26:54 +0800 Subject: [PATCH 26/26] =?UTF-8?q?=E7=89=88=E6=9C=AC=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E8=87=B3=205.3.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 1178e9bc3f..126d7b325c 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,8 +7,8 @@ ext { targetSdkVersion = 26 // application info (每个大版本之间的 versionCode 增加 20) - versionCode = 413 - versionName = "5.3.3" + versionCode = 414 + versionName = "5.3.4" applicationId = "com.gh.gamecenter" // AndroidX