|
|
package com.idormy.sms.forwarder
|
|
|
|
|
|
import android.annotation.SuppressLint
|
|
|
import android.app.Application
|
|
|
import android.app.PendingIntent
|
|
|
import android.content.Context
|
|
|
import android.content.Intent
|
|
|
import android.content.IntentFilter
|
|
|
import android.os.Build
|
|
|
import android.util.Log
|
|
|
import androidx.lifecycle.MutableLiveData
|
|
|
import androidx.multidex.MultiDex
|
|
|
import androidx.work.Configuration
|
|
|
import com.gyf.cactus.Cactus
|
|
|
import com.gyf.cactus.callback.CactusCallback
|
|
|
import com.gyf.cactus.ext.cactus
|
|
|
import com.idormy.sms.forwarder.activity.MainActivity
|
|
|
import com.idormy.sms.forwarder.core.Core
|
|
|
import com.idormy.sms.forwarder.database.AppDatabase
|
|
|
import com.idormy.sms.forwarder.database.repository.FrpcRepository
|
|
|
import com.idormy.sms.forwarder.database.repository.LogsRepository
|
|
|
import com.idormy.sms.forwarder.database.repository.RuleRepository
|
|
|
import com.idormy.sms.forwarder.database.repository.SenderRepository
|
|
|
import com.idormy.sms.forwarder.entity.SimInfo
|
|
|
import com.idormy.sms.forwarder.receiver.CactusReceiver
|
|
|
import com.idormy.sms.forwarder.service.BatteryService
|
|
|
import com.idormy.sms.forwarder.service.ForegroundService
|
|
|
import com.idormy.sms.forwarder.service.HttpService
|
|
|
import com.idormy.sms.forwarder.utils.*
|
|
|
import com.idormy.sms.forwarder.utils.sdkinit.ANRWatchDogInit
|
|
|
import com.idormy.sms.forwarder.utils.sdkinit.UMengInit
|
|
|
import com.idormy.sms.forwarder.utils.sdkinit.XBasicLibInit
|
|
|
import com.idormy.sms.forwarder.utils.sdkinit.XUpdateInit
|
|
|
import com.idormy.sms.forwarder.utils.tinker.TinkerLoadLibrary
|
|
|
import com.xuexiang.xutil.app.AppUtils
|
|
|
import io.reactivex.Observable
|
|
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
|
import io.reactivex.disposables.Disposable
|
|
|
import io.reactivex.schedulers.Schedulers
|
|
|
import kotlinx.coroutines.*
|
|
|
import java.io.File
|
|
|
import java.text.SimpleDateFormat
|
|
|
import java.util.*
|
|
|
import java.util.concurrent.TimeUnit
|
|
|
|
|
|
@Suppress("PrivatePropertyName")
|
|
|
class App : Application(), CactusCallback, Configuration.Provider by Core {
|
|
|
|
|
|
val applicationScope = CoroutineScope(SupervisorJob())
|
|
|
val database by lazy { AppDatabase.getInstance(this) }
|
|
|
val frpcRepository by lazy { FrpcRepository(database.frpcDao()) }
|
|
|
val logsRepository by lazy { LogsRepository(database.logsDao()) }
|
|
|
val ruleRepository by lazy { RuleRepository(database.ruleDao()) }
|
|
|
val senderRepository by lazy { SenderRepository(database.senderDao()) }
|
|
|
|
|
|
companion object {
|
|
|
const val TAG: String = "SmsForwarder"
|
|
|
|
|
|
@SuppressLint("StaticFieldLeak")
|
|
|
lateinit var context: Context
|
|
|
|
|
|
//已插入SIM卡信息
|
|
|
var SimInfoList: MutableMap<Int, SimInfo> = mutableMapOf()
|
|
|
|
|
|
//已安装App信息
|
|
|
var AppInfoList: List<AppUtils.AppInfo> = arrayListOf()
|
|
|
|
|
|
/**
|
|
|
* @return 当前app是否是调试开发模式
|
|
|
*/
|
|
|
val isDebug: Boolean
|
|
|
get() = BuildConfig.DEBUG
|
|
|
|
|
|
//Cactus结束时间
|
|
|
val mEndDate = MutableLiveData<String>()
|
|
|
|
|
|
//Cactus上次存活时间
|
|
|
val mLastTimer = MutableLiveData<String>()
|
|
|
|
|
|
//Cactus存活时间
|
|
|
val mTimer = MutableLiveData<String>()
|
|
|
|
|
|
//Cactus运行状态
|
|
|
val mStatus = MutableLiveData<Boolean>().apply { value = true }
|
|
|
}
|
|
|
|
|
|
override fun attachBaseContext(base: Context) {
|
|
|
super.attachBaseContext(base)
|
|
|
//解决4.x运行崩溃的问题
|
|
|
MultiDex.install(this)
|
|
|
}
|
|
|
|
|
|
override fun onCreate() {
|
|
|
super.onCreate()
|
|
|
try {
|
|
|
//动态加载FrpcLib
|
|
|
val libPath = filesDir.absolutePath + "/libs"
|
|
|
val soFile = File(libPath)
|
|
|
try {
|
|
|
TinkerLoadLibrary.installNativeLibraryPath(classLoader, soFile)
|
|
|
} catch (throwable: Throwable) {
|
|
|
Log.e("APP", throwable.message!!)
|
|
|
}
|
|
|
|
|
|
context = applicationContext
|
|
|
initLibs()
|
|
|
|
|
|
//启动前台服务
|
|
|
val intent = Intent(this, ForegroundService::class.java)
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
startForegroundService(intent)
|
|
|
} else {
|
|
|
startService(intent)
|
|
|
}
|
|
|
|
|
|
//电池状态监听
|
|
|
val batteryServiceIntent = Intent(this, BatteryService::class.java)
|
|
|
startService(batteryServiceIntent)
|
|
|
|
|
|
//异步获取所有已安装 App 信息
|
|
|
val get = GlobalScope.async(Dispatchers.IO) {
|
|
|
AppInfoList = AppUtils.getAppsInfo()
|
|
|
}
|
|
|
GlobalScope.launch(Dispatchers.Main) {
|
|
|
runCatching {
|
|
|
get.await()
|
|
|
Log.d("GlobalScope", "AppUtils.getAppsInfo() Done")
|
|
|
}.onFailure {
|
|
|
Log.e("GlobalScope", it.message.toString())
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//启动HttpServer
|
|
|
if (HttpServerUtils.enableServerAutorun) {
|
|
|
startService(Intent(this, HttpService::class.java))
|
|
|
}
|
|
|
|
|
|
//Cactus 集成双进程前台服务,JobScheduler,onePix(一像素),WorkManager,无声音乐
|
|
|
if (!isDebug) {
|
|
|
//注册广播监听器
|
|
|
registerReceiver(CactusReceiver(), IntentFilter().apply {
|
|
|
addAction(Cactus.CACTUS_WORK)
|
|
|
addAction(Cactus.CACTUS_STOP)
|
|
|
addAction(Cactus.CACTUS_BACKGROUND)
|
|
|
addAction(Cactus.CACTUS_FOREGROUND)
|
|
|
})
|
|
|
//设置通知栏点击事件
|
|
|
val activityIntent = Intent(this, MainActivity::class.java)
|
|
|
val flags = if (Build.VERSION.SDK_INT >= 30) PendingIntent.FLAG_IMMUTABLE else PendingIntent.FLAG_UPDATE_CURRENT
|
|
|
val pendingIntent = PendingIntent.getActivity(this, 0, activityIntent, flags)
|
|
|
cactus {
|
|
|
setServiceId(FRONT_NOTIFY_ID) //服务Id
|
|
|
setChannelId(FRONT_CHANNEL_ID) //渠道Id
|
|
|
setChannelName(FRONT_CHANNEL_NAME) //渠道名
|
|
|
setTitle(getString(R.string.app_name))
|
|
|
setContent(SettingUtils.notifyContent.toString())
|
|
|
setSmallIcon(R.drawable.ic_forwarder)
|
|
|
setLargeIcon(R.mipmap.ic_launcher)
|
|
|
setPendingIntent(pendingIntent)
|
|
|
//无声音乐
|
|
|
if (SettingUtils.enablePlaySilenceMusic) {
|
|
|
setMusicEnabled(true)
|
|
|
setBackgroundMusicEnabled(true)
|
|
|
setMusicId(R.raw.silence)
|
|
|
//设置音乐间隔时间,时间间隔越长,越省电
|
|
|
setMusicInterval(10)
|
|
|
isDebug(true)
|
|
|
}
|
|
|
//是否可以使用一像素,默认可以使用,只有在android p以下可以使用
|
|
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P && SettingUtils.enableOnePixelActivity) {
|
|
|
setOnePixEnabled(true)
|
|
|
}
|
|
|
//奔溃是否可以重启用户界面
|
|
|
setCrashRestartUIEnabled(true)
|
|
|
addCallback({
|
|
|
Log.d(TAG, "Cactus保活:onStop回调")
|
|
|
}) {
|
|
|
Log.d(TAG, "Cactus保活:doWork回调")
|
|
|
}
|
|
|
//切后台切换回调
|
|
|
addBackgroundCallback {
|
|
|
Log.d(TAG, if (it) "SmsForwarder 切换到后台运行" else "SmsForwarder 切换到前台运行")
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
} catch (e: Exception) {
|
|
|
e.printStackTrace()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 初始化基础库
|
|
|
*/
|
|
|
private fun initLibs() {
|
|
|
Core.init(this)
|
|
|
// 转发历史工具类初始化
|
|
|
HistoryUtils.init(this)
|
|
|
// X系列基础库初始化
|
|
|
XBasicLibInit.init(this)
|
|
|
// 版本更新初始化
|
|
|
XUpdateInit.init(this)
|
|
|
// 运营统计数据
|
|
|
UMengInit.init(this)
|
|
|
// ANR监控
|
|
|
ANRWatchDogInit.init()
|
|
|
}
|
|
|
|
|
|
private var mDisposable: Disposable? = null
|
|
|
|
|
|
@SuppressLint("CheckResult")
|
|
|
override fun doWork(times: Int) {
|
|
|
Log.d(TAG, "doWork:$times")
|
|
|
mStatus.postValue(true)
|
|
|
val dateFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
|
|
|
dateFormat.timeZone = TimeZone.getTimeZone("GMT+00:00")
|
|
|
var oldTimer = CactusSave.timer
|
|
|
if (times == 1) {
|
|
|
CactusSave.lastTimer = oldTimer
|
|
|
CactusSave.endDate = CactusSave.date
|
|
|
oldTimer = 0L
|
|
|
}
|
|
|
mLastTimer.postValue(dateFormat.format(Date(CactusSave.lastTimer * 1000)))
|
|
|
mEndDate.postValue(CactusSave.endDate)
|
|
|
mDisposable = Observable.interval(1, TimeUnit.SECONDS)
|
|
|
.map {
|
|
|
oldTimer + it
|
|
|
}
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
.subscribe { aLong ->
|
|
|
CactusSave.timer = aLong
|
|
|
CactusSave.date = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).run {
|
|
|
format(Date())
|
|
|
}
|
|
|
mTimer.value = dateFormat.format(Date(aLong * 1000))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
override fun onStop() {
|
|
|
Log.d(TAG, "onStop")
|
|
|
mStatus.postValue(false)
|
|
|
mDisposable?.apply {
|
|
|
if (!isDisposed) {
|
|
|
dispose()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
} |