diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c4dddf2c..f4ccc22c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -264,31 +264,32 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ android:permission="android.permission.READ_PHONE_STATE">
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/idormy/sms/forwarder/App.kt b/app/src/main/java/com/idormy/sms/forwarder/App.kt
index 9c1a3510..d9f88b83 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/App.kt
+++ b/app/src/main/java/com/idormy/sms/forwarder/App.kt
@@ -6,6 +6,8 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.net.ConnectivityManager
+import android.net.wifi.WifiManager
import android.os.Build
import android.util.Log
import androidx.lifecycle.MutableLiveData
@@ -21,6 +23,7 @@ import com.idormy.sms.forwarder.database.repository.*
import com.idormy.sms.forwarder.entity.SimInfo
import com.idormy.sms.forwarder.receiver.BatteryReceiver
import com.idormy.sms.forwarder.receiver.CactusReceiver
+import com.idormy.sms.forwarder.receiver.NetworkChangeReceiver
import com.idormy.sms.forwarder.service.ForegroundService
import com.idormy.sms.forwarder.service.HttpServerService
import com.idormy.sms.forwarder.utils.*
@@ -38,6 +41,7 @@ import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
+@Suppress("DEPRECATION")
class App : Application(), CactusCallback, Configuration.Provider by Core {
val applicationScope = CoroutineScope(SupervisorJob())
@@ -128,8 +132,18 @@ class App : Application(), CactusCallback, Configuration.Provider by Core {
//监听电量&充电状态变化
val batteryReceiver = BatteryReceiver()
- val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
- registerReceiver(batteryReceiver, filter)
+ val batteryFilter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
+ registerReceiver(batteryReceiver, batteryFilter)
+
+ //监听网络变化
+ val networkReceiver = NetworkChangeReceiver()
+ val networkFilter = IntentFilter().apply {
+ addAction(ConnectivityManager.CONNECTIVITY_ACTION)
+ addAction(WifiManager.WIFI_STATE_CHANGED_ACTION)
+ addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION)
+ //addAction("android.intent.action.DATA_CONNECTION_STATE_CHANGED")
+ }
+ registerReceiver(networkReceiver, networkFilter)
//Cactus 集成双进程前台服务,JobScheduler,onePix(一像素),WorkManager,无声音乐
if (SettingUtils.enableCactus) {
diff --git a/app/src/main/java/com/idormy/sms/forwarder/entity/task/NetworkSetting.kt b/app/src/main/java/com/idormy/sms/forwarder/entity/task/NetworkSetting.kt
index 025a64bf..a538137f 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/entity/task/NetworkSetting.kt
+++ b/app/src/main/java/com/idormy/sms/forwarder/entity/task/NetworkSetting.kt
@@ -7,9 +7,12 @@ import java.io.Serializable
data class NetworkSetting(
var description: String = "", //描述
var networkState: Int = 0, //网络状态:0-没有网络,1-移动网络,2-WiFi,3-以太网, 4-未知
+ var dataSimSlot: Int = 0, //数据卡槽:0-不限,1-卡1,2-卡2
+ var wifiSsid: String = "", //WiFi名称
) : Serializable {
- constructor(networkStateCheckId: Int) : this() {
+ constructor(networkStateCheckId: Int, dataSimSlotCheckId: Int, ssid: String) : this() {
+ wifiSsid = ssid
networkState = when (networkStateCheckId) {
R.id.rb_no_network -> 0
R.id.rb_net_mobile -> 1
@@ -17,6 +20,12 @@ data class NetworkSetting(
R.id.rb_net_ethernet -> 3
else -> 4
}
+ dataSimSlot = when (dataSimSlotCheckId) {
+ R.id.rb_data_sim_slot_0 -> 0
+ R.id.rb_data_sim_slot_1 -> 1
+ R.id.rb_data_sim_slot_2 -> 2
+ else -> 0
+ }
description = String.format(
getString(R.string.network_state),
when (networkState) {
@@ -27,6 +36,12 @@ data class NetworkSetting(
else -> getString(R.string.net_unknown)
}
)
+ if (networkState == 1 && dataSimSlot != 0) {
+ description += ", " + getString(R.string.data_sim_index) + ": SIM-" + dataSimSlot
+ }
+ if (networkState == 2 && wifiSsid.isNotEmpty()) {
+ description += ", " + getString(R.string.wifi_ssid) + ": " + wifiSsid
+ }
}
fun getNetworkStateCheckId(): Int {
@@ -38,4 +53,13 @@ data class NetworkSetting(
else -> R.id.rb_net_unknown
}
}
+
+ fun getDataSimSlotCheckId(): Int {
+ return when (dataSimSlot) {
+ 0 -> R.id.rb_data_sim_slot_0
+ 1 -> R.id.rb_data_sim_slot_1
+ 2 -> R.id.rb_data_sim_slot_2
+ else -> R.id.rb_data_sim_slot_0
+ }
+ }
}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/SettingsFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/SettingsFragment.kt
index c45561d1..250c4465 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/fragment/SettingsFragment.kt
+++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/SettingsFragment.kt
@@ -118,9 +118,6 @@ class SettingsFragment : BaseFragment(), View.OnClickL
SettingUtils.autoCleanLogsDays = newValue
}
- //监听网络状态变化
- switchNetworkStateReceiver(binding!!.sbNetworkStateReceiver)
-
//开机启动
checkWithReboot(binding!!.sbWithReboot, binding!!.tvAutoStartup)
//忽略电池优化设置
@@ -607,15 +604,6 @@ class SettingsFragment : BaseFragment(), View.OnClickL
}
}
- //监听网络状态变化
- @SuppressLint("UseSwitchCompatOrMaterialCode")
- fun switchNetworkStateReceiver(sbNetworkStateReceiver: SwitchButton) {
- sbNetworkStateReceiver.isChecked = SettingUtils.enableNetworkStateReceiver
- sbNetworkStateReceiver.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
- SettingUtils.enableNetworkStateReceiver = isChecked
- }
- }
-
//开机启动
private fun checkWithReboot(
@SuppressLint("UseSwitchCompatOrMaterialCode") sbWithReboot: SwitchButton, tvAutoStartup: TextView
diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/condition/NetworkFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/condition/NetworkFragment.kt
index b54d16ec..73a0ac2f 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/fragment/condition/NetworkFragment.kt
+++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/condition/NetworkFragment.kt
@@ -69,11 +69,19 @@ class NetworkFragment : BaseFragment(), V
}
})
+ binding!!.rgNetworkState.setOnCheckedChangeListener { _, checkedId ->
+ Log.d(TAG, "rgNetworkState checkedId:$checkedId")
+ binding!!.layoutDataSimSlot.visibility = if (checkedId == R.id.rb_net_mobile) View.VISIBLE else View.GONE
+ binding!!.layoutWifiSsid.visibility = if (checkedId == R.id.rb_net_wifi) View.VISIBLE else View.GONE
+ }
+
Log.d(TAG, "initViews eventData:$eventData")
if (eventData != null) {
val settingVo = Gson().fromJson(eventData, NetworkSetting::class.java)
Log.d(TAG, "initViews settingVo:$settingVo")
binding!!.rgNetworkState.check(settingVo.getNetworkStateCheckId())
+ binding!!.rgDataSimSlot.check(settingVo.getDataSimSlotCheckId())
+ binding!!.etWifiSsid.setText(settingVo.wifiSsid)
}
}
@@ -136,6 +144,8 @@ class NetworkFragment : BaseFragment(), V
//检查设置
private fun checkSetting(): NetworkSetting {
val networkStateCheckId = binding!!.rgNetworkState.checkedRadioButtonId
- return NetworkSetting(networkStateCheckId)
+ val dataSimSlotCheckId = binding!!.rgDataSimSlot.checkedRadioButtonId
+ val wifiSsid = binding!!.etWifiSsid.text.toString().trim()
+ return NetworkSetting(networkStateCheckId, dataSimSlotCheckId, wifiSsid)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/receiver/NetworkChangeReceiver.kt b/app/src/main/java/com/idormy/sms/forwarder/receiver/NetworkChangeReceiver.kt
new file mode 100644
index 00000000..4f160978
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/receiver/NetworkChangeReceiver.kt
@@ -0,0 +1,196 @@
+@file:Suppress("DEPRECATION")
+
+package com.idormy.sms.forwarder.receiver
+
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.net.ConnectivityManager
+import android.net.NetworkInfo
+import android.net.wifi.WifiManager
+import android.os.Build
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.util.Log
+import androidx.annotation.RequiresApi
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkManager
+import androidx.work.workDataOf
+import com.idormy.sms.forwarder.utils.TASK_CONDITION_NETWORK
+import com.idormy.sms.forwarder.utils.TaskWorker
+import com.idormy.sms.forwarder.utils.task.TaskUtils
+import com.idormy.sms.forwarder.workers.NetworkWorker
+
+@Suppress("PrivatePropertyName", "DEPRECATION", "UNUSED_PARAMETER")
+class NetworkChangeReceiver : BroadcastReceiver() {
+
+ private val TAG: String = NetworkChangeReceiver::class.java.simpleName
+
+ override fun onReceive(context: Context, intent: Intent) {
+ Log.d(TAG, "onReceive: ${intent.action}")
+ when (intent.action) {
+ ConnectivityManager.CONNECTIVITY_ACTION -> {
+ handleConnectivityChange(context)
+ }
+
+ WifiManager.WIFI_STATE_CHANGED_ACTION -> {
+ handleWifiStateChanged(context, intent)
+ }
+
+ WifiManager.NETWORK_STATE_CHANGED_ACTION -> {
+ handleNetworkStateChanged(context, intent)
+ }
+
+ //"android.intent.action.DATA_CONNECTION_STATE_CHANGED" -> {
+ // handleDataConnectionStateChanged(context, intent)
+ //}
+ }
+ }
+
+ private fun handleConnectivityChange(context: Context) {
+ val networkStateOld = TaskUtils.networkState
+ val dataSimSlotOld = TaskUtils.dataSimSlot
+ val wifiSsidOld = TaskUtils.wifiSsid
+ val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ val networkInfo = connectivityManager.activeNetworkInfo
+ if (networkInfo != null && networkInfo.isConnected) {
+ Log.d(TAG, "Network Connected")
+ if (networkInfo.type == ConnectivityManager.TYPE_MOBILE) {
+ //移动网络
+ TaskUtils.networkState = 1
+ //获取当前使用的 SIM index
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ TaskUtils.dataSimSlot = getSlotIndex(context) + 1
+ }
+ } else if (networkInfo.type == ConnectivityManager.TYPE_WIFI) {
+ //WiFi网络
+ TaskUtils.networkState = 2
+ //获取WiFi名称
+ val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
+ val wifiInfo = wifiManager.connectionInfo
+ TaskUtils.wifiSsid = wifiInfo.ssid.replace("\"", "")
+ }
+ } else {
+ Log.d(TAG, "Network Disconnected")
+ TaskUtils.networkState = 0
+ TaskUtils.dataSimSlot = 0
+ TaskUtils.wifiSsid = ""
+ }
+
+ //网络状态未改变,不执行任务,避免重复通知
+ if (networkStateOld == TaskUtils.networkState && dataSimSlotOld == TaskUtils.dataSimSlot && wifiSsidOld == TaskUtils.wifiSsid) {
+ Log.d(TAG, "Network State Not Changed")
+ return
+ }
+
+ //获取公网IP地址后执行任务
+ val request = OneTimeWorkRequestBuilder().setInputData(
+ workDataOf(
+ TaskWorker.conditionType to TASK_CONDITION_NETWORK,
+ )
+ ).build()
+ WorkManager.getInstance(context).enqueue(request)
+ }
+
+ private fun handleWifiStateChanged(context: Context, intent: Intent) {
+ val wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)
+ Log.d(TAG, "WiFi State Changed: $wifiState")
+
+ when (wifiState) {
+ WifiManager.WIFI_STATE_ENABLED -> {
+ Log.d(TAG, "WiFi Enabled")
+ }
+
+ WifiManager.WIFI_STATE_DISABLED -> {
+ Log.d(TAG, "WiFi Disabled")
+ }
+ }
+ }
+
+ private fun handleNetworkStateChanged(context: Context, intent: Intent) {
+ val networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO)
+ if (networkInfo != null && networkInfo.isConnected) {
+ Log.d(TAG, "Network State Changed: Connected")
+ } else {
+ Log.d(TAG, "Network State Changed: Disconnected")
+ }
+ }
+
+ //private fun handleDataConnectionStateChanged(context: Context, intent: Intent) {
+ // val extraData = intent.extras
+ // val state = extraData?.getString("state")
+ // val reason = extraData?.getString("reason")
+ //
+ // if (state != null && reason != null) {
+ // Log.d(TAG, "Data Connection State Changed: $state, Reason: $reason")
+ // }
+ //}
+
+ // 获取当前数据连接的卡槽ID,不需要判断手机数据流量是否打开(上层已判断)
+ @RequiresApi(Build.VERSION_CODES.Q)
+ private fun getSlotIndex(context: Context): Int {
+ return try {
+ val subscriptionId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ SubscriptionManager.getDefaultDataSubscriptionId()
+ } else {
+ getDataSubId(context)
+ }
+ SubscriptionManager.getSlotIndex(subscriptionId)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ -1
+ }
+ }
+
+ // 获取数据连接的订阅ID
+ @SuppressLint("DiscouragedPrivateApi")
+ private fun getDataSubId(context: Context): Int {
+ val defaultDataSlotId = getDefaultDataSlotId(context)
+
+ return try {
+ val obj = Class.forName("android.telephony.SubscriptionManager")
+ .getDeclaredMethod("getSubId", Int::class.javaPrimitiveType)
+ .invoke(null, defaultDataSlotId)
+ obj?.let {
+ when (Build.VERSION.SDK_INT) {
+ Build.VERSION_CODES.LOLLIPOP -> (it as? LongArray)?.get(0)?.toInt()
+ else -> (it as? IntArray)?.get(0)
+ }
+ } ?: defaultDataSlotId
+ } catch (e: Exception) {
+ e.printStackTrace()
+ defaultDataSlotId
+ }
+ }
+
+ // 获取默认数据卡的卡槽ID
+ private fun getDefaultDataSlotId(context: Context): Int {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ val subscriptionManager = SubscriptionManager.from(context.applicationContext)
+ subscriptionManager?.let {
+ try {
+ val subClass = Class.forName(it.javaClass.name)
+ val getSubID = subClass.getMethod("getDefaultDataSubscriptionInfo")
+ val subInfo = getSubID.invoke(it) as? SubscriptionInfo
+ return subInfo?.simSlotIndex ?: -1
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ } else {
+ try {
+ val cls = Class.forName("android.telephony.SubscriptionManager")
+ val methodName = if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) "getSlotId" else "getSlotIndex"
+ val getSubId = cls.getDeclaredMethod("getDefaultDataSubId") ?: cls.getDeclaredMethod("getDefaultDataSubscriptionId")
+ val subId = getSubId.invoke(null) as? Int ?: return -1
+ val getSlotId = cls.getDeclaredMethod(methodName, Int::class.javaPrimitiveType)
+ return getSlotId.invoke(null, subId) as? Int ?: -1
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ return -1
+ }
+
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt
index c59eb647..829d98e5 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/Constants.kt
@@ -62,8 +62,6 @@ 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_NET_STATE_RECEIVER = "enable_network_state_receiver"
-
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"
@@ -577,7 +575,14 @@ var TASK_ACTION_FRAGMENT_LIST = listOf(
),
)
+const val SP_BATTERY_INFO = "battery_info"
const val SP_BATTERY_STATUS = "battery_status"
const val SP_BATTERY_LEVEL = "battery_level"
const val SP_BATTERY_PCT = "battery_pct"
-const val SP_BATTERY_PLUGGED = "battery_plugged"
\ No newline at end of file
+const val SP_BATTERY_PLUGGED = "battery_plugged"
+
+const val SP_NETWORK_STATE = "network_state"
+const val SP_DATA_SIM_SLOT = "data_sim_slot"
+const val SP_WIFI_SSID = "wifi_ssid"
+const val SP_IPV4 = "ipv4"
+const val SP_IPV6 = "ipv6"
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtils.kt
index a0dae5a3..da6ade74 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtils.kt
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtils.kt
@@ -74,9 +74,6 @@ class SettingUtils private constructor() {
//自动删除N天前的转发记录
var autoCleanLogsDays: Int by SharedPreference(SP_AUTO_CLEAN_LOGS_DAYS, 0)
- //是否监听网络状态变化
- var enableNetworkStateReceiver: Boolean by SharedPreference(SP_NET_STATE_RECEIVER, false)
-
//是否不在最近任务列表中显示
var enableExcludeFromRecents: Boolean by SharedPreference(SP_ENABLE_EXCLUDE_FROM_RECENTS, false)
diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/task/TaskUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/task/TaskUtils.kt
index 5dd476e1..c684ad48 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/utils/task/TaskUtils.kt
+++ b/app/src/main/java/com/idormy/sms/forwarder/utils/task/TaskUtils.kt
@@ -1,10 +1,16 @@
package com.idormy.sms.forwarder.utils.task
import android.os.BatteryManager
+import com.idormy.sms.forwarder.utils.SP_BATTERY_INFO
import com.idormy.sms.forwarder.utils.SP_BATTERY_LEVEL
import com.idormy.sms.forwarder.utils.SP_BATTERY_PCT
import com.idormy.sms.forwarder.utils.SP_BATTERY_PLUGGED
import com.idormy.sms.forwarder.utils.SP_BATTERY_STATUS
+import com.idormy.sms.forwarder.utils.SP_DATA_SIM_SLOT
+import com.idormy.sms.forwarder.utils.SP_IPV4
+import com.idormy.sms.forwarder.utils.SP_IPV6
+import com.idormy.sms.forwarder.utils.SP_NETWORK_STATE
+import com.idormy.sms.forwarder.utils.SP_WIFI_SSID
import com.idormy.sms.forwarder.utils.SharedPreference
/**
@@ -15,7 +21,7 @@ class TaskUtils private constructor() {
companion object {
//电池信息
- var batteryInfo: String by SharedPreference("batteryInfo", "")
+ var batteryInfo: String by SharedPreference(SP_BATTERY_INFO, "")
//当前电量
var batteryLevel: Int by SharedPreference(SP_BATTERY_LEVEL, 0)
@@ -28,5 +34,20 @@ class TaskUtils private constructor() {
//充电方式
var batteryPlugged: Int by SharedPreference(SP_BATTERY_PLUGGED, BatteryManager.BATTERY_PLUGGED_AC)
+
+ //网络状态:0-没有网络,1-移动网络,2-WiFi,3-以太网, 4-未知
+ var networkState: Int by SharedPreference(SP_NETWORK_STATE, 0)
+
+ //数据卡槽:0-未知,1-卡1,2-卡2
+ var dataSimSlot: Int by SharedPreference(SP_DATA_SIM_SLOT, 0)
+
+ //WiFi名称
+ var wifiSsid: String by SharedPreference(SP_WIFI_SSID, "")
+
+ //IPv4地址
+ var ipv4: String by SharedPreference(SP_IPV4, "")
+
+ //IPv6地址
+ var ipv6: String by SharedPreference(SP_IPV6, "")
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/workers/ActionWorker.kt b/app/src/main/java/com/idormy/sms/forwarder/workers/ActionWorker.kt
index b4897507..c7170d15 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/workers/ActionWorker.kt
+++ b/app/src/main/java/com/idormy/sms/forwarder/workers/ActionWorker.kt
@@ -52,51 +52,49 @@ class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker
var successNum = 0
for (action in actionList) {
- when (action.type) {
- TASK_ACTION_SENDSMS -> {
- val smsSetting = Gson().fromJson(action.setting, SmsSetting::class.java)
- if (smsSetting == null) {
- Log.d(TAG, "任务$taskId:smsSetting is null")
- continue
- }
- //获取卡槽信息
- if (App.SimInfoList.isEmpty()) {
- App.SimInfoList = PhoneUtils.getSimMultiInfo()
- }
- Log.d(TAG, App.SimInfoList.toString())
+ try {
+ when (action.type) {
+ TASK_ACTION_SENDSMS -> {
+ val smsSetting = Gson().fromJson(action.setting, SmsSetting::class.java)
+ if (smsSetting == null) {
+ Log.d(TAG, "任务$taskId:smsSetting is null")
+ continue
+ }
+ //获取卡槽信息
+ if (App.SimInfoList.isEmpty()) {
+ App.SimInfoList = PhoneUtils.getSimMultiInfo()
+ }
+ Log.d(TAG, App.SimInfoList.toString())
- //发送卡槽: 1=SIM1, 2=SIM2
- val simSlotIndex = smsSetting.simSlot - 1
- //TODO:取不到卡槽信息时,采用默认卡槽发送
- val mSubscriptionId: Int = App.SimInfoList[simSlotIndex]?.mSubscriptionId ?: -1
+ //发送卡槽: 1=SIM1, 2=SIM2
+ val simSlotIndex = smsSetting.simSlot - 1
+ //TODO:取不到卡槽信息时,采用默认卡槽发送
+ val mSubscriptionId: Int = App.SimInfoList[simSlotIndex]?.mSubscriptionId ?: -1
- val msg = if (ActivityCompat.checkSelfPermission(XUtil.getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
- ResUtils.getString(R.string.no_sms_sending_permission)
- } else {
- PhoneUtils.sendSms(mSubscriptionId, smsSetting.phoneNumbers, smsSetting.msgContent)
- successNum++
- }
+ val msg = if (ActivityCompat.checkSelfPermission(XUtil.getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
+ ResUtils.getString(R.string.no_sms_sending_permission)
+ } else {
+ PhoneUtils.sendSms(mSubscriptionId, smsSetting.phoneNumbers, smsSetting.msgContent)
+ successNum++
+ }
- Log.d(TAG, "任务$taskId:send sms result: $msg")
- continue
- }
+ Log.d(TAG, "任务$taskId:send sms result: $msg")
+ }
- TASK_ACTION_NOTIFICATION -> {
- try {
+ TASK_ACTION_NOTIFICATION -> {
val settingVo = Gson().fromJson(action.setting, Rule::class.java)
//自动任务的不需要吐司或者更新日志,特殊处理 logId = -1,msgId = -1
SendUtils.sendMsgSender(msgInfo, settingVo, 0, -1L, -1L)
successNum++
- } catch (e: Exception) {
- e.printStackTrace()
}
- continue
- }
- else -> {
- Log.d(TAG, "任务$taskId:action.type is ${action.type}")
- continue
+ else -> {
+ Log.d(TAG, "任务$taskId:action.type is ${action.type}")
+ }
}
+ } catch (e: Exception) {
+ e.printStackTrace()
+ Log.d(TAG, "任务$taskId:action.type is ${action.type}, exception: ${e.message}")
}
}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/workers/BatteryWorker.kt b/app/src/main/java/com/idormy/sms/forwarder/workers/BatteryWorker.kt
index 619ab326..8fb86141 100644
--- a/app/src/main/java/com/idormy/sms/forwarder/workers/BatteryWorker.kt
+++ b/app/src/main/java/com/idormy/sms/forwarder/workers/BatteryWorker.kt
@@ -39,7 +39,7 @@ class BatteryWorker(context: Context, params: WorkerParameters) : CoroutineWorke
return Result.failure()
}
- val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(TASK_CONDITION_BATTERY)
+ val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
for (task in taskList) {
Log.d(TAG, "task = $task")
@@ -94,7 +94,7 @@ class BatteryWorker(context: Context, params: WorkerParameters) : CoroutineWorke
return Result.failure()
}
- val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(TASK_CONDITION_CHARGE)
+ val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
for (task in taskList) {
Log.d(TAG, "task = $task")
@@ -125,7 +125,7 @@ class BatteryWorker(context: Context, params: WorkerParameters) : CoroutineWorke
//TODO:判断其他条件是否满足
//TODO: 组装消息体 && 执行具体任务
- val msgInfo = MsgInfo("task", task.name, msg, Date(), task.name)
+ val msgInfo = MsgInfo("task", task.name, msg, Date(), task.description)
val actionData = Data.Builder()
.putLong(TaskWorker.taskId, task.id)
.putString(TaskWorker.taskActions, task.actions)
diff --git a/app/src/main/java/com/idormy/sms/forwarder/workers/NetworkWorker.kt b/app/src/main/java/com/idormy/sms/forwarder/workers/NetworkWorker.kt
new file mode 100644
index 00000000..9bb9129c
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/workers/NetworkWorker.kt
@@ -0,0 +1,153 @@
+package com.idormy.sms.forwarder.workers
+
+import android.content.Context
+import android.util.Log
+import androidx.work.CoroutineWorker
+import androidx.work.Data
+import androidx.work.OneTimeWorkRequestBuilder
+import androidx.work.WorkManager
+import androidx.work.WorkerParameters
+import com.google.gson.Gson
+import com.idormy.sms.forwarder.App
+import com.idormy.sms.forwarder.R
+import com.idormy.sms.forwarder.database.AppDatabase
+import com.idormy.sms.forwarder.entity.MsgInfo
+import com.idormy.sms.forwarder.entity.task.NetworkSetting
+import com.idormy.sms.forwarder.entity.task.TaskSetting
+import com.idormy.sms.forwarder.utils.PhoneUtils
+import com.idormy.sms.forwarder.utils.TaskWorker
+import com.idormy.sms.forwarder.utils.task.TaskUtils
+import com.xuexiang.xutil.app.ServiceUtils
+import com.xuexiang.xutil.resource.ResUtils.getString
+import java.net.HttpURLConnection
+import java.net.URL
+import java.util.Date
+
+@Suppress("PrivatePropertyName", "DEPRECATION")
+class NetworkWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
+
+ private val TAG: String = NetworkWorker::class.java.simpleName
+ private val ipv4Pattern = Regex("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")
+ private val ipv6Pattern = Regex("^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$")
+
+ override suspend fun doWork(): Result {
+ val conditionType = inputData.getInt(TaskWorker.conditionType, -1)
+ val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(conditionType)
+ for (task in taskList) {
+ Log.d(TAG, "task = $task")
+
+ // 根据任务信息执行相应操作
+ val conditionList = Gson().fromJson(task.conditions, Array::class.java).toMutableList()
+ if (conditionList.isEmpty()) {
+ Log.d(TAG, "任务${task.id}:conditionList is empty")
+ continue
+ }
+ val firstCondition = conditionList.firstOrNull()
+ if (firstCondition == null) {
+ Log.d(TAG, "任务${task.id}:firstCondition is null")
+ continue
+ }
+
+ val networkSetting = Gson().fromJson(firstCondition.setting, NetworkSetting::class.java)
+ if (networkSetting == null) {
+ Log.d(TAG, "任务${task.id}:networkSetting is null")
+ continue
+ }
+
+ if (TaskUtils.networkState != networkSetting.networkState) {
+ Log.d(TAG, "任务${task.id}:networkState is not match, networkSetting = $networkSetting")
+ continue
+ }
+
+ //TODO:判断其他条件是否满足
+
+ var ipv4 = ""
+ var ipv6 = ""
+ val msg = StringBuilder()
+ msg.append(getString(R.string.network_type)).append(": ")
+ when (networkSetting.networkState) {
+ //移动网络
+ 1 -> {
+ val dataSimSlot = TaskUtils.dataSimSlot
+ if (networkSetting.dataSimSlot != 0 && dataSimSlot != networkSetting.dataSimSlot) {
+ Log.d(TAG, "任务${task.id}:dataSimSlot is not match, networkSetting = $networkSetting")
+ continue
+ }
+ msg.append(getString(R.string.net_mobile)).append("\n")
+
+ if (dataSimSlot != 0) {
+ msg.append(getString(R.string.data_sim_index)).append(": SIM-").append(dataSimSlot).append("\n")
+ // 获取 SIM 卡信息
+ val simIndex = dataSimSlot - 1
+ App.SimInfoList = PhoneUtils.getSimMultiInfo()
+ if (App.SimInfoList[simIndex]?.mCarrierName != null) {
+ //获取网络运营商名称:中国移动、中国联通、中国电信
+ msg.append(getString(R.string.carrier_name)).append(": ").append(App.SimInfoList[simIndex]?.mCarrierName).append("\n")
+ }
+ }
+
+ ipv4 = getPublicIP(false)
+ ipv6 = getPublicIP(true)
+ }
+
+ //WiFi
+ 2 -> {
+ if (networkSetting.wifiSsid.isNotEmpty() && TaskUtils.wifiSsid != networkSetting.wifiSsid) {
+ Log.d(TAG, "任务${task.id}:wifiSsid is not match, networkSetting = $networkSetting")
+ continue
+ }
+ msg.append(getString(R.string.net_wifi)).append("\n")
+ msg.append(getString(R.string.wifi_ssid)).append(": ").append(TaskUtils.wifiSsid).append("\n")
+
+ ipv4 = getPublicIP(false)
+ ipv6 = getPublicIP(true)
+ }
+
+ //未知 && 没有网络
+ else -> {
+ msg.append(getString(R.string.no_network)).append("\n")
+ }
+ }
+
+ val isHttpServerRunning = ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpServerService")
+ if (ipv4Pattern.matches(ipv4)) {
+ msg.append(getString(R.string.ipv4)).append(": ").append(ipv4).append("\n")
+ TaskUtils.ipv4 = ipv4
+ if (isHttpServerRunning) {
+ msg.append(getString(R.string.http_server)).append(": ").append("http://${ipv4}:5000").append("\n")
+ }
+ } else {
+ TaskUtils.ipv4 = ""
+ }
+
+ if (ipv6Pattern.matches(ipv6)) {
+ msg.append(getString(R.string.ipv6)).append(": ").append(ipv6).append("\n")
+ TaskUtils.ipv6 = ipv6
+ if (isHttpServerRunning) {
+ msg.append(getString(R.string.http_server)).append(": ").append("http://[${ipv6}]:5000").append("\n")
+ }
+ } else {
+ TaskUtils.ipv6 = ""
+ }
+
+ //TODO: 组装消息体 && 执行具体任务
+ val msgInfo = MsgInfo("task", task.name, msg.toString().trimEnd(), Date(), task.description)
+ val actionData = Data.Builder().putLong(TaskWorker.taskId, task.id).putString(TaskWorker.taskActions, task.actions).putString(TaskWorker.msgInfo, Gson().toJson(msgInfo)).build()
+ val actionRequest = OneTimeWorkRequestBuilder().setInputData(actionData).build()
+ WorkManager.getInstance().enqueue(actionRequest)
+ }
+
+ return Result.success()
+
+ }
+
+ //获取公网IP地址
+ private fun getPublicIP(ipv6: Boolean = false): String {
+ val url = if (ipv6) URL("https://api6.ipify.org/") else URL("https://api.ipify.org/")
+ val urlConnection = url.openConnection() as HttpURLConnection
+ urlConnection.requestMethod = "GET"
+ val inputStream = urlConnection.inputStream
+ return inputStream.bufferedReader().use { it.readText() }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_senders_socket.xml b/app/src/main/res/layout/fragment_senders_socket.xml
index 9de65201..1cc4f5d0 100644
--- a/app/src/main/res/layout/fragment_senders_socket.xml
+++ b/app/src/main/res/layout/fragment_senders_socket.xml
@@ -357,6 +357,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index 1c4cb0d9..45c199c6 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -557,9 +557,7 @@
SIM State Monitor
[Note] You need to manually create APP forwarding rules, package name: 66666666
Network State Monitor
- [Note] You need to manually create APP forwarding rules, package name: 77777777
Network State Change Remind
- Send a notification when the network status changes (connection mode/IP change)
Keep Alive
It is recommended to open the first three switch, do not disable the notification bar, to avoid APP being killed
Custom Settings
@@ -693,7 +691,7 @@
Logging
About
- Http Server
+ HttpServer
Start Server
Stop Server
Server is shutting down. Please wait.
@@ -1083,6 +1081,9 @@
Unknown
Network State: %s
WiFi SSID
+ If left blank, it won\'t check the connected WiFi SSID.
+ IPv4
+ IPv6
Enable {{LOCATION}} Tag
Insert location info into forwarded msg.
@@ -1191,4 +1192,8 @@
Absent
Ready
Unknown
+
+ Any SIM
+ SIM-1
+ SIM-2
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4406bb98..42b71af3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -558,9 +558,7 @@
SIM卡槽状态监控
需要手动创建APP转发规则,包名:66666666
网络状态监控
- 需要手动创建APP转发规则,包名:77777777
网络状态改变提醒
- 网络状态改变(连接方式/IP变化)时发出通知
保活措施
建议开启前三项授权或设置,不要禁用通知栏,避免APP被杀
个性设置
@@ -694,7 +692,7 @@
Logging
About
- Http Server
+ HttpServer
启动服务
停止服务
Server is shutting down. Please wait.
@@ -1084,6 +1082,9 @@
未知网络
网络状态:%s
WiFi名称
+ 留空则不判断连接的WiFi-SSID
+ IPv4
+ IPv6
启用 {{定位信息}} 标签
在转发信息中插入手机的当前定位信息
@@ -1192,4 +1193,8 @@
被移除
已就绪
未知
+
+ 不限卡槽
+ SIM-1
+ SIM-2