修复:手机GPS禁用时,启用增强功能`GPS定位服务`导致SmsF启动奔溃

This commit is contained in:
pppscn 2024-02-11 11:19:33 +08:00
parent 44ab934873
commit c0afc9f529
7 changed files with 175 additions and 141 deletions

View File

@ -7,6 +7,7 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.Criteria
import android.location.LocationManager
import android.net.Uri
import android.os.Build
import android.os.Environment
@ -112,7 +113,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
switchEnableAppNotify(binding!!.sbEnableAppNotify, binding!!.scbCancelAppNotify, binding!!.scbNotUserPresent)
//启用GPS定位功能
switchEnableLocation(binding!!.sbEnableLocation, binding!!.layoutLocationSetting, binding!!.rgAccuracy, binding!!.rgPowerRequirement, binding!!.etMinInterval, binding!!.etMinDistance)
switchEnableLocation(binding!!.sbEnableLocation, binding!!.layoutLocationSetting, binding!!.rgAccuracy, binding!!.rgPowerRequirement, binding!!.xsbMinInterval, binding!!.xsbMinDistance)
//短信指令
switchEnableSmsCommand(binding!!.sbEnableSmsCommand, binding!!.etSafePhone)
//启动时异步获取已安装App信息
@ -513,7 +514,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
}
//启用定位功能
private fun switchEnableLocation(@SuppressLint("UseSwitchCompatOrMaterialCode") sbEnableLocation: SwitchButton, layoutLocationSetting: LinearLayout, rgAccuracy: RadioGroup, rgPowerRequirement: RadioGroup, etMinInterval: EditText, etMinDistance: EditText) {
private fun switchEnableLocation(@SuppressLint("UseSwitchCompatOrMaterialCode") sbEnableLocation: SwitchButton, layoutLocationSetting: LinearLayout, rgAccuracy: RadioGroup, rgPowerRequirement: RadioGroup, xsbMinInterval: XSeekBar, xsbMinDistance: XSeekBar) {
//是否启用定位功能
sbEnableLocation.isChecked = SettingUtils.enableLocation
layoutLocationSetting.visibility = if (SettingUtils.enableLocation) View.VISIBLE else View.GONE
@ -560,7 +561,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
R.id.rb_accuracy_no_requirement -> Criteria.NO_REQUIREMENT
else -> Criteria.ACCURACY_FINE
}
restartLocationService("rgAccuracy")
restartLocationService()
}
//设置电量消耗:低电耗(默认)
@ -581,49 +582,38 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
R.id.rb_power_requirement_no_requirement -> Criteria.NO_REQUIREMENT
else -> Criteria.POWER_LOW
}
restartLocationService("rgPowerRequirement")
restartLocationService()
}
//设置位置更新最小时间间隔(单位:毫秒); 默认间隔10000毫秒最小间隔1000毫秒
etMinInterval.setText((SettingUtils.locationMinInterval / 1000).toString())
etMinInterval.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable) {
val changedText = s.toString()
if (changedText.isEmpty() || changedText == "0") {
etMinInterval.setText("1")
etMinInterval.setSelection(etMinInterval.text.length) // 将光标移至文本末尾
return
}
SettingUtils.locationMinInterval = changedText.toLong() * 1000
restartLocationService()
}
})
xsbMinInterval.setDefaultValue((SettingUtils.locationMinInterval / 1000).toInt())
xsbMinInterval.setOnSeekBarListener { _: XSeekBar?, newValue: Int ->
SettingUtils.locationMinInterval = newValue * 1000L
restartLocationService()
}
//设置位置更新最小距离单位默认距离0米
etMinDistance.setText(SettingUtils.locationMinDistance.toString())
etMinDistance.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable) {
val changedText = s.toString()
if (changedText.isEmpty()) {
etMinDistance.setText("0")
etMinDistance.setSelection(etMinInterval.text.length) // 将光标移至文本末尾
return
}
SettingUtils.locationMinDistance = changedText.toInt()
restartLocationService()
}
})
xsbMinDistance.setDefaultValue(SettingUtils.locationMinDistance)
xsbMinDistance.setOnSeekBarListener { _: XSeekBar?, newValue: Int ->
SettingUtils.locationMinDistance = newValue
restartLocationService()
}
}
//重启定位服务
private fun restartLocationService(action: String = "RESTART") {
Log.d(TAG, "restartLocationService, action: $action")
val serviceIntent = Intent(requireContext(), LocationService::class.java)
serviceIntent.action = action
val locationManager = App.context.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
val isGpsEnabled = locationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER) == true
if (!isGpsEnabled && SettingUtils.enableLocation) {
XToastUtils.error(getString(R.string.toast_gps_not_enabled))
SettingUtils.enableLocation = false
binding!!.sbEnableLocation.isChecked = false
serviceIntent.action = "STOP"
} else {
serviceIntent.action = action
}
requireContext().startService(serviceIntent)
}

View File

@ -2,8 +2,12 @@ package com.idormy.sms.forwarder.service
import android.annotation.SuppressLint
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.location.Location
import android.location.LocationManager
import android.os.IBinder
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
@ -23,14 +27,20 @@ import com.king.location.LocationErrorCode
import com.king.location.OnExceptionListener
import com.king.location.OnLocationListener
import com.xuexiang.xaop.util.PermissionUtils
import com.yanzhenjie.andserver.Server
import java.util.Date
@SuppressLint("SimpleDateFormat")
@Suppress("PrivatePropertyName", "DEPRECATION")
class LocationService : Service(), Server.ServerListener {
class LocationService : Service() {
private val TAG: String = LocationService::class.java.simpleName
private val gpsStatusReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == LocationManager.PROVIDERS_CHANGED_ACTION) {
handleGpsStatusChanged()
}
}
}
companion object {
var isRunning = false
@ -45,13 +55,16 @@ class LocationService : Service(), Server.ServerListener {
super.onCreate()
if (!SettingUtils.enableLocation) return
//注册广播接收器
registerReceiver(gpsStatusReceiver, IntentFilter(LocationManager.PROVIDERS_CHANGED_ACTION))
startService()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
if (!SettingUtils.enableLocation || intent == null) return START_NOT_STICKY
if (intent == null) return START_NOT_STICKY
Log.i(TAG, "onStartCommand: ${intent.action}")
@ -60,11 +73,10 @@ class LocationService : Service(), Server.ServerListener {
} else if (intent.action == "STOP" && isRunning) {
stopService()
} else if (intent.action == "RESTART") {
stopService()
startService()
restartLocation()
}
return START_NOT_STICKY
return START_STICKY
}
override fun onDestroy() {
@ -73,18 +85,8 @@ class LocationService : Service(), Server.ServerListener {
if (!SettingUtils.enableLocation) return
stopService()
}
override fun onException(e: Exception?) {
Log.i(TAG, "onException: ")
}
override fun onStarted() {
Log.i(TAG, "onStarted: ")
}
override fun onStopped() {
Log.i(TAG, "onStopped: ")
//在 Service 销毁时记得注销广播接收器
unregisterReceiver(gpsStatusReceiver)
}
private fun startService() {
@ -94,16 +96,6 @@ class LocationService : Service(), Server.ServerListener {
TaskUtils.locationInfoOld = LocationInfo()
if (SettingUtils.enableLocation && PermissionUtils.isGranted(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION)) {
//可根据具体需求设置定位配置参数(这里只列出一些主要的参数)
val locationOption = App.LocationClient.getLocationOption().setAccuracy(SettingUtils.locationAccuracy)//设置位置精度:高精度
.setPowerRequirement(SettingUtils.locationPowerRequirement) //设置电量消耗:低电耗
.setMinTime(SettingUtils.locationMinInterval)//设置位置更新最小时间间隔(单位:毫秒); 默认间隔10000毫秒最小间隔1000毫秒
.setMinDistance(SettingUtils.locationMinDistance)//设置位置更新最小距离单位默认距离0米
.setOnceLocation(false)//设置是否只定位一次,默认为 false当设置为 true 时,则只定位一次后,会自动停止定位
.setLastKnownLocation(false)//设置是否获取最后一次缓存的已知位置,默认为 true
//设置定位配置参数
App.LocationClient.setLocationOption(locationOption)
App.LocationClient.startLocation()
//设置定位监听
App.LocationClient.setOnLocationListener(object : OnLocationListener() {
@ -125,7 +117,7 @@ class LocationService : Service(), Server.ServerListener {
HttpServerUtils.apiLocationCache = locationInfoNew
TaskUtils.locationInfoNew = locationInfoNew
//TODO: 触发自动任务
//触发自动任务
val locationInfoOld = TaskUtils.locationInfoOld
if (locationInfoOld.longitude != locationInfoNew.longitude || locationInfoOld.latitude != locationInfoNew.latitude || locationInfoOld.address != locationInfoNew.address) {
Log.d(TAG, "locationInfoOld = $locationInfoOld")
@ -139,34 +131,18 @@ class LocationService : Service(), Server.ServerListener {
TaskUtils.locationInfoOld = locationInfoNew
}
}
override fun onProviderEnabled(provider: String) {
super.onProviderEnabled(provider)
Log.d(TAG, "onProviderEnabled(provider = ${provider})")
}
override fun onProviderDisabled(provider: String) {
super.onProviderDisabled(provider)
Log.d(TAG, "onProviderDisabled(provider = ${provider})")
}
})
//设置异常监听
App.LocationClient.setOnExceptionListener(object : OnExceptionListener {
override fun onException(@LocationErrorCode errorCode: Int, e: Exception) {
//定位出现异常
//定位出现异常 && 尝试重启定位
Log.w(TAG, "onException(errorCode = ${errorCode}, e = ${e})")
//TODO: 重启定位
App.LocationClient.startLocation()
restartLocation()
}
})
if (App.LocationClient.isStarted()) {//如果已经开始定位,则先停止定位
App.LocationClient.stopLocation()
}
App.LocationClient.startLocation()
restartLocation()
isRunning = true
} else if (!SettingUtils.enableLocation && App.LocationClient.isStarted()) {
Log.d(TAG, "stopLocation")
@ -200,20 +176,59 @@ class LocationService : Service(), Server.ServerListener {
}
}
private fun restartLocation() {
//如果已经开始定位,则先停止定位
if (App.LocationClient.isStarted()) {
App.LocationClient.stopLocation()
}
if (isGpsEnabled()) {
//可根据具体需求设置定位配置参数(这里只列出一些主要的参数)
val locationOption = App.LocationClient.getLocationOption().setAccuracy(SettingUtils.locationAccuracy)//设置位置精度:高精度
.setPowerRequirement(SettingUtils.locationPowerRequirement) //设置电量消耗:低电耗
.setMinTime(SettingUtils.locationMinInterval)//设置位置更新最小时间间隔(单位:毫秒); 默认间隔10000毫秒最小间隔1000毫秒
.setMinDistance(SettingUtils.locationMinDistance)//设置位置更新最小距离单位默认距离0米
.setOnceLocation(false)//设置是否只定位一次,默认为 false当设置为 true 时,则只定位一次后,会自动停止定位
.setLastKnownLocation(false)//设置是否获取最后一次缓存的已知位置,默认为 true
//设置定位配置参数
App.LocationClient.setLocationOption(locationOption)
App.LocationClient.startLocation()
} else {
Log.w(TAG, "onException: GPS未开启")
}
}
private fun enqueueLocationWorkerRequest(
conditionType: Int,
locationJsonOld: String,
locationJsonNew: String
conditionType: Int, locationJsonOld: String, locationJsonNew: String
) {
val locationWorkerRequest = OneTimeWorkRequestBuilder<LocationWorker>().setInputData(
workDataOf(
TaskWorker.conditionType to conditionType,
"locationJsonOld" to locationJsonOld,
"locationJsonNew" to locationJsonNew
TaskWorker.conditionType to conditionType, "locationJsonOld" to locationJsonOld, "locationJsonNew" to locationJsonNew
)
).build()
WorkManager.getInstance(applicationContext).enqueue(locationWorkerRequest)
}
private fun handleGpsStatusChanged() {
val isGpsEnabled = isGpsEnabled()
//处理 GPS 状态变化
if (isGpsEnabled) {
//GPS 已启用
Log.d(TAG, "handleGpsStatusChanged: GPS 已启用")
if (SettingUtils.enableLocation && !App.LocationClient.isStarted()) {
App.LocationClient.startLocation()
}
} else {
//GPS 已停用
Log.d(TAG, "handleGpsStatusChanged: GPS 已停用")
if (SettingUtils.enableLocation && App.LocationClient.isStarted()) {
App.LocationClient.stopLocation()
}
}
}
private fun isGpsEnabled(): Boolean {
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager?
return locationManager?.isProviderEnabled(LocationManager.GPS_PROVIDER) == true
}
}

View File

@ -502,65 +502,86 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/min_interval"
android:text="@string/location_update"
android:textSize="@dimen/text_size_small"
android:textStyle="bold"
tools:ignore="SmallSp" />
<EditText
android:id="@+id/et_min_interval"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:digits="0123456789"
android:importantForAutofill="no"
android:inputType="number"
android:paddingTop="0dp"
android:paddingBottom="3dp"
android:singleLine="true"
android:textAlignment="center"
tools:ignore="LabelFor,SpeakableTextPresentCheck,TouchTargetSizeCheck" />
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/seconds"
android:textSize="@dimen/text_size_small"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/config_margin_10dp"
android:text="@string/min_distance"
android:textSize="@dimen/text_size_small"
android:textStyle="bold"
tools:ignore="SmallSp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/min_interval"
android:textSize="@dimen/text_size_small"
android:textStyle="bold" />
<EditText
android:id="@+id/et_min_distance"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:digits="0123456789"
android:importantForAutofill="no"
android:inputType="number"
android:paddingTop="0dp"
android:paddingBottom="3dp"
android:singleLine="true"
android:textAlignment="center"
tools:ignore="LabelFor,SpeakableTextPresentCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.picker.XSeekBar
android:id="@+id/xsb_min_interval"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:padding="0dp"
app:xsb_max="120"
app:xsb_min="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/meter"
android:textSize="@dimen/text_size_small"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/seconds"
android:textSize="@dimen/text_size_small"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/min_distance"
android:textSize="@dimen/text_size_small"
android:textStyle="bold" />
<com.xuexiang.xui.widget.picker.XSeekBar
android:id="@+id/xsb_min_distance"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:padding="0dp"
app:xsb_max="100"
app:xsb_min="1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/meter"
android:textSize="@dimen/text_size_small"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -1129,7 +1129,8 @@
<string name="power_requirement_low">Low</string>
<string name="power_requirement_medium">Medium</string>
<string name="power_requirement_high">High</string>
<string name="min_interval">To Update: Min Interval</string>
<string name="location_update">Location Update</string>
<string name="min_interval">Min Interval</string>
<string name="min_distance">Min Distance</string>
<string name="meter">m</string>
<string name="uid">UID</string>
@ -1339,4 +1340,5 @@
<string name="union_id">Union ID</string>
<string name="chat_id">Chat ID</string>
<string name="receive_id">Receive ID</string>
<string name="toast_gps_not_enabled">GPS is not enabled, please enable GPS first!</string>
</resources>

View File

@ -1130,7 +1130,8 @@
<string name="power_requirement_low"></string>
<string name="power_requirement_medium"></string>
<string name="power_requirement_high"></string>
<string name="min_interval">位置更新:最小时间间隔</string>
<string name="location_update">位置更新</string>
<string name="min_interval">最小时间间隔</string>
<string name="min_distance">最小距离间隔</string>
<string name="meter"></string>
<string name="uid">UID</string>
@ -1340,4 +1341,5 @@
<string name="union_id">Union ID</string>
<string name="chat_id">Chat ID</string>
<string name="receive_id">消息接收者ID</string>
<string name="toast_gps_not_enabled">GPS未开启请先开启GPS</string>
</resources>

View File

@ -1130,7 +1130,8 @@
<string name="power_requirement_low"></string>
<string name="power_requirement_medium"></string>
<string name="power_requirement_high"></string>
<string name="min_interval">位置更新:最小時間間隔</string>
<string name="location_update">位置更新</string>
<string name="min_interval">最小時間間隔</string>
<string name="min_distance">最小距離間隔</string>
<string name="meter"></string>
<string name="uid">UID</string>
@ -1341,4 +1342,5 @@
<string name="union_id">Union ID</string>
<string name="chat_id">Chat ID</string>
<string name="receive_id">訊息接收者ID</string>
<string name="toast_gps_not_enabled">GPS未開啟請先開啟GPS</string>
</resources>

View File

@ -1130,7 +1130,8 @@
<string name="power_requirement_low"></string>
<string name="power_requirement_medium"></string>
<string name="power_requirement_high"></string>
<string name="min_interval">位置更新:最小时间间隔</string>
<string name="location_update">位置更新</string>
<string name="min_interval">最小时间间隔</string>
<string name="min_distance">最小距离间隔</string>
<string name="meter"></string>
<string name="uid">UID</string>
@ -1340,4 +1341,5 @@
<string name="union_id">Union ID</string>
<string name="chat_id">Chat ID</string>
<string name="receive_id">消息接收者ID</string>
<string name="toast_gps_not_enabled">GPS未开启请先开启GPS</string>
</resources>