Commit e8f694cc authored by 许译文's avatar 许译文

add ad,notification

parent fa4e93cf
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" project-jdk-name="Android API 33, extension level 3 Platform" project-jdk-type="Android SDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
......@@ -4,8 +4,10 @@
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="gradleJvm" value="jbr-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
......
......@@ -64,6 +64,7 @@ dependencies {
implementation libs.androidx.lifecycle.livedata.ktx
implementation libs.androidx.lifecycle.viewmodel.ktx
implementation libs.androidx.fragment.ktx
implementation libs.installreferrer
testImplementation libs.junit
androidTestImplementation libs.androidx.junit
androidTestImplementation libs.androidx.espresso.core
......@@ -88,15 +89,18 @@ dependencies {
implementation 'com.google.android.ump:user-messaging-platform:2.1.0'
implementation "androidx.lifecycle:lifecycle-process:2.2.0"
implementation "androidx.lifecycle:lifecycle-process:2.6.2"
implementation 'com.google.code.gson:gson:2.8.8'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
// compile(name:'trustlook_cleanjunk_sdk_release_3.0.4.20240322',ext:'aar')
implementation files('libs/trustlook_cleanjunk_sdk_release_3.0.4.20240322.aar')
implementation files('libs/cloudscan_sdk_5.0.5.20240306.aar')
implementation("com.github.bumptech.glide:glide:4.15.1")
implementation("com.blankj:utilcodex:1.31.1")
implementation("androidx.datastore:datastore-preferences:1.0.0")
}
package com.xm.test.myfilemaster
import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.Lifecycle
......@@ -12,26 +15,35 @@ import com.applovin.mediation.MaxAd
import com.applovin.mediation.MaxAdListener
import com.applovin.mediation.MaxError
import com.applovin.mediation.ads.MaxAppOpenAd
import com.applovin.sdk.AppLovinMediationProvider
import com.applovin.sdk.AppLovinSdk
import com.cloud.cleanjunksdk.task.CheckSdkCallback
import com.cloud.cleanjunksdk.task.Clean
import com.cloud.cleanjunksdk.task.CleanSDK
import com.cloud.cleanjunksdk.tools.Region
import com.trustlook.sdk.cloudscan.CloudScanClient
import com.xm.test.myfilemaster.ad.GravitySensorManager
import com.xm.test.myfilemaster.notification.ActionBroadcast
import com.xm.test.myfilemaster.util.UrlManager
class MyApplication : Application() {
private lateinit var appOpenManager: ExampleAppOpenManager
private lateinit var gravitySensorManager: GravitySensorManager
companion object {
var mCleanSdk: Clean? = null
@SuppressLint("StaticFieldLeak")
var mCloudScan: CloudScanClient? = null
var mSp: SharedPreferences? = null
@SuppressLint("StaticFieldLeak")
@JvmStatic
lateinit var fContext: Context
}
override fun onCreate() {
super.onCreate()
fContext=this
// AppLovinSdk.getInstance( this ).initializeSdk({ configuration: AppLovinSdkConfiguration ->
// {
// appOpenManager = ExampleAppOpenManager(applicationContext)
......@@ -55,50 +67,31 @@ class MyApplication : Application() {
.setSocketTimeout(30000)
.build()
AppLovinSdk.getInstance(this).initializeSdk {
appOpenManager = ExampleAppOpenManager(applicationContext)
}
}
class ExampleAppOpenManager(applicationContext: Context?) : LifecycleObserver, MaxAdListener {
private lateinit var appOpenAd: MaxAppOpenAd
private lateinit var context: Context
init {
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
context = applicationContext!!
appOpenAd = MaxAppOpenAd(UrlManager.AD_UNIT_ID, applicationContext)
appOpenAd.setListener(this)
appOpenAd.loadAd()
}
private fun showAdIfReady() {
if (appOpenAd == null || !AppLovinSdk.getInstance(context).isInitialized) return
if (appOpenAd.isReady) {
appOpenAd.showAd(UrlManager.TEST_PLACEMENT_HERE)
} else {
appOpenAd.loadAd()
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
showAdIfReady()
}
override fun onAdLoaded(ad: MaxAd) {}
override fun onAdLoadFailed(adUnitId: String, error: MaxError) {}
override fun onAdDisplayed(ad: MaxAd) {}
override fun onAdClicked(ad: MaxAd) {}
override fun onAdHidden(ad: MaxAd) {
appOpenAd.loadAd()
}
AppLovinSdk.getInstance(this).mediationProvider = AppLovinMediationProvider.MAX
initBroadcast()
}
override fun onAdDisplayFailed(ad: MaxAd, error: MaxError) {
appOpenAd.loadAd()
}
private fun initBroadcast(){
gravitySensorManager = GravitySensorManager(this)
gravitySensorManager.registerListener()
val filter = IntentFilter()
filter.addAction(Intent.ACTION_SCREEN_OFF)
filter.addAction(Intent.ACTION_SCREEN_ON)
filter.addAction(Intent.ACTION_PACKAGE_ADDED)
filter.addAction(Intent.ACTION_PACKAGE_REMOVED)
filter.addAction(Intent.ACTION_USER_PRESENT)
filter.addAction(Intent.ACTION_POWER_CONNECTED)
filter.addAction(Intent.ACTION_POWER_DISCONNECTED)
filter.addAction(Intent.ACTION_BATTERY_CHANGED)
filter.addAction(Intent.ACTION_MEDIA_MOUNTED)
filter.addAction(Intent.ACTION_MEDIA_REMOVED)
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED)
filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL)
filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW)
filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK)
filter.addDataScheme("package")
registerReceiver(ActionBroadcast(), filter)
}
}
\ No newline at end of file
package com.xm.test.myfilemaster
import android.os.Build
import android.util.Log
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.DeviceUtils
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.ScreenUtils
import com.xm.test.myfilemaster.ad.AESHelper
import com.xm.test.myfilemaster.ad.ConfigHelper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import okhttp3.Call
import okhttp3.Callback
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import org.json.JSONObject
import java.io.IOException
fun netSendEvent(key: String, value: String? = null, ext: JSONObject? = null) {
val pkg = ConfigHelper.packageName
val d1 = JSONObject()
.put("action", key)
.put("value", value)
.put("ext", ext)
val d2 = JSONObject()
.put("${pkg}_1", "${ScreenUtils.getScreenHeight()}")
.put("${pkg}_2", "${ScreenUtils.getScreenWidth()}")
.put("${pkg}_3", DeviceUtils.getModel())
.put("${pkg}_4", Build.MANUFACTURER)
.put("${pkg}_5", Build.VERSION.SDK_INT)
.put("${pkg}_6", "${NetworkUtils.getNetworkType()}")
.put("${pkg}_8", AppUtils.getAppVersionName())
.put("${pkg}_9", DeviceUtils.getAndroidID())
.put("${pkg}_10", ConfigHelper.gid)
.put("${pkg}_11", System.getProperty("http.agent"))
.put("${pkg}_13", "android")
.put("${pkg}_14", "${AppUtils.getAppVersionCode()}")
.put("${pkg}_15", "google")
// .put("${pkg}_24",BuildConfig.BUILD_TYPE)
val data = JSONObject()
.put("data", d1)
.put("bp", d2)
.toString()
val body =
AESHelper.encrypt(data).toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull())
val client = OkHttpClient.Builder().apply {
// if (BuildConfig.DEBUG) {
// addInterceptor(HttpLoggingInterceptor().apply {
// level = HttpLoggingInterceptor.Level.BODY
// })
// }
}.build()
val request = Request.Builder()
.url(eventUrl)
.post(body)
.build()
CoroutineScope(Dispatchers.IO).launch {
delay(1000)
client.newCall(request = request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.d("glc", "onFailure:${e.message}")
}
override fun onResponse(call: Call, response: Response) {
Log.d("glc","net success")
}
})
}
}
val eventUrl by lazy {
val pkg = ConfigHelper.packageName
val url = StringBuilder("${ConfigHelper.eventUrl}/${pkg.filter { it.isLowerCase() }.substring(4, 9)}sp")
url.append("?pkg=$pkg")
url.toString()
}
\ No newline at end of file
......@@ -63,6 +63,7 @@ class FileManagerActivity : BaseActivity() {
mFileBeanList.addAll(FileUtil.getFileType(FileUtil.WORD_MIME_TYPE, this))
mFileBeanList.addAll(FileUtil.getFileType(FileUtil.EXCEL_MIME_TYPE, this))
mFileBeanList.addAll(FileUtil.getFileType(FileUtil.PPT_MIME_TYPE, this))
mFileBeanList.addAll(FileUtil.getFileType(FileUtil.PDF_MIME_TYPE, this))
} else {
mFileBeanList = when (mFileType) {
"apk" -> {
......
package com.xm.test.myfilemaster.ad
import android.util.Base64
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
object AESHelper {
private const val aesKey = "ccc7okanmfth88nb"
private val cipher by lazy {
Cipher.getInstance("AES/GCM/NoPadding")
}
fun encrypt(content: String): String {
try {
val iv = ByteArray(12).apply {
SecureRandom().nextBytes(this)
}
val contentBytes = content.toByteArray(Charsets.UTF_8)
val params = GCMParameterSpec(128, iv)
cipher.init(
Cipher.ENCRYPT_MODE,
secretKey, params
)
val encryptData = cipher.doFinal(contentBytes)
assert(encryptData.size == contentBytes.size + 16)
val message = ByteArray(12 + contentBytes.size + 16)
System.arraycopy(iv, 0, message, 0, 12)
System.arraycopy(encryptData, 0, message, 12, encryptData.size)
return String(Base64.encode(message, Base64.NO_WRAP), Charsets.UTF_8)
} catch (_: Exception) {
}
return content
}
@Synchronized
fun decrypt(content: String): String {
try {
val con = content.replace(" ".toRegex(), "+")
val contentByte = Base64.decode(con, Base64.NO_WRAP)
require(contentByte.size >= 12 + 16)
val params = GCMParameterSpec(128, contentByte, 0, 12)
cipher.init(
Cipher.DECRYPT_MODE,
secretKey, params
)
val decryptData = cipher.doFinal(contentByte, 12, contentByte.size - 12)
return String(decryptData, Charsets.UTF_8)
} catch (_: Exception) {
}
return content
}
private val secretKey by lazy {
SecretKeySpec(aesKey.toByteArray(), "AES")
}
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad
import android.text.TextUtils
import com.xm.test.myfilemaster.MyApplicaiton
object AdUtils {
fun isShowAd(slot: String): Boolean {
val adEntity = ComUtils.getAdPositionData(slot)
if (!PushManager.newUserPush(adEntity.new_user_avoid_time)) {
return false
}
if (!UserChancelEx.getUserChancelSwitch(adEntity.is_show)) {
return false
}
if (TextUtils.equals(adEntity.type, "interstitial")) {
val isOrganic = UserChancelEx.isOrganicUser()
if (isOrganic) {
if (!canNextTime("interstitial", ComUtils.getComConfig().nature_insert_interval)) {
return false
}
} else {
if (!canNextTime("interstitial", ComUtils.getComConfig().buy_insert_interval)) {
return false
}
}
}
if (!canNextTime(slot, adEntity.show_interval)) {
return false
}
val adNum = MyApplicaiton.fContext.queryDataStoreBlock(getIntString(slot + "_ad_show_num") , 0)
if (adNum >= adEntity.show_limit) {
return false
}
return true
}
/**
* 间隔
* @param interval 单位分钟
*/
private fun canNextTime(key: String, interval: Int): Boolean {
val lastPushTime = MyApplicaiton.fContext.queryDataStoreBlock(getLongKey(key), 0)
return (System.currentTimeMillis() - lastPushTime) / 1000 > interval
}
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad
object ConfigHelper {
var gid = ""
// 以上默认即可,以下需要手动配置
// 域名
const val eventUrl = "https://rp.expert3326.xyz"
const val apiUrl = "https://api.expert3326.xyz"
// 正式包名
const val packageName = "com.xm.test.myfilemaster"
// // 继承自 BaseSplashActivity 的类
// val splashActivity = SplashActivity::class.java
//
// val noLoadingActivities = listOf(
// "full", // 过滤全屏广告
// "adActivity",
// splashActivity.simpleName
// // 返回前台时不跳转启动页的 activity
// )
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad
fun loadSatisfyLimit():Boolean{
return true
}
fun showSatisfyLimit():Boolean{
return true
}
fun recordShowCount(){
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
val INSTALL_INFO = stringPreferencesKey("install_info_source")
//第一次启动时间
val FIRST_LAUNCH_TIME_KEY = longPreferencesKey("install_info")
//上次与推送通知时间
val ALL_LAST_PUSH_TIME = longPreferencesKey("all_last_push_time")
fun getStringKey(string: String): Preferences.Key<String> {
return stringPreferencesKey(string)
}
fun getLongKey(string: String): Preferences.Key<Long> {
return longPreferencesKey(string)
}
fun createByActionId(actionId: Int): Preferences.Key<Long> {
return longPreferencesKey("actionId_$actionId")
}
fun getLongString(string: String): Preferences.Key<Long> {
return longPreferencesKey(string)
}
fun getIntString(string: String): Preferences.Key<Int> {
return intPreferencesKey(string)
}
suspend fun <T> Context.saveDataStore(key: Preferences.Key<T>, any: T) {
dataStore.edit { it[key] = any }
}
fun <T> Context.saveDataStoreBlock(key: Preferences.Key<T>, any: T) {
runBlocking {
dataStore.edit { it[key] = any }
}
}
suspend fun <T> Context.queryDataStore(key: Preferences.Key<T>, action: suspend (any: T?) -> Unit) {
val flow = dataStore.data.map { it[key] }
action.invoke(flow.first())
}
/**
* 同步方式查询
*/
fun <T> Context.queryDataStoreBlock(key: Preferences.Key<T>, defValue: T): T {
var value = defValue
runBlocking {
val flow = dataStore.data.map { preferences ->
preferences[key] ?: defValue
}
value = flow.first()
}
return value
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad
import android.os.Build
import android.util.Log
import com.blankj.utilcode.util.AppUtils
import com.blankj.utilcode.util.DeviceUtils
import com.blankj.utilcode.util.NetworkUtils
import com.blankj.utilcode.util.SPUtils
import com.blankj.utilcode.util.ScreenUtils
import com.xm.test.myfilemaster.MyApplication
import com.xm.test.myfilemaster.ad.KokoReportHelper.isCharging
import com.xm.test.myfilemaster.BuildConfig
import okhttp3.Call
import okhttp3.Callback
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import org.json.JSONObject
import java.io.IOException
object EventHelper {
private val url by lazy {
val pkg = ConfigHelper.packageName
val url = StringBuilder("${ConfigHelper.eventUrl}/${pkg.filter { it.isLowerCase() }.substring(4, 9)}sp")
url.append("?pkg=$pkg")
url.toString()
}
fun event(key: String, value: String? = null, ext: JSONObject? = null, isSingleEvent: Boolean = false) {
if (isSingleEvent) {
val stringSet = SPUtils.getInstance().getStringSet("singleEvent")
if (stringSet.contains(key)) {
return
}
}
val pkg = ConfigHelper.packageName
val d1 = JSONObject()
.put("action", key)
.put("value", value)
.put("ext", ext)
val d2 = JSONObject()
.put("${pkg}_1", "${ScreenUtils.getScreenHeight()}")
.put("${pkg}_2", "${ScreenUtils.getScreenWidth()}")
.put("${pkg}_3", DeviceUtils.getModel())
.put("${pkg}_4", Build.MANUFACTURER)
.put("${pkg}_5", Build.VERSION.SDK_INT)
.put("${pkg}_6", "${NetworkUtils.getNetworkType()}")
.put("${pkg}_8", AppUtils.getAppVersionName())
.put("${pkg}_9", DeviceUtils.getAndroidID())
.put("${pkg}_10", ConfigHelper.gid)
.put("${pkg}_11", System.getProperty("http.agent"))
.put("${pkg}_13", "android")
.put("${pkg}_14", "${AppUtils.getAppVersionCode()}")
.put("${pkg}_15", "google")
.put("${pkg}_24", BuildConfig.BUILD_TYPE)
// .put("${pkg}_25", PhoneTools.isRoot())
.put("${pkg}_25", KokoReportHelper.isShellRooted())
// .put("${pkg}_26", PhoneTools.isHooked())
.put("${pkg}_26", KokoReportHelper.isHooked())
// .put("${pkg}_27", PhoneTools.isEmulator())
.put("${pkg}_27", KokoReportHelper.isVirtualMachine())
// .put("${pkg}_29", PhoneTools.checkWifiProxy())
.put("${pkg}_29", KokoReportHelper.isWifiProxy(MyApplication.fContext))
// .put("${pkg}_30", PhoneTools.hasVPN())
.put("${pkg}_30", KokoReportHelper.isVpnConnected(MyApplication.fContext))
// .put("${pkg}_31", if(DeviceUtils.isDevelopmentSettingsEnabled()){1} else 0)
.put("${pkg}_31", if (KokoReportHelper.isEnableDeveloperDebug(MyApplication.fContext)) 1 else 0)
// .put("${pkg}_32", PhoneTools.isBatteryCharg())
.put("${pkg}_32", isCharging(MyApplication.fContext))
// .put("${pkg}_33", ConfigHelper.sensorParm)
.put("${pkg}_33", GravitySensorManager.sensorParm)
val data = JSONObject()
.put("data", d1)
.put("bp", d2)
.toString()
val body = AESHelper.encrypt(data).toRequestBody("application/json;charset=utf-8".toMediaTypeOrNull())
val client = OkHttpClient.Builder().apply {
if (BuildConfig.DEBUG) {
addInterceptor(HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
})
}
}.build()
val request = Request.Builder()
.url(url)
.post(body)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
}
override fun onResponse(call: Call, response: Response) {
Log.d("TAG", "event: $key")
if (isSingleEvent) {
val stringSet = SPUtils.getInstance().getStringSet("singleEvent", mutableSetOf())
stringSet.add(key)
SPUtils.getInstance().put("singleEvent", stringSet)
}
}
})
}
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.util.Log
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.math.sqrt
import kotlin.time.Duration.Companion.seconds
import kotlin.time.DurationUnit
/**
* 重量传感器
*/
class GravitySensorManager(val context: Context) {
private var sensorManager: SensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
private var mySensorEventListener: MySensorEventListener? = null
private var xWave = 0f
private var yWave = 0f
private var zWave = 0f
private val initValue = AtomicBoolean(false)
companion object {
private var x: Float = 0f
private var y: Float = 0f
private var z: Float = 0f
var sensorParm: String = "$x:$y:$z"
}
init {
val time = Timer()
val timerTask = object : TimerTask() {
override fun run() {
}
}
time.schedule(timerTask, 5.seconds.toLong(DurationUnit.MILLISECONDS), 20.seconds.toLong(DurationUnit.MILLISECONDS))
}
inner class MySensorEventListener : SensorEventListener {
/**
* 传感器实时测量出来的变化值
*/
override fun onSensorChanged(event: SensorEvent) {
if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
// if (!initValue.get()) {
// x = event.values[SensorManager.DATA_X]
// y = event.values[SensorManager.DATA_Y]
// z = event.values[SensorManager.DATA_Z]
// initValue.set(true)
// } else {
//
// val changeX = x - event.values[SensorManager.DATA_X]
// val changeY = y - event.values[SensorManager.DATA_Y]
// val changeZ = z - event.values[SensorManager.DATA_Z]
//
// xWave = changeX.coerceAtLeast(xWave)
// yWave = changeY.coerceAtLeast(yWave)
// zWave = changeZ.coerceAtLeast(zWave)
//
// }
x = event.values[SensorManager.DATA_X]
y = event.values[SensorManager.DATA_Y]
z = event.values[SensorManager.DATA_Z]
// Log.e("GravitySensorManager", "$x:$y:$z")
}
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
}
}
/**
* onResume() 注册
*/
fun registerListener() {
if (mySensorEventListener == null) {
mySensorEventListener = MySensorEventListener()
}
val sensorAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sensorManager.registerListener(mySensorEventListener, sensorAccelerometer, SensorManager.SENSOR_DELAY_UI)
}
/**
* onPause()注销
*/
fun unregisterListener() {
sensorManager.unregisterListener(mySensorEventListener)
}
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.hardware.Sensor
import android.hardware.SensorManager
import android.net.ConnectivityManager
import android.net.Proxy
import android.os.BatteryManager
import android.os.Build
import android.telephony.TelephonyManager
import android.text.TextUtils
import java.io.DataOutputStream
import java.io.File
import java.lang.reflect.Method
object KokoReportHelper {
//https://blog.51cto.com/u_16213304/7913939
//是否root
/**
* 通过Path判断是否root
*/
fun isPathRooted(): Boolean {
val paths = arrayOf("/system/bin/", "/system/xbin/", "/su/bin/", "/sbin/", "/su/")
for (path in paths) {
if (File(path + "su").exists()) {
return true
}
}
return false
}
/**
* 通过执行shell命令来判断设备是否已经root
*/
fun isShellRooted(): Boolean {
try {
val process = Runtime.getRuntime().exec("su")
val os = DataOutputStream(process.outputStream)
os.writeBytes("echo root\n")
os.writeBytes("exit\n")
os.flush()
process.waitFor()
if (process.exitValue() == 0) {
return true
}
} catch (e: Exception) {
// e.printStackTrace()
}
return false
}
/**
* 是否是虚拟机
* https://blog.51cto.com/u_16175492/7712954
* 检查当前设备的信息,包括设备型号、产品名称、品牌、硬件等
*/
fun isVirtualMachine(): Boolean {
val manufacturer = Build.MANUFACTURER
val model = Build.MODEL
val product = Build.PRODUCT
return if (manufacturer.contains("Genymotion") || model.contains("Emulator") || product.contains("sdk")) {
true
} else false
}
/**
* 是否插sim卡
*/
fun isSimCardInserted(context: Context): Boolean {
val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
return telephonyManager.getSimState() == TelephonyManager.SIM_STATE_READY
}
/**
* 是否有代理
* 判断设备 是否使用代理上网
* https://blog.csdn.net/verynewbeee/article/details/135698990
*/
@SuppressLint("ObsoleteSdkInt")
fun isWifiProxy(context: Context?): Boolean {
val IS_ICS_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH
val proxyAddress: String
val proxyPort: Int
if (IS_ICS_OR_LATER) {
proxyAddress = System.getProperty("http.proxyHost") ?: ""
val portStr = System.getProperty("http.proxyPort")
proxyPort = (portStr ?: "-1").toInt()
} else {
proxyAddress = Proxy.getHost(context)
proxyPort = Proxy.getPort(context)
}
return !TextUtils.isEmpty(proxyAddress) && proxyPort != -1
}
/**
* 是否开启vpn
* https://cloud.tencent.com/developer/ask/2122015
*/
@SuppressLint("ObsoleteSdkInt")
fun isVpnConnected(context: Context): Boolean {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val networkInfo = cm.activeNetworkInfo
if (networkInfo != null) {
return networkInfo.type == ConnectivityManager.TYPE_VPN
}
} else {
// 低版本 Android 系统可能需要使用其他方法检测 VPN 连接
}
return false
}
/**
* 开发者模式是否开启
*
* 检测是否开启动了usb 调试模式
*/
@SuppressLint("PrivateApi")
fun isEnableDeveloperDebug(context: Context): Boolean {
var adb = ""
try {
val clazz = Class.forName("android.os.SystemProperties")
val get: Method = clazz.getMethod("get", String::class.java, String::class.java)
adb = get.invoke(clazz, "persist.sys.usb.config", "")?.toString() ?: ""
} catch (e: java.lang.Exception) {
}
return adb == "adb"
}
/**
* 是否在充电
* https://blog.csdn.net/su749520/article/details/83898354
*/
fun isCharging(context: Context): Boolean {
val batteryBroadcast = context.registerReceiver(
null,
IntentFilter(Intent.ACTION_BATTERY_CHANGED)
)
// 0 means we are discharging, anything else means charging
val isCharging = batteryBroadcast!!.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0
return isCharging
}
/**
* 获取手机中所有app列表
* 获取所有带有桌面属性的APK
*/
@SuppressLint("QueryPermissionsNeeded")
fun getAllLauncherAppPackage(context: Context): List<String> {
val intent = Intent().apply {
action = Intent.ACTION_MAIN
addCategory(Intent.CATEGORY_LAUNCHER)
}
val resolveInfos = context.packageManager.queryIntentActivities(
intent, PackageManager.MATCH_ALL
)
return resolveInfos.map { it.activityInfo.packageName }
}
/**
* 是否支持重力传感器
*/
fun isSupportAccelerometer(context: Context): Boolean {
val sensorManager: SensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensorAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
return sensorAccelerometer != null
}
fun isHooked(): Int {
try {
// 检测Xposed
Class.forName("de.robv.android.xposed.XposedBridge")
return 1
} catch (e: ClassNotFoundException) {
// 忽略异常
}
try {
// 检测Frida
Class.forName("com.android.server.frida.Server")
return 1
} catch (e: ClassNotFoundException) {
// 忽略异常
}
// 检测Substrate
if (File("/data/local/tmp/inject").exists()) {
return 1
}
return 0
}
}
package com.xm.test.myfilemaster.ad
import android.view.View
object MyReportViewListener {
class ReportViewListener(val className: String, val click: () -> Unit) : View.OnClickListener {
override fun onClick(v: View) {
val idString = v.context.resources.getResourceEntryName(v.id)
EventHelper.event("viewClick_${className}_$idString")
click.invoke()
}
}
fun View.setMyReportViewListener(className: String, click: () -> Unit) {
this.setOnClickListener(ReportViewListener(className, click))
}
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad
import com.xm.test.myfilemaster.MyApplication
import com.xm.test.myfilemaster.ad.bean.PushCfg
object PushManager {
/**
* 新用户是否显示
*/
fun newUserPush(newUserAvoidTime: Int): Boolean {
val firstLaunchTime = MyApplication.fContext.queryDataStoreBlock(FIRST_LAUNCH_TIME_KEY, 0L)
val flag = (System.currentTimeMillis() - firstLaunchTime) / 1000 > newUserAvoidTime
return flag
}
/**
* 所有推送是否推送大于间隔时间
* @param interval 单位分钟
*/
fun canPushNextTime(interval: Int): Boolean {
val lastPushTime = MyApplication.fContext.queryDataStoreBlock(ALL_LAST_PUSH_TIME, 0)
return (System.currentTimeMillis() - lastPushTime) / 1000 > interval
}
/**
* 根据id判断通知是否可推送
* @param actionId 功能或者场景的id
*/
fun isPush(actionId: Int): Boolean {
// 新用户是否显示
val pushManagement = ComUtils.getPushConfig()
if (!newUserPush(pushManagement.newuser_avoid_time)) {
return false
}
// 渠道用户是否推送
if (!UserChancelEx.getUserChancelSwitch(pushManagement.push_show)) {
return false
}
//是否上次推送间隔大于配置间隔
val isOganic = UserChancelEx.isOrganicUser()
val interval = if (isOganic) pushManagement.o_push_interval else pushManagement.all_push_interval
if (!canPushNextTime(interval)) {
return false
}
//当前类型通知推送间隔是否大于配置间隔
if (!actionTypeCanPsh(actionId)) {
return false
}
return true
}
/**
* 当前类型通知推送间隔是否大于配置间隔
*/
private fun actionTypeCanPsh(actionId: Int): Boolean {
val pushCfg: PushCfg? = ComUtils.getPushTypeData(actionId.toString())
val pushInterval = pushCfg?.push_interval ?: 0
val lastTypePushTime = MyApplication.fContext.queryDataStoreBlock(createByActionId(actionId), 0L)
return (System.currentTimeMillis() - lastTypePushTime) / 1000 > pushInterval
}
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad
import android.content.Context
import android.telephony.TelephonyManager
import com.xm.test.myfilemaster.MyApplication
/**
* 判断用户渠道的方法
*/
object UserChancelEx {
fun getUserChancelSwitch(int: Int): Boolean {
val isOrganic = isOrganicUser()
val isHasSim = isSimCardAvailable()
return l(int, isHasSim, isOrganic)
}
fun l(i2: Int, isHasSim: Boolean, isOrganic: Boolean): Boolean {
return if (!isOrganic && !k(i2, 3)) {
false
} else if (isOrganic && !k(i2, 2)) {
false
} else if (!isHasSim && !k(i2, 1)) {
false
} else if (isHasSim && !k(i2, 0)) {
false
} else k(i2, 4)
}
fun k(i2: Int, i3: Int): Boolean {
return i2 shr i3 and 1 == 1
}
/**
* 是否是自然用户
*/
fun isOrganicUser(): Boolean {
val source: String = MyApplication.fContext.queryDataStoreBlock(INSTALL_INFO, "")//是存储的installReferrer
return !(source.contains("gclid") || source.contains("facebook"))
}
fun isSimCardAvailable(): Boolean {
val telephonyManager = MyApplication.fContext.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
return telephonyManager.simState != TelephonyManager.SIM_STATE_ABSENT
}
}
\ No newline at end of file
package com.xm.test.myfilemaster.ad.bean
data class AdUnitCfg(
val banner: AdUnitEntity,
val native: AdUnitEntity,
val rewardAd: AdUnitEntity,
val openAd: AdUnitEntity?,
val interAd: AdUnitEntity
) {
data class AdUnitEntity(
val unit_id: String = "wwwsss"
)
}
package com.xm.test.myfilemaster.ad.bean
/**
* 广告位配置
*/
data class AdsCfg(
val banner: AdEntity,
val interstitial: AdEntity,
val rewardAd: AdEntity,
val splash: AdEntity,
val ad_open: AdEntity
) {
/**
* 开屏广告配置配
*/
data class AdEntity(
var is_show: Int = 31,//是否展示
var show_interval: Int = 0,//展示间隔
var new_user_avoid_time: Int = 0,//新用户避免开启
var unit_id: String = "12312443123",
var type: String = "3",
var open_ad_is_show: Int = 31,
var loading_page_time: Int = 5,
var show_limit: Int = 40
)
}
package com.xm.test.myfilemaster.ad.bean
/**
* 广告配置数据
*/
data class ConfigureData(
val ads_cfg: AdsCfg,
val ad_unit_cfg: AdUnitCfg,
val global_config: GlobalConfig,
val push_cfg : List<PushCfg>,
val push_management: PushManagement
)
\ No newline at end of file
package com.xm.test.myfilemaster.ad.bean
/**
* 全局配置
*/
data class GlobalConfig(
var cache_time: Int = 0,
var rate_window_interval: Int = 0,
var buy_insert_interval: Int = 0,
var nature_insert_interval: Int = 0,
var not_dialog_interval: Int = 0
)
package com.xm.test.myfilemaster.ad.bean
/**
* 功能和场景的推送配置
*
* 扩展字段,主要是触发弹窗的阈值设定。比如内存低于10%,启动弹窗,配置值为10。 内存使用占比阈值,当前温度阈值,当前电量阈值
* @param feature_ex1
*
*/
class PushCfg(
val actionId: Int = 0,
val push_stay_time: Int = 10,
val last_use_interval: Int = 0,
val push_interval: Int = 0,
val feature_ex1: Int = 0,
) {
companion object {
//功能触发push actionId 主动发送
const val ID_JUNK_CLEAN_PUSH = 11001 //清理垃圾
const val ID_BOOST_PUSH = 11002 //性能优化
const val ID_VIRUS_PUSH = 11003//扫描病毒
const val ID_BATTERY_PUSH = 11004// 电量优化
const val ID_COOL_PUSH = 11005//手机降温
const val ID_BIGFILE_PUSH = 11006// 大文件清理
const val ID_DUPLICATE_FILE_PUSH = 11007//文件备份,重复文件,相似文件
const val ID_VIDEO_CLEAN_PUSH = 11008//清理视频缓存
const val ID_PHOTO_CLEAN_PUSH = 11009//清理相册
//场景触发push actionId 被动发送
const val ID_WIFI_PUSH = 22001//连接wifi时
const val ID_INSTALL_PACKAGE_PUSH = 22002//安装应用
const val ID_UNINSTALL_PACKAGE_PUSH = 22003//卸载应用
const val ID_CHARGE = 22004//充电
const val ID_LOW_BATTERY_PUSH = 22005//电量低于阈值时
const val ID_LOW_JUNK_PUSH = 22007//垃圾文件高于阈值时
}
}
package com.xm.test.myfilemaster.ad.bean
/**
* 推送管理
*/
data class PushManagement(
var push_show: Int = 0,
var newuser_avoid_time: Int = 0,
var all_push_interval: Int = 0,
var o_push_interval: Int = 0,
var push_circle_order: List<Int> = listOf(),
var scene_push: List<Int> = listOf(),
)
package com.xm.test.myfilemaster.ad.bean
import com.xm.test.myfilemaster.ad.bean.ConfigureData
data class ZxhyConfigure(
val data: ConfigureData
)
......@@ -205,11 +205,22 @@ abstract class BaseActivity : BaseAbsView(), BaseActivityListener{
MyApplication.mCleanSdk?.delete(File(fileBean.filePath))
}
mFileAdapter.setData(mItemDataList)
if (mItemDataList.size == 0){
mFilesItemListView.visibility = View.GONE
mNotFileFoundLayout.visibility = View.VISIBLE
mEditBtn.visibility = View.GONE
}else{
mFilesItemListView.visibility = View.VISIBLE
mNotFileFoundLayout.visibility = View.GONE
mEditBtn.visibility = View.VISIBLE
mFileAdapter.setData(mItemDataList)
}
}).show()
customDialog.isShowEditText(false)
customDialog.setsTitle("Delete")
customDialog.setsHint("Are you sure you want to delete ${mFileCheckedItemList.size} item?")
customDialog.setsRightDelete("Delete")
cancel()
}
R.id.btn_share ->{
if (switchNumber > 1){
......@@ -395,8 +406,17 @@ abstract class BaseActivity : BaseAbsView(), BaseActivityListener{
Thread(Runnable {
runOnUiThread {
mItemDataList = mCurrentFileBean!!.childList
val fileListSort = FileUtil.fileListSort(mItemDataList)
mFileAdapter.setData(fileListSort)
mItemDataList = FileUtil.fileListSort(mItemDataList)
if (mItemDataList.size == 0){
mFilesItemListView.visibility = View.GONE
mNotFileFoundLayout.visibility = View.VISIBLE
mEditBtn.visibility = View.GONE
}else{
mFilesItemListView.visibility = View.VISIBLE
mNotFileFoundLayout.visibility = View.GONE
mEditBtn.visibility = View.VISIBLE
mFileAdapter.setData(mItemDataList)
}
}
}).start()
}else if(mCurrentFileBean?.fileType.equals("dir") && mCurrentFileBean?.childList?.size == 0){
......
package com.xm.test.myfilemaster.notification
import android.app.ActivityManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.BatteryManager
import android.util.Log
import com.xm.test.myfilemaster.MyApplication
import com.xm.test.myfilemaster.ad.ComUtils
import com.xm.test.myfilemaster.ad.PushManager
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_BOOST_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_CHARGE
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_INSTALL_PACKAGE_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_LOW_BATTERY_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_LOW_JUNK_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_UNINSTALL_PACKAGE_PUSH
import com.xm.test.myfilemaster.notification.NotificationHelper.postNotification
import com.xm.test.myfilemaster.common.notification.NotificationEx
import java.io.File
class ActionBroadcast : BroadcastReceiver() {
private var mIsScreenOn = false
private var isLock = false
override fun onReceive(context: Context?, intent: Intent?) {
val action = intent?.action ?: 0
if (action == Intent.ACTION_SCREEN_ON) {
Log.d("glc", "屏幕解锁广播...")
Log.d("glc", "屏幕亮广播")
mIsScreenOn = true
if (!isLock && mIsScreenOn) {
val id = NotificationEx.getPresentPushId()
val flag = PushManager.isPush(id)
if (flag) {
MyApplication.fContext.postNotification(id)
}
}
} else if (action == Intent.ACTION_SCREEN_OFF) {
Log.d("glc", "屏幕加锁广播...")
Log.d("glc", "屏幕熄灭广播")
mIsScreenOn = false
isLock = true
} else if (action == Intent.ACTION_USER_PRESENT) {
isLock = false
// Log.d("glc", "解锁")
if (mIsScreenOn && !isLock) {
// 展示主动推送
val id = NotificationEx.getPresentPushId()
val flag = PushManager.isPush(id)
if (flag) {
MyApplication.fContext.postNotification(id)
}
}
} else if (action == Intent.ACTION_PACKAGE_REMOVED) {
// Log.d("glc", "app卸载")
Log.d("glc", "app卸载")
val flag = PushManager.isPush(ID_UNINSTALL_PACKAGE_PUSH)
if (flag) {
MyApplication.fContext.postNotification(ID_UNINSTALL_PACKAGE_PUSH)
}
} else if (action == Intent.ACTION_PACKAGE_ADDED) {
// Log.d("glc", "app安装")
Log.d("glc","app安装")
val flag = PushManager.isPush(ID_INSTALL_PACKAGE_PUSH)
if (flag) {
MyApplication.fContext.postNotification(ID_INSTALL_PACKAGE_PUSH)
}
} else if (action == Intent.ACTION_POWER_DISCONNECTED || action == Intent.ACTION_POWER_CONNECTED) {
// Log.d("glc", "拔电和插电")
Log.d("glc","拔电和插电")
val flag = PushManager.isPush(ID_CHARGE)
if (flag) {
MyApplication.fContext.postNotification(ID_CHARGE)
}
} else if (action == Intent.ACTION_BATTERY_CHANGED) {
//电量发生变化
val level = intent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
val scale: Int? = intent?.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
// Log.d("mxl", "ACTION_BATTERY_CHANGED")
//低电量阀值推送
val config = ComUtils.getPushTypeData(ID_LOW_BATTERY_PUSH.toString())
val flag = PushManager.isPush(ID_LOW_BATTERY_PUSH)
val lowValue = config?.feature_ex1 ?: 0
if (flag && (level < lowValue)) {
MyApplication.fContext.postNotification(ID_LOW_BATTERY_PUSH)
}
} else if (action == Intent.ACTION_MEDIA_MOUNTED || action == Intent.ACTION_MEDIA_REMOVED || action == Intent.ACTION_MEDIA_UNMOUNTED || action == Intent.ACTION_MEDIA_BAD_REMOVAL) {
val path = intent?.data?.path
val file = File(path)
val availableSpace = file.usableSpace
val totalSpace = file.totalSpace
val num = totalSpace - availableSpace
val entity = ComUtils.getPushTypeData("22007")
if (num <= entity?.feature_ex1 ?: 0) {
//展示垃圾文件过大推送
val flag = PushManager.isPush(ID_LOW_JUNK_PUSH)
if (flag) {
MyApplication.fContext.postNotification(ID_LOW_JUNK_PUSH)
}
}
} else if (action == Intent.ACTION_DEVICE_STORAGE_LOW || action == Intent.ACTION_DEVICE_STORAGE_OK) {
val activityManager = context!!.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val memoryInfo = ActivityManager.MemoryInfo()
activityManager.getMemoryInfo(memoryInfo)
val availableMemory = memoryInfo.availMem
val totalMemory = memoryInfo.totalMem
val num = totalMemory - availableMemory
val entity = ComUtils.getPushTypeData("22005")
if (num >= entity?.feature_ex1 ?: 0) {
// 展示性能变差推送
val flag = PushManager.isPush(ID_BOOST_PUSH)
if (flag) {
MyApplication.fContext.postNotification(ID_BOOST_PUSH)
}
}
}
}
}
\ No newline at end of file
package com.xm.test.myfilemaster.common.notification
import com.xm.test.myfilemaster.ad.ComUtils
object NotificationEx {
var mList :MutableList<Int> =ArrayList()
fun getPresentPushId():Int{
if(mList.size<=0){
mList.addAll(ComUtils.getPushConfig().push_circle_order)
}
val i = mList[0]
mList.add(i)
mList.removeAt(0)
return i
}
}
\ No newline at end of file
package com.xm.test.myfilemaster.notification
import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.graphics.Color
import android.os.Build
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import com.xm.test.myfilemaster.MyApplication
import com.xm.test.myfilemaster.R
import com.xm.test.myfilemaster.activity.HomeActivity
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_BATTERY_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_BIGFILE_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_BOOST_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_CHARGE
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_COOL_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_DUPLICATE_FILE_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_INSTALL_PACKAGE_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_JUNK_CLEAN_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_LOW_BATTERY_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_LOW_JUNK_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_PHOTO_CLEAN_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_UNINSTALL_PACKAGE_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_VIDEO_CLEAN_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_VIRUS_PUSH
import com.xm.test.myfilemaster.ad.bean.PushCfg.Companion.ID_WIFI_PUSH
import com.xm.test.myfilemaster.ad.createByActionId
import com.xm.test.myfilemaster.ad.saveDataStoreBlock
import kotlin.random.Random
/**
* 动态申请 <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
*/
object NotificationHelper {
private const val CHANNEL_ID = "msjdhusjdsd"
private const val CHANNEL_NAME = "File Manager Select"
@SuppressLint("RemoteViewLayout")
fun Context.postNotification(actionId: Int) {
// Log.d("glc", "actionId:" + actionId)
val intent = Intent(applicationContext, HomeActivity::class.java)
var remoteViews: RemoteViews
var myValue = 0
when (actionId) {
ID_JUNK_CLEAN_PUSH -> {
remoteViews = RemoteViews(packageName, R.layout.notification_junk_clean)
}
ID_BOOST_PUSH -> {
return
}
ID_VIRUS_PUSH -> {
return
}
ID_BATTERY_PUSH -> {
remoteViews = RemoteViews(packageName, R.layout.notification_battery)
}
ID_COOL_PUSH -> {
return
}
ID_BIGFILE_PUSH -> {
remoteViews = RemoteViews(packageName, R.layout.notification_large_file)
}
ID_DUPLICATE_FILE_PUSH -> {
return
}
ID_VIDEO_CLEAN_PUSH -> {
return
}
ID_PHOTO_CLEAN_PUSH -> {
return
}
//==================================下面是被动推送的情况===============================================
ID_WIFI_PUSH -> {
return
}
ID_INSTALL_PACKAGE_PUSH -> {
remoteViews = RemoteViews(packageName, R.layout.notification_install)
}
ID_UNINSTALL_PACKAGE_PUSH -> {
remoteViews = RemoteViews(packageName, R.layout.notification_uninstall)
}
ID_CHARGE -> {
remoteViews = RemoteViews(packageName, R.layout.notification_battery)
}
ID_LOW_BATTERY_PUSH -> {
remoteViews = RemoteViews(packageName, R.layout.notification_battery_low)
}
ID_LOW_JUNK_PUSH -> {
return
}
else -> {
return
}
}
myValue = actionId
val customKey = "type"
intent.putExtra(customKey, myValue)
MyApplication.fContext.saveDataStoreBlock(createByActionId(actionId), System.currentTimeMillis())
showNotification(applicationContext, intent, remoteViews)
}
//创建通知通道
private fun createNotificationChannel(
context: Context,
channelId: String = CHANNEL_ID,
channelName: String = CHANNEL_NAME,
) {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_HIGH
val channel = NotificationChannel(channelId, channelName, importance).apply {
enableLights(true)
enableVibration(false)
vibrationPattern = longArrayOf(0)
lightColor = Color.RED
}
// Register the channel with the system
val notificationManager: NotificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
@SuppressLint("MissingPermission")
//Manifest.permission.POST_NOTIFICATIONS
fun showNotification(context: Context, intent: Intent, remoteViews: RemoteViews) {
createNotificationChannel(context)
val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
//requestCode每次需要改变
val requestCode = Random.nextInt(0, 1000)
val pendingIntent = PendingIntent.getActivity(
context, requestCode, intent, flag
)
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_logo24)
.setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.ic_logo24))
.setCustomContentView(remoteViews)
.setCustomHeadsUpContentView(remoteViews)
.setCustomBigContentView(remoteViews)
.setContent(remoteViews)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setColor(Color.TRANSPARENT)
.setAutoCancel(true)
.setOngoing(true)
.setDefaults(NotificationCompat.FLAG_ONLY_ALERT_ONCE)
.setVibrate(longArrayOf(0))
.setContentIntent(pendingIntent)
val notificationId = Random.nextInt(0, 1200)
with(NotificationManagerCompat.from(context)) {
notify(notificationId, builder.build())
}
}
}
\ No newline at end of file
......@@ -28,8 +28,9 @@ object PermissionUtil {
context?.startActivity(intent)
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val intent = Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
action = Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION
data = Uri.fromParts("package", context?.packageName, null)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
context?.startActivity(intent)
}else{
......
......@@ -75,7 +75,7 @@
<LinearLayout
android:layout_marginTop="155dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/ad_layout" />
......
[versions]
agp = "8.0.0"
agp = "8.1.3"
kotlin = "1.9.0"
coreKtx = "1.10.1"
junit = "4.13.2"
......@@ -27,6 +27,7 @@ androidx-legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragmentKtx" }
installreferrer = { group = "com.android.installreferrer", name = "installreferrer", version = "2.2" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
......
#Tue Mar 26 19:05:58 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment