mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-03 01:17:41 +08:00
新增:自动任务·快捷指令 —— 网络状态改变(废弃:77777777
)
This commit is contained in:
parent
eb20d8ea05
commit
2233c0032f
@ -263,6 +263,44 @@
|
||||
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
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>
|
||||
<receiver
|
||||
android:name=".receiver.NetworkChangeReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.READ_PHONE_STATE">
|
||||
<intent-filter>
|
||||
<action
|
||||
android:name="android.net.conn.CONNECTIVITY_CHANGE"
|
||||
tools:ignore="BatteryLife" />
|
||||
<action
|
||||
android:name="android.net.wifi.WIFI_STATE_CHANGED"
|
||||
tools:ignore="BatteryLife" />
|
||||
<action
|
||||
android:name="android.net.wifi.STATE_CHANGE"
|
||||
tools:ignore="BatteryLife" />
|
||||
<!--<action
|
||||
android:name="android.intent.action.DATA_CONNECTION_STATE_CHANGED"
|
||||
tools:ignore="BatteryLife" />-->
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".receiver.SimStateReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.SIM_STATE_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".receiver.SmsReceiver"
|
||||
android:exported="true"
|
||||
@ -282,24 +320,6 @@
|
||||
<data android:mimeType="application/vnd.wap.mms-message" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
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>
|
||||
<receiver
|
||||
android:name=".receiver.SimStateReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.SIM_STATE_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,9 +118,6 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
SettingUtils.autoCleanLogsDays = newValue
|
||||
}
|
||||
|
||||
//监听网络状态变化
|
||||
switchNetworkStateReceiver(binding!!.sbNetworkStateReceiver)
|
||||
|
||||
//开机启动
|
||||
checkWithReboot(binding!!.sbWithReboot, binding!!.tvAutoStartup)
|
||||
//忽略电池优化设置
|
||||
@ -607,15 +604,6 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), 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
|
||||
|
@ -69,11 +69,19 @@ class NetworkFragment : BaseFragment<FragmentTasksConditionNetworkBinding?>(), 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<FragmentTasksConditionNetworkBinding?>(), 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)
|
||||
}
|
||||
}
|
@ -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<NetworkWorker>().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<NetworkInfo>(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
|
||||
}
|
||||
|
||||
}
|
@ -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"
|
||||
|
||||
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"
|
@ -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)
|
||||
|
||||
|
@ -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, "")
|
||||
}
|
||||
}
|
@ -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")
|
||||
}
|
||||
|
||||
Log.d(TAG, "任务$taskId:send sms result: $msg")
|
||||
continue
|
||||
}
|
||||
|
||||
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}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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<TaskSetting>::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<ActionWorker>().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() }
|
||||
}
|
||||
|
||||
}
|
@ -357,6 +357,7 @@
|
||||
<RadioButton
|
||||
android:id="@+id/rb_uriType_tcp"
|
||||
style="@style/rg_rb_style"
|
||||
android:checked="true"
|
||||
android:text="@string/tcp" />
|
||||
|
||||
<RadioButton
|
||||
|
@ -700,64 +700,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/network_state_monitor"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:text="@string/network_state_monitor_tips"
|
||||
android:textSize="10sp"
|
||||
tools:ignore="SmallSp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
style="@style/settingBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/network_state_change_remind"
|
||||
android:textStyle="bold"
|
||||
tools:ignore="RelativeOverlap" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/network_state_change_remind_tips"
|
||||
android:textSize="9sp"
|
||||
tools:ignore="SmallSp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
|
||||
android:id="@+id/sb_network_state_receiver"
|
||||
style="@style/SwitchButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -56,22 +56,102 @@
|
||||
android:text="@string/net_mobile"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_data_sim_slot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="@dimen/config_margin_10dp"
|
||||
android:layout_marginEnd="@dimen/config_margin_10dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="30dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/data_sim_index"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/rg_data_sim_slot"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_data_sim_slot_0"
|
||||
style="@style/rg_rb_style_wrap"
|
||||
android:checked="true"
|
||||
android:text="@string/sim_any"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_data_sim_slot_1"
|
||||
style="@style/rg_rb_style_wrap"
|
||||
android:text="@string/sim_1"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_data_sim_slot_2"
|
||||
style="@style/rg_rb_style_wrap"
|
||||
android:text="@string/sim_2"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_net_wifi"
|
||||
style="@style/rg_rb_style_match"
|
||||
android:text="@string/net_wifi"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_wifi_ssid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/config_margin_10dp"
|
||||
android:layout_marginEnd="@dimen/config_margin_10dp"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:text="@string/wifi_ssid"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_wifi_ssid"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_weight="1"
|
||||
android:hint="@string/wifi_ssid_hint"
|
||||
android:importantForAutofill="no"
|
||||
tools:ignore="TextContrastCheck,TextFields,TouchTargetSizeCheck" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_net_ethernet"
|
||||
style="@style/rg_rb_style_match"
|
||||
android:text="@string/net_ethernet"
|
||||
android:visibility="gone"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_net_unknown"
|
||||
style="@style/rg_rb_style_match"
|
||||
android:text="@string/net_unknown"
|
||||
android:visibility="gone"
|
||||
tools:ignore="TouchTargetSizeCheck,DuplicateSpeakableTextCheck" />
|
||||
|
||||
</RadioGroup>
|
||||
|
@ -557,9 +557,7 @@
|
||||
<string name="sim_state_monitor">SIM State Monitor</string>
|
||||
<string name="sim_state_monitor_tips">[Note] You need to manually create APP forwarding rules, package name: 66666666</string>
|
||||
<string name="network_state_monitor">Network State Monitor</string>
|
||||
<string name="network_state_monitor_tips">[Note] You need to manually create APP forwarding rules, package name: 77777777</string>
|
||||
<string name="network_state_change_remind">Network State Change Remind</string>
|
||||
<string name="network_state_change_remind_tips">Send a notification when the network status changes (connection mode/IP change)</string>
|
||||
<string name="keep_alive">Keep Alive</string>
|
||||
<string name="keep_alive_tips">It is recommended to open the first three switch, do not disable the notification bar, to avoid APP being killed</string>
|
||||
<string name="custom_settings">Custom Settings</string>
|
||||
@ -693,7 +691,7 @@
|
||||
<string name="nav_item_logging">Logging</string>
|
||||
<string name="nav_item_about">About</string>
|
||||
|
||||
<string name="http_server">Http Server</string>
|
||||
<string name="http_server">HttpServer</string>
|
||||
<string name="start_server">Start Server</string>
|
||||
<string name="stop_server">Stop Server</string>
|
||||
<string name="server_is_stopping">Server is shutting down. Please wait.</string>
|
||||
@ -1083,6 +1081,9 @@
|
||||
<string name="net_unknown">Unknown</string>
|
||||
<string name="network_state">Network State: %s</string>
|
||||
<string name="wifi_ssid">WiFi SSID</string>
|
||||
<string name="wifi_ssid_hint">If left blank, it won\'t check the connected WiFi SSID.</string>
|
||||
<string name="ipv4">IPv4</string>
|
||||
<string name="ipv6">IPv6</string>
|
||||
|
||||
<string name="enable_location_tag">Enable {{LOCATION}} Tag</string>
|
||||
<string name="enable_location_tag_tips">Insert location info into forwarded msg.</string>
|
||||
@ -1191,4 +1192,8 @@
|
||||
<string name="sim_state_absent">Absent</string>
|
||||
<string name="sim_state_ready">Ready</string>
|
||||
<string name="sim_state_unknown">Unknown</string>
|
||||
|
||||
<string name="sim_any">Any SIM</string>
|
||||
<string name="sim_1">SIM-1</string>
|
||||
<string name="sim_2">SIM-2</string>
|
||||
</resources>
|
||||
|
@ -558,9 +558,7 @@
|
||||
<string name="sim_state_monitor">SIM卡槽状态监控</string>
|
||||
<string name="sim_state_monitor_tips">需要手动创建APP转发规则,包名:66666666</string>
|
||||
<string name="network_state_monitor">网络状态监控</string>
|
||||
<string name="network_state_monitor_tips">需要手动创建APP转发规则,包名:77777777</string>
|
||||
<string name="network_state_change_remind">网络状态改变提醒</string>
|
||||
<string name="network_state_change_remind_tips">网络状态改变(连接方式/IP变化)时发出通知</string>
|
||||
<string name="keep_alive">保活措施</string>
|
||||
<string name="keep_alive_tips">建议开启前三项授权或设置,不要禁用通知栏,避免APP被杀</string>
|
||||
<string name="custom_settings">个性设置</string>
|
||||
@ -694,7 +692,7 @@
|
||||
<string name="nav_item_logging">Logging</string>
|
||||
<string name="nav_item_about">About</string>
|
||||
|
||||
<string name="http_server">Http Server</string>
|
||||
<string name="http_server">HttpServer</string>
|
||||
<string name="start_server">启动服务</string>
|
||||
<string name="stop_server">停止服务</string>
|
||||
<string name="server_is_stopping">Server is shutting down. Please wait.</string>
|
||||
@ -1084,6 +1082,9 @@
|
||||
<string name="net_unknown">未知网络</string>
|
||||
<string name="network_state">网络状态:%s</string>
|
||||
<string name="wifi_ssid">WiFi名称</string>
|
||||
<string name="wifi_ssid_hint">留空则不判断连接的WiFi-SSID</string>
|
||||
<string name="ipv4">IPv4</string>
|
||||
<string name="ipv6">IPv6</string>
|
||||
|
||||
<string name="enable_location_tag">启用 {{定位信息}} 标签</string>
|
||||
<string name="enable_location_tag_tips">在转发信息中插入手机的当前定位信息</string>
|
||||
@ -1192,4 +1193,8 @@
|
||||
<string name="sim_state_absent">被移除</string>
|
||||
<string name="sim_state_ready">已就绪</string>
|
||||
<string name="sim_state_unknown">未知</string>
|
||||
|
||||
<string name="sim_any">不限卡槽</string>
|
||||
<string name="sim_1">SIM-1</string>
|
||||
<string name="sim_2">SIM-2</string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user