mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-02 17:07:41 +08:00
优化:短信/通话转发获取卡槽信息机制(自行备注卡槽SubId对应)#228 #235
This commit is contained in:
parent
442c29fd3d
commit
65e861ba62
@ -144,8 +144,8 @@ class App : Application(), CactusCallback, Configuration.Provider by Core {
|
||||
runCatching {
|
||||
get.await()
|
||||
Log.d("GlobalScope", "AppUtils.getAppsInfo() Done")
|
||||
Log.d("GlobalScope", "UserAppList = $UserAppList")
|
||||
Log.d("GlobalScope", "SystemAppList = $SystemAppList")
|
||||
//Log.d("GlobalScope", "UserAppList = $UserAppList")
|
||||
//Log.d("GlobalScope", "SystemAppList = $SystemAppList")
|
||||
}.onFailure {
|
||||
//Log.e("GlobalScope", it.message.toString())
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import com.idormy.sms.forwarder.utils.DATABASE_NAME
|
||||
|
||||
@Database(
|
||||
entities = [Frpc::class, Logs::class, Rule::class, Sender::class],
|
||||
version = 10,
|
||||
version = 11,
|
||||
exportSchema = false
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
@ -95,6 +95,7 @@ custom_domains = smsf.demo.com
|
||||
MIGRATION_7_8,
|
||||
MIGRATION_8_9,
|
||||
MIGRATION_9_10,
|
||||
MIGRATION_10_11,
|
||||
)
|
||||
|
||||
/*if (BuildConfig.DEBUG) {
|
||||
@ -277,6 +278,12 @@ CREATE TABLE "Sender" (
|
||||
}
|
||||
}
|
||||
|
||||
//转发日志添加SIM卡槽ID
|
||||
private val MIGRATION_10_11 = object : Migration(10, 11) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("Alter table Logs add column sub_id INTEGER NOT NULL DEFAULT 0 ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,61 +1,62 @@
|
||||
package com.idormy.sms.forwarder.database.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.*
|
||||
import com.idormy.sms.forwarder.R
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.util.*
|
||||
|
||||
@Parcelize
|
||||
@Entity(
|
||||
tableName = "Logs",
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Rule::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["rule_id"],
|
||||
onDelete = ForeignKey.CASCADE, //级联操作
|
||||
onUpdate = ForeignKey.CASCADE //级联操作
|
||||
)
|
||||
],
|
||||
indices = [
|
||||
Index(value = ["id"], unique = true),
|
||||
Index(value = ["rule_id"])
|
||||
]
|
||||
)
|
||||
data class Logs(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = "id") var id: Long,
|
||||
@ColumnInfo(name = "type", defaultValue = "sms") var type: String,
|
||||
@ColumnInfo(name = "from", defaultValue = "") var from: String,
|
||||
@ColumnInfo(name = "content", defaultValue = "") var content: String,
|
||||
@ColumnInfo(name = "rule_id", defaultValue = "0") var ruleId: Long = 0,
|
||||
@ColumnInfo(name = "sim_info", defaultValue = "") var simInfo: String = "",
|
||||
@ColumnInfo(name = "forward_status", defaultValue = "1") var forwardStatus: Int = 1,
|
||||
@ColumnInfo(name = "forward_response", defaultValue = "") var forwardResponse: String = "",
|
||||
@ColumnInfo(name = "time") var time: Date = Date(),
|
||||
) : Parcelable {
|
||||
|
||||
val simImageId: Int
|
||||
get() {
|
||||
if (simInfo.isNotEmpty()) {
|
||||
if (simInfo.replace("-", "").startsWith("SIM2")) {
|
||||
return R.drawable.ic_sim2 //mipmap
|
||||
} else if (simInfo.replace("-", "").startsWith("SIM1")) {
|
||||
return R.drawable.ic_sim1
|
||||
}
|
||||
}
|
||||
return R.drawable.ic_sim
|
||||
}
|
||||
|
||||
val statusImageId: Int
|
||||
get() {
|
||||
if (forwardStatus == 1) {
|
||||
return R.drawable.ic_round_warning
|
||||
} else if (forwardStatus == 2) {
|
||||
return R.drawable.ic_round_check
|
||||
}
|
||||
return R.drawable.ic_round_cancel
|
||||
}
|
||||
|
||||
package com.idormy.sms.forwarder.database.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.*
|
||||
import com.idormy.sms.forwarder.R
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.util.*
|
||||
|
||||
@Parcelize
|
||||
@Entity(
|
||||
tableName = "Logs",
|
||||
foreignKeys = [
|
||||
ForeignKey(
|
||||
entity = Rule::class,
|
||||
parentColumns = ["id"],
|
||||
childColumns = ["rule_id"],
|
||||
onDelete = ForeignKey.CASCADE, //级联操作
|
||||
onUpdate = ForeignKey.CASCADE //级联操作
|
||||
)
|
||||
],
|
||||
indices = [
|
||||
Index(value = ["id"], unique = true),
|
||||
Index(value = ["rule_id"])
|
||||
]
|
||||
)
|
||||
data class Logs(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = "id") var id: Long,
|
||||
@ColumnInfo(name = "type", defaultValue = "sms") var type: String,
|
||||
@ColumnInfo(name = "from", defaultValue = "") var from: String,
|
||||
@ColumnInfo(name = "content", defaultValue = "") var content: String,
|
||||
@ColumnInfo(name = "rule_id", defaultValue = "0") var ruleId: Long = 0,
|
||||
@ColumnInfo(name = "sim_info", defaultValue = "") var simInfo: String = "",
|
||||
@ColumnInfo(name = "sub_id", defaultValue = "0") var subId: Int = 0,
|
||||
@ColumnInfo(name = "forward_status", defaultValue = "1") var forwardStatus: Int = 1,
|
||||
@ColumnInfo(name = "forward_response", defaultValue = "") var forwardResponse: String = "",
|
||||
@ColumnInfo(name = "time") var time: Date = Date(),
|
||||
) : Parcelable {
|
||||
|
||||
val simImageId: Int
|
||||
get() {
|
||||
if (simInfo.isNotEmpty()) {
|
||||
if (simInfo.replace("-", "").startsWith("SIM2")) {
|
||||
return R.drawable.ic_sim2 //mipmap
|
||||
} else if (simInfo.replace("-", "").startsWith("SIM1")) {
|
||||
return R.drawable.ic_sim1
|
||||
}
|
||||
}
|
||||
return R.drawable.ic_sim
|
||||
}
|
||||
|
||||
val statusImageId: Int
|
||||
get() {
|
||||
if (forwardStatus == 1) {
|
||||
return R.drawable.ic_round_warning
|
||||
} else if (forwardStatus == 2) {
|
||||
return R.drawable.ic_round_check
|
||||
}
|
||||
return R.drawable.ic_round_cancel
|
||||
}
|
||||
|
||||
}
|
@ -1,55 +1,58 @@
|
||||
package com.idormy.sms.forwarder.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.idormy.sms.forwarder.R
|
||||
import java.io.Serializable
|
||||
|
||||
data class CallInfo(
|
||||
//姓名
|
||||
var name: String = "",
|
||||
//号码
|
||||
var number: String = "",
|
||||
//获取通话日期
|
||||
var dateLong: Long = 0L,
|
||||
//获取通话时长,值为多少秒
|
||||
var duration: Int = 0,
|
||||
//通话类型:1=呼入, 2=呼出, 3=未接, 4=未接提醒
|
||||
var type: Int = 1,
|
||||
//被呼号码
|
||||
@SerializedName("via_number")
|
||||
var viaNumber: String = "",
|
||||
//卡槽ID: 0=Sim1, 1=Sim2, -1=获取失败
|
||||
@SerializedName("sim_id")
|
||||
var simId: Int = -1,
|
||||
) : Serializable {
|
||||
|
||||
val typeImageId: Int
|
||||
get() {
|
||||
return when (type) {
|
||||
1 -> R.drawable.ic_phone_in
|
||||
2 -> R.drawable.ic_phone_out
|
||||
else -> R.drawable.ic_phone_missed
|
||||
}
|
||||
}
|
||||
|
||||
val simImageId: Int
|
||||
get() {
|
||||
return when (simId) {
|
||||
0 -> R.drawable.ic_sim1
|
||||
1 -> R.drawable.ic_sim2
|
||||
else -> R.drawable.ic_sim
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "CallInfo{" +
|
||||
"name='" + name + '\'' +
|
||||
", number='" + number + '\'' +
|
||||
", dateLong=" + dateLong +
|
||||
", duration=" + duration +
|
||||
", type=" + type +
|
||||
", viaNumber=" + viaNumber +
|
||||
", simId=" + simId +
|
||||
'}'
|
||||
}
|
||||
package com.idormy.sms.forwarder.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.idormy.sms.forwarder.R
|
||||
import java.io.Serializable
|
||||
|
||||
data class CallInfo(
|
||||
//姓名
|
||||
var name: String = "",
|
||||
//号码
|
||||
var number: String = "",
|
||||
//获取通话日期
|
||||
var dateLong: Long = 0L,
|
||||
//获取通话时长,值为多少秒
|
||||
var duration: Int = 0,
|
||||
//通话类型:1=呼入, 2=呼出, 3=未接, 4=未接提醒
|
||||
var type: Int = 1,
|
||||
//被呼号码
|
||||
@SerializedName("via_number")
|
||||
var viaNumber: String = "",
|
||||
//卡槽ID: 0=Sim1, 1=Sim2, -1=获取失败
|
||||
@SerializedName("sim_id")
|
||||
var simId: Int = -1,
|
||||
//卡槽主键
|
||||
@SerializedName("sub_id")
|
||||
var subId: Int = 0,
|
||||
) : Serializable {
|
||||
|
||||
val typeImageId: Int
|
||||
get() {
|
||||
return when (type) {
|
||||
1 -> R.drawable.ic_phone_in
|
||||
2 -> R.drawable.ic_phone_out
|
||||
else -> R.drawable.ic_phone_missed
|
||||
}
|
||||
}
|
||||
|
||||
val simImageId: Int
|
||||
get() {
|
||||
return when (simId) {
|
||||
0 -> R.drawable.ic_sim1
|
||||
1 -> R.drawable.ic_sim2
|
||||
else -> R.drawable.ic_sim
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "CallInfo{" +
|
||||
"name='" + name + '\'' +
|
||||
", number='" + number + '\'' +
|
||||
", dateLong=" + dateLong +
|
||||
", duration=" + duration +
|
||||
", type=" + type +
|
||||
", viaNumber=" + viaNumber +
|
||||
", simId=" + simId +
|
||||
'}'
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ data class MsgInfo(
|
||||
var date: Date,
|
||||
var simInfo: String,
|
||||
var simSlot: Int = -1, //卡槽id:-1=获取失败、0=卡槽1、1=卡槽2
|
||||
var subId: Int = 0, //卡槽主键
|
||||
) : Serializable {
|
||||
|
||||
val titleForSend: String
|
||||
@ -36,13 +37,14 @@ data class MsgInfo(
|
||||
fun getTitleForSend(titleTemplate: String, regexReplace: String): String {
|
||||
var template = titleTemplate.replace("null", "")
|
||||
if (TextUtils.isEmpty(template)) template = getString(R.string.tag_from)
|
||||
val deviceMark = extraDeviceMark!!.trim()
|
||||
val deviceMark = extraDeviceMark.trim()
|
||||
val versionName = AppUtils.getAppVersionName()
|
||||
val titleForSend: String = template.replace(getString(R.string.tag_from), from)
|
||||
.replace(getString(R.string.tag_package_name), from)
|
||||
.replace(getString(R.string.tag_sms), content)
|
||||
.replace(getString(R.string.tag_msg), content)
|
||||
.replace(getString(R.string.tag_card_slot), simInfo)
|
||||
.replace(getString(R.string.tag_card_subid), subId.toString())
|
||||
.replace(getString(R.string.tag_title), simInfo)
|
||||
.replace(getString(R.string.tag_receive_time), SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date))
|
||||
.replace(getString(R.string.tag_device_name), deviceMark)
|
||||
@ -60,10 +62,11 @@ data class MsgInfo(
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
fun getContentForSend(ruleSmsTemplate: String, regexReplace: String): String {
|
||||
val deviceMark = extraDeviceMark!!.trim()
|
||||
val deviceMark = extraDeviceMark.trim()
|
||||
var customSmsTemplate: String = getString(R.string.tag_from).toString() + "\n" +
|
||||
getString(R.string.tag_sms) + "\n" +
|
||||
getString(R.string.tag_card_slot) + "\n" +
|
||||
"SubId:" + getString(R.string.tag_card_subid) + "\n" +
|
||||
getString(R.string.tag_receive_time) + "\n" +
|
||||
getString(R.string.tag_device_name)
|
||||
|
||||
@ -72,7 +75,7 @@ data class MsgInfo(
|
||||
customSmsTemplate = ruleSmsTemplate.replace("null", "")
|
||||
} else {
|
||||
val switchSmsTemplate = enableSmsTemplate
|
||||
val smsTemplate = smsTemplate.toString().trim()
|
||||
val smsTemplate = smsTemplate.trim()
|
||||
if (switchSmsTemplate && smsTemplate.isNotEmpty()) {
|
||||
customSmsTemplate = smsTemplate.replace("null", "")
|
||||
}
|
||||
@ -83,6 +86,7 @@ data class MsgInfo(
|
||||
.replace(getString(R.string.tag_sms), content)
|
||||
.replace(getString(R.string.tag_msg), content)
|
||||
.replace(getString(R.string.tag_card_slot), simInfo)
|
||||
.replace(getString(R.string.tag_card_subid), subId.toString())
|
||||
.replace(getString(R.string.tag_title), simInfo)
|
||||
.replace(getString(R.string.tag_receive_time), SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date))
|
||||
.replace(getString(R.string.tag_device_name), deviceMark)
|
||||
|
@ -1,37 +1,37 @@
|
||||
package com.idormy.sms.forwarder.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.io.Serializable
|
||||
|
||||
//SIM卡信息
|
||||
data class SimInfo(
|
||||
//运营商信息:中国移动 中国联通 中国电信
|
||||
@SerializedName("carrier_name")
|
||||
var mCarrierName: String? = null,
|
||||
//集成电路卡识别码即SIM卡卡号
|
||||
@SerializedName("icc_id")
|
||||
var mIccId: String? = null,
|
||||
//卡槽id:-1=没插入、 0=卡槽1 、1=卡槽2
|
||||
@SerializedName("sim_slot_index")
|
||||
var mSimSlotIndex: Int = 0,
|
||||
//号码
|
||||
@SerializedName("number")
|
||||
var mNumber: String? = null,
|
||||
//国家代码
|
||||
@SerializedName("country_iso")
|
||||
var mCountryIso: String? = null,
|
||||
//SIM的 Subscription Id (SIM插入顺序)
|
||||
@SerializedName("subscription_id")
|
||||
var mSubscriptionId: Int = 0,
|
||||
) : Serializable {
|
||||
override fun toString(): String {
|
||||
return "SimInfo{" +
|
||||
"mCarrierName=" + mCarrierName +
|
||||
", mIccId=" + mIccId +
|
||||
", mSimSlotIndex=" + mSimSlotIndex +
|
||||
", mNumber=" + mNumber +
|
||||
", mCountryIso=" + mCountryIso +
|
||||
", mSubscriptionId=" + mSubscriptionId +
|
||||
'}'
|
||||
}
|
||||
}
|
||||
package com.idormy.sms.forwarder.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.io.Serializable
|
||||
|
||||
//SIM卡信息
|
||||
data class SimInfo(
|
||||
//运营商信息:中国移动 中国联通 中国电信
|
||||
@SerializedName("carrier_name")
|
||||
var mCarrierName: String? = null,
|
||||
//集成电路卡识别码即SIM卡卡号
|
||||
@SerializedName("icc_id")
|
||||
var mIccId: String? = null,
|
||||
//卡槽id:-1=没插入、 0=卡槽1 、1=卡槽2
|
||||
@SerializedName("sim_slot_index")
|
||||
var mSimSlotIndex: Int = 0,
|
||||
//号码
|
||||
@SerializedName("number")
|
||||
var mNumber: String? = null,
|
||||
//国家代码
|
||||
@SerializedName("country_iso")
|
||||
var mCountryIso: String? = null,
|
||||
//SIM的 Subscription Id (SIM插入顺序)
|
||||
@SerializedName("subscription_id")
|
||||
var mSubscriptionId: Int = 0,
|
||||
) : Serializable {
|
||||
override fun toString(): String {
|
||||
return "SimInfo{" +
|
||||
"mCarrierName=" + mCarrierName +
|
||||
", mIccId=" + mIccId +
|
||||
", mSimSlotIndex=" + mSimSlotIndex +
|
||||
", mNumber=" + mNumber +
|
||||
", mCountryIso=" + mCountryIso +
|
||||
", mSubscriptionId=" + mSubscriptionId +
|
||||
'}'
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,36 @@
|
||||
package com.idormy.sms.forwarder.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.idormy.sms.forwarder.R
|
||||
import java.io.Serializable
|
||||
|
||||
data class SmsInfo(
|
||||
// 联系人姓名
|
||||
var name: String = "",
|
||||
// 联系人号码
|
||||
var number: String = "",
|
||||
// 短信内容
|
||||
var content: String = "",
|
||||
// 短信时间
|
||||
var date: Long = 0L,
|
||||
// 短信类型: 1=接收, 2=发送
|
||||
var type: Int = 1,
|
||||
// 卡槽ID: 0=Sim1, 1=Sim2, -1=获取失败
|
||||
@SerializedName("sim_id")
|
||||
var simId: Int = -1,
|
||||
) : Serializable {
|
||||
|
||||
val typeImageId: Int = R.drawable.ic_sms
|
||||
|
||||
val simImageId: Int
|
||||
get() {
|
||||
return when (simId) {
|
||||
0 -> R.drawable.ic_sim1
|
||||
1 -> R.drawable.ic_sim2
|
||||
else -> R.drawable.ic_sim
|
||||
}
|
||||
}
|
||||
}
|
||||
package com.idormy.sms.forwarder.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.idormy.sms.forwarder.R
|
||||
import java.io.Serializable
|
||||
|
||||
data class SmsInfo(
|
||||
// 联系人姓名
|
||||
var name: String = "",
|
||||
// 联系人号码
|
||||
var number: String = "",
|
||||
// 短信内容
|
||||
var content: String = "",
|
||||
// 短信时间
|
||||
var date: Long = 0L,
|
||||
// 短信类型: 1=接收, 2=发送
|
||||
var type: Int = 1,
|
||||
// 卡槽ID: 0=Sim1, 1=Sim2, -1=获取失败
|
||||
@SerializedName("sim_id")
|
||||
var simId: Int = -1,
|
||||
// 卡槽主键
|
||||
@SerializedName("sub_id")
|
||||
var subId: Int = 0,
|
||||
) : Serializable {
|
||||
|
||||
val typeImageId: Int = R.drawable.ic_sms
|
||||
|
||||
val simImageId: Int
|
||||
get() {
|
||||
return when (simId) {
|
||||
0 -> R.drawable.ic_sim1
|
||||
1 -> R.drawable.ic_sim2
|
||||
else -> R.drawable.ic_sim
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.text.Editable
|
||||
import android.text.TextUtils
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
@ -128,6 +129,10 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
|
||||
//设备备注
|
||||
editAddExtraDeviceMark(binding!!.etExtraDeviceMark)
|
||||
//SIM1主键
|
||||
editAddSubidSim1(binding!!.etSubidSim1)
|
||||
//SIM2主键
|
||||
editAddSubidSim2(binding!!.etSubidSim2)
|
||||
//SIM1备注
|
||||
editAddExtraSim1(binding!!.etExtraSim1)
|
||||
//SIM2备注
|
||||
@ -200,6 +205,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
return
|
||||
}
|
||||
val simInfo: SimInfo? = App.SimInfoList[0]
|
||||
binding!!.etSubidSim1.setText(simInfo?.mSubscriptionId.toString())
|
||||
binding!!.etExtraSim1.setText(simInfo?.mCarrierName.toString() + "_" + simInfo?.mNumber.toString())
|
||||
return
|
||||
}
|
||||
@ -222,6 +228,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
return
|
||||
}
|
||||
val simInfo: SimInfo? = App.SimInfoList[1]
|
||||
binding!!.etSubidSim2.setText(simInfo?.mSubscriptionId.toString())
|
||||
binding!!.etExtraSim2.setText(simInfo?.mCarrierName.toString() + "_" + simInfo?.mNumber.toString())
|
||||
return
|
||||
}
|
||||
@ -729,6 +736,40 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
})
|
||||
}
|
||||
|
||||
//设置SIM1主键
|
||||
private fun editAddSubidSim1(etSubidSim1: EditText) {
|
||||
etSubidSim1.setText(SettingUtils.subidSim1.toString())
|
||||
etSubidSim1.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
val v = etSubidSim1.text.toString()
|
||||
SettingUtils.subidSim1 = if (!TextUtils.isEmpty(v)) {
|
||||
v.toInt()
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//设置SIM2主键
|
||||
private fun editAddSubidSim2(etSubidSim2: EditText) {
|
||||
etSubidSim2.setText(SettingUtils.subidSim2.toString())
|
||||
etSubidSim2.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
val v = etSubidSim2.text.toString()
|
||||
SettingUtils.subidSim2 = if (!TextUtils.isEmpty(v)) {
|
||||
v.toInt()
|
||||
} else {
|
||||
2
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//设置SIM1备注
|
||||
private fun editAddExtraSim1(etExtraSim1: EditText) {
|
||||
etExtraSim1.setText(SettingUtils.extraSim1)
|
||||
@ -783,6 +824,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
${getString(R.string.tag_from)}
|
||||
${getString(R.string.tag_sms)}
|
||||
${getString(R.string.tag_card_slot)}
|
||||
SubId:${getString(R.string.tag_card_subid)}
|
||||
${getString(R.string.tag_receive_time)}
|
||||
${getString(R.string.tag_device_name)}
|
||||
""".trimIndent()
|
||||
|
@ -51,82 +51,85 @@ class PhoneStateReceiver : BroadcastReceiver() {
|
||||
TelephonyManager.EXTRA_STATE_RINGING -> state = TelephonyManager.CALL_STATE_RINGING
|
||||
}
|
||||
Log.d(TAG, "state=$state, number=$number")
|
||||
var callSavedNumber: String by SharedPreference("CALL_SAVED_NUMBER", "")
|
||||
if (!TextUtils.isEmpty(number)) callSavedNumber = number.toString()
|
||||
|
||||
onCallStateChanged(context, state, number)
|
||||
//Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
|
||||
//Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
|
||||
var lastState: Int by SharedPreference("CALL_LAST_STATE", TelephonyManager.CALL_STATE_IDLE)
|
||||
if (lastState == state || (state == TelephonyManager.CALL_STATE_RINGING && number == null)) {
|
||||
//No change, debounce extras
|
||||
Log.d(TAG, "状态没变,防止抖动")
|
||||
return
|
||||
}
|
||||
|
||||
lastState = state
|
||||
var callIsIncoming: Boolean by SharedPreference("CALL_IS_INCOMING", false)
|
||||
Log.d(TAG, "lastState=$lastState, callIsIncoming=$callIsIncoming, callSavedNumber=$callSavedNumber")
|
||||
|
||||
when (state) {
|
||||
TelephonyManager.CALL_STATE_RINGING -> {
|
||||
Log.d(TAG, "电话响铃")
|
||||
callIsIncoming = true
|
||||
|
||||
//来电提醒
|
||||
if (!TextUtils.isEmpty(number) && SettingUtils.enableCallType4) {
|
||||
val contacts = PhoneUtils.getContactByNumber(number)
|
||||
val contactName = if (contacts.isNotEmpty()) contacts[0].name else getString(R.string.unknown_number)
|
||||
|
||||
val sb = StringBuilder()
|
||||
sb.append(getString(R.string.linkman)).append(contactName).append("\n")
|
||||
sb.append(getString(R.string.mandatory_type))
|
||||
sb.append(getString(R.string.incoming_call))
|
||||
|
||||
val msgInfo = MsgInfo("call", number.toString(), sb.toString(), Date(), "", -1)
|
||||
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
|
||||
workDataOf(
|
||||
Worker.sendMsgInfo to Gson().toJson(msgInfo)
|
||||
)
|
||||
).build()
|
||||
WorkManager.getInstance(context).enqueue(request)
|
||||
}
|
||||
}
|
||||
TelephonyManager.CALL_STATE_OFFHOOK ->
|
||||
//Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
|
||||
callIsIncoming = when {
|
||||
lastState != TelephonyManager.CALL_STATE_RINGING -> {
|
||||
Log.d(TAG, "去电接通")
|
||||
if (!TextUtils.isEmpty(number)) callSavedNumber = number.toString()
|
||||
false
|
||||
}
|
||||
else -> {
|
||||
Log.d(TAG, "来电接通")
|
||||
true
|
||||
}
|
||||
}
|
||||
TelephonyManager.CALL_STATE_IDLE ->
|
||||
//Went to idle- this is the end of a call. What type depends on previous state(s)
|
||||
when {
|
||||
lastState == TelephonyManager.CALL_STATE_RINGING -> {
|
||||
Log.d(TAG, "来电未接")
|
||||
sendReceiveCallMsg(context, 3, callSavedNumber)
|
||||
callSavedNumber = ""
|
||||
}
|
||||
callIsIncoming -> {
|
||||
Log.d(TAG, "来电挂机")
|
||||
sendReceiveCallMsg(context, 1, callSavedNumber)
|
||||
callSavedNumber = ""
|
||||
}
|
||||
else -> {
|
||||
Log.d(TAG, "去电挂机")
|
||||
sendReceiveCallMsg(context, 2, callSavedNumber)
|
||||
callSavedNumber = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, e.message.toString())
|
||||
}
|
||||
}
|
||||
|
||||
//Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
|
||||
//Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
|
||||
private fun onCallStateChanged(context: Context, state: Int, number: String?) {
|
||||
var lastState: Int by SharedPreference("CALL_LAST_STATE", TelephonyManager.CALL_STATE_IDLE)
|
||||
if (lastState == state || (state == TelephonyManager.CALL_STATE_RINGING && number == null)) {
|
||||
//No change, debounce extras
|
||||
return
|
||||
}
|
||||
|
||||
lastState = state
|
||||
var callIsIncoming: Boolean by SharedPreference("CALL_IS_INCOMING", false)
|
||||
var callSavedNumber: String by SharedPreference("CALL_SAVED_NUMBER", "")
|
||||
when (state) {
|
||||
TelephonyManager.CALL_STATE_RINGING -> {
|
||||
Log.d(TAG, "来电响铃")
|
||||
callIsIncoming = true
|
||||
callSavedNumber = number.toString()
|
||||
|
||||
//来电提醒
|
||||
if (!TextUtils.isEmpty(number) && SettingUtils.enableCallType4) {
|
||||
val contacts = PhoneUtils.getContactByNumber(number)
|
||||
val contactName = if (contacts.isNotEmpty()) contacts[0].name else getString(R.string.unknown_number)
|
||||
|
||||
val sb = StringBuilder()
|
||||
sb.append(getString(R.string.linkman)).append(contactName).append("\n")
|
||||
sb.append(getString(R.string.mandatory_type))
|
||||
sb.append(getString(R.string.incoming_call))
|
||||
|
||||
val msgInfo = MsgInfo("call", number.toString(), sb.toString(), Date(), "", -1)
|
||||
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
|
||||
workDataOf(
|
||||
Worker.sendMsgInfo to Gson().toJson(msgInfo)
|
||||
)
|
||||
).build()
|
||||
WorkManager.getInstance(context).enqueue(request)
|
||||
}
|
||||
}
|
||||
TelephonyManager.CALL_STATE_OFFHOOK ->
|
||||
//Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
|
||||
callIsIncoming = when {
|
||||
lastState != TelephonyManager.CALL_STATE_RINGING -> {
|
||||
Log.d(TAG, "去电接通")
|
||||
false
|
||||
}
|
||||
else -> {
|
||||
Log.d(TAG, "来电接通")
|
||||
true
|
||||
}
|
||||
}
|
||||
TelephonyManager.CALL_STATE_IDLE ->
|
||||
//Went to idle- this is the end of a call. What type depends on previous state(s)
|
||||
when {
|
||||
lastState == TelephonyManager.CALL_STATE_RINGING -> {
|
||||
Log.d(TAG, "来电未接")
|
||||
sendReceiveCallMsg(context, 3, callSavedNumber)
|
||||
}
|
||||
callIsIncoming -> {
|
||||
Log.d(TAG, "来电挂机")
|
||||
sendReceiveCallMsg(context, 1, callSavedNumber)
|
||||
}
|
||||
else -> {
|
||||
Log.d(TAG, "去电挂机")
|
||||
sendReceiveCallMsg(context, 2, callSavedNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendReceiveCallMsg(context: Context, callType: Int, phoneNumber: String?) {
|
||||
//必须休眠才能获取来电记录,否则可能获取到上一次通话的
|
||||
Thread.sleep(500)
|
||||
@ -158,7 +161,7 @@ class PhoneStateReceiver : BroadcastReceiver() {
|
||||
}
|
||||
|
||||
val msgInfo = MsgInfo(
|
||||
"call", callInfo.number, PhoneUtils.getCallMsg(callInfo), Date(), simInfo, simSlot
|
||||
"call", callInfo.number, PhoneUtils.getCallMsg(callInfo), Date(), simInfo, simSlot, callInfo.subId
|
||||
)
|
||||
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
|
||||
workDataOf(
|
||||
|
@ -1,95 +1,96 @@
|
||||
package com.idormy.sms.forwarder.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.Telephony
|
||||
import android.util.Log
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.workDataOf
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.App
|
||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||
import com.idormy.sms.forwarder.utils.PhoneUtils
|
||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||
import com.idormy.sms.forwarder.utils.Worker
|
||||
import com.idormy.sms.forwarder.workers.SendWorker
|
||||
import java.util.*
|
||||
|
||||
//短信广播
|
||||
@Suppress("PrivatePropertyName", "DEPRECATION")
|
||||
class SmsReceiver : BroadcastReceiver() {
|
||||
|
||||
private var TAG = "SmsReceiver"
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
try {
|
||||
//纯客户端模式
|
||||
if (SettingUtils.enablePureClientMode) return
|
||||
|
||||
//总开关
|
||||
if (!SettingUtils.enableSms) return
|
||||
|
||||
//过滤广播
|
||||
if (intent.action != Telephony.Sms.Intents.SMS_RECEIVED_ACTION && intent.action != Telephony.Sms.Intents.SMS_DELIVER_ACTION) return
|
||||
|
||||
//权限判断
|
||||
//if (ActivityCompat.checkSelfPermission(context, Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED) return
|
||||
|
||||
var from = ""
|
||||
var content = ""
|
||||
for (smsMessage in Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
|
||||
from = smsMessage.displayOriginatingAddress
|
||||
content += smsMessage.messageBody
|
||||
}
|
||||
Log.d(TAG, "from = $from")
|
||||
Log.d(TAG, "content = $content")
|
||||
|
||||
//获取卡槽信息
|
||||
if (App.SimInfoList.isEmpty()) {
|
||||
App.SimInfoList = PhoneUtils.getSimMultiInfo()
|
||||
}
|
||||
Log.e(TAG, "SimInfoList = " + App.SimInfoList.toString())
|
||||
|
||||
//TODO:准确获取卡槽信息,目前测试结果只有 subscription 相对靠谱
|
||||
val slot = intent.extras?.getInt("slot") ?: -1
|
||||
val simId = intent.extras?.getInt("simId") ?: slot
|
||||
val subscription = intent.extras?.getInt("subscription") ?: simId
|
||||
Log.d(TAG, "slot = $slot, simId = $simId, subscription = $subscription")
|
||||
|
||||
//卡槽id:-1=获取失败、0=卡槽1、1=卡槽2
|
||||
var simSlot = -1
|
||||
if (App.SimInfoList.isNotEmpty()) {
|
||||
for (simInfo in App.SimInfoList.values) {
|
||||
if (simInfo.mSubscriptionId == subscription) {
|
||||
simSlot = simInfo.mSimSlotIndex
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
//获取卡槽信息
|
||||
val simInfo = when (simSlot) {
|
||||
0 -> "SIM1_" + SettingUtils.extraSim1
|
||||
1 -> "SIM2_" + SettingUtils.extraSim2
|
||||
else -> ""
|
||||
}
|
||||
|
||||
val msgInfo = MsgInfo("sms", from, content, Date(), simInfo, simSlot)
|
||||
Log.d(TAG, "msgInfo = $msgInfo")
|
||||
|
||||
val request = OneTimeWorkRequestBuilder<SendWorker>()
|
||||
.setInputData(
|
||||
workDataOf(
|
||||
Worker.sendMsgInfo to Gson().toJson(msgInfo)
|
||||
)
|
||||
)
|
||||
.build()
|
||||
WorkManager.getInstance(context).enqueue(request)
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Parsing SMS failed: " + e.message.toString())
|
||||
}
|
||||
}
|
||||
|
||||
package com.idormy.sms.forwarder.receiver
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.Telephony
|
||||
import android.util.Log
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.workDataOf
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.App
|
||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||
import com.idormy.sms.forwarder.utils.PhoneUtils
|
||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||
import com.idormy.sms.forwarder.utils.Worker
|
||||
import com.idormy.sms.forwarder.workers.SendWorker
|
||||
import java.util.*
|
||||
|
||||
//短信广播
|
||||
@Suppress("PrivatePropertyName", "DEPRECATION")
|
||||
class SmsReceiver : BroadcastReceiver() {
|
||||
|
||||
private var TAG = "SmsReceiver"
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
try {
|
||||
//纯客户端模式
|
||||
if (SettingUtils.enablePureClientMode) return
|
||||
|
||||
//总开关
|
||||
if (!SettingUtils.enableSms) return
|
||||
|
||||
//过滤广播
|
||||
if (intent.action != Telephony.Sms.Intents.SMS_RECEIVED_ACTION && intent.action != Telephony.Sms.Intents.SMS_DELIVER_ACTION) return
|
||||
|
||||
var from = ""
|
||||
var content = ""
|
||||
for (smsMessage in Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
|
||||
from = smsMessage.displayOriginatingAddress
|
||||
content += smsMessage.messageBody
|
||||
}
|
||||
Log.d(TAG, "from = $from")
|
||||
Log.d(TAG, "content = $content")
|
||||
|
||||
//TODO:准确获取卡槽信息,目前测试结果只有 subscription 相对靠谱
|
||||
val slot = intent.extras?.getInt("slot") ?: -1
|
||||
val simId = intent.extras?.getInt("simId") ?: slot
|
||||
val subscription = intent.extras?.getInt("subscription") ?: simId
|
||||
Log.d(TAG, "slot = $slot, simId = $simId, subscription = $subscription")
|
||||
|
||||
//卡槽id:-1=获取失败、0=卡槽1、1=卡槽2
|
||||
var simSlot = -1
|
||||
//以自定义卡槽信息优先
|
||||
if (SettingUtils.subidSim1 > 0 || SettingUtils.subidSim2 > 0) {
|
||||
simSlot = if (subscription == SettingUtils.subidSim1) 0 else 1
|
||||
} else {
|
||||
//获取卡槽信息
|
||||
if (App.SimInfoList.isEmpty()) {
|
||||
App.SimInfoList = PhoneUtils.getSimMultiInfo()
|
||||
}
|
||||
Log.d(TAG, "SimInfoList = " + App.SimInfoList.toString())
|
||||
|
||||
if (App.SimInfoList.isNotEmpty()) {
|
||||
for (simInfo in App.SimInfoList.values) {
|
||||
if (simInfo.mSubscriptionId == subscription) {
|
||||
simSlot = simInfo.mSimSlotIndex
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//获取卡槽信息
|
||||
val simInfo = when (simSlot) {
|
||||
0 -> "SIM1_" + SettingUtils.extraSim1
|
||||
1 -> "SIM2_" + SettingUtils.extraSim2
|
||||
else -> ""
|
||||
}
|
||||
|
||||
val msgInfo = MsgInfo("sms", from, content, Date(), simInfo, simSlot, subscription)
|
||||
Log.d(TAG, "msgInfo = $msgInfo")
|
||||
|
||||
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
|
||||
workDataOf(
|
||||
Worker.sendMsgInfo to Gson().toJson(msgInfo)
|
||||
)
|
||||
).build()
|
||||
WorkManager.getInstance(context).enqueue(request)
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Parsing SMS failed: " + e.message.toString())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,396 +1,398 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.idormy.sms.forwarder.utils
|
||||
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.xuexiang.xpage.enums.CoreAnim
|
||||
import com.xuexiang.xpage.model.PageInfo
|
||||
import com.xuexiang.xui.utils.ResUtils.getString
|
||||
|
||||
object Worker {
|
||||
const val sendMsgInfo = "send_msg_info"
|
||||
const val sendLogId = "send_log_id"
|
||||
const val sendSbnId = "send_sbn_id"
|
||||
const val updateLogs = "update_logs"
|
||||
}
|
||||
|
||||
//初始化相关
|
||||
const val IS_FIRST_OPEN_KEY = "is_first_open_key"
|
||||
const val IS_AGREE_PRIVACY_KEY = "is_agree_privacy_key"
|
||||
|
||||
//数据库
|
||||
const val DATABASE_NAME = "sms_forwarder.db"
|
||||
const val PACKAGE_NAME = "com.idormy.sms.forwarder"
|
||||
|
||||
//通用设置
|
||||
const val SP_ENABLE_SMS = "enable_sms"
|
||||
|
||||
const val SP_ENABLE_PHONE = "enable_phone"
|
||||
const val SP_ENABLE_CALL_TYPE_1 = "enable_call_type_1"
|
||||
const val SP_ENABLE_CALL_TYPE_2 = "enable_call_type_2"
|
||||
const val SP_ENABLE_CALL_TYPE_3 = "enable_call_type_3"
|
||||
const val SP_ENABLE_CALL_TYPE_4 = "enable_call_type_4"
|
||||
|
||||
const val SP_ENABLE_APP_NOTIFY = "enable_app_notify"
|
||||
const val SP_ENABLE_CANCEL_APP_NOTIFY = "enable_cancel_app_notify"
|
||||
const val SP_ENABLE_NOT_USER_PRESENT = "enable_not_user_present"
|
||||
|
||||
const val ENABLE_LOAD_APP_LIST = "enable_load_app_list"
|
||||
const val ENABLE_LOAD_USER_APP_LIST = "enable_load_user_app_list"
|
||||
const val ENABLE_LOAD_SYSTEM_APP_LIST = "enable_load_system_app_list"
|
||||
|
||||
const val SP_DUPLICATE_MESSAGES_LIMITS = "duplicate_messages_limits"
|
||||
const val SP_SILENT_PERIOD_START = "silent_period_start"
|
||||
const val SP_SILENT_PERIOD_END = "silent_period_end"
|
||||
const val SP_AUTO_CLEAN_LOGS_DAYS = "auto_clean_logs_days"
|
||||
|
||||
const val SP_BATTERY_RECEIVER = "enable_battery_receiver"
|
||||
const val SP_BATTERY_STATUS = "battery_status"
|
||||
const val SP_BATTERY_LEVEL_MIN = "battery_level_min"
|
||||
const val SP_BATTERY_LEVEL_MAX = "battery_level_max"
|
||||
const val SP_BATTERY_LEVEL_ONCE = "battery_level_once"
|
||||
const val SP_BATTERY_LEVEL_CURRENT = "battery_level_current"
|
||||
|
||||
const val SP_BATTERY_CRON = "enable_battery_cron"
|
||||
const val SP_BATTERY_CRON_START_TIME = "battery_cron_start_time"
|
||||
const val SP_BATTERY_CRON_INTERVAL = "battery_cron_interval"
|
||||
|
||||
const val SP_ENABLE_EXCLUDE_FROM_RECENTS = "enable_exclude_from_recents"
|
||||
const val SP_ENABLE_PLAY_SILENCE_MUSIC = "enable_play_silence_music"
|
||||
const val SP_ENABLE_ONE_PIXEL_ACTIVITY = "enable_one_pixel_activity"
|
||||
|
||||
const val SP_REQUEST_RETRY_TIMES = "request_retry_times"
|
||||
const val SP_REQUEST_DELAY_TIME = "request_delay_time"
|
||||
const val SP_REQUEST_TIMEOUT = "request_timeout"
|
||||
|
||||
const val SP_NOTIFY_CONTENT = "notify_content"
|
||||
const val SP_EXTRA_DEVICE_MARK = "extra_device_mark"
|
||||
const val SP_EXTRA_SIM1 = "extra_sim1"
|
||||
const val SP_EXTRA_SIM2 = "extra_sim2"
|
||||
const val SP_ENABLE_SMS_TEMPLATE = "enable_sms_template"
|
||||
const val SP_SMS_TEMPLATE = "sms_template"
|
||||
|
||||
const val SP_ENABLE_HELP_TIP = "enable_help_tip"
|
||||
const val SP_PURE_CLIENT_MODE = "enable_pure_client_mode"
|
||||
|
||||
const val SP_ENABLE_CACTUS = "enable_cactus"
|
||||
const val CACTUS_TIMER = "cactus_timer"
|
||||
const val CACTUS_LAST_TIMER = "cactus_last_timer"
|
||||
const val CACTUS_DATE = "cactus_date"
|
||||
const val CACTUS_END_DATE = "cactus_end_date"
|
||||
|
||||
//OkHttp 请求超时时间
|
||||
const val REQUEST_TIMEOUT_SECONDS = 5
|
||||
|
||||
//规则相关
|
||||
const val STATUS_ON = 1
|
||||
const val STATUS_OFF = 0
|
||||
const val FILED_TRANSPOND_ALL = "transpond_all"
|
||||
const val FILED_PHONE_NUM = "phone_num"
|
||||
const val FILED_PACKAGE_NAME = "package_name"
|
||||
const val FILED_MSG_CONTENT = "msg_content"
|
||||
const val FILED_INFORM_CONTENT = "inform_content"
|
||||
const val FILED_MULTI_MATCH = "multi_match"
|
||||
const val CHECK_IS = "is"
|
||||
const val CHECK_CONTAIN = "contain"
|
||||
const val CHECK_NOT_CONTAIN = "notcontain"
|
||||
const val CHECK_START_WITH = "startwith"
|
||||
const val CHECK_END_WITH = "endwith"
|
||||
const val CHECK_NOT_IS = "notis"
|
||||
const val CHECK_REGEX = "regex"
|
||||
const val CHECK_SIM_SLOT_ALL = "ALL"
|
||||
const val CHECK_SIM_SLOT_1 = "SIM1"
|
||||
const val CHECK_SIM_SLOT_2 = "SIM2"
|
||||
val TYPE_MAP = object : HashMap<String, String>() {
|
||||
init {
|
||||
put("sms", getString(R.string.rule_sms))
|
||||
put("call", getString(R.string.rule_call))
|
||||
put("app", getString(R.string.rule_app))
|
||||
}
|
||||
}
|
||||
val FILED_MAP = object : HashMap<String, String>() {
|
||||
init {
|
||||
put("transpond_all", getString(R.string.rule_transpond_all))
|
||||
put("phone_num", getString(R.string.rule_phone_num))
|
||||
put("msg_content", getString(R.string.rule_msg_content))
|
||||
put("multi_match", getString(R.string.rule_multi_match))
|
||||
put("package_name", getString(R.string.rule_package_name))
|
||||
put("inform_content", getString(R.string.rule_inform_content))
|
||||
}
|
||||
}
|
||||
val CHECK_MAP = object : HashMap<String, String>() {
|
||||
init {
|
||||
put("is", getString(R.string.rule_is))
|
||||
put("notis", getString(R.string.rule_notis))
|
||||
put("contain", getString(R.string.rule_contain))
|
||||
put("startwith", getString(R.string.rule_startwith))
|
||||
put("endwith", getString(R.string.rule_endwith))
|
||||
put("notcontain", getString(R.string.rule_notcontain))
|
||||
put("regex", getString(R.string.rule_regex))
|
||||
}
|
||||
}
|
||||
val SIM_SLOT_MAP = object : HashMap<String, String>() {
|
||||
init {
|
||||
put("ALL", getString(R.string.rule_all))
|
||||
put("SIM1", "SIM1")
|
||||
put("SIM2", "SIM2")
|
||||
}
|
||||
}
|
||||
val FORWARD_STATUS_MAP = object : HashMap<Int, String>() {
|
||||
init {
|
||||
put(0, getString(R.string.failed))
|
||||
put(1, getString(R.string.processing))
|
||||
put(2, getString(R.string.success))
|
||||
}
|
||||
}
|
||||
val BARK_LEVEL_MAP = mapOf(
|
||||
"active" to getString(R.string.bark_level_active),
|
||||
"timeSensitive" to getString(R.string.bark_level_timeSensitive),
|
||||
"passive" to getString(R.string.bark_level_passive)
|
||||
)
|
||||
|
||||
//发送通道
|
||||
const val TYPE_DINGTALK_GROUP_ROBOT = 0
|
||||
const val TYPE_EMAIL = 1
|
||||
const val TYPE_BARK = 2
|
||||
const val TYPE_WEBHOOK = 3
|
||||
const val TYPE_WEWORK_ROBOT = 4
|
||||
const val TYPE_WEWORK_AGENT = 5
|
||||
const val TYPE_SERVERCHAN = 6
|
||||
const val TYPE_TELEGRAM = 7
|
||||
const val TYPE_SMS = 8
|
||||
const val TYPE_FEISHU = 9
|
||||
const val TYPE_PUSHPLUS = 10
|
||||
const val TYPE_GOTIFY = 11
|
||||
const val TYPE_DINGTALK_INNER_ROBOT = 12
|
||||
const val TYPE_FEISHU_APP = 13
|
||||
var SENDER_FRAGMENT_LIST = listOf(
|
||||
PageInfo(
|
||||
getString(R.string.dingtalk_robot),
|
||||
"com.idormy.sms.forwarder.fragment.senders.DingtalkGroupRobotFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_dingtalk
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.email),
|
||||
"com.idormy.sms.forwarder.fragment.senders.EmailFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_email
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.bark),
|
||||
"com.idormy.sms.forwarder.fragment.senders.BarkFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_bark
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.webhook),
|
||||
"com.idormy.sms.forwarder.fragment.senders.WebhookFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_webhook
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.wework_robot),
|
||||
"com.idormy.sms.forwarder.fragment.senders.WeworkRobotFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_wework_robot
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.wework_agent),
|
||||
"com.idormy.sms.forwarder.fragment.senders.WeworkAgentFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_wework_agent
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.server_chan),
|
||||
"com.idormy.sms.forwarder.fragment.senders.ServerchanFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_serverchan
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.telegram),
|
||||
"com.idormy.sms.forwarder.fragment.senders.TelegramFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_telegram
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.sms_menu),
|
||||
"com.idormy.sms.forwarder.fragment.senders.SmsFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_sms
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.feishu),
|
||||
"com.idormy.sms.forwarder.fragment.senders.FeishuFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_feishu
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.pushplus),
|
||||
"com.idormy.sms.forwarder.fragment.senders.PushplusFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_pushplus
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.gotify),
|
||||
"com.idormy.sms.forwarder.fragment.senders.GotifyFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_gotify
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.dingtalk_inner_robot),
|
||||
"com.idormy.sms.forwarder.fragment.senders.DingtalkInnerRobotFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_dingtalk_inner
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.feishu_app),
|
||||
"com.idormy.sms.forwarder.fragment.senders.FeishuAppFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_feishu_app
|
||||
),
|
||||
)
|
||||
|
||||
//前台服务
|
||||
const val FRONT_NOTIFY_ID = 0x1010
|
||||
const val FRONT_CHANNEL_ID = "com.idormy.sms.forwarder"
|
||||
const val FRONT_CHANNEL_NAME = "SmsForwarder Foreground Service"
|
||||
|
||||
//Frp内网穿透
|
||||
const val FRPC_LIB_DOWNLOAD_URL = "https://xupdate.ppps.cn/uploads/%s/%s/libgojni.so"
|
||||
const val FRPC_LIB_VERSION = "0.44.0"
|
||||
const val EVENT_FRPC_UPDATE_CONFIG = "EVENT_FRPC_UPDATE_CONFIG"
|
||||
const val EVENT_FRPC_DELETE_CONFIG = "EVENT_FRPC_DELETE_CONFIG"
|
||||
const val EVENT_FRPC_RUNNING_ERROR = "EVENT_FRPC_RUNNING_ERROR"
|
||||
const val EVENT_FRPC_RUNNING_SUCCESS = "EVENT_FRPC_RUNNING_SUCCESS"
|
||||
const val INTENT_FRPC_EDIT_FILE = "INTENT_FRPC_EDIT_FILE"
|
||||
const val INTENT_FRPC_APPLY_FILE = "INTENT_FRPC_APPLY_FILE"
|
||||
|
||||
//来电监听
|
||||
const val ACTION_CALL_IN = "android.intent.action.PHONE_STATE"
|
||||
const val ACTION_CALL_OUT = "android.intent.action.NEW_OUTGOING_CALL"
|
||||
const val EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"
|
||||
|
||||
//Markdown 查看页面
|
||||
const val KEY_TITLE = "key_title"
|
||||
const val KEY_URL = "key_url"
|
||||
|
||||
//主页监听时间
|
||||
const val EVENT_UPDATE_LOGS_TYPE = "key_logs_type"
|
||||
const val EVENT_UPDATE_RULE_TYPE = "key_status"
|
||||
const val EVENT_UPDATE_NOTIFY = "key_notify"
|
||||
|
||||
const val KEY_SENDER_ID = "key_sender_id"
|
||||
const val KEY_SENDER_TYPE = "key_sender_type"
|
||||
const val KEY_SENDER_CLONE = "key_sender_clone"
|
||||
const val KEY_SENDER_TEST = "key_sender_test"
|
||||
|
||||
const val KEY_RULE_ID = "key_rule_id"
|
||||
const val KEY_RULE_TYPE = "key_rule_type"
|
||||
const val KEY_RULE_CLONE = "key_rule_clone"
|
||||
|
||||
const val EVENT_KEY_SIM_SLOT = "EVENT_KEY_SIM_SLOT"
|
||||
const val EVENT_KEY_PHONE_NUMBERS = "EVENT_KEY_PHONE_NUMBERS"
|
||||
|
||||
//在线升级URL
|
||||
const val KEY_UPDATE_URL = "https://xupdate.ppps.cn/update/checkVersion"
|
||||
|
||||
//HttpServer相关
|
||||
const val ENABLE_HTTP_SERVER = "enable_http_server"
|
||||
const val HTTP_SERVER_PORT = 5000
|
||||
const val HTTP_SERVER_TIME_OUT = 10
|
||||
const val HTTP_SERVER_NOTIFY_ID = 0x1011
|
||||
const val HTTP_SERVER_CHANNEL_ID = "http_server_notification_channel"
|
||||
const val HTTP_SERVER_CHANNEL_NAME = "Http-Server Service"
|
||||
const val START_ACTION = "start"
|
||||
const val STOP_ACTION = "stop"
|
||||
const val HTTP_SUCCESS_CODE: Int = 200
|
||||
const val HTTP_FAILURE_CODE: Int = 500
|
||||
const val SP_ENABLE_SERVER = "enable_server"
|
||||
const val SP_ENABLE_SERVER_AUTORUN = "enable_server_autorun"
|
||||
const val SP_SERVER_SAFETY_MEASURES = "server_safety_measures"
|
||||
const val SP_SERVER_SIGN_KEY = "server_sign_key"
|
||||
const val SP_SERVER_TIME_TOLERANCE = "server_time_tolerance"
|
||||
const val SP_SERVER_SM4_KEY = "server_sm4_key"
|
||||
const val SP_SERVER_PUBLIC_KEY = "server_public_key"
|
||||
const val SP_SERVER_PRIVATE_KEY = "server_private_key"
|
||||
const val SP_SERVER_WEB_PATH = "server_web_path"
|
||||
const val SP_ENABLE_API_CLONE = "enable_api_clone"
|
||||
const val SP_ENABLE_API_SMS_SEND = "enable_api_sms_send"
|
||||
const val SP_ENABLE_API_SMS_QUERY = "enable_api_sms_query"
|
||||
const val SP_ENABLE_API_CALL_QUERY = "enable_api_call_query"
|
||||
const val SP_ENABLE_API_CONTACT_QUERY = "enable_api_contact_query"
|
||||
const val SP_ENABLE_API_BATTERY_QUERY = "enable_api_battery_query"
|
||||
const val SP_ENABLE_API_WOL = "enable_api_wol"
|
||||
const val SP_WOL_HISTORY = "wol_history"
|
||||
const val SP_SERVER_ADDRESS = "server_address"
|
||||
const val SP_SERVER_HISTORY = "server_history"
|
||||
const val SP_SERVER_CONFIG = "server_config"
|
||||
const val SP_CLIENT_SAFETY_MEASURES = "client_safety_measures"
|
||||
const val SP_CLIENT_SIGN_KEY = "client_sign_key"
|
||||
|
||||
var CLIENT_FRAGMENT_LIST = listOf(
|
||||
PageInfo(
|
||||
getString(R.string.api_clone),
|
||||
"com.idormy.sms.forwarder.fragment.client.CloneFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_clone
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_sms_send),
|
||||
"com.idormy.sms.forwarder.fragment.client.SmsSendFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_sms_send
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_sms_query),
|
||||
"com.idormy.sms.forwarder.fragment.client.SmsQueryFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_sms_query
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_call_query),
|
||||
"com.idormy.sms.forwarder.fragment.client.CallQueryFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_call_query
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_contact_query),
|
||||
"com.idormy.sms.forwarder.fragment.client.ContactQueryFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_contact_query
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_battery_query),
|
||||
"com.idormy.sms.forwarder.fragment.client.BatteryQueryFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_battery_query
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_wol),
|
||||
"com.idormy.sms.forwarder.fragment.client.WolSendFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_wol
|
||||
),
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.idormy.sms.forwarder.utils
|
||||
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.xuexiang.xpage.enums.CoreAnim
|
||||
import com.xuexiang.xpage.model.PageInfo
|
||||
import com.xuexiang.xui.utils.ResUtils.getString
|
||||
|
||||
object Worker {
|
||||
const val sendMsgInfo = "send_msg_info"
|
||||
const val sendLogId = "send_log_id"
|
||||
const val sendSbnId = "send_sbn_id"
|
||||
const val updateLogs = "update_logs"
|
||||
}
|
||||
|
||||
//初始化相关
|
||||
const val IS_FIRST_OPEN_KEY = "is_first_open_key"
|
||||
const val IS_AGREE_PRIVACY_KEY = "is_agree_privacy_key"
|
||||
|
||||
//数据库
|
||||
const val DATABASE_NAME = "sms_forwarder.db"
|
||||
const val PACKAGE_NAME = "com.idormy.sms.forwarder"
|
||||
|
||||
//通用设置
|
||||
const val SP_ENABLE_SMS = "enable_sms"
|
||||
|
||||
const val SP_ENABLE_PHONE = "enable_phone"
|
||||
const val SP_ENABLE_CALL_TYPE_1 = "enable_call_type_1"
|
||||
const val SP_ENABLE_CALL_TYPE_2 = "enable_call_type_2"
|
||||
const val SP_ENABLE_CALL_TYPE_3 = "enable_call_type_3"
|
||||
const val SP_ENABLE_CALL_TYPE_4 = "enable_call_type_4"
|
||||
|
||||
const val SP_ENABLE_APP_NOTIFY = "enable_app_notify"
|
||||
const val SP_ENABLE_CANCEL_APP_NOTIFY = "enable_cancel_app_notify"
|
||||
const val SP_ENABLE_NOT_USER_PRESENT = "enable_not_user_present"
|
||||
|
||||
const val ENABLE_LOAD_APP_LIST = "enable_load_app_list"
|
||||
const val ENABLE_LOAD_USER_APP_LIST = "enable_load_user_app_list"
|
||||
const val ENABLE_LOAD_SYSTEM_APP_LIST = "enable_load_system_app_list"
|
||||
|
||||
const val SP_DUPLICATE_MESSAGES_LIMITS = "duplicate_messages_limits"
|
||||
const val SP_SILENT_PERIOD_START = "silent_period_start"
|
||||
const val SP_SILENT_PERIOD_END = "silent_period_end"
|
||||
const val SP_AUTO_CLEAN_LOGS_DAYS = "auto_clean_logs_days"
|
||||
|
||||
const val SP_BATTERY_RECEIVER = "enable_battery_receiver"
|
||||
const val SP_BATTERY_STATUS = "battery_status"
|
||||
const val SP_BATTERY_LEVEL_MIN = "battery_level_min"
|
||||
const val SP_BATTERY_LEVEL_MAX = "battery_level_max"
|
||||
const val SP_BATTERY_LEVEL_ONCE = "battery_level_once"
|
||||
const val SP_BATTERY_LEVEL_CURRENT = "battery_level_current"
|
||||
|
||||
const val SP_BATTERY_CRON = "enable_battery_cron"
|
||||
const val SP_BATTERY_CRON_START_TIME = "battery_cron_start_time"
|
||||
const val SP_BATTERY_CRON_INTERVAL = "battery_cron_interval"
|
||||
|
||||
const val SP_ENABLE_EXCLUDE_FROM_RECENTS = "enable_exclude_from_recents"
|
||||
const val SP_ENABLE_PLAY_SILENCE_MUSIC = "enable_play_silence_music"
|
||||
const val SP_ENABLE_ONE_PIXEL_ACTIVITY = "enable_one_pixel_activity"
|
||||
|
||||
const val SP_REQUEST_RETRY_TIMES = "request_retry_times"
|
||||
const val SP_REQUEST_DELAY_TIME = "request_delay_time"
|
||||
const val SP_REQUEST_TIMEOUT = "request_timeout"
|
||||
|
||||
const val SP_NOTIFY_CONTENT = "notify_content"
|
||||
const val SP_EXTRA_DEVICE_MARK = "extra_device_mark"
|
||||
const val SP_SUBID_SIM1 = "subid_sim1"
|
||||
const val SP_SUBID_SIM2 = "subid_sim2"
|
||||
const val SP_EXTRA_SIM1 = "extra_sim1"
|
||||
const val SP_EXTRA_SIM2 = "extra_sim2"
|
||||
const val SP_ENABLE_SMS_TEMPLATE = "enable_sms_template"
|
||||
const val SP_SMS_TEMPLATE = "sms_template"
|
||||
|
||||
const val SP_ENABLE_HELP_TIP = "enable_help_tip"
|
||||
const val SP_PURE_CLIENT_MODE = "enable_pure_client_mode"
|
||||
|
||||
const val SP_ENABLE_CACTUS = "enable_cactus"
|
||||
const val CACTUS_TIMER = "cactus_timer"
|
||||
const val CACTUS_LAST_TIMER = "cactus_last_timer"
|
||||
const val CACTUS_DATE = "cactus_date"
|
||||
const val CACTUS_END_DATE = "cactus_end_date"
|
||||
|
||||
//OkHttp 请求超时时间
|
||||
const val REQUEST_TIMEOUT_SECONDS = 5
|
||||
|
||||
//规则相关
|
||||
const val STATUS_ON = 1
|
||||
const val STATUS_OFF = 0
|
||||
const val FILED_TRANSPOND_ALL = "transpond_all"
|
||||
const val FILED_PHONE_NUM = "phone_num"
|
||||
const val FILED_PACKAGE_NAME = "package_name"
|
||||
const val FILED_MSG_CONTENT = "msg_content"
|
||||
const val FILED_INFORM_CONTENT = "inform_content"
|
||||
const val FILED_MULTI_MATCH = "multi_match"
|
||||
const val CHECK_IS = "is"
|
||||
const val CHECK_CONTAIN = "contain"
|
||||
const val CHECK_NOT_CONTAIN = "notcontain"
|
||||
const val CHECK_START_WITH = "startwith"
|
||||
const val CHECK_END_WITH = "endwith"
|
||||
const val CHECK_NOT_IS = "notis"
|
||||
const val CHECK_REGEX = "regex"
|
||||
const val CHECK_SIM_SLOT_ALL = "ALL"
|
||||
const val CHECK_SIM_SLOT_1 = "SIM1"
|
||||
const val CHECK_SIM_SLOT_2 = "SIM2"
|
||||
val TYPE_MAP = object : HashMap<String, String>() {
|
||||
init {
|
||||
put("sms", getString(R.string.rule_sms))
|
||||
put("call", getString(R.string.rule_call))
|
||||
put("app", getString(R.string.rule_app))
|
||||
}
|
||||
}
|
||||
val FILED_MAP = object : HashMap<String, String>() {
|
||||
init {
|
||||
put("transpond_all", getString(R.string.rule_transpond_all))
|
||||
put("phone_num", getString(R.string.rule_phone_num))
|
||||
put("msg_content", getString(R.string.rule_msg_content))
|
||||
put("multi_match", getString(R.string.rule_multi_match))
|
||||
put("package_name", getString(R.string.rule_package_name))
|
||||
put("inform_content", getString(R.string.rule_inform_content))
|
||||
}
|
||||
}
|
||||
val CHECK_MAP = object : HashMap<String, String>() {
|
||||
init {
|
||||
put("is", getString(R.string.rule_is))
|
||||
put("notis", getString(R.string.rule_notis))
|
||||
put("contain", getString(R.string.rule_contain))
|
||||
put("startwith", getString(R.string.rule_startwith))
|
||||
put("endwith", getString(R.string.rule_endwith))
|
||||
put("notcontain", getString(R.string.rule_notcontain))
|
||||
put("regex", getString(R.string.rule_regex))
|
||||
}
|
||||
}
|
||||
val SIM_SLOT_MAP = object : HashMap<String, String>() {
|
||||
init {
|
||||
put("ALL", getString(R.string.rule_all))
|
||||
put("SIM1", "SIM1")
|
||||
put("SIM2", "SIM2")
|
||||
}
|
||||
}
|
||||
val FORWARD_STATUS_MAP = object : HashMap<Int, String>() {
|
||||
init {
|
||||
put(0, getString(R.string.failed))
|
||||
put(1, getString(R.string.processing))
|
||||
put(2, getString(R.string.success))
|
||||
}
|
||||
}
|
||||
val BARK_LEVEL_MAP = mapOf(
|
||||
"active" to getString(R.string.bark_level_active),
|
||||
"timeSensitive" to getString(R.string.bark_level_timeSensitive),
|
||||
"passive" to getString(R.string.bark_level_passive)
|
||||
)
|
||||
|
||||
//发送通道
|
||||
const val TYPE_DINGTALK_GROUP_ROBOT = 0
|
||||
const val TYPE_EMAIL = 1
|
||||
const val TYPE_BARK = 2
|
||||
const val TYPE_WEBHOOK = 3
|
||||
const val TYPE_WEWORK_ROBOT = 4
|
||||
const val TYPE_WEWORK_AGENT = 5
|
||||
const val TYPE_SERVERCHAN = 6
|
||||
const val TYPE_TELEGRAM = 7
|
||||
const val TYPE_SMS = 8
|
||||
const val TYPE_FEISHU = 9
|
||||
const val TYPE_PUSHPLUS = 10
|
||||
const val TYPE_GOTIFY = 11
|
||||
const val TYPE_DINGTALK_INNER_ROBOT = 12
|
||||
const val TYPE_FEISHU_APP = 13
|
||||
var SENDER_FRAGMENT_LIST = listOf(
|
||||
PageInfo(
|
||||
getString(R.string.dingtalk_robot),
|
||||
"com.idormy.sms.forwarder.fragment.senders.DingtalkGroupRobotFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_dingtalk
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.email),
|
||||
"com.idormy.sms.forwarder.fragment.senders.EmailFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_email
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.bark),
|
||||
"com.idormy.sms.forwarder.fragment.senders.BarkFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_bark
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.webhook),
|
||||
"com.idormy.sms.forwarder.fragment.senders.WebhookFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_webhook
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.wework_robot),
|
||||
"com.idormy.sms.forwarder.fragment.senders.WeworkRobotFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_wework_robot
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.wework_agent),
|
||||
"com.idormy.sms.forwarder.fragment.senders.WeworkAgentFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_wework_agent
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.server_chan),
|
||||
"com.idormy.sms.forwarder.fragment.senders.ServerchanFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_serverchan
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.telegram),
|
||||
"com.idormy.sms.forwarder.fragment.senders.TelegramFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_telegram
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.sms_menu),
|
||||
"com.idormy.sms.forwarder.fragment.senders.SmsFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_sms
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.feishu),
|
||||
"com.idormy.sms.forwarder.fragment.senders.FeishuFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_feishu
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.pushplus),
|
||||
"com.idormy.sms.forwarder.fragment.senders.PushplusFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_pushplus
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.gotify),
|
||||
"com.idormy.sms.forwarder.fragment.senders.GotifyFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_gotify
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.dingtalk_inner_robot),
|
||||
"com.idormy.sms.forwarder.fragment.senders.DingtalkInnerRobotFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_dingtalk_inner
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.feishu_app),
|
||||
"com.idormy.sms.forwarder.fragment.senders.FeishuAppFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_feishu_app
|
||||
),
|
||||
)
|
||||
|
||||
//前台服务
|
||||
const val FRONT_NOTIFY_ID = 0x1010
|
||||
const val FRONT_CHANNEL_ID = "com.idormy.sms.forwarder"
|
||||
const val FRONT_CHANNEL_NAME = "SmsForwarder Foreground Service"
|
||||
|
||||
//Frp内网穿透
|
||||
const val FRPC_LIB_DOWNLOAD_URL = "https://xupdate.ppps.cn/uploads/%s/%s/libgojni.so"
|
||||
const val FRPC_LIB_VERSION = "0.44.0"
|
||||
const val EVENT_FRPC_UPDATE_CONFIG = "EVENT_FRPC_UPDATE_CONFIG"
|
||||
const val EVENT_FRPC_DELETE_CONFIG = "EVENT_FRPC_DELETE_CONFIG"
|
||||
const val EVENT_FRPC_RUNNING_ERROR = "EVENT_FRPC_RUNNING_ERROR"
|
||||
const val EVENT_FRPC_RUNNING_SUCCESS = "EVENT_FRPC_RUNNING_SUCCESS"
|
||||
const val INTENT_FRPC_EDIT_FILE = "INTENT_FRPC_EDIT_FILE"
|
||||
const val INTENT_FRPC_APPLY_FILE = "INTENT_FRPC_APPLY_FILE"
|
||||
|
||||
//来电监听
|
||||
const val ACTION_CALL_IN = "android.intent.action.PHONE_STATE"
|
||||
const val ACTION_CALL_OUT = "android.intent.action.NEW_OUTGOING_CALL"
|
||||
const val EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"
|
||||
|
||||
//Markdown 查看页面
|
||||
const val KEY_TITLE = "key_title"
|
||||
const val KEY_URL = "key_url"
|
||||
|
||||
//主页监听时间
|
||||
const val EVENT_UPDATE_LOGS_TYPE = "key_logs_type"
|
||||
const val EVENT_UPDATE_RULE_TYPE = "key_status"
|
||||
const val EVENT_UPDATE_NOTIFY = "key_notify"
|
||||
|
||||
const val KEY_SENDER_ID = "key_sender_id"
|
||||
const val KEY_SENDER_TYPE = "key_sender_type"
|
||||
const val KEY_SENDER_CLONE = "key_sender_clone"
|
||||
const val KEY_SENDER_TEST = "key_sender_test"
|
||||
|
||||
const val KEY_RULE_ID = "key_rule_id"
|
||||
const val KEY_RULE_TYPE = "key_rule_type"
|
||||
const val KEY_RULE_CLONE = "key_rule_clone"
|
||||
|
||||
const val EVENT_KEY_SIM_SLOT = "EVENT_KEY_SIM_SLOT"
|
||||
const val EVENT_KEY_PHONE_NUMBERS = "EVENT_KEY_PHONE_NUMBERS"
|
||||
|
||||
//在线升级URL
|
||||
const val KEY_UPDATE_URL = "https://xupdate.ppps.cn/update/checkVersion"
|
||||
|
||||
//HttpServer相关
|
||||
const val ENABLE_HTTP_SERVER = "enable_http_server"
|
||||
const val HTTP_SERVER_PORT = 5000
|
||||
const val HTTP_SERVER_TIME_OUT = 10
|
||||
const val HTTP_SERVER_NOTIFY_ID = 0x1011
|
||||
const val HTTP_SERVER_CHANNEL_ID = "http_server_notification_channel"
|
||||
const val HTTP_SERVER_CHANNEL_NAME = "Http-Server Service"
|
||||
const val START_ACTION = "start"
|
||||
const val STOP_ACTION = "stop"
|
||||
const val HTTP_SUCCESS_CODE: Int = 200
|
||||
const val HTTP_FAILURE_CODE: Int = 500
|
||||
const val SP_ENABLE_SERVER = "enable_server"
|
||||
const val SP_ENABLE_SERVER_AUTORUN = "enable_server_autorun"
|
||||
const val SP_SERVER_SAFETY_MEASURES = "server_safety_measures"
|
||||
const val SP_SERVER_SIGN_KEY = "server_sign_key"
|
||||
const val SP_SERVER_TIME_TOLERANCE = "server_time_tolerance"
|
||||
const val SP_SERVER_SM4_KEY = "server_sm4_key"
|
||||
const val SP_SERVER_PUBLIC_KEY = "server_public_key"
|
||||
const val SP_SERVER_PRIVATE_KEY = "server_private_key"
|
||||
const val SP_SERVER_WEB_PATH = "server_web_path"
|
||||
const val SP_ENABLE_API_CLONE = "enable_api_clone"
|
||||
const val SP_ENABLE_API_SMS_SEND = "enable_api_sms_send"
|
||||
const val SP_ENABLE_API_SMS_QUERY = "enable_api_sms_query"
|
||||
const val SP_ENABLE_API_CALL_QUERY = "enable_api_call_query"
|
||||
const val SP_ENABLE_API_CONTACT_QUERY = "enable_api_contact_query"
|
||||
const val SP_ENABLE_API_BATTERY_QUERY = "enable_api_battery_query"
|
||||
const val SP_ENABLE_API_WOL = "enable_api_wol"
|
||||
const val SP_WOL_HISTORY = "wol_history"
|
||||
const val SP_SERVER_ADDRESS = "server_address"
|
||||
const val SP_SERVER_HISTORY = "server_history"
|
||||
const val SP_SERVER_CONFIG = "server_config"
|
||||
const val SP_CLIENT_SAFETY_MEASURES = "client_safety_measures"
|
||||
const val SP_CLIENT_SIGN_KEY = "client_sign_key"
|
||||
|
||||
var CLIENT_FRAGMENT_LIST = listOf(
|
||||
PageInfo(
|
||||
getString(R.string.api_clone),
|
||||
"com.idormy.sms.forwarder.fragment.client.CloneFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_clone
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_sms_send),
|
||||
"com.idormy.sms.forwarder.fragment.client.SmsSendFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_sms_send
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_sms_query),
|
||||
"com.idormy.sms.forwarder.fragment.client.SmsQueryFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_sms_query
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_call_query),
|
||||
"com.idormy.sms.forwarder.fragment.client.CallQueryFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_call_query
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_contact_query),
|
||||
"com.idormy.sms.forwarder.fragment.client.ContactQueryFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_contact_query
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_battery_query),
|
||||
"com.idormy.sms.forwarder.fragment.client.BatteryQueryFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_battery_query
|
||||
),
|
||||
PageInfo(
|
||||
getString(R.string.api_wol),
|
||||
"com.idormy.sms.forwarder.fragment.client.WolSendFragment",
|
||||
"{\"\":\"\"}",
|
||||
CoreAnim.slide,
|
||||
R.drawable.icon_api_wol
|
||||
),
|
||||
)
|
File diff suppressed because it is too large
Load Diff
@ -114,6 +114,12 @@ class SettingUtils private constructor() {
|
||||
//设备名称
|
||||
var extraDeviceMark: String by SharedPreference(SP_EXTRA_DEVICE_MARK, "")
|
||||
|
||||
//SM1主键
|
||||
var subidSim1: Int by SharedPreference(SP_SUBID_SIM1, 0)
|
||||
|
||||
//SM2主键
|
||||
var subidSim2: Int by SharedPreference(SP_SUBID_SIM2, 0)
|
||||
|
||||
//SM1备注
|
||||
var extraSim1: String by SharedPreference(SP_EXTRA_SIM1, "")
|
||||
|
||||
|
@ -1,74 +1,74 @@
|
||||
package com.idormy.sms.forwarder.utils.sender
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import com.idormy.sms.forwarder.App
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.database.entity.Rule
|
||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||
import com.idormy.sms.forwarder.entity.setting.SmsSetting
|
||||
import com.idormy.sms.forwarder.utils.PhoneUtils
|
||||
import com.idormy.sms.forwarder.utils.SendUtils
|
||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||
import com.xuexiang.xui.utils.ResUtils
|
||||
import com.xuexiang.xutil.XUtil
|
||||
import com.xuexiang.xutil.net.NetworkUtils
|
||||
|
||||
@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused")
|
||||
class SmsUtils {
|
||||
companion object {
|
||||
|
||||
private val TAG: String = SmsUtils::class.java.simpleName
|
||||
|
||||
fun sendMsg(
|
||||
setting: SmsSetting,
|
||||
msgInfo: MsgInfo,
|
||||
rule: Rule?,
|
||||
logId: Long?,
|
||||
) {
|
||||
//仅当无网络时启用 && 判断是否真实有网络
|
||||
if (setting.onlyNoNetwork == true && NetworkUtils.isHaveInternet() && NetworkUtils.isAvailableByPing()) {
|
||||
SendUtils.updateLogs(logId, 0, ResUtils.getString(R.string.OnlyNoNetwork))
|
||||
return
|
||||
}
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(XUtil.getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
|
||||
SendUtils.updateLogs(logId, 0, ResUtils.getString(R.string.no_sms_sending_permission))
|
||||
return
|
||||
}
|
||||
|
||||
val content: String = if (rule != null) {
|
||||
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)
|
||||
} else {
|
||||
msgInfo.getContentForSend(SettingUtils.smsTemplate.toString())
|
||||
}
|
||||
|
||||
//【注意】判断卡槽配置:0=原进原出、1=卡槽1、2=卡槽2
|
||||
val simSlotIndex = if (setting.simSlot == 0) msgInfo.simSlot else setting.simSlot - 1
|
||||
|
||||
//获取卡槽信息
|
||||
if (App.SimInfoList.isEmpty()) {
|
||||
App.SimInfoList = PhoneUtils.getSimMultiInfo()
|
||||
}
|
||||
Log.d(TAG, App.SimInfoList.toString())
|
||||
|
||||
//替换 {{来源号码}} 标签
|
||||
val mobiles = setting.mobiles.replace(ResUtils.getString(R.string.tag_from), msgInfo.from)
|
||||
|
||||
//TODO:取不到卡槽信息时,采用默认卡槽发送
|
||||
val mSubscriptionId: Int = App.SimInfoList[simSlotIndex]?.mSubscriptionId ?: -1
|
||||
val res: String? = PhoneUtils.sendSms(mSubscriptionId, mobiles, content)
|
||||
if (res == null) {
|
||||
SendUtils.updateLogs(logId, 2, ResUtils.getString(R.string.request_succeeded))
|
||||
} else {
|
||||
SendUtils.updateLogs(logId, 0, res)
|
||||
}
|
||||
}
|
||||
|
||||
fun sendMsg(setting: SmsSetting, msgInfo: MsgInfo) {
|
||||
sendMsg(setting, msgInfo, null, null)
|
||||
}
|
||||
}
|
||||
package com.idormy.sms.forwarder.utils.sender
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import com.idormy.sms.forwarder.App
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.database.entity.Rule
|
||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||
import com.idormy.sms.forwarder.entity.setting.SmsSetting
|
||||
import com.idormy.sms.forwarder.utils.PhoneUtils
|
||||
import com.idormy.sms.forwarder.utils.SendUtils
|
||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||
import com.xuexiang.xui.utils.ResUtils
|
||||
import com.xuexiang.xutil.XUtil
|
||||
import com.xuexiang.xutil.net.NetworkUtils
|
||||
|
||||
@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused")
|
||||
class SmsUtils {
|
||||
companion object {
|
||||
|
||||
private val TAG: String = SmsUtils::class.java.simpleName
|
||||
|
||||
fun sendMsg(
|
||||
setting: SmsSetting,
|
||||
msgInfo: MsgInfo,
|
||||
rule: Rule?,
|
||||
logId: Long?,
|
||||
) {
|
||||
//仅当无网络时启用 && 判断是否真实有网络
|
||||
if (setting.onlyNoNetwork == true && NetworkUtils.isHaveInternet() && NetworkUtils.isAvailableByPing()) {
|
||||
SendUtils.updateLogs(logId, 0, ResUtils.getString(R.string.OnlyNoNetwork))
|
||||
return
|
||||
}
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(XUtil.getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
|
||||
SendUtils.updateLogs(logId, 0, ResUtils.getString(R.string.no_sms_sending_permission))
|
||||
return
|
||||
}
|
||||
|
||||
val content: String = if (rule != null) {
|
||||
msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace)
|
||||
} else {
|
||||
msgInfo.getContentForSend(SettingUtils.smsTemplate)
|
||||
}
|
||||
|
||||
//【注意】判断卡槽配置:0=原进原出、1=卡槽1、2=卡槽2
|
||||
val simSlotIndex = if (setting.simSlot == 0) msgInfo.simSlot else setting.simSlot - 1
|
||||
|
||||
//获取卡槽信息
|
||||
if (App.SimInfoList.isEmpty()) {
|
||||
App.SimInfoList = PhoneUtils.getSimMultiInfo()
|
||||
}
|
||||
Log.d(TAG, App.SimInfoList.toString())
|
||||
|
||||
//替换 {{来源号码}} 标签
|
||||
val mobiles = setting.mobiles.replace(ResUtils.getString(R.string.tag_from), msgInfo.from)
|
||||
|
||||
//TODO:取不到卡槽信息时,采用默认卡槽发送
|
||||
val mSubscriptionId: Int = App.SimInfoList[simSlotIndex]?.mSubscriptionId ?: -1
|
||||
val res: String? = PhoneUtils.sendSms(mSubscriptionId, mobiles, content)
|
||||
if (res == null) {
|
||||
SendUtils.updateLogs(logId, 2, ResUtils.getString(R.string.request_succeeded))
|
||||
} else {
|
||||
SendUtils.updateLogs(logId, 0, res)
|
||||
}
|
||||
}
|
||||
|
||||
fun sendMsg(setting: SmsSetting, msgInfo: MsgInfo) {
|
||||
sendMsg(setting, msgInfo, null, null)
|
||||
}
|
||||
}
|
||||
}
|
@ -83,7 +83,7 @@ class SendWorker(
|
||||
for (rule in ruleList) {
|
||||
if (!rule.rule.checkMsg(msgInfo)) continue
|
||||
val log = Logs(
|
||||
0, msgInfo.type, msgInfo.from, msgInfo.content, rule.rule.id, msgInfo.simInfo
|
||||
0, msgInfo.type, msgInfo.from, msgInfo.content, rule.rule.id, msgInfo.simInfo, msgInfo.subId
|
||||
)
|
||||
val logId = Core.logs.insert(log)
|
||||
SendUtils.sendMsgSender(msgInfo, rule.rule, rule.sender, logId)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -334,9 +334,12 @@
|
||||
<!--SettingActivity-->
|
||||
<string name="notify_content">Notify Content</string>
|
||||
<string name="device_name">Device Name</string>
|
||||
<string name="sim1_remark" tools:ignore="Typos">SIM1 Label</string>
|
||||
<string name="sim2_remark" tools:ignore="Typos">SIM2 Label</string>
|
||||
<string name="sim_sub_id">SIM1 SubId</string>
|
||||
<string name="sim1_remark" tools:ignore="Typos">SIM1 SubId/Label</string>
|
||||
<string name="sim2_remark" tools:ignore="Typos">SIM2 SubId/Label</string>
|
||||
<string name="carrier_mobile" tools:ignore="Typos">Label of SIM,\neg. AT&T_88888888</string>
|
||||
<string name="tip_number_only_error_message">Number must be greater than 0!</string>
|
||||
<string name="regexp_number_only">^[1-9]?\\d+$</string>
|
||||
<string name="low_power_alarm_threshold">Low Power Alarm</string>
|
||||
<string name="low_power_alarm_threshold_tips">Value range: 0–99.\nLeft blank or 0 is disabled</string>
|
||||
<string name="retry_interval">Retry Interval</string>
|
||||
@ -543,6 +546,7 @@
|
||||
<string name="tag_app_name">{{APP_NAME}}</string>
|
||||
<string name="tag_msg">{{MSG}}</string>
|
||||
<string name="tag_card_slot">{{CARD_SLOT}}</string>
|
||||
<string name="tag_card_subid">{{CARD_SUBID}}</string>
|
||||
<string name="tag_receive_time">{{RECEIVE_TIME}}</string>
|
||||
<string name="tag_device_name">{{DEVICE_NAME}}</string>
|
||||
<string name="tag_app_version">{{APP_VERSION}}</string>
|
||||
|
@ -335,9 +335,12 @@
|
||||
<!--SettingActivity-->
|
||||
<string name="notify_content">通知文案</string>
|
||||
<string name="device_name">设备名称</string>
|
||||
<string name="sim1_remark" tools:ignore="Typos">SIM1备注</string>
|
||||
<string name="sim2_remark" tools:ignore="Typos">SIM2备注</string>
|
||||
<string name="carrier_mobile">运营商_手机号</string>
|
||||
<string name="sim_sub_id">卡槽主键</string>
|
||||
<string name="sim1_remark" tools:ignore="Typos">SIM1主键/备注</string>
|
||||
<string name="sim2_remark" tools:ignore="Typos">SIM2主键/备注</string>
|
||||
<string name="carrier_mobile">序号/运营商_手机号</string>
|
||||
<string name="tip_number_only_error_message">数字必须大于0!</string>
|
||||
<string name="regexp_number_only">^[1-9]?\\d+$</string>
|
||||
<string name="low_power_alarm_threshold">安全电量范围(%)</string>
|
||||
<string name="low_power_alarm_threshold_tips">超出安全范围将发出预警</string>
|
||||
<string name="retry_interval">请求重试机制</string>
|
||||
@ -544,6 +547,7 @@
|
||||
<string name="tag_app_name">{{APP名称}}</string>
|
||||
<string name="tag_msg">{{通知内容}}</string>
|
||||
<string name="tag_card_slot">{{卡槽信息}}</string>
|
||||
<string name="tag_card_subid">{{卡槽主键}}</string>
|
||||
<string name="tag_receive_time">{{接收时间}}</string>
|
||||
<string name="tag_device_name">{{设备名称}}</string>
|
||||
<string name="tag_app_version">{{当前应用版本号}}</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user