mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-04 01:47:40 +08:00
优化:来电转发逻辑 & 新增提醒类型(1.来电挂机 2.去电挂机 3.未接来电 4.来电提醒 5.来电接通 6.去电拨出)
This commit is contained in:
parent
b79d3d8493
commit
04d8c9015a
@ -242,11 +242,12 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".receiver.PhoneStateReceiver"
|
android:name=".receiver.CallReceiver"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
tools:ignore="IntentFilterExportedReceiver">
|
tools:ignore="IntentFilterExportedReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.PHONE_STATE" />
|
<action android:name="android.intent.action.PHONE_STATE" />
|
||||||
|
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
</application>
|
</application>
|
||||||
|
@ -13,7 +13,7 @@ data class CallInfo(
|
|||||||
var dateLong: Long = 0L,
|
var dateLong: Long = 0L,
|
||||||
//获取通话时长,值为多少秒
|
//获取通话时长,值为多少秒
|
||||||
var duration: Int = 0,
|
var duration: Int = 0,
|
||||||
//通话类型:1=呼入, 2=呼出, 3=未接, 4=未接提醒
|
//通话类型:1.来电挂机 2.去电挂机 3.未接来电 4.来电提醒 5.来电接通 6.去电拨出
|
||||||
var type: Int = 1,
|
var type: Int = 1,
|
||||||
//被呼号码
|
//被呼号码
|
||||||
@SerializedName("via_number")
|
@SerializedName("via_number")
|
||||||
|
@ -21,6 +21,12 @@ data class CloneInfo(
|
|||||||
var callType2: Boolean = false,
|
var callType2: Boolean = false,
|
||||||
@SerializedName("call_type3")
|
@SerializedName("call_type3")
|
||||||
var callType3: Boolean = false,
|
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")
|
@SerializedName("enable_app_notify")
|
||||||
var enableAppNotify: Boolean = false,
|
var enableAppNotify: Boolean = false,
|
||||||
@SerializedName("cancel_app_notify")
|
@SerializedName("cancel_app_notify")
|
||||||
|
@ -80,7 +80,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
switchEnableSms(binding!!.sbEnableSms)
|
switchEnableSms(binding!!.sbEnableSms)
|
||||||
//转发通话记录
|
//转发通话记录
|
||||||
switchEnablePhone(
|
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(
|
switchEnableAppNotify(
|
||||||
@ -304,15 +304,17 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
//转发通话
|
//转发通话
|
||||||
@SuppressLint("UseSwitchCompatOrMaterialCode")
|
@SuppressLint("UseSwitchCompatOrMaterialCode")
|
||||||
fun switchEnablePhone(
|
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
|
sbEnablePhone.isChecked = SettingUtils.enablePhone
|
||||||
scbCallType1.isChecked = SettingUtils.enableCallType1
|
scbCallType1.isChecked = SettingUtils.enableCallType1
|
||||||
scbCallType2.isChecked = SettingUtils.enableCallType2
|
scbCallType2.isChecked = SettingUtils.enableCallType2
|
||||||
scbCallType3.isChecked = SettingUtils.enableCallType3
|
scbCallType3.isChecked = SettingUtils.enableCallType3
|
||||||
scbCallType4.isChecked = SettingUtils.enableCallType4
|
scbCallType4.isChecked = SettingUtils.enableCallType4
|
||||||
|
scbCallType5.isChecked = SettingUtils.enableCallType5
|
||||||
|
scbCallType6.isChecked = SettingUtils.enableCallType6
|
||||||
sbEnablePhone.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
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)
|
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||||
SettingUtils.enablePhone = false
|
SettingUtils.enablePhone = false
|
||||||
sbEnablePhone.isChecked = false
|
sbEnablePhone.isChecked = false
|
||||||
@ -354,7 +356,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
}
|
}
|
||||||
scbCallType1.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
scbCallType1.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||||
SettingUtils.enableCallType1 = isChecked
|
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)
|
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||||
SettingUtils.enablePhone = false
|
SettingUtils.enablePhone = false
|
||||||
sbEnablePhone.isChecked = false
|
sbEnablePhone.isChecked = false
|
||||||
@ -362,7 +364,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
}
|
}
|
||||||
scbCallType2.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
scbCallType2.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||||
SettingUtils.enableCallType2 = isChecked
|
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)
|
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||||
SettingUtils.enablePhone = false
|
SettingUtils.enablePhone = false
|
||||||
sbEnablePhone.isChecked = false
|
sbEnablePhone.isChecked = false
|
||||||
@ -370,7 +372,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
}
|
}
|
||||||
scbCallType3.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
scbCallType3.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||||
SettingUtils.enableCallType3 = isChecked
|
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)
|
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||||
SettingUtils.enablePhone = false
|
SettingUtils.enablePhone = false
|
||||||
sbEnablePhone.isChecked = false
|
sbEnablePhone.isChecked = false
|
||||||
@ -378,7 +380,23 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
}
|
}
|
||||||
scbCallType4.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
scbCallType4.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||||
SettingUtils.enableCallType4 = isChecked
|
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)
|
XToastUtils.info(R.string.enable_phone_fw_tips)
|
||||||
SettingUtils.enablePhone = false
|
SettingUtils.enablePhone = false
|
||||||
sbEnablePhone.isChecked = 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
|
package com.idormy.sms.forwarder.receiver
|
||||||
|
|
||||||
import android.Manifest
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.TelephonyManager
|
||||||
import android.text.TextUtils
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.app.ActivityCompat
|
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||||
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 java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
class PhoneStateReceiver : BroadcastReceiver() {
|
abstract class PhoneStateReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
try {
|
|
||||||
//纯客户端模式
|
//纯客户端模式
|
||||||
if (SettingUtils.enablePureClientMode) return
|
if (SettingUtils.enablePureClientMode) return
|
||||||
|
|
||||||
//总开关
|
//总开关
|
||||||
if (!SettingUtils.enablePhone) return
|
if (!SettingUtils.enablePhone) return
|
||||||
|
|
||||||
//过滤广播
|
//We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number.
|
||||||
if (TelephonyManager.ACTION_PHONE_STATE_CHANGED != intent.action) return
|
if (intent.action == CallReceiver.ACTION_OUT) {
|
||||||
|
savedNumber = intent.extras!!.getString(CallReceiver.EXTRA_PHONE_NUMBER)
|
||||||
//权限判断
|
Log.d(TAG, "savedNumber:$savedNumber")
|
||||||
if (ActivityCompat.checkSelfPermission(
|
} else {
|
||||||
context, Manifest.permission.READ_PHONE_STATE
|
|
||||||
) != PackageManager.PERMISSION_GRANTED
|
|
||||||
) return
|
|
||||||
|
|
||||||
//获取来电号码
|
|
||||||
val number = intent.extras!!.getString(TelephonyManager.EXTRA_INCOMING_NUMBER)
|
|
||||||
val stateStr = intent.extras!!.getString(TelephonyManager.EXTRA_STATE)
|
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
|
var state = 0
|
||||||
|
|
||||||
when (stateStr) {
|
when (stateStr) {
|
||||||
TelephonyManager.EXTRA_STATE_IDLE -> state = TelephonyManager.CALL_STATE_IDLE
|
TelephonyManager.EXTRA_STATE_IDLE -> state = TelephonyManager.CALL_STATE_IDLE
|
||||||
TelephonyManager.EXTRA_STATE_OFFHOOK -> state = TelephonyManager.CALL_STATE_OFFHOOK
|
TelephonyManager.EXTRA_STATE_OFFHOOK -> state = TelephonyManager.CALL_STATE_OFFHOOK
|
||||||
TelephonyManager.EXTRA_STATE_RINGING -> state = TelephonyManager.CALL_STATE_RINGING
|
TelephonyManager.EXTRA_STATE_RINGING -> state = TelephonyManager.CALL_STATE_RINGING
|
||||||
}
|
}
|
||||||
Log.d(TAG, "state=$state, number=$number")
|
onCallStateChanged(context, state, number)
|
||||||
var callSavedNumber: String by SharedPreference("CALL_SAVED_NUMBER", "")
|
}
|
||||||
if (!TextUtils.isEmpty(number)) callSavedNumber = number.toString()
|
}
|
||||||
|
|
||||||
|
//Derived classes should override these to respond to specific events of interest
|
||||||
|
protected abstract fun onIncomingCallReceived(context: Context, number: String?, start: Date)
|
||||||
|
|
||||||
|
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
|
//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
|
//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)
|
private fun onCallStateChanged(context: Context, state: Int, number: String?) {
|
||||||
if (lastState == state || (state == TelephonyManager.CALL_STATE_RINGING && number == null)) {
|
if (lastState == state || number == null) {
|
||||||
//No change, debounce extras
|
//No change, debounce extras
|
||||||
Log.d(TAG, "状态没变,防止抖动")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
lastState = state
|
|
||||||
var callIsIncoming: Boolean by SharedPreference("CALL_IS_INCOMING", false)
|
|
||||||
Log.d(TAG, "lastState=$lastState, callIsIncoming=$callIsIncoming, callSavedNumber=$callSavedNumber")
|
|
||||||
|
|
||||||
when (state) {
|
when (state) {
|
||||||
TelephonyManager.CALL_STATE_RINGING -> {
|
TelephonyManager.CALL_STATE_RINGING -> {
|
||||||
Log.d(TAG, "电话响铃")
|
isIncoming = true
|
||||||
callIsIncoming = true
|
callStartTime = Date()
|
||||||
|
savedNumber = number
|
||||||
|
|
||||||
//来电提醒
|
onIncomingCallReceived(context, number, callStartTime)
|
||||||
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 ->
|
TelephonyManager.CALL_STATE_OFFHOOK ->
|
||||||
//Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
|
//Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
|
||||||
callIsIncoming = when {
|
if (lastState != TelephonyManager.CALL_STATE_RINGING) {
|
||||||
lastState != TelephonyManager.CALL_STATE_RINGING -> {
|
isIncoming = false
|
||||||
Log.d(TAG, "去电接通")
|
callStartTime = Date()
|
||||||
if (!TextUtils.isEmpty(number)) callSavedNumber = number.toString()
|
|
||||||
false
|
onOutgoingCallStarted(context, savedNumber, callStartTime)
|
||||||
}
|
} else {
|
||||||
else -> {
|
isIncoming = true
|
||||||
Log.d(TAG, "来电接通")
|
callStartTime = Date()
|
||||||
true
|
|
||||||
}
|
onIncomingCallAnswered(context, savedNumber, callStartTime)
|
||||||
}
|
}
|
||||||
TelephonyManager.CALL_STATE_IDLE ->
|
TelephonyManager.CALL_STATE_IDLE ->
|
||||||
//Went to idle- this is the end of a call. What type depends on previous state(s)
|
//Went to idle- this is the end of a call. What type depends on previous state(s)
|
||||||
when {
|
if (lastState == TelephonyManager.CALL_STATE_RINGING) {
|
||||||
lastState == TelephonyManager.CALL_STATE_RINGING -> {
|
//Ring but no pickup
|
||||||
Log.d(TAG, "来电未接")
|
onMissedCall(context, savedNumber, callStartTime)
|
||||||
sendReceiveCallMsg(context, 3, callSavedNumber)
|
} else if (isIncoming) {
|
||||||
callSavedNumber = ""
|
onIncomingCallEnded(context, savedNumber, callStartTime, Date())
|
||||||
}
|
} else {
|
||||||
callIsIncoming -> {
|
onOutgoingCallEnded(context, savedNumber, callStartTime, Date())
|
||||||
Log.d(TAG, "来电挂机")
|
|
||||||
sendReceiveCallMsg(context, 1, callSavedNumber)
|
|
||||||
callSavedNumber = ""
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
Log.d(TAG, "去电挂机")
|
|
||||||
sendReceiveCallMsg(context, 2, callSavedNumber)
|
|
||||||
callSavedNumber = ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
lastState = state
|
||||||
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, e.message.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
//判断是否开启该类型转发
|
|
||||||
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)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
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_2 = "enable_call_type_2"
|
||||||
const val SP_ENABLE_CALL_TYPE_3 = "enable_call_type_3"
|
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_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_APP_NOTIFY = "enable_app_notify"
|
||||||
const val SP_ENABLE_CANCEL_APP_NOTIFY = "enable_cancel_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.callType1 = SettingUtils.enableCallType1
|
||||||
cloneInfo.callType2 = SettingUtils.enableCallType2
|
cloneInfo.callType2 = SettingUtils.enableCallType2
|
||||||
cloneInfo.callType3 = SettingUtils.enableCallType3
|
cloneInfo.callType3 = SettingUtils.enableCallType3
|
||||||
|
cloneInfo.callType4 = SettingUtils.enableCallType4
|
||||||
|
cloneInfo.callType5 = SettingUtils.enableCallType5
|
||||||
|
cloneInfo.callType6 = SettingUtils.enableCallType6
|
||||||
cloneInfo.enableAppNotify = SettingUtils.enableAppNotify
|
cloneInfo.enableAppNotify = SettingUtils.enableAppNotify
|
||||||
cloneInfo.cancelAppNotify = SettingUtils.enableCancelAppNotify
|
cloneInfo.cancelAppNotify = SettingUtils.enableCancelAppNotify
|
||||||
cloneInfo.enableNotUserPresent = SettingUtils.enableNotUserPresent
|
cloneInfo.enableNotUserPresent = SettingUtils.enableNotUserPresent
|
||||||
@ -181,6 +184,9 @@ class HttpServerUtils private constructor() {
|
|||||||
SettingUtils.enableCallType1 = cloneInfo.callType1
|
SettingUtils.enableCallType1 = cloneInfo.callType1
|
||||||
SettingUtils.enableCallType2 = cloneInfo.callType2
|
SettingUtils.enableCallType2 = cloneInfo.callType2
|
||||||
SettingUtils.enableCallType3 = cloneInfo.callType3
|
SettingUtils.enableCallType3 = cloneInfo.callType3
|
||||||
|
SettingUtils.enableCallType4 = cloneInfo.callType4
|
||||||
|
SettingUtils.enableCallType5 = cloneInfo.callType5
|
||||||
|
SettingUtils.enableCallType6 = cloneInfo.callType6
|
||||||
SettingUtils.enableAppNotify = cloneInfo.enableAppNotify
|
SettingUtils.enableAppNotify = cloneInfo.enableAppNotify
|
||||||
SettingUtils.enableCancelAppNotify = cloneInfo.cancelAppNotify
|
SettingUtils.enableCancelAppNotify = cloneInfo.cancelAppNotify
|
||||||
SettingUtils.enableNotUserPresent = cloneInfo.enableNotUserPresent
|
SettingUtils.enableNotUserPresent = cloneInfo.enableNotUserPresent
|
||||||
|
@ -187,11 +187,9 @@ class PhoneUtils private constructor() {
|
|||||||
Log.d(TAG, "selectionArgs = $selectionArgs")
|
Log.d(TAG, "selectionArgs = $selectionArgs")
|
||||||
|
|
||||||
//为了兼容性这里全部取出后手动分页
|
//为了兼容性这里全部取出后手动分页
|
||||||
val cursor = (if (limit == 1) 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"
|
|
||||||
) else Core.app.contentResolver.query(
|
|
||||||
CallLog.Calls.CONTENT_URI, null, selection, selectionArgs.toTypedArray(), CallLog.Calls.DEFAULT_SORT_ORDER // + " limit $limit offset $offset"
|
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)
|
Log.i(TAG, "cursor count:" + cursor.count)
|
||||||
|
|
||||||
// 避免超过总数后循环取出
|
// 避免超过总数后循环取出
|
||||||
@ -348,12 +346,15 @@ class PhoneUtils private constructor() {
|
|||||||
sb.append(callInfo.duration).append("s\n")
|
sb.append(callInfo.duration).append("s\n")
|
||||||
}
|
}
|
||||||
sb.append(ResUtils.getString(R.string.mandatory_type))
|
sb.append(ResUtils.getString(R.string.mandatory_type))
|
||||||
//通话类型:1.呼入 2.呼出 3.未接 4.来电提醒
|
//通话类型:1.来电挂机 2.去电挂机 3.未接来电 4.来电提醒 5.来电接通 6.去电拨出
|
||||||
when (callInfo.type) {
|
when (callInfo.type) {
|
||||||
1 -> sb.append(ResUtils.getString(R.string.received_call))
|
1 -> sb.append(ResUtils.getString(R.string.incoming_call_ended))
|
||||||
2 -> sb.append(ResUtils.getString(R.string.local_outgoing_call))
|
2 -> sb.append(ResUtils.getString(R.string.outgoing_call_ended))
|
||||||
3 -> sb.append(ResUtils.getString(R.string.missed_call))
|
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()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
@ -18,10 +18,10 @@ class SettingUtils private constructor() {
|
|||||||
//是否转发通话
|
//是否转发通话
|
||||||
var enablePhone: Boolean by SharedPreference(SP_ENABLE_PHONE, false)
|
var enablePhone: Boolean by SharedPreference(SP_ENABLE_PHONE, false)
|
||||||
|
|
||||||
//是否转发通话——已接来电
|
//是否转发通话——来电挂机
|
||||||
var enableCallType1: Boolean by SharedPreference(SP_ENABLE_CALL_TYPE_1, false)
|
var enableCallType1: Boolean by SharedPreference(SP_ENABLE_CALL_TYPE_1, false)
|
||||||
|
|
||||||
//是否转发通话——本机去电
|
//是否转发通话——去电挂机
|
||||||
var enableCallType2: Boolean by SharedPreference(SP_ENABLE_CALL_TYPE_2, 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 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)
|
var enableAppNotify: Boolean by SharedPreference(SP_ENABLE_APP_NOTIFY, false)
|
||||||
|
|
||||||
|
@ -100,18 +100,30 @@
|
|||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="25dp"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/type"
|
android:text="@string/mandatory_type"
|
||||||
android:textSize="10sp"
|
android:textSize="10sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
tools:ignore="SmallSp" />
|
tools:ignore="SmallSp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||||
android:id="@+id/scb_call_type3"
|
android:id="@+id/scb_call_type3"
|
||||||
android:layout_width="15dp"
|
android:layout_width="15dp"
|
||||||
@ -130,14 +142,14 @@
|
|||||||
android:id="@+id/scb_call_type1"
|
android:id="@+id/scb_call_type1"
|
||||||
android:layout_width="15dp"
|
android:layout_width="15dp"
|
||||||
android:layout_height="15dp"
|
android:layout_height="15dp"
|
||||||
android:layout_marginStart="3dp"
|
android:layout_marginStart="5dp"
|
||||||
app:scb_color_checked="@color/colorPrimary" />
|
app:scb_color_checked="@color/colorPrimary" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="@string/received_call"
|
android:text="@string/incoming_call_ended"
|
||||||
android:textSize="10sp"
|
android:textSize="10sp"
|
||||||
tools:ignore="SmallSp" />
|
tools:ignore="SmallSp" />
|
||||||
|
|
||||||
@ -145,32 +157,74 @@
|
|||||||
android:id="@+id/scb_call_type2"
|
android:id="@+id/scb_call_type2"
|
||||||
android:layout_width="15dp"
|
android:layout_width="15dp"
|
||||||
android:layout_height="15dp"
|
android:layout_height="15dp"
|
||||||
android:layout_marginStart="3dp"
|
android:layout_marginStart="5dp"
|
||||||
app:scb_color_checked="@color/colorPrimary" />
|
app:scb_color_checked="@color/colorPrimary" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="@string/local_outgoing_call"
|
android:text="@string/outgoing_call_ended"
|
||||||
android:textSize="10sp"
|
android:textSize="10sp"
|
||||||
tools:ignore="SmallSp" />
|
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
|
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
||||||
android:id="@+id/scb_call_type4"
|
android:id="@+id/scb_call_type4"
|
||||||
android:layout_width="15dp"
|
android:layout_width="15dp"
|
||||||
android:layout_height="15dp"
|
android:layout_height="15dp"
|
||||||
android:layout_marginStart="3dp"
|
|
||||||
app:scb_color_checked="@color/colorPrimary" />
|
app:scb_color_checked="@color/colorPrimary" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="@string/incoming_call"
|
android:text="@string/incoming_call_received"
|
||||||
android:textSize="10sp"
|
android:textSize="10sp"
|
||||||
tools:ignore="SmallSp" />
|
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>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -222,6 +222,10 @@
|
|||||||
<string name="test_package_name">Test PackageName</string>
|
<string name="test_package_name">Test PackageName</string>
|
||||||
<string name="test_inform_title">Test Notify Title</string>
|
<string name="test_inform_title">Test Notify Title</string>
|
||||||
<string name="test_inform_content">Test Notify Content</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_sim_slot">SIM Slot</string>
|
||||||
<string name="match_field">Field</string>
|
<string name="match_field">Field</string>
|
||||||
<string name="phone_number">Phone No.</string>
|
<string name="phone_number">Phone No.</string>
|
||||||
@ -505,10 +509,13 @@
|
|||||||
<string name="ring_duration">Ring duration: </string>
|
<string name="ring_duration">Ring duration: </string>
|
||||||
<string name="type">Type: </string>
|
<string name="type">Type: </string>
|
||||||
<string name="mandatory_type">Call 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="missed_call">Missed</string>
|
||||||
<string name="incoming_call">Incoming</string>
|
<string name="unknown_call">Unknown</string>
|
||||||
<string name="received_call">Received</string>
|
|
||||||
<string name="local_outgoing_call">Call out</string>
|
|
||||||
<string name="optional_action">Optional: </string>
|
<string name="optional_action">Optional: </string>
|
||||||
<string name="optional_type">Optional: </string>
|
<string name="optional_type">Optional: </string>
|
||||||
<string name="active_request">Active request</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="frpc_failed_to_run">Frpc failed to run</string>
|
||||||
<string name="successfully_deleted">Successfully deleted</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_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="local_call">Local Call:</string>
|
||||||
<string name="remote_sms">Remote SMS:</string>
|
<string name="remote_sms">Remote SMS:</string>
|
||||||
<string name="clear">Clear</string>
|
<string name="clear">Clear</string>
|
||||||
@ -941,4 +949,6 @@
|
|||||||
<string name="copy_public_key">Copy</string>
|
<string name="copy_public_key">Copy</string>
|
||||||
<string name="sm4_key">SM4 Key</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="sm4_key_tips">Client or server interaction messages are all encrypted and decrypted using SM4</string>
|
||||||
|
|
||||||
|
<string name="sender_del">Del Sender</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -510,10 +510,13 @@
|
|||||||
<string name="ring_duration">响铃时长:</string>
|
<string name="ring_duration">响铃时长:</string>
|
||||||
<string name="type">类型:</string>
|
<string name="type">类型:</string>
|
||||||
<string name="mandatory_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="missed_call">未接来电</string>
|
||||||
<string name="incoming_call">来电提醒</string>
|
<string name="unknown_call">未知通话</string>
|
||||||
<string name="received_call">已接来电</string>
|
|
||||||
<string name="local_outgoing_call">本机去电</string>
|
|
||||||
<string name="optional_action">可选操作:</string>
|
<string name="optional_action">可选操作:</string>
|
||||||
<string name="optional_type">可选类型:</string>
|
<string name="optional_type">可选类型:</string>
|
||||||
<string name="active_request">主动请求</string>
|
<string name="active_request">主动请求</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user