添加机房B面
This commit is contained in:
parent
6ed1de4f0c
commit
519a4a5873
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,3 +13,4 @@
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
/app/release/
|
||||
|
||||
@ -56,6 +56,7 @@ android {
|
||||
}
|
||||
buildFeatures{
|
||||
viewBinding = true
|
||||
aidl = true
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +91,6 @@ dependencies {
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
|
||||
|
||||
implementation(files("libs/UpLoadLibrary_12_03_15_13-release.aar"))
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
|
||||
implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")
|
||||
implementation("com.google.android.gms:play-services-location:21.0.1")
|
||||
@ -103,7 +103,7 @@ dependencies {
|
||||
implementation ("com.squareup.okhttp3:okhttp:4.12.0")
|
||||
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
|
||||
|
||||
|
||||
implementation(files("libs/magiclock-debug.aar"))
|
||||
implementation(files("libs/IronSourceLibrary_01_07_18_13-release.aar"))
|
||||
|
||||
//---------------------------ironSource
|
||||
|
||||
Binary file not shown.
BIN
app/libs/magiclock-debug.aar
Normal file
BIN
app/libs/magiclock-debug.aar
Normal file
Binary file not shown.
3
app/proguard-rules.pro
vendored
3
app/proguard-rules.pro
vendored
@ -31,3 +31,6 @@
|
||||
-keepattributes Signature
|
||||
-keepattributes AnnotationDefault,RuntimeVisibleAnnotations
|
||||
|
||||
-keep class com.gallery.free.wallpaper.environment.hy.IdProvider { *; }
|
||||
-keep class com.gallery.free.wallpaper.environment.hy.SimIdProvider { *; }
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:ignore="DiscouragedApi,LockedOrientationActivity">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
@ -15,6 +17,8 @@
|
||||
|
||||
<uses-permission android:name="android.permission.AD_ID" />
|
||||
|
||||
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
|
||||
|
||||
<application
|
||||
android:name=".MyApplication"
|
||||
android:allowBackup="true"
|
||||
@ -24,19 +28,18 @@
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:largeHeap="true"
|
||||
android:networkSecurityConfig="@xml/net"
|
||||
android:persistableMode="persistAcrossReboots"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:supportsRtl="true"
|
||||
tools:replace="networkSecurityConfig"
|
||||
android:networkSecurityConfig="@xml/net"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
|
||||
tools:replace="networkSecurityConfig"
|
||||
tools:targetApi="30">
|
||||
|
||||
|
||||
|
||||
<activity
|
||||
android:name=".LocalPreActivity"
|
||||
android:exported="false"
|
||||
@ -48,16 +51,28 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
|
||||
<activity
|
||||
android:name=".SplaActivity"
|
||||
android:name="com.gallery.free.wallpaper.SplashActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<action android:name="best.log" />
|
||||
<category android:name="best.facebook.go.log" />
|
||||
|
||||
<action android:name="best.wash.param" />
|
||||
<category android:name="best.wash.param.go" />
|
||||
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.gallery.free.wallpaper.environment.MainActivity2"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="false"
|
||||
|
||||
12
app/src/main/aidl/com/ad/click/cp/IMyAidlCallback.aidl
Normal file
12
app/src/main/aidl/com/ad/click/cp/IMyAidlCallback.aidl
Normal file
@ -0,0 +1,12 @@
|
||||
package com.ad.click.cp;
|
||||
|
||||
interface IMyAidlCallback {
|
||||
//广告指令执行完毕
|
||||
void onClickComplete(boolean b);
|
||||
//参数修改指令执行完毕
|
||||
void onParametersComplete(boolean b);
|
||||
//展示广告成功
|
||||
void onAdDisplayed();
|
||||
//展示广告失败
|
||||
void onAdDisplayFailed();
|
||||
}
|
||||
23
app/src/main/aidl/com/ad/click/cp/IMyAidlInterface.aidl
Normal file
23
app/src/main/aidl/com/ad/click/cp/IMyAidlInterface.aidl
Normal file
@ -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();
|
||||
}
|
||||
|
||||
@ -14,7 +14,8 @@ import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.gallery.free.wallpaper.database.FavorWpManager
|
||||
import com.up.uploadlibrary.UpLoadManager
|
||||
import com.gallery.free.wallpaper.environment.ad.AdActivityManager
|
||||
import com.gallery.free.wallpaper.environment.jb.MagicLockManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
@ -76,7 +77,8 @@ class MyApplication : Application() {
|
||||
// 验证固定分类文件
|
||||
validateFixedCategories()
|
||||
|
||||
UpLoadManager.init(this,"ocean", callback = { _, _ -> })
|
||||
AdActivityManager.instance.setControl(this)
|
||||
MagicLockManager.init(this)
|
||||
|
||||
ISAdManager.init("-------WallpaperGallery--------",this,"24e146eb5","1x1dmfonwgx54zkn","3r21zexffllavwqj","4v2mbujbbk8wq7ed",false,{
|
||||
|
||||
|
||||
@ -7,8 +7,10 @@ import android.os.CountDownTimer
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.ad.ironsourcelibrary.ISAdManager
|
||||
import com.gallery.free.wallpaper.databinding.ActivitySplaBinding
|
||||
import com.gallery.free.wallpaper.environment.MainActivity2
|
||||
import com.gallery.free.wallpaper.environment.hy.IdProvider
|
||||
|
||||
class SplaActivity : AppCompatActivity() {
|
||||
class SplashActivity : AppCompatActivity() {
|
||||
private var countDownTimer: CountDownTimer? = null
|
||||
private var vb: ActivitySplaBinding? = null
|
||||
private val totalTime: Long = 15000
|
||||
@ -19,7 +21,7 @@ class SplaActivity : AppCompatActivity() {
|
||||
vb = ActivitySplaBinding.inflate(layoutInflater)
|
||||
Utils_com.initFull(this, true)
|
||||
setContentView(vb?.getRoot())
|
||||
|
||||
if (IdProvider().getId() == 0L) {
|
||||
countDownTimer = ISAdManager.showWelcomeAd(this, totalTime, { millisUntilFinished ->
|
||||
val progressPercentage = ((100 * millisUntilFinished) / totalTime).toInt()
|
||||
|
||||
@ -28,11 +30,16 @@ class SplaActivity : AppCompatActivity() {
|
||||
vb?.progressbar?.progress = countdownPercentage
|
||||
}) {
|
||||
vb?.progressbar?.progress = 100
|
||||
val intent = Intent(this@SplaActivity, MainActivity::class.java)
|
||||
val intent = Intent(this@SplashActivity, MainActivity::class.java)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
countDownTimer?.start()
|
||||
} else {
|
||||
val intent = Intent(this@SplashActivity, MainActivity2::class.java)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,238 @@
|
||||
package com.gallery.free.wallpaper.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.gallery.free.wallpaper.environment.hy.TimeoutManager
|
||||
import com.gallery.free.wallpaper.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<Boolean>()
|
||||
|
||||
//连接是否断开
|
||||
val connectCompleteLiveData = MutableLiveData<Boolean>()
|
||||
|
||||
val clickAdCompleteLiveData = MutableLiveData<Boolean>()
|
||||
|
||||
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() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,740 @@
|
||||
package com.gallery.free.wallpaper.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.core.graphics.toColorInt
|
||||
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.unity3d.mediation.LevelPlay
|
||||
import com.unity3d.mediation.LevelPlayAdInfo
|
||||
import com.unity3d.mediation.LevelPlayConfiguration
|
||||
import com.unity3d.mediation.LevelPlayInitError
|
||||
import com.unity3d.mediation.LevelPlayInitListener
|
||||
import com.unity3d.mediation.LevelPlayInitRequest
|
||||
import com.gallery.free.wallpaper.R
|
||||
import com.gallery.free.wallpaper.databinding.ActivityMain2Binding
|
||||
import com.gallery.free.wallpaper.environment.ad.AdShowFailed
|
||||
import com.gallery.free.wallpaper.environment.ad.AdsInsUtil
|
||||
import com.gallery.free.wallpaper.environment.ad.InstAdCacheManager
|
||||
import com.gallery.free.wallpaper.environment.ad.LoadListener
|
||||
import com.gallery.free.wallpaper.environment.ad.ShowListener
|
||||
import com.gallery.free.wallpaper.environment.hy.AppLifecycleTracker
|
||||
import com.gallery.free.wallpaper.environment.hy.ConfigCallback
|
||||
import com.gallery.free.wallpaper.environment.hy.IdProvider
|
||||
import com.gallery.free.wallpaper.environment.hy.MyConfigUtil
|
||||
import com.gallery.free.wallpaper.environment.hy.SimIdProvider
|
||||
import com.gallery.free.wallpaper.environment.hy.TimeoutManager
|
||||
import com.gallery.free.wallpaper.environment.hy.TimeoutTask
|
||||
import com.gallery.free.wallpaper.environment.hy.getLocalIpAddress
|
||||
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.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<String> = 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<String> = 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<Boolean>()
|
||||
private val onAdShowFailedLiveData = MutableLiveData<Boolean>()
|
||||
private val onAdClosedLiveData = MutableLiveData<Boolean>()
|
||||
|
||||
@SuppressLint("MissingInflatedId", "SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityMain2Binding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
binding.title.text = "Max(1月15日)-${getString(R.string.app_name)}"
|
||||
// 异步获取 IP,不影响主流程
|
||||
lifecycleScope.launch {
|
||||
remoteIp = getPublicIpAddress()
|
||||
loadJson.addProperty("remoteIp", remoteIp)//远程IP
|
||||
showJson.addProperty("remoteIp", remoteIp)//远程IP
|
||||
}
|
||||
val initRequest = LevelPlayInitRequest.Builder("24e146eb5")
|
||||
.build()
|
||||
|
||||
LevelPlay.init(this, initRequest, object : LevelPlayInitListener {
|
||||
override fun onInitFailed(error: LevelPlayInitError) {
|
||||
//Recommended to initialize again
|
||||
appendLoadingTxt("sdk初始化失败,${timeLeft}秒后将会重置")
|
||||
runOnUiThread {
|
||||
startCountdown()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInitSuccess(configuration: LevelPlayConfiguration) {
|
||||
//Create ad objects and load ads
|
||||
appendLoadingTxt("sdk初始化成功")
|
||||
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<Boolean> {
|
||||
if (it) {
|
||||
appendLoadingTxt("CP控制器连接成功,进行初始化配置")
|
||||
aidlClient.sendBrushMiss()
|
||||
//初始化配置
|
||||
initConfig()
|
||||
//初始化屏幕点击范围
|
||||
magicLockInit()
|
||||
} else {
|
||||
appendLoadingTxt("CP控制器连接失败,检查是否安装了正确的软件")
|
||||
}
|
||||
}
|
||||
|
||||
private val paramCompleteObserver = Observer<Boolean> {
|
||||
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<Boolean> {
|
||||
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<Boolean> {
|
||||
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<Boolean> {
|
||||
Log.d("ocean-brush", "MainActivity 监听到广告展示失败,直接进行重置")
|
||||
TimeoutManager.cancelTimeout(TimeoutTask.SHOW_AD)
|
||||
aidlClient.sendChangeParameters(packageName)
|
||||
}
|
||||
|
||||
private val onAdCloseObserver = Observer<Boolean> {
|
||||
Log.d("ocean-brush", "MainActivity 监听到广告被关闭")
|
||||
TimeoutManager.cancelTimeout(TimeoutTask.CLOSE_AD)
|
||||
}
|
||||
|
||||
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 \nConfig获取失败,请检查是否在后台配置包名,${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: LevelPlayAdInfo) {
|
||||
aidlClient.sendBrushMiss()
|
||||
val loadedEndTime = System.currentTimeMillis()
|
||||
appendLoadingTxt("${placeId}AD加载成功")
|
||||
aidlClient.sendAdsChange(packageName, getInsAdReturnCount())
|
||||
val scientificNotation = ad.revenue
|
||||
val formattedString: String = String.format("%.20f", scientificNotation)
|
||||
appendLoadingTxt("${ad.adNetwork} ecpm->$formattedString")
|
||||
Log.d("ocean", "平台->${ad.adNetwork} ecpm->${ad.revenue}")
|
||||
loadJson.addProperty("succeed", true)//广告加载是否成功
|
||||
loadJson.addProperty("loadTime", loadedEndTime - startLoadTime)//加载时间
|
||||
loadJson.addProperty("adPlatform", "IronSource")//广告平台
|
||||
loadJson.addProperty("countryCode", ad.country)//国家
|
||||
loadJson.addProperty("adId", placeId)//广告Id
|
||||
loadJson.addProperty("platformResponseTime", "")//平台广告响应时间
|
||||
loadJson.addProperty("ecpm", formattedString)//广告单价
|
||||
loadJson.addProperty("dsp", ad.adNetwork)
|
||||
loadJson.addProperty("network", ad.adNetwork)
|
||||
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", "IronSource")//广告平台
|
||||
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: LevelPlayAdInfo) {
|
||||
aidlClient.sendBrushMiss()
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
onAdShownLiveData.value = true
|
||||
}
|
||||
val scientificNotation = ad.revenue
|
||||
val formattedString: String = String.format("%.20f", scientificNotation)
|
||||
|
||||
showJson.addProperty("succeed", true)//广告加载是否成功
|
||||
showJson.addProperty("adPlatform", "IronSource")//广告平台
|
||||
showJson.addProperty("countryCode", ad.country)//国家代码
|
||||
showJson.addProperty("adId", place)//广告Id
|
||||
showJson.addProperty("platformResponseTime", "")//平台广告响应时间
|
||||
showJson.addProperty("ecpm", formattedString)//广告单价
|
||||
showJson.addProperty("dsp", ad.adNetwork)
|
||||
showJson.addProperty("network", ad.adNetwork)
|
||||
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", "IronSource")//广告平台
|
||||
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("#CE3A54".toColorInt())
|
||||
//gaID没有确的值就发送重置广播
|
||||
appendLoadingTxt("没有获取到GAID,$timeLeft 秒后将会重置")
|
||||
Log.d("ocean", "没有获取到GAID")
|
||||
startCountdown()
|
||||
} else {
|
||||
Log.d("ocean", "获取到GAID")
|
||||
binding.gaidLayout.setBackgroundColor("#60D889".toColorInt())
|
||||
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) // 取消倒计时
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
package com.gallery.free.wallpaper.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<TrustManager>(
|
||||
object : X509TrustManager {
|
||||
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
|
||||
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}
|
||||
override fun getAcceptedIssuers(): Array<X509Certificate> = 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)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,220 @@
|
||||
package com.gallery.free.wallpaper.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 android.view.WindowManager
|
||||
import com.vungle.ads.internal.ui.view.MRAIDAdWidget
|
||||
import com.gallery.free.wallpaper.environment.ad.async.Async
|
||||
|
||||
|
||||
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.ironsource.sdk.controller.ControllerActivity
|
||||
|| activity is com.ironsource.sdk.controller.OpenUrlActivity
|
||||
|| activity is com.unity3d.ironsourceads.internal.services.InlineStoreActivity
|
||||
|| activity is com.vungle.ads.internal.ui.AdActivity
|
||||
|| activity is com.mbridge.msdk.activity.MBCommonActivity
|
||||
|| activity is com.mbridge.msdk.config.activity.MBRewardVideoActivity
|
||||
|| activity is com.unity3d.services.ads.adunit.AdUnitActivity
|
||||
|| activity is sg.bigo.ads.ad.splash.AdSplashActivity
|
||||
|| activity is com.chartboost.sdk.internal.clickthrough.EmbeddedBrowserActivity
|
||||
|| activity is com.fyber.inneractive.sdk.activities.InneractiveInternalBrowserActivity
|
||||
|| activity is com.fyber.inneractive.sdk.activities.InneractiveFullscreenAdActivity
|
||||
|| activity is com.fyber.inneractive.sdk.activities.InneractiveRichMediaVideoPlayerActivityCore
|
||||
|| activity is com.fyber.inneractive.sdk.activities.InternalStoreWebpageActivity
|
||||
|| activity is com.fyber.inneractive.sdk.activities.FyberReportAdActivity
|
||||
|| activity is com.inmobi.ads.rendering.InMobiAdActivity
|
||||
|| activity is com.bytedance.sdk.openadsdk.activity.TTBaseActivity
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
/**
|
||||
* 2025年10月15日,尝试使用对应广告的act,里面的关闭方法调用。
|
||||
*/
|
||||
when (adActivity) {
|
||||
is com.ironsource.sdk.controller.ControllerActivity -> {
|
||||
adActivity.onCloseRequested()
|
||||
}
|
||||
|
||||
is com.vungle.ads.internal.ui.AdActivity -> {
|
||||
//反射方式关闭
|
||||
try {
|
||||
// 获取 mraidAdWidget 字段
|
||||
val field =
|
||||
com.vungle.ads.internal.ui.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")
|
||||
}
|
||||
}
|
||||
is com.mbridge.msdk.activity.MBCommonActivity -> {
|
||||
adActivity.finish()
|
||||
}
|
||||
is sg.bigo.ads.ad.splash.AdSplashActivity ->{
|
||||
adActivity.finish()
|
||||
}
|
||||
is com.fyber.inneractive.sdk.activities.InneractiveInternalBrowserActivity->{
|
||||
adActivity.finish()
|
||||
}
|
||||
is com.fyber.inneractive.sdk.activities.InneractiveFullscreenAdActivity->{
|
||||
val closeButton = adActivity.closeButton
|
||||
closeButton?.performClick() ?: adActivity.dismissAd(true)
|
||||
}
|
||||
else -> {
|
||||
adActivity.finish()
|
||||
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) {
|
||||
Log.d("ocean-brush", "广告 Activity 正在销毁,但可能残留窗口")
|
||||
removeVungleWindow(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页面
|
||||
}
|
||||
|
||||
private fun removeVungleWindow(activity: Activity) {
|
||||
try {
|
||||
val windowManager = activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||
val decorView = activity.window.decorView
|
||||
windowManager.removeView(decorView)
|
||||
Log.d("ocean-brush", "AdActivity 残留窗口已移除")
|
||||
} catch (e: Exception) {
|
||||
Log.e("ocean-brush", "移除 AdActivity 窗口失败", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.gallery.free.wallpaper.environment.ad
|
||||
|
||||
import android.app.Activity
|
||||
import android.util.Log
|
||||
import com.unity3d.mediation.LevelPlayAdError
|
||||
import com.unity3d.mediation.LevelPlayAdInfo
|
||||
import com.unity3d.mediation.interstitial.LevelPlayInterstitialAd
|
||||
import com.unity3d.mediation.interstitial.LevelPlayInterstitialAdListener
|
||||
|
||||
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() {
|
||||
// Create the interstitial ad object
|
||||
val mInterstitialAd = LevelPlayInterstitialAd(mPlace)
|
||||
mInterstitialAd.setListener(object : LevelPlayInterstitialAdListener {
|
||||
override fun onAdLoaded(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad was loaded successfully
|
||||
InstAdCacheManager.instance.setAdCache(mPlace, mInterstitialAd)
|
||||
adLoadListener?.loaded(levelPlayAdInfo)
|
||||
}
|
||||
override fun onAdLoadFailed(levelPlayAdError: LevelPlayAdError) {
|
||||
// Ad load failed
|
||||
adLoadListener?.loadFailed("code->${levelPlayAdError.errorCode} message->${levelPlayAdError.errorMessage}")
|
||||
Log.d("ocean", "load ad onError-> code->${levelPlayAdError.errorCode} message->${levelPlayAdError.errorMessage}")
|
||||
}
|
||||
override fun onAdDisplayed(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad was displayed and visible on screen
|
||||
}
|
||||
override fun onAdDisplayFailed(levelPlayAdError: LevelPlayAdError, levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad fails to be displayed
|
||||
// Optional
|
||||
}
|
||||
override fun onAdClicked(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad was clicked
|
||||
// Optional
|
||||
}
|
||||
override fun onAdClosed(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad was closed
|
||||
// Optional
|
||||
}
|
||||
override fun onAdInfoChanged(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Called after the ad info is updated. Available when another interstitial ad has loaded, and includes a higher CPM/Rate
|
||||
// Optional
|
||||
}
|
||||
})
|
||||
mInterstitialAd.loadAd()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
package com.gallery.free.wallpaper.environment.ad
|
||||
|
||||
import android.app.Activity
|
||||
import android.util.Log
|
||||
import com.unity3d.mediation.LevelPlayAdError
|
||||
import com.unity3d.mediation.LevelPlayAdInfo
|
||||
import com.unity3d.mediation.interstitial.LevelPlayInterstitialAdListener
|
||||
import com.gallery.free.wallpaper.environment.ad.async.Async
|
||||
|
||||
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?.setListener(object : LevelPlayInterstitialAdListener{
|
||||
override fun onAdLoaded(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad was loaded successfully
|
||||
}
|
||||
override fun onAdLoadFailed(levelPlayAdError: LevelPlayAdError) {
|
||||
// Ad load failed
|
||||
}
|
||||
override fun onAdDisplayed(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad was displayed and visible on screen
|
||||
showListener?.onAdShown(levelPlayAdInfo)
|
||||
Log.d("ocean", "onAdDisplayed 广告展示回调")
|
||||
autoClose()
|
||||
}
|
||||
override fun onAdDisplayFailed(levelPlayAdError: LevelPlayAdError, levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad fails to be displayed
|
||||
Log.d("ocean", "AdInstShower 视频广告播放失败回调->${levelPlayAdError.errorCode} ${levelPlayAdError.errorMessage}")
|
||||
showListener?.onAdShowFailed(AdShowFailed("${levelPlayAdError.errorCode} ${levelPlayAdError.errorMessage}"))
|
||||
}
|
||||
override fun onAdClicked(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad was clicked
|
||||
showListener?.onAdClicked()
|
||||
Log.d("ocean", "onAdClicked 广告点击回调")
|
||||
}
|
||||
override fun onAdClosed(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Ad was closed
|
||||
showListener?.onAdClosed()
|
||||
Log.d("ocean", "onAdClosed 广告关闭回调")
|
||||
}
|
||||
override fun onAdInfoChanged(levelPlayAdInfo: LevelPlayAdInfo) {
|
||||
// Called after the ad info is updated. Available when another interstitial ad has loaded, and includes a higher CPM/Rate
|
||||
// Optional
|
||||
}
|
||||
})
|
||||
interstitialAd?.showAd(activity!!)
|
||||
}
|
||||
|
||||
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")
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.gallery.free.wallpaper.environment.ad
|
||||
|
||||
data class AdShowFailed(
|
||||
val msg: String = "",
|
||||
)
|
||||
@ -0,0 +1,28 @@
|
||||
package com.gallery.free.wallpaper.environment.ad
|
||||
|
||||
import android.app.Activity
|
||||
|
||||
object AdsInsUtil {
|
||||
|
||||
object Placement {
|
||||
const val TOP_ON_AD_ONE = "1x1dmfonwgx54zkn"
|
||||
const val TOP_ON_AD_TOW = "3r21zexffllavwqj"
|
||||
const val TOP_ON_AD_THREE = "4v2mbujbbk8wq7ed"
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.gallery.free.wallpaper.environment.ad
|
||||
|
||||
import com.unity3d.mediation.interstitial.LevelPlayInterstitialAd
|
||||
|
||||
|
||||
class InstAdCacheManager {
|
||||
private val mAdCacheDict: MutableMap<String, LevelPlayInterstitialAd> = mutableMapOf()
|
||||
|
||||
companion object {
|
||||
val instance: InstAdCacheManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
|
||||
InstAdCacheManager()
|
||||
}
|
||||
}
|
||||
|
||||
fun setAdCache(place: String, adCache: LevelPlayInterstitialAd) {
|
||||
mAdCacheDict[place] = adCache
|
||||
}
|
||||
|
||||
fun getAdCache(place: String): LevelPlayInterstitialAd? {
|
||||
return mAdCacheDict[place]
|
||||
}
|
||||
|
||||
fun getLoadedInstCount(): Int {
|
||||
var count = 0
|
||||
try {
|
||||
mAdCacheDict.forEach { (key, value) ->
|
||||
if (value.isAdReady) {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
|
||||
}
|
||||
return count
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.gallery.free.wallpaper.environment.ad
|
||||
|
||||
import com.unity3d.mediation.LevelPlayAdInfo
|
||||
|
||||
interface LoadListener {
|
||||
fun loadFailed(error: String) {}
|
||||
fun loaded(ad: LevelPlayAdInfo) {}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package com.gallery.free.wallpaper.environment.ad
|
||||
|
||||
import com.unity3d.mediation.LevelPlayAdInfo
|
||||
|
||||
interface ShowListener {
|
||||
fun onAdShown(ad: LevelPlayAdInfo) {}
|
||||
fun onAdShowFailed(error: AdShowFailed?) {}
|
||||
fun onAdClosed() {}
|
||||
fun onAdClicked() {}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
package com.gallery.free.wallpaper.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 <T> Future<T> submit(Callable<T> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
package com.gallery.free.wallpaper.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<Runnable> asyncPool;
|
||||
|
||||
private final Queue<SyncPost> syncPool;
|
||||
|
||||
private final int maxMillisInsideHandleMessage;
|
||||
|
||||
private boolean asyncActive;//执行状态。避免重复发送消息导致消息队列过多
|
||||
|
||||
private boolean syncActive;//执行状态。避免重复发送消息导致消息队列过多
|
||||
|
||||
HandlerPoster(Looper looper, int maxMillisInsideHandleMessage) {
|
||||
super(looper);
|
||||
this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
|
||||
asyncPool = new LinkedList<Runnable>();
|
||||
syncPool = new LinkedList<SyncPost>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.gallery.free.wallpaper.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.gallery.free.wallpaper.environment.ad.async;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class TaskQueue extends Thread{
|
||||
private BlockingQueue<Object> mQueue;
|
||||
|
||||
public TaskQueue() {
|
||||
mQueue = new LinkedBlockingQueue<Object>();
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,158 @@
|
||||
package com.gallery.free.wallpaper.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<Integer, Object> 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<Runnable>());
|
||||
|
||||
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 <T> Future<T> submitTask(Callable<T> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.gallery.free.wallpaper.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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.gallery.free.wallpaper.environment.hy
|
||||
|
||||
import java.net.InetAddress
|
||||
import java.net.NetworkInterface
|
||||
import java.util.Enumeration
|
||||
|
||||
fun getLocalIpAddress(): String? {
|
||||
try {
|
||||
val interfaces: Enumeration<NetworkInterface> = NetworkInterface.getNetworkInterfaces()
|
||||
while (interfaces.hasMoreElements()) {
|
||||
val networkInterface: NetworkInterface = interfaces.nextElement()
|
||||
val addresses: Enumeration<InetAddress> = 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
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.gallery.free.wallpaper.environment.hy
|
||||
|
||||
import java.io.IOException
|
||||
|
||||
interface ConfigCallback {
|
||||
fun onResponse(result: String)
|
||||
fun onFailure(e: IOException)
|
||||
}
|
||||
@ -0,0 +1,181 @@
|
||||
package com.gallery.free.wallpaper.environment.hy;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class ConfigUtil {
|
||||
public static final String TAG = "--ocean--";
|
||||
|
||||
public static final String POST_BID = "http://mobile.jeanell.vip/data/dataAnalysis";//上传gaid,价格等地址
|
||||
public static final String POST_LOAD_LOG_URL = "http://192.168.40.190/top_selection/save_ad_load_log";
|
||||
|
||||
// public static final String GET_CONFIG_URL = "http://mobile.jeanell.vip/exhibit/config";//获取配置地址
|
||||
public static final String GET_CONFIG_URL = "http://192.168.40.190/top_selection/config";
|
||||
public static final String POST_APP_START = "http://192.168.40.190/top_selection/save_app_start_log";
|
||||
public static final String POST_SHOW_LOG_URL = "http://192.168.40.190/top_selection/save_ad_show_log";
|
||||
|
||||
public static final MediaType JSONMediaType = MediaType.parse("application/json; charset=utf-8");
|
||||
|
||||
public static void initPostBid(JsonObject json) {
|
||||
Thread mThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
postBid(json);
|
||||
}
|
||||
});
|
||||
mThread.start();
|
||||
}
|
||||
|
||||
private static void postBid(JsonObject json) {
|
||||
Log.d("ocean", "json->" + json);
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
RequestBody requestBody = RequestBody.create(JSONMediaType, json.toString());
|
||||
Request request = new Request.Builder()
|
||||
.url(ConfigUtil.POST_BID)
|
||||
.post(requestBody)
|
||||
.build();
|
||||
Response response = null;
|
||||
try {
|
||||
response = client.newCall(request).execute();
|
||||
String requestJson = response.body().string();
|
||||
Log.d(TAG, "requestJson:" + requestJson);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void initPostLoadLog(JsonObject json) {
|
||||
Thread mThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
postLoadLog(json);
|
||||
}
|
||||
});
|
||||
mThread.start();
|
||||
}
|
||||
|
||||
private static void postLoadLog(JsonObject json) {
|
||||
Log.d("ocean", "postLoadLog json->" + json);
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
RequestBody requestBody = RequestBody.create(JSONMediaType, json.toString());
|
||||
Request request = new Request.Builder()
|
||||
.url(ConfigUtil.POST_LOAD_LOG_URL)
|
||||
.post(requestBody)
|
||||
.build();
|
||||
Response response = null;
|
||||
try {
|
||||
response = client.newCall(request).execute();
|
||||
String requestJson = response.body().string();
|
||||
Log.d(TAG, "postLoadLog requestJson:" + requestJson);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void initPostShowLog(JsonObject json) {
|
||||
Thread mThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
postShowLog(json);
|
||||
}
|
||||
});
|
||||
mThread.start();
|
||||
}
|
||||
|
||||
private static void postShowLog(JsonObject json) {
|
||||
Log.d("ocean", "show json->" + json);
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
RequestBody requestBody = RequestBody.create(JSONMediaType, json.toString());
|
||||
Request request = new Request.Builder()
|
||||
.url(ConfigUtil.POST_SHOW_LOG_URL)
|
||||
.post(requestBody)
|
||||
.build();
|
||||
Response response = null;
|
||||
try {
|
||||
response = client.newCall(request).execute();
|
||||
String requestJson = response.body().string();
|
||||
Log.d(TAG, "show requestJson:" + requestJson);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void getConfig(String pkg, final MyCallback callback) {
|
||||
String url = GET_CONFIG_URL + "?pkg=" + pkg;
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
|
||||
// 发送异步GET请求
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
||||
// 请求失败时回调onFailure方法
|
||||
callback.onFailure(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
|
||||
// 请求成功时回调onResponse方法
|
||||
if (response.isSuccessful()) {
|
||||
final String responseData = response.body().string();
|
||||
callback.onResponse(responseData);
|
||||
} else {
|
||||
// 处理请求失败的情况
|
||||
callback.onFailure(new IOException("Unexpected code " + response));
|
||||
}
|
||||
// 记得关闭响应,释放资源
|
||||
response.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 定义一个接口用于回调请求结果
|
||||
public interface MyCallback {
|
||||
void onResponse(String result);
|
||||
|
||||
void onFailure(IOException e);
|
||||
}
|
||||
|
||||
public static void initPostAppStart(JsonObject json) {
|
||||
Thread mThread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
postAppStart(json);
|
||||
}
|
||||
});
|
||||
mThread.start();
|
||||
}
|
||||
|
||||
private static void postAppStart(JsonObject json) {
|
||||
Log.d("ocean", "POST_APP_START json->" + json);
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
RequestBody requestBody = RequestBody.create(JSONMediaType, json.toString());
|
||||
Request request = new Request.Builder()
|
||||
.url(ConfigUtil.POST_APP_START)
|
||||
.post(requestBody)
|
||||
.build();
|
||||
Response response = null;
|
||||
try {
|
||||
response = client.newCall(request).execute();
|
||||
String requestJson = response.body().string();
|
||||
Log.d(TAG, "POST_APP_START requestJson:" + requestJson);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.gallery.free.wallpaper.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)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.gallery.free.wallpaper.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)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.gallery.free.wallpaper.environment.hy
|
||||
|
||||
class IdProvider {
|
||||
fun getId(): Long {
|
||||
return 0 // 默认返回值,可以被 Hook 替换
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
package com.gallery.free.wallpaper.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()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.gallery.free.wallpaper.environment.hy
|
||||
|
||||
class SimIdProvider {
|
||||
fun getSimId(): Long {
|
||||
return 0 // 默认返回值,可以被 Hook 替换
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.gallery.free.wallpaper.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<String, Runnable>() // 存储超时任务
|
||||
|
||||
// 统一管理超时任务的超时时间
|
||||
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", "🛑 所有超时检测已取消")
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.gallery.free.wallpaper.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");
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package com.gallery.free.wallpaper.environment.jb;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import com.applock.filemanager.magiclock.control.MagicLock;
|
||||
import com.gallery.free.wallpaper.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();
|
||||
}
|
||||
|
||||
}
|
||||
94
app/src/main/res/layout/activity_main2.xml
Normal file
94
app/src/main/res/layout/activity_main2.xml
Normal file
@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.3"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="90dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textColor="#FF018786"
|
||||
android:textSize="16dp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/applicationId"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textColor="#FF018786"
|
||||
android:textSize="14dp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gaid_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="110dp"
|
||||
android:background="@color/green"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gaid_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text=""
|
||||
android:textColor="#000000"
|
||||
android:textSize="14dp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loading_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/red"
|
||||
android:textSize="12dp" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="#cccccc" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/info_tv"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/red"
|
||||
android:textSize="12dp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@ -5,7 +5,7 @@
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.gallery.free.wallpaper.SplaActivity">
|
||||
tools:context="com.gallery.free.wallpaper.SplashActivity">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@ -9,4 +9,6 @@
|
||||
<color name="light_purple">#CCCCFF</color>
|
||||
<color name="light_gray">#D3D3D3</color>
|
||||
<color name="transparent">#00000000</color>
|
||||
<color name="green">#60D889</color>
|
||||
<color name="red">#CE3A54</color>
|
||||
</resources>
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config xmlns:tools="http://schemas.android.com/tools">
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain tools:ignore="NetworkSecurityConfig">mobile-server.lux-ad.com</domain>
|
||||
<domain tools:ignore="NetworkSecurityConfig">172.24.100.10</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user