优化运动状态检测模块,运动状态检测阈值标准未测定。
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Tue Nov 04 12:54:59 GMT 2025
|
||||
#Wed Nov 05 08:47:36 GMT 2025
|
||||
stageCount=18
|
||||
libraryProject=
|
||||
baseVersion=15.0
|
||||
publishVersion=15.0.17
|
||||
buildCount=20
|
||||
buildCount=29
|
||||
baseBetaVersion=15.0.18
|
||||
|
||||
@@ -3,13 +3,12 @@ package cc.winboll.studio.positions.services;
|
||||
/**
|
||||
* @Author ZhanGSKen<zhangsken@qq.com>
|
||||
* @Date 2024/07/19 14:30:57
|
||||
* @Describe 应用主要服务组件类(适配运动状态GPS控制)
|
||||
* @Describe 应用主要服务组件类(适配运动状态GPS控制+静止10秒切换)
|
||||
*/
|
||||
import android.app.Service;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Location;
|
||||
@@ -25,7 +24,6 @@ import cc.winboll.studio.libappbase.LogUtils;
|
||||
import cc.winboll.studio.libappbase.ToastUtils;
|
||||
import cc.winboll.studio.positions.models.PositionModel;
|
||||
import cc.winboll.studio.positions.models.PositionTaskModel;
|
||||
import cc.winboll.studio.positions.receivers.MotionStatusReceiver;
|
||||
import cc.winboll.studio.positions.utils.AppConfigsUtil;
|
||||
import cc.winboll.studio.positions.utils.DistanceCalculatorUtil;
|
||||
import cc.winboll.studio.positions.utils.NotificationUtil;
|
||||
@@ -38,83 +36,125 @@ import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import cc.winboll.studio.positions.utils.LocalMotionDetector;
|
||||
|
||||
public class MainService extends Service {
|
||||
public class MainService extends Service implements LocalMotionDetector.MotionStatusCallback {
|
||||
|
||||
public static final String TAG = "MainService";
|
||||
public static final String EXTRA_IS_SETTING_TO_ENABLE = "EXTRA_IS_SETTING_TO_ENABLE";
|
||||
|
||||
// ---------------------- 定时器相关变量 ----------------------
|
||||
// 静止时GPS定时任务变量(Java 7 显式声明)
|
||||
private ScheduledExecutorService gpsStaticTimer; // 静止时GPS定时获取线程池
|
||||
private volatile boolean isGpsListening = false; // GPS是否处于持续监听状态
|
||||
private static final long GPS_STATIC_DURATION = 3; // 静止时GPS单次获取超时时间(秒)
|
||||
// ---------------------- 核心:LocalMotionDetector 实例(唯一运动状态检测工具) ----------------------
|
||||
private LocalMotionDetector mMotionDetector; // 本地运动状态检测器
|
||||
private static final long GPS_STATIC_INTERVAL = 30; // 静止时GPS间隔(30秒)
|
||||
|
||||
// GPS监听接口(Java 7 标准接口定义)
|
||||
// ---------------------- 定时器相关变量 ----------------------
|
||||
private ScheduledExecutorService gpsStaticTimer; // 静止时GPS定时任务
|
||||
private volatile boolean isGpsListening = false; // GPS是否持续监听
|
||||
private static final long GPS_STATIC_DURATION = 3; // 单次GPS获取超时(秒)
|
||||
|
||||
// ---------------------- 静止延迟切换配置(核心功能) ----------------------
|
||||
private static final long STATIC_DELAY_MS = 10 * 1000; // 静止10秒后切换
|
||||
private Handler staticDelayHandler; // 延迟执行切换逻辑的Handler
|
||||
private volatile boolean isDelaySwitching = false; // 标记是否正在等待延迟切换
|
||||
|
||||
// GPS监听接口
|
||||
public interface GpsUpdateListener {
|
||||
void onGpsPositionUpdated(PositionModel currentGpsPos);
|
||||
void onGpsStatusChanged(String status);
|
||||
}
|
||||
|
||||
// 任务更新监听接口(Java 7 风格)
|
||||
// 任务更新监听接口
|
||||
public interface TaskUpdateListener {
|
||||
void onTaskUpdated();
|
||||
}
|
||||
|
||||
// 监听管理(弱引用+线程安全集合,适配Java 7)
|
||||
// 监听管理
|
||||
private final Set<WeakReference<GpsUpdateListener>> mGpsListeners = new HashSet<WeakReference<GpsUpdateListener>>();
|
||||
private final Set<WeakReference<TaskUpdateListener>> mTaskListeners = new HashSet<WeakReference<TaskUpdateListener>>();
|
||||
private final Object mListenerLock = new Object(); // 监听操作锁
|
||||
private final Object mListenerLock = new Object();
|
||||
|
||||
// 原有核心变量(Java 7 显式初始化)
|
||||
private LocalBinder mLocalBinder; // 持有 LocalBinder 实例
|
||||
// 原有核心变量
|
||||
private LocalBinder mLocalBinder;
|
||||
private LocationManager mLocationManager;
|
||||
private LocationListener mGpsLocationListener;
|
||||
private static final long GPS_UPDATE_INTERVAL = 2000; // GPS更新间隔:2秒
|
||||
private static final float GPS_UPDATE_DISTANCE = 1; // GPS更新距离阈值:1米
|
||||
private boolean isGpsEnabled = false; // GPS是否启用标记
|
||||
private boolean isGpsPermissionGranted = false; // 定位权限是否授予标记
|
||||
private static final long GPS_UPDATE_INTERVAL = 2000; // 实时GPS更新间隔:2秒
|
||||
private static final float GPS_UPDATE_DISTANCE = 1; // 实时GPS更新距离:1米
|
||||
private boolean isGpsEnabled = false;
|
||||
private boolean isGpsPermissionGranted = false;
|
||||
|
||||
// 数据存储集合(Java 7 基础集合)
|
||||
private final ArrayList<PositionModel> mPositionList = new ArrayList<PositionModel>(); // 位置数据列表
|
||||
private final ArrayList<PositionTaskModel> mAllTasks = new ArrayList<PositionTaskModel>();// 任务数据列表
|
||||
private static PositionModel _mCurrentGpsPosition; // 当前GPS定位数据
|
||||
// 数据存储集合
|
||||
private final ArrayList<PositionModel> mPositionList = new ArrayList<PositionModel>();
|
||||
private final ArrayList<PositionTaskModel> mAllTasks = new ArrayList<PositionTaskModel>();
|
||||
private static PositionModel _mCurrentGpsPosition;
|
||||
|
||||
// 服务相关变量(Java 7 显式声明)
|
||||
// 服务相关变量
|
||||
MyServiceConnection mMyServiceConnection;
|
||||
volatile static boolean _mIsServiceRunning; // 服务运行状态(volatile保证可见性)
|
||||
volatile static boolean _mIsServiceRunning;
|
||||
AppConfigsUtil mAppConfigsUtil;
|
||||
private ScheduledExecutorService distanceExecutor = Executors.newSingleThreadScheduledExecutor(); // 距离计算线程池
|
||||
private final Set<String> mVisiblePositionIds = new HashSet<String>(); // 可见位置ID集合
|
||||
private ScheduledExecutorService distanceExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
private final Set<String> mVisiblePositionIds = new HashSet<String>();
|
||||
|
||||
// 单例+应用上下文(Java 7 静态变量)
|
||||
// 单例+应用上下文
|
||||
private static volatile MainService sInstance;
|
||||
private static Context sAppContext;
|
||||
|
||||
// 核心:运动状态Receiver(动态注册/注销,Java 7 显式声明)
|
||||
private MotionStatusReceiver mMotionStatusReceiver;
|
||||
private IntentFilter mMotionStatusFilter;
|
||||
|
||||
// =========================================================================
|
||||
// 核心:运动状态回调(仅通过LocalMotionDetector触发,低运动归类为静止)
|
||||
// =========================================================================
|
||||
@Override
|
||||
public void onMotionStatusChanged(boolean isWalking, String statusDesc) {
|
||||
LogUtils.d(TAG, "运动状态回调:" + statusDesc + "(isWalking=" + isWalking + ")");
|
||||
updateNotificationGpsStatus("当前状态:" + statusDesc);
|
||||
|
||||
// 仅行走状态切实时GPS,非行走(静止+低运动)统一按静止处理
|
||||
if (isWalking) {
|
||||
// 行走状态:立即切回实时GPS(取消未执行的延迟任务)
|
||||
if (staticDelayHandler != null) {
|
||||
staticDelayHandler.removeCallbacksAndMessages(null); // 清空延迟任务
|
||||
isDelaySwitching = false; // 重置标记
|
||||
}
|
||||
stopGpsStaticTimer(); // 停止定时GPS
|
||||
startGpsLocation(); // 启动实时GPS
|
||||
LogUtils.d(TAG, "行走状态:已切换为实时GPS(2秒/1米)");
|
||||
|
||||
} else {
|
||||
// 非行走状态:延迟10秒切换为定时GPS
|
||||
if (isGpsListening && !isDelaySwitching) { // 仅实时GPS运行且无延迟任务时触发
|
||||
isDelaySwitching = true;
|
||||
staticDelayHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
stopGpsLocation(); // 停止实时GPS
|
||||
startGpsStaticTimer(GPS_STATIC_INTERVAL); // 启动30秒定时GPS
|
||||
LogUtils.d(TAG, "静止/低运动10秒:已切换为30秒定时GPS");
|
||||
isDelaySwitching = false; // 重置标记
|
||||
}
|
||||
}, STATIC_DELAY_MS);
|
||||
LogUtils.d(TAG, "检测到静止/低运动:将在10秒后切换为定时GPS(若持续非行走)");
|
||||
}
|
||||
LogUtils.d(TAG, "静止/低运动状态:等待延迟切换GPS");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// 静止GPS定时任务方法(Java 7 语法)
|
||||
// 静止GPS定时任务方法(适配Java7)
|
||||
// =========================================================================
|
||||
// 启动静止时GPS定时获取
|
||||
public void startGpsStaticTimer(long interval) {
|
||||
// 先销毁旧定时器(避免重复创建)
|
||||
// 启动静止时GPS定时获取(间隔:秒)
|
||||
public void startGpsStaticTimer(long intervalSeconds) {
|
||||
stopGpsStaticTimer();
|
||||
|
||||
// 创建单线程定时器
|
||||
gpsStaticTimer = Executors.newSingleThreadScheduledExecutor();
|
||||
gpsStaticTimer.scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
LogUtils.d(TAG, "静止时GPS定时任务触发:开始单次GPS获取");
|
||||
startSingleGpsRetrieve(); // 单次GPS获取
|
||||
startSingleGpsRetrieve();
|
||||
}
|
||||
}, 0, interval, TimeUnit.MINUTES); // 立即执行第一次,之后按间隔执行
|
||||
}, 0, intervalSeconds, TimeUnit.SECONDS);
|
||||
|
||||
LogUtils.d(TAG, "静止时GPS定时任务已启动(间隔:" + interval + "分钟)");
|
||||
LogUtils.d(TAG, "静止时GPS定时任务已启动(间隔:" + intervalSeconds + "秒)");
|
||||
}
|
||||
|
||||
// 停止静止时GPS定时任务
|
||||
@@ -135,7 +175,7 @@ public class MainService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
// 单次GPS获取(获取后关闭监听,Java 7 匿名内部类)
|
||||
// 单次GPS获取(获取后关闭监听)
|
||||
private void startSingleGpsRetrieve() {
|
||||
if (!checkGpsReady()) {
|
||||
LogUtils.w(TAG, "单次GPS获取:GPS未就绪,跳过");
|
||||
@@ -143,13 +183,11 @@ public class MainService extends Service {
|
||||
}
|
||||
|
||||
try {
|
||||
// 注册临时GPS监听(仅获取一次位置)
|
||||
mLocationManager.requestSingleUpdate(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
new LocationListener() {
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
// 获取到位置:同步数据+关闭监听
|
||||
if (location != null) {
|
||||
PositionModel gpsPos = new PositionModel();
|
||||
gpsPos.setLatitude(location.getLatitude());
|
||||
@@ -159,7 +197,6 @@ public class MainService extends Service {
|
||||
syncCurrentGpsPosition(gpsPos);
|
||||
LogUtils.d(TAG, "单次GPS获取成功:纬度=" + location.getLatitude());
|
||||
}
|
||||
// 移除监听(避免内存泄漏)
|
||||
mLocationManager.removeUpdates(this);
|
||||
}
|
||||
|
||||
@@ -171,24 +208,23 @@ public class MainService extends Service {
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
mLocationManager.removeUpdates(this); // 禁用时移除监听
|
||||
mLocationManager.removeUpdates(this);
|
||||
}
|
||||
},
|
||||
Looper.getMainLooper()
|
||||
);
|
||||
|
||||
// 超时处理:指定时间内未获取则强制关闭
|
||||
// 超时处理
|
||||
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// 移除所有临时监听
|
||||
mLocationManager.removeUpdates(new LocationListener() {
|
||||
@Override public void onLocationChanged(Location location) {}
|
||||
@Override public void onStatusChanged(String provider, int status, Bundle extras) {}
|
||||
@Override public void onProviderEnabled(String provider) {}
|
||||
@Override public void onProviderDisabled(String provider) {}
|
||||
});
|
||||
LogUtils.d(TAG, "单次GPS获取超时(" + GPS_STATIC_DURATION + "秒),已强制关闭监听");
|
||||
LogUtils.d(TAG, "单次GPS获取超时(" + GPS_STATIC_DURATION + "秒)");
|
||||
}
|
||||
}, GPS_STATIC_DURATION * 1000);
|
||||
|
||||
@@ -201,7 +237,7 @@ public class MainService extends Service {
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// 任务操作核心接口(Java 7 实现)
|
||||
// 任务操作核心接口
|
||||
// =========================================================================
|
||||
public void addTask(PositionTaskModel newTask) {
|
||||
if (newTask == null || TextUtils.isEmpty(newTask.getPositionId())) {
|
||||
@@ -209,7 +245,6 @@ public class MainService extends Service {
|
||||
return;
|
||||
}
|
||||
|
||||
// 任务去重(Java 7 迭代器遍历)
|
||||
boolean isDuplicate = false;
|
||||
Iterator<PositionTaskModel> taskIter = mAllTasks.iterator();
|
||||
while (taskIter.hasNext()) {
|
||||
@@ -236,7 +271,6 @@ public class MainService extends Service {
|
||||
return posTasks;
|
||||
}
|
||||
|
||||
// 筛选任务(Java 7 迭代器遍历)
|
||||
Iterator<PositionTaskModel> taskIter = mAllTasks.iterator();
|
||||
while (taskIter.hasNext()) {
|
||||
PositionTaskModel task = taskIter.next();
|
||||
@@ -280,7 +314,6 @@ public class MainService extends Service {
|
||||
return;
|
||||
}
|
||||
|
||||
// 迭代器删除(Java 7 安全方式)
|
||||
Iterator<PositionTaskModel> taskIter = mAllTasks.iterator();
|
||||
while (taskIter.hasNext()) {
|
||||
PositionTaskModel task = taskIter.next();
|
||||
@@ -326,7 +359,6 @@ public class MainService extends Service {
|
||||
while (iter.hasNext()) {
|
||||
final WeakReference<TaskUpdateListener> ref = iter.next();
|
||||
if (ref.get() != null) {
|
||||
// 主线程判断+切换(Java 7 匿名Runnable)
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
ref.get().onTaskUpdated();
|
||||
} else {
|
||||
@@ -338,7 +370,7 @@ public class MainService extends Service {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
iter.remove(); // 清理已回收弱引用
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,7 +378,7 @@ public class MainService extends Service {
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// 服务基础方法(核心调整:动态注册/注销MotionStatusReceiver)
|
||||
// 服务基础方法(初始化LocalMotionDetector,删除Receiver相关逻辑)
|
||||
// =========================================================================
|
||||
public static synchronized MainService getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
@@ -364,7 +396,7 @@ public class MainService extends Service {
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mLocalBinder; // 返回LocalBinder暴露服务
|
||||
return mLocalBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -374,31 +406,29 @@ public class MainService extends Service {
|
||||
sInstance = this;
|
||||
sAppContext = getApplicationContext();
|
||||
|
||||
// 初始化LocalBinder
|
||||
mLocalBinder = new LocalBinder(this);
|
||||
|
||||
_mIsServiceRunning = false;
|
||||
mAppConfigsUtil = AppConfigsUtil.getInstance(this);
|
||||
|
||||
// 初始化服务连接
|
||||
if (mMyServiceConnection == null) {
|
||||
mMyServiceConnection = new MyServiceConnection();
|
||||
}
|
||||
|
||||
// 初始化GPS监听(仅初始化,不启动)
|
||||
//initGpsLocationListener();
|
||||
// 初始化:LocalMotionDetector+延迟切换Handler(Java7兼容)
|
||||
mMotionDetector = LocalMotionDetector.getInstance();
|
||||
staticDelayHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
if (mAppConfigsUtil.isEnableMainService(true)) {
|
||||
run(); // 启动服务核心逻辑
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
// 服务核心运行方法(调整:启动服务时仅注册Receiver,不启动GPS)
|
||||
// 服务核心运行方法(删除Receiver注册逻辑)
|
||||
public void run() {
|
||||
if (mAppConfigsUtil.isEnableMainService(true)) {
|
||||
if (!_mIsServiceRunning) {
|
||||
_mIsServiceRunning = true;
|
||||
wakeupAndBindAssistant(); // 唤醒并绑定辅助服务
|
||||
wakeupAndBindAssistant();
|
||||
|
||||
// 启动前台服务
|
||||
String initialStatus = "[ Positions ] is in Service.";
|
||||
@@ -406,23 +436,15 @@ public class MainService extends Service {
|
||||
startForeground(NotificationUtil.FOREGROUND_SERVICE_NOTIFICATION_ID,
|
||||
NotificationUtil.createForegroundServiceNotification(this, initialStatus));
|
||||
|
||||
// 初始化LocationManager(仅初始化,不启动GPS)
|
||||
// 初始化LocationManager
|
||||
mLocationManager = (LocationManager) sInstance.getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
|
||||
|
||||
// 加载本地数据
|
||||
PositionModel.loadBeanList(MainService.this, mPositionList, PositionModel.class);
|
||||
PositionTaskModel.loadBeanList(MainService.this, mAllTasks, PositionTaskModel.class);
|
||||
|
||||
// 初始化运动状态Receiver(动态注册准备)
|
||||
initMotionStatusReceiver();
|
||||
|
||||
// 动态注册MotionStatusReceiver(核心:交给Receiver控制GPS)
|
||||
registerMotionStatusReceiver();
|
||||
|
||||
Intent triggerIntent = new Intent(MotionStatusReceiver.ACTION_MOTION_STATUS_RECEIVER);
|
||||
triggerIntent.putExtra(MotionStatusReceiver.EXTRA_SENSORS_ENABLE, true);
|
||||
sendBroadcast(triggerIntent);
|
||||
LogUtils.d(TAG, "已发送自主触发广播,唤醒MotionStatusReceiver");
|
||||
// 核心:启动LocalMotionDetector监测(唯一运动状态来源)
|
||||
mMotionDetector.startDetection(this, this);
|
||||
|
||||
// 提示与日志
|
||||
ToastUtils.show(initialStatus);
|
||||
@@ -431,45 +453,6 @@ public class MainService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化运动状态Receiver和IntentFilter
|
||||
private void initMotionStatusReceiver() {
|
||||
LogUtils.d(TAG, "initMotionStatusReceiver()");
|
||||
mMotionStatusReceiver = new MotionStatusReceiver();
|
||||
mMotionStatusFilter = new IntentFilter();
|
||||
mMotionStatusFilter.addAction(MotionStatusReceiver.ACTION_MOTION_STATUS_RECEIVER);
|
||||
}
|
||||
|
||||
// 动态注册MotionStatusReceiver
|
||||
private void registerMotionStatusReceiver() {
|
||||
LogUtils.d(TAG, "registerMotionStatusReceiver()");
|
||||
if (mMotionStatusReceiver != null && mMotionStatusFilter != null) {
|
||||
try {
|
||||
registerReceiver(mMotionStatusReceiver, mMotionStatusFilter);
|
||||
LogUtils.d(TAG, "MotionStatusReceiver 动态注册成功");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "MotionStatusReceiver 注册失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 动态注销MotionStatusReceiver
|
||||
//
|
||||
private void unregisterMotionStatusReceiver() {
|
||||
if (mMotionStatusReceiver != null) {
|
||||
try {
|
||||
unregisterReceiver(mMotionStatusReceiver);
|
||||
mMotionStatusReceiver.forceCleanResources(); // 新增:强制清理传感器
|
||||
LogUtils.d(TAG, "MotionStatusReceiver 注销并强制清理传感器");
|
||||
} catch (Exception e) {
|
||||
LogUtils.e(TAG, "MotionStatusReceiver 注销失败:" + e.getMessage());
|
||||
} finally {
|
||||
mMotionStatusReceiver = null;
|
||||
mMotionStatusFilter = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isServiceRunning() {
|
||||
return _mIsServiceRunning;
|
||||
}
|
||||
@@ -479,37 +462,44 @@ public class MainService extends Service {
|
||||
super.onDestroy();
|
||||
sInstance = null;
|
||||
|
||||
// 核心清理:1.注销MotionStatusReceiver 2.关闭GPS 3.停止定时任务
|
||||
unregisterMotionStatusReceiver(); // 注销Receiver,避免内存泄漏
|
||||
stopGpsLocation(); // 强制关闭GPS监听
|
||||
stopGpsStaticTimer(); // 停止静止时GPS定时任务
|
||||
// 核心:停止LocalMotionDetector(避免传感器内存泄漏)
|
||||
if (mMotionDetector != null) {
|
||||
mMotionDetector.stopDetection();
|
||||
LogUtils.d(TAG, "LocalMotionDetector 已停止检测");
|
||||
}
|
||||
|
||||
// 其他资源清理
|
||||
// 清理延迟Handler任务(避免内存泄漏)
|
||||
if (staticDelayHandler != null) {
|
||||
staticDelayHandler.removeCallbacksAndMessages(null);
|
||||
staticDelayHandler = null;
|
||||
}
|
||||
|
||||
// 原有清理逻辑(已删除Receiver注销代码)
|
||||
stopGpsLocation();
|
||||
stopGpsStaticTimer();
|
||||
clearAllData();
|
||||
stopForeground(true);
|
||||
|
||||
// 清理所有监听者
|
||||
synchronized (mListenerLock) {
|
||||
mGpsListeners.clear();
|
||||
mTaskListeners.clear();
|
||||
}
|
||||
|
||||
// 销毁线程池
|
||||
if (distanceExecutor != null && !distanceExecutor.isShutdown()) {
|
||||
distanceExecutor.shutdown();
|
||||
}
|
||||
|
||||
// 重置状态变量
|
||||
_mIsServiceRunning = false;
|
||||
isGpsEnabled = false;
|
||||
isGpsListening = false;
|
||||
isDelaySwitching = false;
|
||||
mLocationManager = null;
|
||||
LogUtils.d(TAG, "MainService 销毁完成,所有资源已清理");
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// 位置操作方法(Java 7 语法)
|
||||
// 位置操作方法
|
||||
// =========================================================================
|
||||
public ArrayList<PositionModel> getPositionList() {
|
||||
return mPositionList;
|
||||
@@ -519,7 +509,6 @@ public class MainService extends Service {
|
||||
return _mCurrentGpsPosition;
|
||||
}
|
||||
|
||||
// 对外提供:判断GPS是否处于持续监听状态(给MotionStatusReceiver调用)
|
||||
public boolean isGpsListening() {
|
||||
return isGpsListening;
|
||||
}
|
||||
@@ -529,7 +518,6 @@ public class MainService extends Service {
|
||||
LogUtils.w(TAG, "removePosition:参数无效");
|
||||
return;
|
||||
}
|
||||
// 迭代器遍历删除
|
||||
Iterator<PositionModel> iter = mPositionList.iterator();
|
||||
while (iter.hasNext()) {
|
||||
PositionModel pos = iter.next();
|
||||
@@ -546,7 +534,6 @@ public class MainService extends Service {
|
||||
LogUtils.w(TAG, "updatePosition:参数无效");
|
||||
return;
|
||||
}
|
||||
// 基础for循环查找并更新
|
||||
for (int i = 0; i < mPositionList.size(); i++) {
|
||||
PositionModel oldPos = mPositionList.get(i);
|
||||
if (updatedPos.getPositionId().equals(oldPos.getPositionId())) {
|
||||
@@ -573,7 +560,6 @@ public class MainService extends Service {
|
||||
LogUtils.w(TAG, "addPosition:位置为空");
|
||||
return;
|
||||
}
|
||||
// 位置去重(增强for循环)
|
||||
boolean isDuplicate = false;
|
||||
for (PositionModel pos : mPositionList) {
|
||||
if (newPos.getPositionId().equals(pos.getPositionId())) {
|
||||
@@ -613,7 +599,6 @@ public class MainService extends Service {
|
||||
LogUtils.d(TAG, "syncCurrentGpsPosition:成功(纬度=" + position.getLatitude() + ",经度=" + position.getLongitude() + ")");
|
||||
notifyAllGpsListeners(position);
|
||||
|
||||
// 服务运行中同步通知栏状态
|
||||
if (_mIsServiceRunning) {
|
||||
syncGpsStatusToNotification();
|
||||
}
|
||||
@@ -623,14 +608,12 @@ public class MainService extends Service {
|
||||
if (!_mIsServiceRunning || _mCurrentGpsPosition == null) {
|
||||
return;
|
||||
}
|
||||
// 格式化通知内容
|
||||
final String gpsStatus = String.format(
|
||||
"GPS位置:北纬%.4f° 东经%.4f° | 可见位置:%d个",
|
||||
_mCurrentGpsPosition.getLatitude(),
|
||||
_mCurrentGpsPosition.getLongitude(),
|
||||
mVisiblePositionIds.size()
|
||||
);
|
||||
// 主线程切换
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
NotificationUtil.updateForegroundServiceStatus(this, gpsStatus);
|
||||
} else {
|
||||
@@ -645,7 +628,7 @@ public class MainService extends Service {
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// 服务生命周期+辅助服务相关(Java 7 语法)
|
||||
// 服务生命周期+辅助服务相关
|
||||
// =========================================================================
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
@@ -653,24 +636,18 @@ public class MainService extends Service {
|
||||
if (intent != null) {
|
||||
isSettingToEnable = intent.getBooleanExtra(EXTRA_IS_SETTING_TO_ENABLE, false);
|
||||
if (isSettingToEnable) {
|
||||
run(); // 重启服务核心逻辑(重新注册Receiver)
|
||||
run();
|
||||
}
|
||||
}
|
||||
|
||||
// 根据是否自启动返回对应启动模式
|
||||
return isSettingToEnable ? Service.START_STICKY : super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
// 服务连接内部类
|
||||
private class MyServiceConnection implements ServiceConnection {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
// 空实现(如需绑定辅助服务可补充逻辑)
|
||||
}
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
// 辅助服务断开时重新绑定
|
||||
if (mAppConfigsUtil.isEnableMainService(true)) {
|
||||
wakeupAndBindAssistant();
|
||||
}
|
||||
@@ -678,9 +655,7 @@ public class MainService extends Service {
|
||||
}
|
||||
|
||||
void wakeupAndBindAssistant() {
|
||||
// 检查辅助服务是否存活
|
||||
if (!ServiceUtil.isServiceAlive(getApplicationContext(), AssistantService.class.getName())) {
|
||||
// 启动+绑定辅助服务
|
||||
startService(new Intent(MainService.this, AssistantService.class));
|
||||
bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT);
|
||||
}
|
||||
@@ -688,28 +663,25 @@ public class MainService extends Service {
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// GPS相关核心方法(Java 7 语法,仅保留Receiver调用的启动/停止逻辑)
|
||||
// GPS相关核心方法
|
||||
// =========================================================================
|
||||
public MainService() {
|
||||
distanceExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
initGpsLocationListener();
|
||||
}
|
||||
|
||||
// 初始化GPS监听(仅创建Listener,不注册)
|
||||
private void initGpsLocationListener() {
|
||||
LogUtils.d(TAG, "initGpsLocationListener");
|
||||
mGpsLocationListener = new LocationListener() {
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
if (location != null) {
|
||||
// 封装GPS位置
|
||||
PositionModel gpsPos = new PositionModel();
|
||||
gpsPos.setLatitude(location.getLatitude());
|
||||
gpsPos.setLongitude(location.getLongitude());
|
||||
gpsPos.setPositionId("CURRENT_GPS_POS");
|
||||
gpsPos.setMemo("实时GPS位置");
|
||||
|
||||
// 同步位置+校验任务
|
||||
syncCurrentGpsPosition(gpsPos);
|
||||
DistanceCalculatorUtil.getInstance(MainService.this).checkAllTaskTriggerCondition(gpsPos);
|
||||
LogUtils.d(TAG, "GPS位置更新:纬度=" + location.getLatitude() + ",经度=" + location.getLongitude());
|
||||
@@ -720,7 +692,6 @@ public class MainService extends Service {
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
if (provider.equals(LocationManager.GPS_PROVIDER)) {
|
||||
String statusDesc = "";
|
||||
// Java 7 基础switch
|
||||
switch (status) {
|
||||
case LocationProvider.AVAILABLE:
|
||||
statusDesc = "GPS状态:已就绪(可用)";
|
||||
@@ -745,8 +716,7 @@ public class MainService extends Service {
|
||||
String statusDesc = "GPS已开启(用户手动打开)";
|
||||
LogUtils.d(TAG, statusDesc);
|
||||
notifyAllGpsStatusListeners(statusDesc);
|
||||
updateNotificationGpsStatus("GPS已开启,等待Receiver控制启动...");
|
||||
// 不主动启动GPS,由Receiver根据运动状态控制
|
||||
updateNotificationGpsStatus("GPS已开启,等待运动状态触发...");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -766,20 +736,15 @@ public class MainService extends Service {
|
||||
};
|
||||
}
|
||||
|
||||
// GPS就绪检查(给Receiver调用的GPS操作做前置判断)
|
||||
private boolean checkGpsReady() {
|
||||
// 检查定位权限
|
||||
isGpsPermissionGranted = checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
// 初始化LocationManager
|
||||
if (mLocationManager == null) {
|
||||
mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||
}
|
||||
// 检查GPS是否启用
|
||||
isGpsEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
|
||||
|
||||
// 权限未授予处理
|
||||
if (!isGpsPermissionGranted) {
|
||||
String tip = "GPS准备失败:缺少精确定位权限";
|
||||
LogUtils.e(TAG, tip);
|
||||
@@ -788,7 +753,6 @@ public class MainService extends Service {
|
||||
ToastUtils.show("请授予定位权限,否则无法获取GPS位置");
|
||||
return false;
|
||||
}
|
||||
// GPS未启用处理
|
||||
if (!isGpsEnabled) {
|
||||
String tip = "GPS准备失败:系统GPS未开启";
|
||||
LogUtils.e(TAG, tip);
|
||||
@@ -802,14 +766,13 @@ public class MainService extends Service {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 启动GPS持续监听(仅Receiver可调用)
|
||||
// 启动GPS持续监听(运动状态回调调用)
|
||||
public void startGpsLocation() {
|
||||
if (!checkGpsReady() || isGpsListening) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 注册GPS位置更新
|
||||
mLocationManager.requestLocationUpdates(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
GPS_UPDATE_INTERVAL,
|
||||
@@ -818,10 +781,9 @@ public class MainService extends Service {
|
||||
Looper.getMainLooper()
|
||||
);
|
||||
|
||||
// 标记GPS进入持续监听状态
|
||||
isGpsListening = true;
|
||||
|
||||
// 获取最后已知GPS位置
|
||||
// 获取最后已知位置
|
||||
Location lastKnownLocation = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
|
||||
if (lastKnownLocation != null) {
|
||||
PositionModel lastGpsPos = new PositionModel();
|
||||
@@ -853,9 +815,8 @@ public class MainService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
// 停止GPS持续监听(仅Receiver可调用)
|
||||
// 停止GPS持续监听(运动状态回调调用)
|
||||
public void stopGpsLocation() {
|
||||
// 校验参数:避免空指针+权限未授予时调用
|
||||
if (mLocationManager != null && mGpsLocationListener != null && isGpsPermissionGranted) {
|
||||
try {
|
||||
mLocationManager.removeUpdates(mGpsLocationListener);
|
||||
@@ -878,7 +839,6 @@ public class MainService extends Service {
|
||||
return;
|
||||
}
|
||||
|
||||
// 格式化通知内容
|
||||
final String triggerContent = String.format(
|
||||
"任务触发:%s\n位置:%s\n当前距离:%.1f米(条件:%s%d米)",
|
||||
task.getTaskDescription(),
|
||||
@@ -888,10 +848,8 @@ public class MainService extends Service {
|
||||
task.getDiscussDistance()
|
||||
);
|
||||
|
||||
// 更新前台通知
|
||||
updateNotificationGpsStatus(triggerContent);
|
||||
|
||||
// 显示Toast(主线程安全)
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
ToastUtils.show(triggerContent);
|
||||
NotificationUtil.show(MainService.this, task.getTaskId(), task.getPositionId(), task.getTaskDescription());
|
||||
@@ -910,7 +868,6 @@ public class MainService extends Service {
|
||||
// 更新前台通知的GPS状态
|
||||
void updateNotificationGpsStatus(final String statusText) {
|
||||
if (_mIsServiceRunning) {
|
||||
// 主线程判断+切换(Java7匿名内部类)
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
NotificationUtil.updateForegroundServiceStatus(this, statusText);
|
||||
} else {
|
||||
@@ -926,7 +883,7 @@ public class MainService extends Service {
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// GPS监听通知相关方法(Java7语法,给外部监听者回调)
|
||||
// GPS监听通知相关方法
|
||||
// =========================================================================
|
||||
public void notifyAllGpsListeners(PositionModel currentGpsPos) {
|
||||
if (currentGpsPos == null || mGpsListeners.isEmpty()) {
|
||||
@@ -940,7 +897,7 @@ public class MainService extends Service {
|
||||
if (listener != null) {
|
||||
notifySingleListener(listener, currentGpsPos);
|
||||
} else {
|
||||
iter.remove(); // 清理已回收监听者
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -969,7 +926,6 @@ public class MainService extends Service {
|
||||
WeakReference<GpsUpdateListener> ref = iter.next();
|
||||
final GpsUpdateListener listener = ref.get();
|
||||
if (listener != null) {
|
||||
// 主线程切换,避免UI异常(Java7匿名Runnable)
|
||||
if (Looper.myLooper() == Looper.getMainLooper()) {
|
||||
listener.onGpsStatusChanged(status);
|
||||
} else {
|
||||
@@ -981,7 +937,7 @@ public class MainService extends Service {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
iter.remove(); // 清理无效弱引用
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -995,7 +951,6 @@ public class MainService extends Service {
|
||||
synchronized (mListenerLock) {
|
||||
mGpsListeners.add(new WeakReference<GpsUpdateListener>(listener));
|
||||
LogUtils.d(TAG, "GPS监听注册成功,当前数量:" + mGpsListeners.size());
|
||||
// 注册后推送当前GPS位置(避免监听者遗漏初始数据)
|
||||
if (_mCurrentGpsPosition != null) {
|
||||
notifySingleListener(listener, _mCurrentGpsPosition);
|
||||
}
|
||||
@@ -1021,9 +976,9 @@ public class MainService extends Service {
|
||||
}
|
||||
|
||||
|
||||
// =========================================================================
|
||||
// LocalBinder 定义(与Activity绑定用,Java7内部类)
|
||||
// =========================================================================
|
||||
// =========================================================================
|
||||
// LocalBinder 定义(无修改)
|
||||
// =========================================================================
|
||||
public class LocalBinder extends android.os.Binder {
|
||||
private MainService mService;
|
||||
|
||||
@@ -1032,7 +987,7 @@ public class MainService extends Service {
|
||||
}
|
||||
|
||||
public MainService getService() {
|
||||
return mService; // 暴露MainService实例给绑定的Activity
|
||||
return mService;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
package cc.winboll.studio.positions.utils;
|
||||
|
||||
/**
|
||||
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
|
||||
* @Date 2025/11/05 15:49
|
||||
* @Describe LocalMotionDetector
|
||||
*/
|
||||
import android.content.Context;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
/**
|
||||
* 本机运动状态监测工具(无联网,纯传感器)
|
||||
*/
|
||||
public class LocalMotionDetector implements SensorEventListener {
|
||||
public static final String TAG = "LocalMotionDetector";
|
||||
|
||||
// 配置参数(重点修改:调高运动阈值,适配坐立持机场景)
|
||||
private static final float MOTION_THRESHOLD = 1.8f; // 从0.5f调高到1.8f(过滤坐立轻微晃动)
|
||||
private static final long STATUS_CHECK_INTERVAL = 3000; // 3秒判断一次状态
|
||||
private static final int STEP_CHANGE_THRESHOLD = 2; // 3秒≥2步判定行走
|
||||
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mAccelerometer;
|
||||
private Sensor mStepCounter;
|
||||
private Handler mMainHandler;
|
||||
private MotionStatusCallback mCallback;
|
||||
|
||||
private boolean mIsDetecting = false;
|
||||
private float mLastAccelMagnitude = 0f;
|
||||
private int mLastStepCount = 0;
|
||||
private int mCurrentStepCount = 0;
|
||||
private boolean mIsWalking = false;
|
||||
|
||||
// 单例模式
|
||||
private static LocalMotionDetector sInstance;
|
||||
public static LocalMotionDetector getInstance() {
|
||||
if (sInstance == null) {
|
||||
synchronized (LocalMotionDetector.class) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new LocalMotionDetector();
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private LocalMotionDetector() {
|
||||
mMainHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始监测运动状态
|
||||
*/
|
||||
public void startDetection(Context context, MotionStatusCallback callback) {
|
||||
if (mIsDetecting) return;
|
||||
mCallback = callback;
|
||||
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
|
||||
// 初始化传感器
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
mStepCounter = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
|
||||
|
||||
// 注册传感器监听
|
||||
if (mAccelerometer != null) {
|
||||
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL, mMainHandler);
|
||||
}
|
||||
if (mStepCounter != null) {
|
||||
mSensorManager.registerListener(this, mStepCounter, SensorManager.SENSOR_DELAY_NORMAL, mMainHandler);
|
||||
LogUtils.d(TAG, "计步传感器已启动");
|
||||
} else {
|
||||
LogUtils.d(TAG, "设备不支持计步传感器,仅用加速度判断");
|
||||
}
|
||||
|
||||
// 启动定时状态检测
|
||||
mMainHandler.postDelayed(mStatusCheckRunnable, STATUS_CHECK_INTERVAL);
|
||||
mIsDetecting = true;
|
||||
LogUtils.d(TAG, "运动状态监测已启动");
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止监测
|
||||
*/
|
||||
public void stopDetection() {
|
||||
if (!mIsDetecting) return;
|
||||
if (mSensorManager != null) {
|
||||
mSensorManager.unregisterListener(this);
|
||||
}
|
||||
mMainHandler.removeCallbacksAndMessages(null);
|
||||
mIsDetecting = false;
|
||||
mIsWalking = false;
|
||||
mCallback = null;
|
||||
LogUtils.d(TAG, "运动状态监测已停止");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
if (!mIsDetecting) return;
|
||||
switch (event.sensor.getType()) {
|
||||
case Sensor.TYPE_ACCELEROMETER:
|
||||
// 计算加速度幅度(保留原逻辑,阈值已调高)
|
||||
float accelX = Math.abs(event.values[0]);
|
||||
float accelY = Math.abs(event.values[1]);
|
||||
float accelZ = Math.abs(event.values[2]);
|
||||
mLastAccelMagnitude = accelX + accelY + accelZ;
|
||||
break;
|
||||
case Sensor.TYPE_STEP_COUNTER:
|
||||
// 累计步数
|
||||
mCurrentStepCount = (int) event.values[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时判断运动状态(优化逻辑:计步为0时,即使有轻微加速度也判定为静止)
|
||||
*/
|
||||
private final Runnable mStatusCheckRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!mIsDetecting || mCallback == null) return;
|
||||
|
||||
//LogUtils.d(TAG, "mStatusCheckRunnable run");
|
||||
|
||||
boolean newIsWalking = false;
|
||||
// 结合计步器+加速度判断(优化:优先计步,无步数时严格按高阈值判断)
|
||||
if (mStepCounter != null) {
|
||||
int stepChange = mCurrentStepCount - mLastStepCount;
|
||||
// 只有“步数达标” 或 “无步数但加速度远超坐立幅度”,才判定为行走
|
||||
newIsWalking = (stepChange >= STEP_CHANGE_THRESHOLD)
|
||||
&& (mLastAccelMagnitude >= MOTION_THRESHOLD); // 增加步数+加速度双重校验
|
||||
mLastStepCount = mCurrentStepCount;
|
||||
} else {
|
||||
// 无计步器时,仅用高阈值判断
|
||||
newIsWalking = mLastAccelMagnitude >= MOTION_THRESHOLD;
|
||||
}
|
||||
|
||||
// 状态变化时回调
|
||||
if (newIsWalking != mIsWalking) {
|
||||
mIsWalking = newIsWalking;
|
||||
String statusDesc = mIsWalking ? "行走状态" : "静止/低运动状态";
|
||||
LogUtils.d(TAG, "运动状态变化:" + statusDesc + " | 加速度幅度:" + mLastAccelMagnitude); // 增加日志便于调试
|
||||
mCallback.onMotionStatusChanged(mIsWalking, statusDesc);
|
||||
}
|
||||
|
||||
LogUtils.d(TAG, String.format("运动状态 newIsWalking %s", newIsWalking));
|
||||
|
||||
// 循环检测
|
||||
mMainHandler.postDelayed(this, STATUS_CHECK_INTERVAL);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
|
||||
|
||||
/**
|
||||
* 运动状态回调接口
|
||||
*/
|
||||
public interface MotionStatusCallback {
|
||||
void onMotionStatusChanged(boolean isWalking, String statusDesc);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user