mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-02 17:07:41 +08:00
优化:来电转发逻辑 & 新增提醒类型(1.来电挂机 2.去电挂机 3.未接来电 4.来电提醒 5.来电接通 6.去电拨出)
This commit is contained in:
parent
b79d3d8493
commit
04d8c9015a
@ -242,11 +242,12 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".receiver.PhoneStateReceiver"
|
||||
android:name=".receiver.CallReceiver"
|
||||
android:exported="true"
|
||||
tools:ignore="IntentFilterExportedReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PHONE_STATE" />
|
||||
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
|
@ -13,7 +13,7 @@ data class CallInfo(
|
||||
var dateLong: Long = 0L,
|
||||
//获取通话时长,值为多少秒
|
||||
var duration: Int = 0,
|
||||
//通话类型:1=呼入, 2=呼出, 3=未接, 4=未接提醒
|
||||
//通话类型:1.来电挂机 2.去电挂机 3.未接来电 4.来电提醒 5.来电接通 6.去电拨出
|
||||
var type: Int = 1,
|
||||
//被呼号码
|
||||
@SerializedName("via_number")
|
||||
|
@ -1,82 +1,88 @@
|
||||
package com.idormy.sms.forwarder.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.idormy.sms.forwarder.database.entity.Frpc
|
||||
import com.idormy.sms.forwarder.database.entity.Rule
|
||||
import com.idormy.sms.forwarder.database.entity.Sender
|
||||
import java.io.Serializable
|
||||
|
||||
data class CloneInfo(
|
||||
@SerializedName("version_code")
|
||||
var versionCode: Int = 0,
|
||||
@SerializedName("version_name")
|
||||
var versionName: String? = null,
|
||||
@SerializedName("enable_sms")
|
||||
var enableSms: Boolean = false,
|
||||
@SerializedName("enable_phone")
|
||||
var enablePhone: Boolean = false,
|
||||
@SerializedName("call_type1")
|
||||
var callType1: Boolean = false,
|
||||
@SerializedName("call_type2")
|
||||
var callType2: Boolean = false,
|
||||
@SerializedName("call_type3")
|
||||
var callType3: Boolean = false,
|
||||
@SerializedName("enable_app_notify")
|
||||
var enableAppNotify: Boolean = false,
|
||||
@SerializedName("cancel_app_notify")
|
||||
var cancelAppNotify: Boolean = false,
|
||||
@SerializedName("enable_not_user_present")
|
||||
var enableNotUserPresent: Boolean = false,
|
||||
@SerializedName("enable_load_app_list")
|
||||
var enableLoadAppList: Boolean = false,
|
||||
@SerializedName("enable_load_user_app_list")
|
||||
var enableLoadUserAppList: Boolean = false,
|
||||
@SerializedName("enable_load_system_app_list")
|
||||
var enableLoadSystemAppList: Boolean = false,
|
||||
@SerializedName("duplicate_messages_limits")
|
||||
var duplicateMessagesLimits: Int = 0,
|
||||
@SerializedName("enable_battery_receiver")
|
||||
var enableBatteryReceiver: Boolean = false,
|
||||
@SerializedName("battery_level_min")
|
||||
var batteryLevelMin: Int = 0,
|
||||
@SerializedName("battery_level_max")
|
||||
var batteryLevelMax: Int = 0,
|
||||
@SerializedName("battery_level_once")
|
||||
var batteryLevelOnce: Boolean = false,
|
||||
@SerializedName("enable_battery_cron")
|
||||
var enableBatteryCron: Boolean = false,
|
||||
@SerializedName("battery_cron_start_time")
|
||||
var batteryCronStartTime: String? = null,
|
||||
@SerializedName("battery_cron_interval")
|
||||
var batteryCronInterval: Int = 0,
|
||||
@SerializedName("enable_exclude_from_recents")
|
||||
var enableExcludeFromRecents: Boolean = false,
|
||||
@SerializedName("enable_cactus")
|
||||
var enableCactus: Boolean = false,
|
||||
@SerializedName("enable_play_silence_music")
|
||||
var enablePlaySilenceMusic: Boolean = false,
|
||||
@SerializedName("enable_one_pixel_activity")
|
||||
var enableOnePixelActivity: Boolean = false,
|
||||
@SerializedName("request_retry_times")
|
||||
var requestRetryTimes: Int = 0,
|
||||
@SerializedName("request_delay_time")
|
||||
var requestDelayTime: Int = 0,
|
||||
@SerializedName("request_timeout")
|
||||
var requestTimeout: Int = 0,
|
||||
@SerializedName("notify_content")
|
||||
var notifyContent: String? = null,
|
||||
@SerializedName("enable_sms_template")
|
||||
var enableSmsTemplate: Boolean = false,
|
||||
@SerializedName("sms_template")
|
||||
var smsTemplate: String? = null,
|
||||
@SerializedName("enable_help_tip")
|
||||
var enableHelpTip: Boolean = false,
|
||||
@SerializedName("enable_pure_client_mode")
|
||||
var enablePureClientMode: Boolean = false,
|
||||
@SerializedName("sender_list")
|
||||
var senderList: List<Sender>? = null,
|
||||
@SerializedName("rule_list")
|
||||
var ruleList: List<Rule>? = null,
|
||||
@SerializedName("frpc_list")
|
||||
var frpcList: List<Frpc>? = null,
|
||||
package com.idormy.sms.forwarder.entity
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.idormy.sms.forwarder.database.entity.Frpc
|
||||
import com.idormy.sms.forwarder.database.entity.Rule
|
||||
import com.idormy.sms.forwarder.database.entity.Sender
|
||||
import java.io.Serializable
|
||||
|
||||
data class CloneInfo(
|
||||
@SerializedName("version_code")
|
||||
var versionCode: Int = 0,
|
||||
@SerializedName("version_name")
|
||||
var versionName: String? = null,
|
||||
@SerializedName("enable_sms")
|
||||
var enableSms: Boolean = false,
|
||||
@SerializedName("enable_phone")
|
||||
var enablePhone: Boolean = false,
|
||||
@SerializedName("call_type1")
|
||||
var callType1: Boolean = false,
|
||||
@SerializedName("call_type2")
|
||||
var callType2: Boolean = false,
|
||||
@SerializedName("call_type3")
|
||||
var callType3: Boolean = false,
|
||||
@SerializedName("call_type4")
|
||||
var callType4: Boolean = false,
|
||||
@SerializedName("call_type5")
|
||||
var callType5: Boolean = false,
|
||||
@SerializedName("call_type6")
|
||||
var callType6: Boolean = false,
|
||||
@SerializedName("enable_app_notify")
|
||||
var enableAppNotify: Boolean = false,
|
||||
@SerializedName("cancel_app_notify")
|
||||
var cancelAppNotify: Boolean = false,
|
||||
@SerializedName("enable_not_user_present")
|
||||
var enableNotUserPresent: Boolean = false,
|
||||
@SerializedName("enable_load_app_list")
|
||||
var enableLoadAppList: Boolean = false,
|
||||
@SerializedName("enable_load_user_app_list")
|
||||
var enableLoadUserAppList: Boolean = false,
|
||||
@SerializedName("enable_load_system_app_list")
|
||||
var enableLoadSystemAppList: Boolean = false,
|
||||
@SerializedName("duplicate_messages_limits")
|
||||
var duplicateMessagesLimits: Int = 0,
|
||||
@SerializedName("enable_battery_receiver")
|
||||
var enableBatteryReceiver: Boolean = false,
|
||||
@SerializedName("battery_level_min")
|
||||
var batteryLevelMin: Int = 0,
|
||||
@SerializedName("battery_level_max")
|
||||
var batteryLevelMax: Int = 0,
|
||||
@SerializedName("battery_level_once")
|
||||
var batteryLevelOnce: Boolean = false,
|
||||
@SerializedName("enable_battery_cron")
|
||||
var enableBatteryCron: Boolean = false,
|
||||
@SerializedName("battery_cron_start_time")
|
||||
var batteryCronStartTime: String? = null,
|
||||
@SerializedName("battery_cron_interval")
|
||||
var batteryCronInterval: Int = 0,
|
||||
@SerializedName("enable_exclude_from_recents")
|
||||
var enableExcludeFromRecents: Boolean = false,
|
||||
@SerializedName("enable_cactus")
|
||||
var enableCactus: Boolean = false,
|
||||
@SerializedName("enable_play_silence_music")
|
||||
var enablePlaySilenceMusic: Boolean = false,
|
||||
@SerializedName("enable_one_pixel_activity")
|
||||
var enableOnePixelActivity: Boolean = false,
|
||||
@SerializedName("request_retry_times")
|
||||
var requestRetryTimes: Int = 0,
|
||||
@SerializedName("request_delay_time")
|
||||
var requestDelayTime: Int = 0,
|
||||
@SerializedName("request_timeout")
|
||||
var requestTimeout: Int = 0,
|
||||
@SerializedName("notify_content")
|
||||
var notifyContent: String? = null,
|
||||
@SerializedName("enable_sms_template")
|
||||
var enableSmsTemplate: Boolean = false,
|
||||
@SerializedName("sms_template")
|
||||
var smsTemplate: String? = null,
|
||||
@SerializedName("enable_help_tip")
|
||||
var enableHelpTip: Boolean = false,
|
||||
@SerializedName("enable_pure_client_mode")
|
||||
var enablePureClientMode: Boolean = false,
|
||||
@SerializedName("sender_list")
|
||||
var senderList: List<Sender>? = null,
|
||||
@SerializedName("rule_list")
|
||||
var ruleList: List<Rule>? = null,
|
||||
@SerializedName("frpc_list")
|
||||
var frpcList: List<Frpc>? = null,
|
||||
) : Serializable
|
@ -80,7 +80,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
switchEnableSms(binding!!.sbEnableSms)
|
||||
//转发通话记录
|
||||
switchEnablePhone(
|
||||
binding!!.sbEnablePhone, binding!!.scbCallType1, binding!!.scbCallType2, binding!!.scbCallType3, binding!!.scbCallType4
|
||||
binding!!.sbEnablePhone, binding!!.scbCallType1, binding!!.scbCallType2, binding!!.scbCallType3, binding!!.scbCallType4, binding!!.scbCallType5, binding!!.scbCallType6
|
||||
)
|
||||
//转发应用通知
|
||||
switchEnableAppNotify(
|
||||
@ -304,15 +304,17 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
//转发通话
|
||||
@SuppressLint("UseSwitchCompatOrMaterialCode")
|
||||
fun switchEnablePhone(
|
||||
sbEnablePhone: SwitchButton, scbCallType1: SmoothCheckBox, scbCallType2: SmoothCheckBox, scbCallType3: SmoothCheckBox, scbCallType4: SmoothCheckBox
|
||||
sbEnablePhone: SwitchButton, scbCallType1: SmoothCheckBox, scbCallType2: SmoothCheckBox, scbCallType3: SmoothCheckBox, scbCallType4: SmoothCheckBox, scbCallType5: SmoothCheckBox, scbCallType6: SmoothCheckBox
|
||||
) {
|
||||
sbEnablePhone.isChecked = SettingUtils.enablePhone
|
||||
scbCallType1.isChecked = SettingUtils.enableCallType1
|
||||
scbCallType2.isChecked = SettingUtils.enableCallType2
|
||||
scbCallType3.isChecked = SettingUtils.enableCallType3
|
||||
scbCallType4.isChecked = SettingUtils.enableCallType4
|
||||
scbCallType5.isChecked = SettingUtils.enableCallType5
|
||||
scbCallType6.isChecked = SettingUtils.enableCallType6
|
||||
sbEnablePhone.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||
if (isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4) {
|
||||
if (isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4 && !SettingUtils.enableCallType5 && !SettingUtils.enableCallType6) {
|
||||
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||
SettingUtils.enablePhone = false
|
||||
sbEnablePhone.isChecked = false
|
||||
@ -354,7 +356,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
}
|
||||
scbCallType1.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||
SettingUtils.enableCallType1 = isChecked
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4) {
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4 && !SettingUtils.enableCallType5 && !SettingUtils.enableCallType6) {
|
||||
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||
SettingUtils.enablePhone = false
|
||||
sbEnablePhone.isChecked = false
|
||||
@ -362,7 +364,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
}
|
||||
scbCallType2.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||
SettingUtils.enableCallType2 = isChecked
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4) {
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4 && !SettingUtils.enableCallType5 && !SettingUtils.enableCallType6) {
|
||||
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||
SettingUtils.enablePhone = false
|
||||
sbEnablePhone.isChecked = false
|
||||
@ -370,7 +372,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
}
|
||||
scbCallType3.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||
SettingUtils.enableCallType3 = isChecked
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4) {
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4 && !SettingUtils.enableCallType5 && !SettingUtils.enableCallType6) {
|
||||
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||
SettingUtils.enablePhone = false
|
||||
sbEnablePhone.isChecked = false
|
||||
@ -378,7 +380,23 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
}
|
||||
scbCallType4.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||
SettingUtils.enableCallType4 = isChecked
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4) {
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4 && !SettingUtils.enableCallType5 && !SettingUtils.enableCallType6) {
|
||||
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||
SettingUtils.enablePhone = false
|
||||
sbEnablePhone.isChecked = false
|
||||
}
|
||||
}
|
||||
scbCallType5.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||
SettingUtils.enableCallType5 = isChecked
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4 && !SettingUtils.enableCallType5 && !SettingUtils.enableCallType6) {
|
||||
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||
SettingUtils.enablePhone = false
|
||||
sbEnablePhone.isChecked = false
|
||||
}
|
||||
}
|
||||
scbCallType6.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||
SettingUtils.enableCallType6 = isChecked
|
||||
if (!isChecked && !SettingUtils.enableCallType1 && !SettingUtils.enableCallType2 && !SettingUtils.enableCallType3 && !SettingUtils.enableCallType4 && !SettingUtils.enableCallType5 && !SettingUtils.enableCallType6) {
|
||||
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||
SettingUtils.enablePhone = false
|
||||
sbEnablePhone.isChecked = false
|
||||
|
@ -0,0 +1,151 @@
|
||||
package com.idormy.sms.forwarder.receiver
|
||||
|
||||
import android.content.Context
|
||||
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.R
|
||||
import com.idormy.sms.forwarder.entity.CallInfo
|
||||
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 com.xuexiang.xrouter.utils.TextUtils
|
||||
import com.xuexiang.xui.utils.ResUtils.getString
|
||||
import com.xuexiang.xutil.resource.ResUtils
|
||||
import java.util.*
|
||||
|
||||
open class CallReceiver : PhoneStateReceiver() {
|
||||
|
||||
companion object {
|
||||
private val TAG = CallReceiver::class.java.simpleName
|
||||
|
||||
//const val ACTION_IN = "android.intent.action.PHONE_STATE"
|
||||
const val ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL"
|
||||
const val EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER"
|
||||
}
|
||||
|
||||
//来电提醒
|
||||
override fun onIncomingCallReceived(context: Context, number: String?, start: Date) {
|
||||
Log.d(TAG, "onIncomingCallReceived:$number")
|
||||
sendNotice(context, 4, number)
|
||||
}
|
||||
|
||||
//来电接通
|
||||
override fun onIncomingCallAnswered(context: Context, number: String?, start: Date) {
|
||||
Log.d(TAG, "onIncomingCallAnswered:$number")
|
||||
sendNotice(context, 5, number)
|
||||
}
|
||||
|
||||
//来电挂机
|
||||
override fun onIncomingCallEnded(context: Context, number: String?, start: Date, end: Date) {
|
||||
Log.d(TAG, "onIncomingCallEnded:$number")
|
||||
sendCallMsg(context, 1, number)
|
||||
}
|
||||
|
||||
//去电拨出
|
||||
override fun onOutgoingCallStarted(context: Context, number: String?, start: Date) {
|
||||
Log.d(TAG, "onOutgoingCallStarted:$number")
|
||||
sendNotice(context, 6, number)
|
||||
}
|
||||
|
||||
//去电挂机
|
||||
override fun onOutgoingCallEnded(context: Context, number: String?, start: Date, end: Date) {
|
||||
Log.d(TAG, "onOutgoingCallEnded:$number")
|
||||
sendCallMsg(context, 2, number)
|
||||
}
|
||||
|
||||
//未接来电
|
||||
override fun onMissedCall(context: Context, number: String?, start: Date) {
|
||||
Log.d(TAG, "onMissedCall:$number")
|
||||
sendCallMsg(context, 3, number)
|
||||
}
|
||||
|
||||
//转发通话提醒
|
||||
private fun sendNotice(context: Context, callType: Int, phoneNumber: String?) {
|
||||
if (TextUtils.isEmpty(phoneNumber)) return
|
||||
|
||||
//判断是否开启该类型转发
|
||||
if ((callType == 4 && !SettingUtils.enableCallType4) || (callType == 5 && !SettingUtils.enableCallType5) || (callType == 6 && !SettingUtils.enableCallType6)) {
|
||||
Log.w(TAG, "未开启该类型转发,type=$callType")
|
||||
return
|
||||
}
|
||||
|
||||
val contacts = PhoneUtils.getContactByNumber(phoneNumber)
|
||||
val contactName = if (contacts.isNotEmpty()) contacts[0].name else getString(R.string.unknown_number)
|
||||
|
||||
val msg = StringBuilder()
|
||||
msg.append(getString(R.string.linkman)).append(contactName).append("\n")
|
||||
msg.append(getString(R.string.mandatory_type))
|
||||
//通话类型:1.来电挂机 2.去电挂机 3.未接来电 4.来电提醒 5.来电接通 6.去电拨出
|
||||
when (callType) {
|
||||
1 -> msg.append(ResUtils.getString(R.string.incoming_call_ended))
|
||||
2 -> msg.append(ResUtils.getString(R.string.outgoing_call_ended))
|
||||
3 -> msg.append(ResUtils.getString(R.string.missed_call))
|
||||
4 -> msg.append(ResUtils.getString(R.string.incoming_call_received))
|
||||
5 -> msg.append(ResUtils.getString(R.string.incoming_call_answered))
|
||||
6 -> msg.append(ResUtils.getString(R.string.outgoing_call_started))
|
||||
else -> msg.append(ResUtils.getString(R.string.unknown_call))
|
||||
}
|
||||
|
||||
val msgInfo = MsgInfo("call", phoneNumber.toString(), msg.toString(), Date(), "")
|
||||
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
|
||||
workDataOf(
|
||||
Worker.sendMsgInfo to Gson().toJson(msgInfo)
|
||||
)
|
||||
).build()
|
||||
WorkManager.getInstance(context).enqueue(request)
|
||||
}
|
||||
|
||||
//转发通话记录
|
||||
private fun sendCallMsg(context: Context, callType: Int, phoneNumber: String?) {
|
||||
//必须休眠才能获取来电记录,否则可能获取到上一次通话的
|
||||
Thread.sleep(1000)
|
||||
|
||||
//获取后一条通话记录
|
||||
Log.d(TAG, "callType = $callType, phoneNumber = $phoneNumber")
|
||||
val callInfo: CallInfo? = PhoneUtils.getLastCallInfo(callType, phoneNumber)
|
||||
Log.d(TAG, "callInfo = $callInfo")
|
||||
if (callInfo?.number == null) {
|
||||
Log.w(TAG, "查不到通话记录直接发通知")
|
||||
sendNotice(context, callType, phoneNumber)
|
||||
return
|
||||
}
|
||||
|
||||
//判断是否开启该类型转发
|
||||
if ((callInfo.type == 1 && !SettingUtils.enableCallType1) || (callInfo.type == 2 && !SettingUtils.enableCallType2) || (callInfo.type == 3 && !SettingUtils.enableCallType3)) {
|
||||
Log.w(TAG, "未开启该类型转发,type=" + callInfo.type)
|
||||
return
|
||||
}
|
||||
|
||||
//卡槽id:-1=获取失败、0=卡槽1、1=卡槽2
|
||||
val simSlot = callInfo.simId
|
||||
//获取卡槽信息
|
||||
val simInfo = when (simSlot) {
|
||||
0 -> "SIM1_" + SettingUtils.extraSim1
|
||||
1 -> "SIM2_" + SettingUtils.extraSim2
|
||||
else -> ""
|
||||
}
|
||||
|
||||
//获取联系人姓名
|
||||
if (TextUtils.isEmpty(callInfo.name)) {
|
||||
val contacts = PhoneUtils.getContactByNumber(phoneNumber)
|
||||
callInfo.name = if (contacts.isNotEmpty()) contacts[0].name else getString(R.string.unknown_number)
|
||||
}
|
||||
|
||||
val msgInfo = MsgInfo(
|
||||
"call", callInfo.number, PhoneUtils.getCallMsg(callInfo), Date(), simInfo, simSlot, callInfo.subId
|
||||
)
|
||||
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
|
||||
workDataOf(
|
||||
Worker.sendMsgInfo to Gson().toJson(msgInfo)
|
||||
)
|
||||
).build()
|
||||
WorkManager.getInstance(context).enqueue(request)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,178 +1,109 @@
|
||||
package com.idormy.sms.forwarder.receiver
|
||||
|
||||
import android.Manifest
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.telephony.TelephonyManager
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.workDataOf
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.entity.CallInfo
|
||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||
import com.idormy.sms.forwarder.utils.*
|
||||
import com.idormy.sms.forwarder.workers.SendWorker
|
||||
import com.xuexiang.xutil.resource.ResUtils.getString
|
||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||
import java.util.*
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
class PhoneStateReceiver : BroadcastReceiver() {
|
||||
abstract class PhoneStateReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
try {
|
||||
//纯客户端模式
|
||||
if (SettingUtils.enablePureClientMode) return
|
||||
|
||||
//总开关
|
||||
if (!SettingUtils.enablePhone) return
|
||||
//纯客户端模式
|
||||
if (SettingUtils.enablePureClientMode) return
|
||||
|
||||
//过滤广播
|
||||
if (TelephonyManager.ACTION_PHONE_STATE_CHANGED != intent.action) return
|
||||
//总开关
|
||||
if (!SettingUtils.enablePhone) return
|
||||
|
||||
//权限判断
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
context, Manifest.permission.READ_PHONE_STATE
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) return
|
||||
|
||||
//获取来电号码
|
||||
val number = intent.extras!!.getString(TelephonyManager.EXTRA_INCOMING_NUMBER)
|
||||
//We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number.
|
||||
if (intent.action == CallReceiver.ACTION_OUT) {
|
||||
savedNumber = intent.extras!!.getString(CallReceiver.EXTRA_PHONE_NUMBER)
|
||||
Log.d(TAG, "savedNumber:$savedNumber")
|
||||
} else {
|
||||
val stateStr = intent.extras!!.getString(TelephonyManager.EXTRA_STATE)
|
||||
val number = intent.extras!!.getString(TelephonyManager.EXTRA_INCOMING_NUMBER)
|
||||
savedNumber = number
|
||||
Log.d(TAG, "stateStr:$stateStr,savedNumber:$savedNumber")
|
||||
var state = 0
|
||||
|
||||
when (stateStr) {
|
||||
TelephonyManager.EXTRA_STATE_IDLE -> state = TelephonyManager.CALL_STATE_IDLE
|
||||
TelephonyManager.EXTRA_STATE_OFFHOOK -> state = TelephonyManager.CALL_STATE_OFFHOOK
|
||||
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()
|
||||
|
||||
//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())
|
||||
onCallStateChanged(context, state, number)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendReceiveCallMsg(context: Context, callType: Int, phoneNumber: String?) {
|
||||
//必须休眠才能获取来电记录,否则可能获取到上一次通话的
|
||||
Thread.sleep(500)
|
||||
//获取后一条通话记录
|
||||
Log.d(TAG, "callType = $callType, phoneNumber = $phoneNumber")
|
||||
val callInfo: CallInfo? = PhoneUtils.getLastCallInfo(callType, phoneNumber)
|
||||
Log.d(TAG, "callInfo = $callInfo")
|
||||
if (callInfo?.number == null) return
|
||||
//Derived classes should override these to respond to specific events of interest
|
||||
protected abstract fun onIncomingCallReceived(context: Context, number: String?, start: Date)
|
||||
|
||||
//判断是否开启该类型转发
|
||||
if ((callInfo.type == 1 && !SettingUtils.enableCallType1) || (callInfo.type == 2 && !SettingUtils.enableCallType2) || (callInfo.type == 3 && !SettingUtils.enableCallType3)) {
|
||||
Log.w(TAG, "未开启该类型转发,type=" + callInfo.type)
|
||||
protected abstract fun onIncomingCallAnswered(context: Context, number: String?, start: Date)
|
||||
|
||||
protected abstract fun onIncomingCallEnded(context: Context, number: String?, start: Date, end: Date)
|
||||
|
||||
protected abstract fun onOutgoingCallStarted(context: Context, number: String?, start: Date)
|
||||
|
||||
protected abstract fun onOutgoingCallEnded(context: Context, number: String?, start: Date, end: Date)
|
||||
|
||||
protected abstract fun onMissedCall(context: Context, number: String?, start: Date)
|
||||
|
||||
//Deals with actual events
|
||||
|
||||
//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?) {
|
||||
if (lastState == state || number == null) {
|
||||
//No change, debounce extras
|
||||
return
|
||||
}
|
||||
|
||||
//卡槽id:-1=获取失败、0=卡槽1、1=卡槽2
|
||||
val simSlot = callInfo.simId
|
||||
//获取卡槽信息
|
||||
val simInfo = when (simSlot) {
|
||||
0 -> "SIM1_" + SettingUtils.extraSim1
|
||||
1 -> "SIM2_" + SettingUtils.extraSim2
|
||||
else -> ""
|
||||
when (state) {
|
||||
TelephonyManager.CALL_STATE_RINGING -> {
|
||||
isIncoming = true
|
||||
callStartTime = Date()
|
||||
savedNumber = number
|
||||
|
||||
onIncomingCallReceived(context, number, callStartTime)
|
||||
}
|
||||
TelephonyManager.CALL_STATE_OFFHOOK ->
|
||||
//Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
|
||||
if (lastState != TelephonyManager.CALL_STATE_RINGING) {
|
||||
isIncoming = false
|
||||
callStartTime = Date()
|
||||
|
||||
onOutgoingCallStarted(context, savedNumber, callStartTime)
|
||||
} else {
|
||||
isIncoming = true
|
||||
callStartTime = Date()
|
||||
|
||||
onIncomingCallAnswered(context, savedNumber, callStartTime)
|
||||
}
|
||||
TelephonyManager.CALL_STATE_IDLE ->
|
||||
//Went to idle- this is the end of a call. What type depends on previous state(s)
|
||||
if (lastState == TelephonyManager.CALL_STATE_RINGING) {
|
||||
//Ring but no pickup
|
||||
onMissedCall(context, savedNumber, callStartTime)
|
||||
} else if (isIncoming) {
|
||||
onIncomingCallEnded(context, savedNumber, callStartTime, Date())
|
||||
} else {
|
||||
onOutgoingCallEnded(context, savedNumber, callStartTime, Date())
|
||||
}
|
||||
}
|
||||
|
||||
//获取联系人姓名
|
||||
if (TextUtils.isEmpty(callInfo.name)) {
|
||||
val contacts = PhoneUtils.getContactByNumber(phoneNumber)
|
||||
callInfo.name = if (contacts.isNotEmpty()) contacts[0].name else getString(R.string.unknown_number)
|
||||
}
|
||||
|
||||
val msgInfo = MsgInfo(
|
||||
"call", callInfo.number, PhoneUtils.getCallMsg(callInfo), Date(), simInfo, simSlot, callInfo.subId
|
||||
)
|
||||
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
|
||||
workDataOf(
|
||||
Worker.sendMsgInfo to Gson().toJson(msgInfo)
|
||||
)
|
||||
).build()
|
||||
WorkManager.getInstance(context).enqueue(request)
|
||||
|
||||
lastState = state
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "PhoneStateReceiver"
|
||||
private val TAG = PhoneStateReceiver::class.java.simpleName
|
||||
|
||||
//The receiver will be recreated whenever android feels like it. We need a static variable to remember data between instantiations
|
||||
private var lastState = TelephonyManager.CALL_STATE_IDLE
|
||||
private var callStartTime: Date = Date()
|
||||
private var isIncoming: Boolean = false
|
||||
private var savedNumber: String? = null //because the passed incoming is only valid in ringing
|
||||
}
|
||||
}
|
@ -33,6 +33,8 @@ 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_CALL_TYPE_5 = "enable_call_type_5"
|
||||
const val SP_ENABLE_CALL_TYPE_6 = "enable_call_type_6"
|
||||
|
||||
const val SP_ENABLE_APP_NOTIFY = "enable_app_notify"
|
||||
const val SP_ENABLE_CANCEL_APP_NOTIFY = "enable_cancel_app_notify"
|
||||
|
@ -139,6 +139,9 @@ class HttpServerUtils private constructor() {
|
||||
cloneInfo.callType1 = SettingUtils.enableCallType1
|
||||
cloneInfo.callType2 = SettingUtils.enableCallType2
|
||||
cloneInfo.callType3 = SettingUtils.enableCallType3
|
||||
cloneInfo.callType4 = SettingUtils.enableCallType4
|
||||
cloneInfo.callType5 = SettingUtils.enableCallType5
|
||||
cloneInfo.callType6 = SettingUtils.enableCallType6
|
||||
cloneInfo.enableAppNotify = SettingUtils.enableAppNotify
|
||||
cloneInfo.cancelAppNotify = SettingUtils.enableCancelAppNotify
|
||||
cloneInfo.enableNotUserPresent = SettingUtils.enableNotUserPresent
|
||||
@ -181,6 +184,9 @@ class HttpServerUtils private constructor() {
|
||||
SettingUtils.enableCallType1 = cloneInfo.callType1
|
||||
SettingUtils.enableCallType2 = cloneInfo.callType2
|
||||
SettingUtils.enableCallType3 = cloneInfo.callType3
|
||||
SettingUtils.enableCallType4 = cloneInfo.callType4
|
||||
SettingUtils.enableCallType5 = cloneInfo.callType5
|
||||
SettingUtils.enableCallType6 = cloneInfo.callType6
|
||||
SettingUtils.enableAppNotify = cloneInfo.enableAppNotify
|
||||
SettingUtils.enableCancelAppNotify = cloneInfo.cancelAppNotify
|
||||
SettingUtils.enableNotUserPresent = cloneInfo.enableNotUserPresent
|
||||
|
@ -187,11 +187,9 @@ class PhoneUtils private constructor() {
|
||||
Log.d(TAG, "selectionArgs = $selectionArgs")
|
||||
|
||||
//为了兼容性这里全部取出后手动分页
|
||||
val cursor = (if (limit == 1) Core.app.contentResolver.query(
|
||||
CallLog.Calls.CONTENT_URI, null, selection, selectionArgs.toTypedArray(), CallLog.Calls.DEFAULT_SORT_ORDER + " limit $limit offset $offset"
|
||||
) else Core.app.contentResolver.query(
|
||||
val cursor = Core.app.contentResolver.query(
|
||||
CallLog.Calls.CONTENT_URI, null, selection, selectionArgs.toTypedArray(), CallLog.Calls.DEFAULT_SORT_ORDER // + " limit $limit offset $offset"
|
||||
)) ?: return callInfoList
|
||||
) ?: return callInfoList
|
||||
Log.i(TAG, "cursor count:" + cursor.count)
|
||||
|
||||
// 避免超过总数后循环取出
|
||||
@ -348,12 +346,15 @@ class PhoneUtils private constructor() {
|
||||
sb.append(callInfo.duration).append("s\n")
|
||||
}
|
||||
sb.append(ResUtils.getString(R.string.mandatory_type))
|
||||
//通话类型:1.呼入 2.呼出 3.未接 4.来电提醒
|
||||
//通话类型:1.来电挂机 2.去电挂机 3.未接来电 4.来电提醒 5.来电接通 6.去电拨出
|
||||
when (callInfo.type) {
|
||||
1 -> sb.append(ResUtils.getString(R.string.received_call))
|
||||
2 -> sb.append(ResUtils.getString(R.string.local_outgoing_call))
|
||||
1 -> sb.append(ResUtils.getString(R.string.incoming_call_ended))
|
||||
2 -> sb.append(ResUtils.getString(R.string.outgoing_call_ended))
|
||||
3 -> sb.append(ResUtils.getString(R.string.missed_call))
|
||||
else -> sb.append(ResUtils.getString(R.string.incoming_call))
|
||||
4 -> sb.append(ResUtils.getString(R.string.incoming_call_received))
|
||||
5 -> sb.append(ResUtils.getString(R.string.incoming_call_answered))
|
||||
6 -> sb.append(ResUtils.getString(R.string.outgoing_call_started))
|
||||
else -> sb.append(ResUtils.getString(R.string.unknown_call))
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
@ -18,10 +18,10 @@ class SettingUtils private constructor() {
|
||||
//是否转发通话
|
||||
var enablePhone: Boolean by SharedPreference(SP_ENABLE_PHONE, false)
|
||||
|
||||
//是否转发通话——已接来电
|
||||
//是否转发通话——来电挂机
|
||||
var enableCallType1: Boolean by SharedPreference(SP_ENABLE_CALL_TYPE_1, false)
|
||||
|
||||
//是否转发通话——本机去电
|
||||
//是否转发通话——去电挂机
|
||||
var enableCallType2: Boolean by SharedPreference(SP_ENABLE_CALL_TYPE_2, false)
|
||||
|
||||
//是否转发通话——未接来电
|
||||
@ -30,6 +30,12 @@ class SettingUtils private constructor() {
|
||||
//是否转发通话——来电提醒
|
||||
var enableCallType4: Boolean by SharedPreference(SP_ENABLE_CALL_TYPE_4, false)
|
||||
|
||||
//是否转发通话——来电接通
|
||||
var enableCallType5: Boolean by SharedPreference(SP_ENABLE_CALL_TYPE_5, false)
|
||||
|
||||
//是否转发通话——去电拨出
|
||||
var enableCallType6: Boolean by SharedPreference(SP_ENABLE_CALL_TYPE_6, false)
|
||||
|
||||
//是否转发应用通知
|
||||
var enableAppNotify: Boolean by SharedPreference(SP_ENABLE_APP_NOTIFY, false)
|
||||
|
||||
|
@ -100,76 +100,130 @@
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="25dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/type"
|
||||
android:text="@string/mandatory_type"
|
||||
android:textSize="10sp"
|
||||
android:textStyle="bold"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type3"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/missed_call"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type1"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginStart="3dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/received_call"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type3"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type2"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginStart="3dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/missed_call"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/local_outgoing_call"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type1"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginStart="5dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type4"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginStart="3dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/incoming_call_ended"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/incoming_call"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type2"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginStart="5dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/outgoing_call_ended"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type4"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/incoming_call_received"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type5"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginStart="5dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/incoming_call_answered"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||
android:id="@+id/scb_call_type6"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginStart="5dp"
|
||||
app:scb_color_checked="@color/colorPrimary" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="@string/outgoing_call_started"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -222,6 +222,10 @@
|
||||
<string name="test_package_name">Test PackageName</string>
|
||||
<string name="test_inform_title">Test Notify Title</string>
|
||||
<string name="test_inform_content">Test Notify Content</string>
|
||||
<string name="sender_logic">Run Logic</string>
|
||||
<string name="sender_logic_all">All Run</string>
|
||||
<string name="sender_logic_until_fail">Run Until Fail</string>
|
||||
<string name="sender_logic_until_success">Run Until Success</string>
|
||||
<string name="match_sim_slot">SIM Slot</string>
|
||||
<string name="match_field">Field</string>
|
||||
<string name="phone_number">Phone No.</string>
|
||||
@ -505,10 +509,13 @@
|
||||
<string name="ring_duration">Ring duration: </string>
|
||||
<string name="type">Type: </string>
|
||||
<string name="mandatory_type">Call type: </string>
|
||||
<string name="incoming_call_received">Incoming Received</string>
|
||||
<string name="incoming_call_answered">Incoming Answered</string>
|
||||
<string name="incoming_call_ended">Incoming Ended</string>
|
||||
<string name="outgoing_call_started">Outgoing Started</string>
|
||||
<string name="outgoing_call_ended">Outgoing Ended</string>
|
||||
<string name="missed_call">Missed</string>
|
||||
<string name="incoming_call">Incoming</string>
|
||||
<string name="received_call">Received</string>
|
||||
<string name="local_outgoing_call">Call out</string>
|
||||
<string name="unknown_call">Unknown</string>
|
||||
<string name="optional_action">Optional: </string>
|
||||
<string name="optional_type">Optional: </string>
|
||||
<string name="active_request">Active request</string>
|
||||
@ -840,6 +847,7 @@
|
||||
<string name="frpc_failed_to_run">Frpc failed to run</string>
|
||||
<string name="successfully_deleted">Successfully deleted</string>
|
||||
<string name="sender_disabled_tips">[Note] The sending channel has been disabled, and its associated rules will not be sent even if they match!</string>
|
||||
<string name="sender_contains_tips">[Note] The sending channel is already in the list, no need to add it again!</string>
|
||||
<string name="local_call">Local Call:</string>
|
||||
<string name="remote_sms">Remote SMS:</string>
|
||||
<string name="clear">Clear</string>
|
||||
@ -941,4 +949,6 @@
|
||||
<string name="copy_public_key">Copy</string>
|
||||
<string name="sm4_key">SM4 Key</string>
|
||||
<string name="sm4_key_tips">Client or server interaction messages are all encrypted and decrypted using SM4</string>
|
||||
|
||||
<string name="sender_del">Del Sender</string>
|
||||
</resources>
|
||||
|
@ -510,10 +510,13 @@
|
||||
<string name="ring_duration">响铃时长:</string>
|
||||
<string name="type">类型:</string>
|
||||
<string name="mandatory_type">通话类型:</string>
|
||||
<string name="incoming_call_received">来电提醒</string>
|
||||
<string name="incoming_call_answered">来电接通</string>
|
||||
<string name="incoming_call_ended">来电挂机</string>
|
||||
<string name="outgoing_call_started">去电拨出</string>
|
||||
<string name="outgoing_call_ended">去电挂机</string>
|
||||
<string name="missed_call">未接来电</string>
|
||||
<string name="incoming_call">来电提醒</string>
|
||||
<string name="received_call">已接来电</string>
|
||||
<string name="local_outgoing_call">本机去电</string>
|
||||
<string name="unknown_call">未知通话</string>
|
||||
<string name="optional_action">可选操作:</string>
|
||||
<string name="optional_type">可选类型:</string>
|
||||
<string name="active_request">主动请求</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user