diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 47b6c37bc0..b483162762 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -619,6 +619,10 @@ android:name=".qa.questions.draft.QuestionDraftActivity" android:screenOrientation="portrait" /> + + 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 4e05ad9474..8b9feb51e7 100644 --- a/app/src/main/java/com/gh/common/util/ErrorHelper.kt +++ b/app/src/main/java/com/gh/common/util/ErrorHelper.kt @@ -18,6 +18,7 @@ object ErrorHelper { * [showHighPriorityHint] 用来标识有同样错误码可以触发两种处理时,为 true 时选择重要的 * [customizedHandler] 返回 true 为已处理该错误码,false 则交由 [handleError] 处理 */ + @JvmStatic fun handleErrorWithCustomizedHandler(context: Context, errorString: String?, showHighPriorityHint: Boolean = false, diff --git a/app/src/main/java/com/gh/common/util/LogUtils.java b/app/src/main/java/com/gh/common/util/LogUtils.java index b58dbe5f81..b34ed324fb 100644 --- a/app/src/main/java/com/gh/common/util/LogUtils.java +++ b/app/src/main/java/com/gh/common/util/LogUtils.java @@ -767,4 +767,27 @@ public class LogUtils { } LoghubUtils.log(object, "event", false); } + + public static void uploadPackageSkip(String action, String gameId, String gameName) { + JSONObject object = new JSONObject(); + JSONObject payloadObject = new JSONObject(); + try { + object.put("event", "external_jump"); + object.put("action", action); + + if (!TextUtils.isEmpty(gameId)&&!TextUtils.isEmpty(gameName)) { + payloadObject.put("game_id", gameId); + payloadObject.put("game_name", gameName); + object.put("payload", payloadObject); + } + + object.put("meta", getMetaObject()); + } catch (JSONException e) { + e.printStackTrace(); + } + if (BuildConfig.DEBUG) { + Utils.log("LogUtils->" + object.toString()); + } + LoghubUtils.log(object, "event", false); + } } diff --git a/app/src/main/java/com/gh/gamecenter/MainActivity.java b/app/src/main/java/com/gh/gamecenter/MainActivity.java index 8526b3240f..d44fcc16bc 100644 --- a/app/src/main/java/com/gh/gamecenter/MainActivity.java +++ b/app/src/main/java/com/gh/gamecenter/MainActivity.java @@ -20,6 +20,7 @@ import android.view.View; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.lifecycle.ViewModelProviders; import com.gh.base.AppUncaughtHandler; @@ -43,6 +44,7 @@ import com.gh.common.util.DialogUtils; import com.gh.common.util.DirectUtils; import com.gh.common.util.DisplayUtils; import com.gh.common.util.EntranceUtils; +import com.gh.common.util.ErrorHelper; import com.gh.common.util.ExtensionsKt; import com.gh.common.util.GsonUtils; import com.gh.common.util.HomePluggableHelper; @@ -56,6 +58,7 @@ import com.gh.common.util.PlatformUtils; import com.gh.common.util.SPUtils; import com.gh.common.util.ShareUtils; import com.gh.common.util.ToastUtils; +import com.gh.common.util.UrlFilterUtils; import com.gh.download.DownloadManager; import com.gh.gamecenter.download.DownloadFragment; import com.gh.gamecenter.entity.CommunityEntity; @@ -67,20 +70,18 @@ import com.gh.gamecenter.eventbus.EBNetworkState; import com.gh.gamecenter.eventbus.EBReuse; import com.gh.gamecenter.eventbus.EBSkip; import com.gh.gamecenter.fragment.MainWrapperFragment; -import com.gh.gamecenter.gamedetail.GameDetailFragment; +import com.gh.gamecenter.home.skip.PackageSkipActivity; import com.gh.gamecenter.manager.DataCollectionManager; import com.gh.gamecenter.manager.UpdateManager; import com.gh.gamecenter.manager.UserManager; import com.gh.gamecenter.normal.NormalFragment; import com.gh.gamecenter.packagehelper.PackageViewModel; import com.gh.gamecenter.qa.CommunityFragment; -import com.gh.gamecenter.retrofit.BiResponse; import com.gh.gamecenter.retrofit.Response; import com.gh.gamecenter.retrofit.RetrofitManager; import com.gh.gamecenter.suggest.SuggestSelectFragment; import com.gh.gamecenter.suggest.SuggestType; import com.google.gson.Gson; -import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; import com.halo.assistant.HaloApp; import com.lightgame.download.DownloadEntity; @@ -92,7 +93,6 @@ import com.lightgame.utils.Utils; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; -import org.jetbrains.annotations.NotNull; import org.json.JSONObject; import java.io.BufferedReader; @@ -101,6 +101,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Enumeration; +import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.zip.ZipEntry; @@ -108,9 +109,11 @@ import java.util.zip.ZipFile; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; +import kotlin.jvm.functions.Function1; import okhttp3.MediaType; import okhttp3.RequestBody; import okhttp3.ResponseBody; +import retrofit2.HttpException; import static com.gh.common.util.EntranceUtils.ENTRANCE_BROWSER; import static com.gh.common.util.EntranceUtils.HOST_LAUNCH_SIMULATOR_GAME; @@ -122,7 +125,7 @@ import static com.gh.common.util.EntranceUtils.KEY_MARKET_DETAILS; import static com.gh.common.util.EntranceUtils.KEY_NEXT_TO; import static com.gh.common.util.EntranceUtils.KEY_TO; import static com.gh.common.util.EntranceUtils.KEY_TYPE; -import static com.gh.common.util.ExtensionsKt.singleToMain; +import static com.gh.common.util.ExtensionsKt.observableToMain; import static com.gh.gamecenter.fragment.MainWrapperFragment.INDEX_PERSONAL; import static com.gh.gamecenter.personal.PersonalFragment.LOGIN_TAG; import static com.gh.gamecenter.personal.PersonalFragment.LOGOUT_TAG; @@ -453,20 +456,43 @@ public class MainActivity extends BaseActivity { * * @param packageName */ - @SuppressLint("CheckResult") private void redirectGameDetail(String packageName) { - RetrofitManager.getInstance(this).getApi().redirectGameDetail(packageName) - .compose(singleToMain()) - .subscribe(new BiResponse() { + String filterQuery = UrlFilterUtils.getFilterQuery("package", packageName, "type", "package_redirect"); + RetrofitManager.getInstance(this).getApi().loadGameDataByPackageName(filterQuery) + .compose(observableToMain()) + .subscribe(new Response>() { @Override - public void onSuccess(JsonObject data) { - String gameId = data.get("game_id").getAsString(); - DirectUtils.directToGameDetail(MainActivity.this, gameId, GameDetailFragment.INDEX_DESC, "应用跳转"); + public void onResponse(@Nullable List response) { + super.onResponse(response); + if (response == null || response.isEmpty()) return; + if (response.size() > 1) { + startActivity(PackageSkipActivity.getIntent(MainActivity.this, response)); + LogUtils.uploadPackageSkip("show_enter", "", ""); + } else { + GameDetailActivity.startGameDetailActivity(MainActivity.this, response.get(0), "应用跳转"); + LogUtils.uploadPackageSkip("game_detail_enter", response.get(0).getId(), response.get(0).getName()); + } } @Override - public void onFailure(@NotNull Exception exception) { - super.onFailure(exception); + public void onFailure(@Nullable HttpException e) { + super.onFailure(e); + try { + ErrorHelper.handleErrorWithCustomizedHandler(MainActivity.this, e.response().errorBody().string(), false, new Function1() { + @Override + public Boolean invoke(Integer code) { + if (code == 404001) { + toast("抱歉,暂未找到相关内容"); + LogUtils.uploadPackageSkip("game_library_enter", "", ""); + EventBus.getDefault().post(new EBSkip(MainActivity.EB_SKIP_MAIN, MainWrapperFragment.INDEX_GAME)); + return true; + } + return false; + } + }); + } catch (IOException ex) { + ex.printStackTrace(); + } } }); } diff --git a/app/src/main/java/com/gh/gamecenter/home/skip/PackageSkipActivity.kt b/app/src/main/java/com/gh/gamecenter/home/skip/PackageSkipActivity.kt new file mode 100644 index 0000000000..18f7fddc80 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/home/skip/PackageSkipActivity.kt @@ -0,0 +1,32 @@ +package com.gh.gamecenter.home.skip + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.gh.base.BaseActivity +import com.gh.common.util.DisplayUtils +import com.gh.gamecenter.R +import com.gh.gamecenter.entity.GameEntity + +class PackageSkipActivity : BaseActivity() { + + override fun getLayoutId(): Int = R.layout.activity_amway + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val containerFragment = supportFragmentManager.findFragmentByTag(PackageSkipFragment::class.java.simpleName) + ?: PackageSkipFragment().with(intent.extras) + // 若 placeholder 外层为 RelativeLayout 的话,会出现莫名的偏移 + supportFragmentManager.beginTransaction().replace(R.id.placeholder, containerFragment, PackageSkipFragment::class.java.simpleName).commitAllowingStateLoss() + DisplayUtils.setStatusBarColor(this, R.color.transparent, true) + } + + companion object { + @JvmStatic + fun getIntent(context: Context, games: List): Intent { + val intent = Intent(context, PackageSkipActivity::class.java) + intent.putParcelableArrayListExtra(GameEntity::class.java.name, ArrayList(games)) + return intent + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/home/skip/PackageSkipAdapter.kt b/app/src/main/java/com/gh/gamecenter/home/skip/PackageSkipAdapter.kt new file mode 100644 index 0000000000..846a4b9e3e --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/home/skip/PackageSkipAdapter.kt @@ -0,0 +1,53 @@ +package com.gh.gamecenter.home.skip + +import android.content.Context +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.gh.common.util.DownloadItemUtils +import com.gh.common.util.EmptyCallback +import com.gh.common.util.LogUtils +import com.gh.common.util.StringUtils +import com.gh.gamecenter.GameDetailActivity +import com.gh.gamecenter.R +import com.gh.gamecenter.adapter.viewholder.GameViewHolder +import com.gh.gamecenter.databinding.GameItemBinding +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.game.GameItemViewHolder +import com.lightgame.adapter.BaseRecyclerAdapter + +class PackageSkipAdapter(val context: Context, val games: ArrayList, private val itemClickCallback: () -> Unit) : BaseRecyclerAdapter(context) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + return GameItemViewHolder(GameItemBinding.bind(mLayoutInflater.inflate(R.layout.game_item, parent, false))) + } + + override fun getItemCount(): Int = games.size + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + if (holder is GameItemViewHolder) { + val gameEntity = games[position] + holder.binding.game = gameEntity + holder.initServerType(gameEntity) + val subjectData = gameEntity.subjectData + holder.binding.isShowSuffix = subjectData?.isShowSuffix + holder.binding.briefStyle = subjectData?.briefStyle + + holder.binding.executePendingBindings() + DownloadItemUtils.setOnClickListener(mContext, holder.binding.downloadBtn, gameEntity, position, + this, + StringUtils.buildString("应用跳转:", subjectData?.name, "-列表[", (position + 1).toString(), "])"), + StringUtils.buildString("应用跳转-", subjectData?.name, ":", gameEntity.name), null, + object : EmptyCallback { + override fun onCallback() { + LogUtils.uploadPackageSkip("show_download", gameEntity.id, gameEntity.name) + } + }) + DownloadItemUtils.updateItem(mContext, gameEntity, GameViewHolder(holder.binding), !gameEntity.isPluggable, subjectData?.briefStyle) + holder.itemView.setOnClickListener { + LogUtils.uploadPackageSkip("show_click", gameEntity.id, gameEntity.name) + GameDetailActivity.startGameDetailActivity(context, gameEntity, "应用跳转") + itemClickCallback.invoke() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/gh/gamecenter/home/skip/PackageSkipFragment.kt b/app/src/main/java/com/gh/gamecenter/home/skip/PackageSkipFragment.kt new file mode 100644 index 0000000000..dff2050163 --- /dev/null +++ b/app/src/main/java/com/gh/gamecenter/home/skip/PackageSkipFragment.kt @@ -0,0 +1,118 @@ +package com.gh.gamecenter.home.skip + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import androidx.recyclerview.widget.DefaultItemAnimator +import androidx.recyclerview.widget.LinearLayoutManager +import com.gh.base.fragment.BaseFragment +import com.gh.common.util.LogUtils +import com.gh.download.DownloadManager +import com.gh.gamecenter.databinding.FragmentPackageSkipBinding +import com.gh.gamecenter.entity.GameEntity +import com.gh.gamecenter.eventbus.EBDownloadStatus +import com.gh.gamecenter.eventbus.EBPackage +import com.lightgame.download.DataWatcher +import com.lightgame.download.DownloadEntity +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode + +class PackageSkipFragment : BaseFragment() { + + private lateinit var mBinding: FragmentPackageSkipBinding + private lateinit var mAdapter: PackageSkipAdapter + private var games: ArrayList = arrayListOf() + private var positionAndPackageMap = HashMap() + + override fun getLayoutId(): Int = 0 + + private val dataWatcher = object : DataWatcher() { + override fun onDataChanged(downloadEntity: DownloadEntity) { + for (key in positionAndPackageMap.keys) { + if (key.contains(downloadEntity.packageName) && key.contains(downloadEntity.gameId)) { + val position = positionAndPackageMap[key] + if (position != null && position < games.size) { + games[position].getEntryMap()[downloadEntity.platform] = downloadEntity + mAdapter.notifyItemChanged(position) + } + } + } + } + } + + override fun getInflatedLayout(): View { + mBinding = FragmentPackageSkipBinding.inflate(LayoutInflater.from(requireContext()), null, false) + return mBinding.root + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + games = arguments?.getParcelableArrayList(GameEntity::class.java.name) + ?: arrayListOf() + positionAndPackageMap.clear() + games.forEachIndexed { index, gameEntity -> + addGamePositionAndPackage(gameEntity, index) + } + mBinding.normalToolbar.setNavigationOnClickListener { + LogUtils.uploadPackageSkip("home_enter", "", "") + requireActivity().finish() + } + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + mBinding.listRv.apply { + (itemAnimator as DefaultItemAnimator).supportsChangeAnimations = false + layoutManager = LinearLayoutManager(requireContext()) + mAdapter = PackageSkipAdapter(requireContext(), games) { + requireActivity().finish() + } + adapter = mAdapter + } + } + + private fun addGamePositionAndPackage(game: GameEntity, position: Int) { + var packages = "" + for (apkEntity in game.getApk()) { + packages += apkEntity.packageName + } + packages += game.simulator?.apk?.packageName + positionAndPackageMap[packages + position + game.id] = position + game.gameLocation = GameEntity.GameLocation.INDEX + game.setEntryMap(DownloadManager.getInstance(requireContext()).getEntryMap(game.name)) + } + + override fun onResume() { + super.onResume() + DownloadManager.getInstance(requireContext()).addObserver(dataWatcher) + } + + override fun onPause() { + super.onPause() + DownloadManager.getInstance(requireContext()).removeObserver(dataWatcher) + } + + //安装、卸载事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(busFour: EBPackage) { + if ("安装" == busFour.type || "卸载" == busFour.type) { + mAdapter.notifyDataSetChanged() + } + } + + // 下载被删除事件 + @Subscribe(threadMode = ThreadMode.MAIN) + fun onEventMainThread(status: EBDownloadStatus) { + if ("delete" == status.status) { + for (key in positionAndPackageMap.keys) { + if (key.contains(status.packageName) && key.contains(status.gameId)) { + val position = positionAndPackageMap[key] + if (position != null && position < games.size) { + games[position].getEntryMap().remove(status.platform) + mAdapter.notifyItemChanged(position) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_package_skip.xml b/app/src/main/res/layout/fragment_package_skip.xml new file mode 100644 index 0000000000..3c3b7c1693 --- /dev/null +++ b/app/src/main/res/layout/fragment_package_skip.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file