Compare commits

..

No commits in common. 'main' and 'develop' have entirely different histories.

@ -1,57 +1,2 @@
# 老人看护系统 # project
#### 项目简介
老人看护系统是一个综合性 Android 应用,旨在通过智能检测、健康监测、生活提醒和防走失功能,全方位保障老年人的安全与健康。本项目通过传感器、位置信息等多种手段,实现对老人的实时监控、突发状况提醒及健康状况分析。
####功能特性
- 输入健康信息:老人可通过应用录入健康数据(如心率、血压、血糖等),便于后续健康分析。
- 健康监测:老人可定时检测并输入健康数据,系统会生成分析报告,方便监护人和医生了解老人的健康状况。
- 日常生活提醒:亲属可以为老人设置提醒任务,例如按时服药、测量健康数据等。系统通过闹钟提醒老人,避免遗漏重要事项。
- 防走失功能:通过 GPS 定位监控老人的实时位置,可设置安全区域。一旦老人超出安全范围,系统将自动发送提醒通知。
- 紧急呼叫:老人在突发状况下可以通过系统快捷呼叫紧急联系人,同时系统也能自动检测异常情况,向预设联系人发送通知。
- 摔倒检测:通过传感器分析,实时监控老人状况。检测到跌倒后,系统会通知监护人和医生,并触发报警机制。
#### 环境需求
开发工具: Android Studio
Android SDK: 编译版本 34最低支持版本 27
语言: Java
依赖库:
- AppCompat 和 Material Design 组件
- ConstraintLayout 布局管理
- AMap 地图和位置服务
#### 使用说明
1. **项目构建**
克隆项目至本地
打开 Android Studio导入项目根目录。
同步 Gradle 配置文件,依赖配置见 build.gradle 文件.
2. **权限配置**
应用需要以下权限以确保功能正常运行:
- 传感器权限: 用于检测设备加速度和角速度。
- 系统悬浮窗权限: 确保弹窗可覆盖其他应用。
- 定位权限: 实现实时位置监控和安全区域提醒。
- 存储权限: 保存健康数据和分析报告。
#### 模块描述
1. **健康数据模块**
核心功能:
- 提供界面录入健康数据(心率、血压、血糖)。
- 数据录入后生成健康报告,方便监护人查看。
2. **日常提醒模块**
核心功能:
- 亲属可通过设定计划为老人设置日常提醒。
- 提醒通过闹钟弹窗和语音播报告知老人。
3. **防走失模块**
核心功能:
- 通过 GPS 获取老人的实时位置。
- 设置安全区域,一旦老人超出范围,系统发送通知。
4. **紧急呼叫模块**
核心功能:
- 提供快捷呼叫按钮,老人可一键拨打紧急联系人电话。
- 系统自动检测异常情况时,向紧急联系人发送报警信息。
5. **摔倒检测模块**
核心功能:
- 使用设备传感器(加速度计和陀螺仪)实时监测老人的运动状态。
- 通过算法分析检测跌倒事件。
- 检测到跌倒后系统触发弹窗、TTS 提示和紧急通知。

1
doc

@ -0,0 +1 @@
undefined

@ -0,0 +1 @@
undefined

Binary file not shown.

@ -0,0 +1 @@
undefined

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

1
src

@ -0,0 +1 @@
undefined

@ -1,15 +0,0 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="resolveExternalAnnotations" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

@ -1,44 +0,0 @@
plugins {
id 'com.android.application'
}
android {
compileSdk 34
defaultConfig {
applicationId "edu.gatech.seclass.fall_detection_master"
minSdk 27
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation files('libs\\AMap3DMap_10.0.900_AMapSearch_9.7.3_AMapLocation_6.4.7_20240816.jar')
implementation 'com.google.android.material:material:1.0.0'
implementation "androidx.drawerlayout:drawerlayout:1.1.1"
implementation 'com.github.zcweng:switch-button:0.0.3@aar'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

@ -1,21 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -1,20 +0,0 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "edu.gatech.seclass.fall_detection_master",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}

@ -1,26 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("edu.gatech.seclass.fall_detection_master", appContext.getPackageName());
}
}

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="edu.gatech.seclass.fall_detection_master">
<!--允许手机发送SMS短息-->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<!--允许手机振动-->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- 允许一个程序打开窗口使用 TYPE_SYSTEM_ALERT显示在其他所有程序的顶层 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 文本转语音相关权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 用于获取运营商信息,用于支持提供运营商信息相关的接口 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 用于访问wifi网络信息wifi信息会用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 用于获取wifi的获取权限wifi信息会用来进行网络定位 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 用于访问网络,网络定位需要上网 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 用于读取手机当前的状态 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 用于写入缓存数据到扩展存储卡 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 用于申请调用A-GPS模块 -->
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<!-- 用于申获取蓝牙信息进行室内定位 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="aroid.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 添加前台服务权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.SENSORS" />
<application
android:allowBackup="true"
android:name=".Myapp"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.FallDetectionmaster">
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="70a2133616ea4a172806aa922778eb70" />
<activity
android:name=".LoginActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".RegisterActivity" />
<activity android:name=".MainActivity" />
<activity android:name=".MapActivity" />
<activity
android:name=".GeofenceActivity"
android:label="电子围栏设置" />
<activity
android:name=".HealthInfoActivity"
android:label="健康信息" />
<activity
android:name=".HealthReportActivity"
android:label="健康报告" />
<activity
android:name=".AlarmActivity"
android:label="闹钟提醒" />
<service android:name="com.amap.api.location.APSService" />
<service
android:name=".FallDetectionService"
android:enabled="true"
android:exported="true"
android:foregroundServiceType="location"/>
<receiver
android:name=".FallLocalReceiver"
android:enabled="true"
android:exported="true"/>
<service
android:name=".service.AlarmService"
android:enabled="true"
android:exported="false" />
</application>
</manifest>

@ -1,194 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TimePicker;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import edu.gatech.seclass.fall_detection_master.adapter.AlarmAdapter;
import edu.gatech.seclass.fall_detection_master.model.AlarmInfo;
import edu.gatech.seclass.fall_detection_master.db.AlarmDao;
import edu.gatech.seclass.fall_detection_master.service.AlarmService;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
public class AlarmActivity extends AppCompatActivity implements AlarmAdapter.OnItemClickListener {
private RecyclerView rvAlarms;
private FloatingActionButton fabAddAlarm;
private AlarmAdapter alarmAdapter;
private List<AlarmInfo> alarmList;
private AlarmDao alarmDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm);
initViews();
initData();
setupListeners();
}
private void initViews() {
rvAlarms = findViewById(R.id.rv_alarms);
fabAddAlarm = findViewById(R.id.fab_add_alarm);
rvAlarms.setLayoutManager(new LinearLayoutManager(this));
alarmList = new ArrayList<>();
alarmAdapter = new AlarmAdapter(alarmList);
alarmAdapter.setOnItemClickListener(this);
rvAlarms.setAdapter(alarmAdapter);
}
private void initData() {
alarmDao = new AlarmDao(this);
loadAlarms();
}
private void loadAlarms() {
alarmList.clear();
alarmList.addAll(alarmDao.getAllAlarms());
alarmAdapter.notifyDataSetChanged();
}
private void setupListeners() {
fabAddAlarm.setOnClickListener(v -> showAlarmDialog(null));
}
private void showAlarmDialog(AlarmInfo alarm) {
View dialogView = getLayoutInflater().inflate(R.layout.dialog_alarm, null);
TimePicker timePicker = dialogView.findViewById(R.id.time_picker);
EditText etDescription = dialogView.findViewById(R.id.et_description);
// 如果是编辑模式,设置已有的值
if (alarm != null) {
timePicker.setHour(alarm.getHour());
timePicker.setMinute(alarm.getMinute());
etDescription.setText(alarm.getDescription());
}
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle(alarm == null ? "添加闹钟" : "编辑闹钟")
.setView(dialogView)
.setPositiveButton("确定", (dialog, which) -> {
int hour = timePicker.getHour();
int minute = timePicker.getMinute();
String description = etDescription.getText().toString().trim();
if (alarm == null) {
// 添加新闹钟
AlarmInfo newAlarm = new AlarmInfo(hour, minute);
newAlarm.setDescription(description);
long id = alarmDao.insert(newAlarm);
newAlarm.setId((int)id);
alarmList.add(newAlarm);
alarmAdapter.notifyItemInserted(alarmList.size() - 1);
scheduleAlarm(newAlarm);
} else {
// 更新现有闹钟
alarm.setHour(hour);
alarm.setMinute(minute);
alarm.setDescription(description);
alarmDao.update(alarm);
alarmAdapter.notifyDataSetChanged();
if (alarm.isEnabled()) {
cancelAlarm(alarm);
scheduleAlarm(alarm);
}
}
})
.setNegativeButton("取消", null);
builder.create().show();
}
private void scheduleAlarm(AlarmInfo alarm) {
Intent alarmIntent = new Intent(this, AlarmService.class);
alarmIntent.putExtra("alarm_id", alarm.getId());
PendingIntent pendingIntent = PendingIntent.getService(
this,
alarm.getId(),
alarmIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, alarm.getHour());
calendar.set(Calendar.MINUTE, alarm.getMinute());
calendar.set(Calendar.SECOND, 0);
// 如果时间已过,设置为明天
if (calendar.getTimeInMillis() <= System.currentTimeMillis()) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
pendingIntent
);
} else {
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
pendingIntent
);
}
}
private void cancelAlarm(AlarmInfo alarm) {
Intent alarmIntent = new Intent(this, AlarmService.class);
PendingIntent pendingIntent = PendingIntent.getService(
this,
alarm.getId(),
alarmIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
@Override
public void onItemClick(AlarmInfo alarm) {
showAlarmDialog(alarm);
}
@Override
public void onSwitchChanged(AlarmInfo alarm, boolean isChecked) {
alarm.setEnabled(isChecked);
alarmDao.update(alarm);
if (isChecked) {
scheduleAlarm(alarm);
} else {
cancelAlarm(alarm);
}
}
@Override
public void onDeleteClick(AlarmInfo alarm) {
int position = alarmList.indexOf(alarm);
if (position != -1) {
cancelAlarm(alarm);
alarmDao.delete(alarm.getId());
alarmList.remove(position);
alarmAdapter.notifyItemRemoved(position);
}
}
}

@ -1,159 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.util.Log;
public class Fall {
private float highThresholdValue;
private float lowThresholdValue;
// private int SENSOR_RATE;
private boolean isFell;
public static float[] svmData;
public static float[] svmFilteringData;
public static int svmCount = 0;
public static final String TAG = "cauc";
public Fall(){
svmData = new float[150];
svmFilteringData = new float[150];
isFell = false;
}
/*
*/
public void setThresholdValue(float highThreshold, float lowThreshold){
this.highThresholdValue = highThreshold;
this.lowThresholdValue = lowThreshold;
Log.d(TAG, highThreshold + " " + lowThreshold);
}
/*
*/
// public void setSENSOR_RATE(int sensor_rate){
// SENSOR_RATE = sensor_rate;
// }
/*
*/
public void fallDetection(){
Log.d(TAG, "Fall.fallDetection()");
new Thread(new Runnable() {
@Override
public void run() {
boolean running = true;
while(running){
//阈值法
for(int i = 0; i < svmFilteringData.length; i++){
if(svmFilteringData[i] <= lowThresholdValue){
if(i < svmFilteringData.length-10){
for (int j = i; j < i + 10; j++) {
if (svmFilteringData[j] >= highThresholdValue) {
running = false;
setFell(true);
}
}
}else {
for (int j = i; j < svmFilteringData.length; j++) {
if (svmFilteringData[j] >= highThresholdValue) {
running = false;
setFell(true);
}
}
for (int k = 0; k < (10-(svmFilteringData.length - i)); k++){
if (svmFilteringData[k] >= highThresholdValue) {
running = false;
setFell(true);
}
}
}
}
}
}
}
}).start();
}
/*
3ssvm
*/
public static void svmCollector(float svm){
if(svmCount < svmData.length){
svmData[svmCount] = svm;
}else{
svmCount = 0;
svmData[svmCount] = svm;
}
svmCount++;
// Log.d(TAG, "Fall.svmCollector" + svmData[svmCount]);
}
/*
svm
*/
public static void setSvmFilteringData(){
//中值滤波取的三个值
float s1, s2, s3, temp;
//冒泡排序
for (int i = 0; i < svmFilteringData.length-1; i++){
if(i == 0){
s1 = svmData[i];
s2 = svmData[i + 1];
s3 = svmData[i + 2];
}else if(i < svmFilteringData.length-2){
s1 = svmData[i - 1];
s2 = svmData[i];
s3 = svmData[i + 1];
}else{
s1 = svmData[i - 1];
s2 = svmData[i];
s3 = svmData[0];
}
if(s1 > s2){
temp = s1;
s1 = s2;
s2 = temp;
}
if(s2 > s3){
temp = s2;
s2 = s3;
s3 = temp;
}
svmFilteringData[i] = s2;
Log.d(TAG, s1 + " " + s2 + " " + s3);
// Log.d(TAG, "Fall.setSvmFilteringData" + svmFilteringData[i]);
}
}
public boolean isFell() {
// Log.e(TAG, "isFELL" + isFell);
return isFell;
}
public void setFell(boolean fell) {
isFell = fell;
// Log.e(TAG, "setFELL" + isFell);
}
public void cleanData(){
Log.d(TAG , "Fall.clean()");
for (int i = 0; i < svmData.length; i++){
svmData[i] = 0;
}
//中值滤波
for (int i = 0; i < svmFilteringData.length; i++){
svmFilteringData[i] = 0;
}
}
}

@ -1,236 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.WindowManager;
import android.widget.TextView;
import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.util.Timer;
import java.util.TimerTask;
public class FallDetectionService extends Service {
private FallSensorManager fallSensorManager;
public Fall fall;
private final int FELL = 0;
private final int TIME = 1;
private boolean running = false;
private TextView countingView;
private Dialog dialog;
private Timer timer;
private final String TAG = "FallDetection";
private DetectThread detectThread;
private IntentFilter intentFilter;
private LocalBroadcastManager localBroadcastManager;
private FallLocalReceiver fallLocalReceiver;
private static final String CHANNEL_ID = "fall_detection_channel";
private static final String CHANNEL_NAME = "跌倒检测服务";
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "FallDetectionService.onCreate()");
// 创建通知渠道
//createNotificationChannel();
fallSensorManager = new FallSensorManager(this);
fallSensorManager.initSensor();
fallSensorManager.registerSensor();
fall = new Fall();
fall.setThresholdValue(25, 5);
running = true;
localBroadcastManager = LocalBroadcastManager.getInstance(this);
intentFilter = new IntentFilter();
intentFilter.addAction("com.broadcast.FALL_LOCAL_BROADCAST");
fallLocalReceiver = new FallLocalReceiver();
localBroadcastManager.registerReceiver(fallLocalReceiver, intentFilter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "FallDetectionService.onStartCommand");
detectThread = new DetectThread();
detectThread.start();
return START_STICKY;
}
@Override
public void onDestroy() {
fallSensorManager.unregisterSensor();
localBroadcastManager.unregisterReceiver(fallLocalReceiver);
super.onDestroy();
}
class DetectThread extends Thread {
/*
@Override
public void run() {
fall.fallDetection();
Log.d(TAG, "DetectThread.start()");
while (running) {
if (fall.isFell()) {
Log.e(TAG, "跌倒了");
running = false;
Message msg = handler.obtainMessage();
msg.what = FELL;
handler.sendMessage(msg);
fall.setFell(false);
fall.cleanData();
stopSelf();
}
}
}
*/
@Override
public void run() {
fall.fallDetection();
while (running) {
if (fall.isFell()) {
Log.e(TAG, "跌倒了");
running = false;
handler.obtainMessage(FELL).sendToTarget();
fall.setFell(false);
fall.cleanData();
stopSelf();
break;
}
try {
Thread.sleep(200); // 延时,减少循环的频率
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case FELL:
Log.e(TAG, "FELL");
showAlertDialog();
Intent intent = new Intent("com.broadcast.FALL_LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent);
break;
case TIME:
if (msg.arg1 > 0) {
countingView.setText(msg.arg1 + "秒后自动报警");
} else {
if (dialog != null) {
dialog.dismiss();
}
timer.cancel();
}
break;
}
}
};
private void showAlertDialog() {
countingView = new TextView(getApplicationContext());
AlertDialog.Builder builder = new AlertDialog.Builder(getApplicationContext());
builder.setTitle("跌倒警报");
builder.setView(countingView);
builder.setMessage("检测到跌倒发生,是否发出警报?");
builder.setIcon(R.drawable.ic_warning);
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
timer.cancel();
dialog.dismiss();
running = true;
detectThread.interrupt();
detectThread = null;
if (detectThread == null) {
detectThread = new DetectThread();
detectThread.start();
}
}
});
dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
// dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
countDown();
dialog.show();
Log.d(TAG, "dialog.create()");
}
private void countDown() {
timer = new Timer();
TimerTask timerTask = new TimerTask() {
int countTime = 6;
@Override
public void run() {
if (countTime > 0) {
countTime--;
Message msgTime = handler.obtainMessage();
msgTime.what = TIME;
msgTime.arg1 = countTime;
handler.sendMessage(msgTime);
}
}
};
timer.schedule(timerTask, 100, 1000);
}
private void showInNotification() {
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("老人跌倒检测")
.setContentText("老人跌倒检测正在运行")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.ic_app)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_app))
.setContentIntent(pi)
.build();
startForeground(1, notification);
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT);
serviceChannel.setDescription("Channel description");
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (manager != null) {
manager.createNotificationChannel(serviceChannel);
}
}
}
}

@ -1,407 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.speech.tts.TextToSpeech;
import android.telephony.SmsManager;
import android.util.Log;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
public class FallLocalReceiver extends BroadcastReceiver implements AMapLocationListener, LocationListener, TextToSpeech.OnInitListener {
private TextView countingView;
private Dialog dialog;
private Timer timer;
private SharedPreferences sharedPreferences;
private Vibrator vibrator;
private boolean isVibrate;
private MediaPlayer mediaPlayer;
private AMapLocationClient locationClient;
private AMapLocationClientOption locationClientOption;
public String locationAddress;
public String locationTime;
private Context context;
private final String TAG = "FallDetection";
private TextToSpeech textToSpeech;
public FallLocalReceiver() {
}
/*
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "FallLocalReceiver.onReceive()");
this.context = context;
showAlertDialog();
textToSpeech = new TextToSpeech(this, this);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
isVibrate = sharedPreferences.getBoolean("pre_key_vibrate", true);
if (isVibrate) {
startVibrate();
}
startAlarm();
try {
startLocation();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
*/
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "FallLocalReceiver.onReceive()");
this.context = context;
showAlertDialog();
if (textToSpeech != null && textToSpeech.isSpeaking()) {
textToSpeech.stop();
}
/*
if (textToSpeech != null) {
textToSpeech.speak("检测到您已跌倒", TextToSpeech.QUEUE_ADD, null, "FallDetected");
}
*/
if (textToSpeech != null) {
// 使用函数调用
speakFallDetected();
}
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
isVibrate = sharedPreferences.getBoolean("pre_key_vibrate", true);
if (isVibrate) {
// startVibrate();
}
// startAlarm();
initializeTextToSpeech();
try {
startLocation();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void initializeTextToSpeech() {
textToSpeech = new TextToSpeech(context, this);
}
/*
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = textToSpeech.setLanguage(Locale.CHINESE);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e(TAG, "TextToSpeech: 语言不支持");
} else {
// 确保初始化成功后立即播报
speakFallDetected();
}
} else {
Log.e(TAG, "TextToSpeech 初始化失败");
}
}
*/
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = textToSpeech.setLanguage(Locale.CHINESE);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
//Toast.makeText(this, "TTS语音引擎不支持或缺少中文语音数据", Toast.LENGTH_LONG).show();
} else {
speakFallDetected(); // 当初始化成功后直接开始语音播报位置信息
}
} else {
// Toast.makeText(this, "TTS引擎初始化失败", Toast.LENGTH_LONG).show();
}
}
private void speakFallDetected() {
if (textToSpeech != null) {
textToSpeech.speak("检测到您已跌倒", TextToSpeech.QUEUE_ADD, null, "FallDetected");
}
}
/*
private void speakFallDetected() {
if (textToSpeech != null) {
textToSpeech.speak("检测到您已跌倒", TextToSpeech.QUEUE_FLUSH, null, "FallDetected");
}
}
*/
private void showAlertDialog() {
//检查权限
if (!Settings.canDrawOverlays(context)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
context.startActivity(intent);
}
countingView = new TextView(context);
//动态请求权限
if (!Settings.canDrawOverlays(context)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
context.startActivity(intent);
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
//AlertDialog.Builder builder = new AlertDialog.Builder(context.getApplicationContext());
//补充
countingView.setText("您已摔倒"); // 假设倒计时开始时显示 5 秒
builder.setView(countingView);
builder.setTitle("跌倒警报");
builder.setView(countingView);
builder.setMessage("检测到跌倒发生,是否发出警报?");
builder.setIcon(R.drawable.ic_warning);
if (textToSpeech != null && textToSpeech.isSpeaking()) {
textToSpeech.stop();
}
/*
if (textToSpeech != null) {
textToSpeech.speak("检测到您已跌倒", TextToSpeech.QUEUE_ADD, null, "FallDetected");
}
*/
if (textToSpeech != null) {
// 使用函数调用
speakFallDetected();
}
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
timer.cancel();
dialog.dismiss();
if (isVibrate) {
// stopVibrate();
}
// stopAlarm();
Intent startIntent = new Intent(context, FallDetectionService.class);
context.startService(startIntent);
}
});
dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
countDown();
dialog.show();
Log.d(TAG, "dialog.create()");
}
private void countDown() {
timer = new Timer();
TimerTask timerTask = new TimerTask() {
int countTime = 10;
@Override
public void run() {
if (countTime > 0) {
countTime--;
Message msgTime = handler.obtainMessage();
msgTime.arg1 = countTime;
handler.sendMessage(msgTime);
}
}
};
timer.schedule(timerTask, 50, 1000);
}
public Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.arg1 > 0) {
countingView.setText(msg.arg1 + "秒后自动报警");
/*
// 仅在首次倒计时启动时播放铃声
if (msg.arg1 == 10) {
startAlarm();
}
*/
} else {
// 倒计时结束时停止铃声和震动
if (dialog != null) {
dialog.dismiss();
if (isVibrate) {
// stopVibrate();
}
//stopAlarm();
sendSMS(locationAddress, locationTime);
}
timer.cancel();
}
}
};
/*
private void startVibrate() {
if (vibrator == null) {
vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
}
if (vibrator != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
VibrationEffect vibrationEffect = VibrationEffect.createWaveform(new long[]{500, 1000, 500, 1000}, 0);
vibrator.vibrate(vibrationEffect);
} else {
vibrator.vibrate(new long[]{500, 1000, 500, 1000}, 0);
}
Log.d(TAG, "开始震动");
} else {
Log.e(TAG, "无法获取震动服务");
}
}
private void stopVibrate() {
if (vibrator != null) {
vibrator.cancel();
}
}
private void startAlarm() {
if (mediaPlayer == null) {
mediaPlayer = MediaPlayer.create(context, R.raw.alarm_sound);
if (mediaPlayer == null) {
Log.e(TAG, "MediaPlayer 初始化失败,检查资源文件");
return;
}
mediaPlayer.setLooping(true);
}
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
Log.d(TAG, "开始播放警报铃声");
}
}
private void stopAlarm() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
}
*/
private void sendSMS(String address, String time) {
SmsManager smsManager = SmsManager.getDefault();
String name = sharedPreferences.getString("pre_key_name", null);
String phoneNum = sharedPreferences.getString("pre_key_phone", null);
String smsContent = time + name + "在" + address + "发生跌倒了!";
smsManager.sendTextMessage(phoneNum, null, smsContent, null, null);
Toast.makeText(context, "短信已经发出", Toast.LENGTH_SHORT).show();
}
private void startLocation() throws Exception {
Log.d(TAG, "FallLocalReceiver.startLocation()");
locationClient = new AMapLocationClient(context);
locationClientOption = new AMapLocationClientOption();
locationClientOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
locationClientOption.setOnceLocationLatest(true);
locationClient.setLocationListener(this);
locationClient.startLocation();
}
@Override
public void onLocationChanged(Location location) {
double latitude = location.getLatitude();
double longitude = location.getLongitude();
locationAddress = getFormattedAddress(latitude, longitude);
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
@Override
public void onProviderEnabled(String s) {
}
@Override
public void onProviderDisabled(String s) {
}
@Override
public void onLocationChanged(AMapLocation amapLocation) {
if (amapLocation != null) {
if (amapLocation.getErrorCode() == 0) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(amapLocation.getTime());
locationTime = df.format(date);
} else {
Log.e("AmapError", "location Error, ErrCode:" + amapLocation.getErrorCode() + ", errInfo:" + amapLocation.getErrorInfo());
}
}
}
private String getFormattedAddress(double latitude, double longitude) {
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
List<Address> addresses;
String address = "";
try {
addresses = geocoder.getFromLocation(latitude, longitude, 1);
if (addresses != null && !addresses.isEmpty()) {
Address returnedAddress = addresses.get(0);
StringBuilder sb = new StringBuilder();
for (int i = 0; i <= returnedAddress.getMaxAddressLineIndex(); i++) {
sb.append(returnedAddress.getAddressLine(i)).append("\n");
}
address = sb.toString();
}
} catch (IOException e) {
e.printStackTrace();
}
return address;
}
}

@ -1,74 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import static android.content.Context.SENSOR_SERVICE;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
public class FallSensorManager {
private SensorManager sensorManager;
private Sensor accelerometer;
private Context context;
private float accX, accY, accZ;
private float svm;
public Fall fall;
private final String TAG = "FallDetection";
public FallSensorManager(Context context){
this.context = context;
fall = new Fall();
}
/*
*/
public void initSensor(){
//获取SensorManager系统的传感器管理服务
sensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);
//获取accelerometer加速度传感器
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Log.d(TAG, "FallSensorManager.initSensor()");
}
/*
*/
public void registerSensor(){
sensorManager.registerListener(sensorEventListener,
accelerometer, SensorManager.SENSOR_DELAY_GAME);
Log.d(TAG, "FallSensorManager.registerSensor()");
}
/*
*/
public void unregisterSensor(){
sensorManager.unregisterListener(sensorEventListener);
Log.d(TAG, "FallSensorManager.unregisterSensor");
}
public SensorEventListener sensorEventListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
switch (event.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
accX = event.values[0];
accY = event.values[1];
accZ = event.values[2];
svm = (float) Math.sqrt(accX * accX + accY * accY + accZ * accZ);
// Log.d(TAG,accX + " " + accY + " " + accZ );
Fall.svmCollector(svm);
Fall.setSvmFilteringData();
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
}

@ -1,286 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.Manifest;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.MapView;
import com.amap.api.maps.MapsInitializer;
import com.amap.api.maps.model.Circle;
import com.amap.api.maps.model.CircleOptions;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
public class GeofenceActivity extends AppCompatActivity {
private MapView mapView;
private AMap aMap;
private SeekBar seekBarRadius;
private TextView tvRadius;
private Button btnSave;
private Circle geofenceCircle;
private Marker centerMarker;
private LatLng centerPoint;
private int radius = 100;
private AMapLocationClient locationClient;
private AMapLocationClientOption locationOption;
private static final int PERMISSION_REQUEST_CODE = 1;
private static final String[] REQUIRED_PERMISSIONS = new String[] {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 先设置布局
setContentView(R.layout.activity_geofence);
// 初始化视图
initViews();
// 检查权限
if (!checkPermissions()) {
requestPermissions();
} else {
initializeMapAndLocation();
}
}
private boolean checkPermissions() {
for (String permission : REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(this, permission)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private void requestPermissions() {
ActivityCompat.requestPermissions(
this,
REQUIRED_PERMISSIONS,
PERMISSION_REQUEST_CODE
);
}
private void initializeMapAndLocation() {
try {
// 设置隐私政策同意
AMapLocationClient.updatePrivacyShow(this, true, true);
AMapLocationClient.updatePrivacyAgree(this, true);
MapsInitializer.updatePrivacyShow(this, true, true);
MapsInitializer.updatePrivacyAgree(this, true);
// 初始化定位
locationClient = new AMapLocationClient(getApplicationContext());
locationOption = new AMapLocationClientOption();
locationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
locationOption.setOnceLocation(true);
locationClient.setLocationOption(locationOption);
// 设置定位回调
locationClient.setLocationListener(location -> {
if (location != null) {
LatLng currentLocation = new LatLng(location.getLatitude(), location.getLongitude());
if (aMap != null) {
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLocation, 15));
}
}
});
// 初始化地图
initMap(null);
setupListeners();
// 开始定位
if (locationClient != null) {
locationClient.startLocation();
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "初始化失败: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE) {
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) {
initializeMapAndLocation();
} else {
Toast.makeText(this, "需要定位权限才能使用电子围栏功能", Toast.LENGTH_LONG).show();
finish();
}
}
}
private void initViews() {
mapView = findViewById(R.id.map_view);
seekBarRadius = findViewById(R.id.seekbar_radius);
tvRadius = findViewById(R.id.tv_radius);
btnSave = findViewById(R.id.btn_save);
seekBarRadius.setProgress(radius);
tvRadius.setText(radius + "米");
}
private void initMap(Bundle savedInstanceState) {
try {
mapView.onCreate(savedInstanceState);
if (aMap == null) {
aMap = mapView.getMap();
// 设置地图参数
aMap.setMyLocationEnabled(true);
aMap.getUiSettings().setMyLocationButtonEnabled(true);
aMap.getUiSettings().setZoomControlsEnabled(true);
aMap.getUiSettings().setScaleControlsEnabled(true);
}
// 设置地图点击监听
aMap.setOnMapClickListener(latLng -> {
centerPoint = latLng;
updateGeofence();
});
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "地图初始化失败: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
private void setupListeners() {
seekBarRadius.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
radius = progress;
tvRadius.setText(progress + "米");
if (centerPoint != null) {
updateGeofence();
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {}
});
btnSave.setOnClickListener(v -> saveGeofence());
}
private void updateGeofence() {
// 清除旧的标记
if (geofenceCircle != null) {
geofenceCircle.remove();
}
if (centerMarker != null) {
centerMarker.remove();
}
// 添加新的围栏圆圈
CircleOptions circleOptions = new CircleOptions()
.center(centerPoint)
.radius(radius)
.strokeWidth(5)
.strokeColor(Color.argb(50, 1, 1, 1))
.fillColor(Color.argb(100, 255, 0, 0));
geofenceCircle = aMap.addCircle(circleOptions);
// 添加中心点标记
MarkerOptions markerOptions = new MarkerOptions()
.position(centerPoint)
.title("围栏中心");
centerMarker = aMap.addMarker(markerOptions);
// 移动相机到围栏中心
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(centerPoint, 15));
}
private void saveGeofence() {
if (centerPoint == null) {
Toast.makeText(this, "请先在地图上选择围栏中心点", Toast.LENGTH_SHORT).show();
return;
}
// 保存围栏设置到SharedPreferences
getSharedPreferences("geofence", MODE_PRIVATE)
.edit()
.putFloat("latitude", (float) centerPoint.latitude)
.putFloat("longitude", (float) centerPoint.longitude)
.putInt("radius", radius)
.apply();
Toast.makeText(this, "电子围栏设置已保存", Toast.LENGTH_SHORT).show();
finish();
}
@Override
protected void onResume() {
super.onResume();
if (mapView != null) {
mapView.onResume();
}
}
@Override
protected void onPause() {
super.onPause();
if (mapView != null) {
mapView.onPause();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapView != null) {
mapView.onDestroy();
}
if (locationClient != null) {
locationClient.onDestroy();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mapView != null) {
mapView.onSaveInstanceState(outState);
}
}
}

@ -1,76 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import edu.gatech.seclass.fall_detection_master.model.HealthInfo;
import edu.gatech.seclass.fall_detection_master.db.HealthInfoDao;
public class HealthInfoActivity extends AppCompatActivity {
private EditText etSystolic;
private EditText etDiastolic;
private EditText etHeartRate;
private EditText etBloodSugar;
private Button btnSave;
private Button btnViewReport;
private HealthInfoDao healthInfoDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_health_info);
initViews();
initData();
setupListeners();
}
private void initViews() {
etSystolic = findViewById(R.id.et_systolic);
etDiastolic = findViewById(R.id.et_diastolic);
etHeartRate = findViewById(R.id.et_heart_rate);
etBloodSugar = findViewById(R.id.et_blood_sugar);
btnSave = findViewById(R.id.btn_save);
btnViewReport = findViewById(R.id.btn_view_report);
}
private void initData() {
healthInfoDao = new HealthInfoDao(this);
}
private void setupListeners() {
btnSave.setOnClickListener(v -> saveHealthInfo());
btnViewReport.setOnClickListener(v -> viewHealthReport());
}
private void saveHealthInfo() {
try {
HealthInfo healthInfo = new HealthInfo();
healthInfo.setBloodPressureHigh(Integer.parseInt(etSystolic.getText().toString()));
healthInfo.setBloodPressureLow(Integer.parseInt(etDiastolic.getText().toString()));
healthInfo.setHeartRate(Integer.parseInt(etHeartRate.getText().toString()));
healthInfo.setBloodSugar(Float.parseFloat(etBloodSugar.getText().toString()));
healthInfoDao.insert(healthInfo);
Toast.makeText(this, "健康信息保存成功", Toast.LENGTH_SHORT).show();
clearInputs();
} catch (NumberFormatException e) {
Toast.makeText(this, "请输入有效的数值", Toast.LENGTH_SHORT).show();
}
}
private void viewHealthReport() {
Intent intent = new Intent(this, HealthReportActivity.class);
startActivity(intent);
}
private void clearInputs() {
etSystolic.setText("");
etDiastolic.setText("");
etHeartRate.setText("");
etBloodSugar.setText("");
}
}

@ -1,69 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import edu.gatech.seclass.fall_detection_master.db.HealthInfoDao;
import edu.gatech.seclass.fall_detection_master.model.HealthInfo;
import java.util.List;
public class HealthReportActivity extends AppCompatActivity {
private TextView tvReport;
private HealthInfoDao healthInfoDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_health_report);
tvReport = findViewById(R.id.tv_report);
healthInfoDao = new HealthInfoDao(this);
generateReport();
}
private void generateReport() {
List<HealthInfo> recentRecords = healthInfoDao.getRecentRecords(7);
StringBuilder report = new StringBuilder();
report.append("健康状况分析报告\n\n");
if (recentRecords.isEmpty()) {
report.append("暂无健康记录数据");
} else {
// 计算平均值
double avgSystolic = 0, avgDiastolic = 0, avgHeartRate = 0, avgBloodSugar = 0;
for (HealthInfo info : recentRecords) {
avgSystolic += info.getBloodPressureHigh();
avgDiastolic += info.getBloodPressureLow();
avgHeartRate += info.getHeartRate();
avgBloodSugar += info.getBloodSugar();
}
int size = recentRecords.size();
avgSystolic /= size;
avgDiastolic /= size;
avgHeartRate /= size;
avgBloodSugar /= size;
report.append("最近").append(size).append("次记录的平均值:\n\n");
report.append(String.format("血压: %.0f/%.0f mmHg (高压/低压)\n", avgSystolic, avgDiastolic));
report.append(String.format("心率: %.0f 次/分\n", avgHeartRate));
report.append(String.format("血糖: %.1f mmol/L\n\n", avgBloodSugar));
// 健康建议
report.append("健康建议:\n");
if (avgSystolic > 140 || avgDiastolic > 90) {
report.append("· 血压偏高,建议减少盐分摄入,保持规律运动\n");
}
if (avgHeartRate > 100) {
report.append("· 心率偏快,建议注意休息,避免剧烈运动\n");
}
if (avgBloodSugar > 7.0) {
report.append("· 血糖偏高,建议控制饮食,规律作息\n");
}
}
tvReport.setText(report.toString());
}
}

@ -1,38 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import com.suke.widget.SwitchButton;
public class HomeFragment extends Fragment {
private SwitchButton switchButton;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_home,null);
switchButton = (SwitchButton) view.findViewById(R.id.switchButton);
switchButton.setOnCheckedChangeListener(new SwitchButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(SwitchButton view, boolean isChecked) {
if(view.isChecked()){
Intent startIntent = new Intent(getContext(), FallDetectionService.class);
getContext().startService(startIntent);
}else{
Intent stopIntent = new Intent(getContext(), FallDetectionService.class);
getContext().stopService(stopIntent);
}
}
});
return view;
}
}

@ -1,68 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import edu.gatech.seclass.fall_detection_master.db.DBHelper;
import edu.gatech.seclass.fall_detection_master.db.UserDao;
public class LoginActivity extends AppCompatActivity {
private EditText etUsername;
private EditText etPassword;
private Button btnLogin;
private Button btnRegister;
private UserDao userDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// 确保数据库表存在
DBHelper dbHelper = new DBHelper(this);
dbHelper.ensureTableExists();
initViews();
userDao = new UserDao(this);
}
private void initViews() {
etUsername = findViewById(R.id.et_username);
etPassword = findViewById(R.id.et_password);
btnLogin = findViewById(R.id.btn_login);
btnRegister = findViewById(R.id.btn_register);
btnLogin.setOnClickListener(v -> login());
btnRegister.setOnClickListener(v -> {
startActivity(new Intent(this, RegisterActivity.class));
});
}
private void login() {
String username = etUsername.getText().toString().trim();
String password = etPassword.getText().toString().trim();
if (username.isEmpty() || password.isEmpty()) {
Toast.makeText(this, "请输入用户名和密码", Toast.LENGTH_SHORT).show();
return;
}
if (userDao.login(username, password)) {
// 登录成功,保存登录状态
getSharedPreferences("user", MODE_PRIVATE)
.edit()
.putString("username", username)
.putBoolean("isLogin", true)
.apply();
// 跳转到主界面
startActivity(new Intent(this, MainActivity.class));
finish();
} else {
Toast.makeText(this, "用户名或密码错误", Toast.LENGTH_SHORT).show();
}
}
}

@ -1,248 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import android.app.AlertDialog;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.google.android.material.navigation.NavigationView;
import java.util.Locale;
public class MainActivity extends AppCompatActivity implements TextToSpeech.OnInitListener{
private DrawerLayout mDrawerLayout;
private NavigationView mNavigationView;
private Toolbar mToolbar;
// private ActionBarDrawerToggle mDrawerToggle;
private HomeFragment homeFragment;
private SettingsFragment settingsFragment;
private TextToSpeech textToSpeech;
private final int HOME = 1;
private final int SETTINGS = 2;
private final int ABOUT = 3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textToSpeech = new TextToSpeech(this, this);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
// mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.drawer_open,
// R.string.drawer_close);
// mDrawerToggle.syncState();
// mDrawerLayout.addDrawerListener(mDrawerToggle);
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
//为activity窗口设置活动栏
// setSupportActionBar(mToolbar);
final ActionBar actionBar = getSupportActionBar();
//设置导航图标
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);
actionBar.setDisplayHomeAsUpEnabled(true);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
if (mNavigationView != null) {
setupDrawerContent(mNavigationView);
}
// switchToHome();
showFragment(HOME);
// 检查是否需要显示围栏警告
if (getIntent().getBooleanExtra("show_geofence_alert", false)) {
showGeofenceAlertDialog();
}
}
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_item_home:
showFragment(HOME);
mToolbar.setTitle(R.string.app_name);
break;
case R.id.navigation_item_place:
switchToPlace();
break;
case R.id.navigation_item_settings:
showFragment(SETTINGS);
mToolbar.setTitle(R.string.navigation_settings);
break;
case R.id.nav_map:
Intent mapIntent = new Intent(MainActivity.this, GeofenceActivity.class);
startActivity(mapIntent);
break;
case R.id.nav_health:
Intent healthIntent = new Intent(MainActivity.this, HealthInfoActivity.class);
startActivity(healthIntent);
break;
case R.id.nav_report:
Intent reportIntent = new Intent(MainActivity.this, HealthReportActivity.class);
startActivity(reportIntent);
break;
case R.id.nav_alarm:
Intent alarmIntent = new Intent(MainActivity.this, AlarmActivity.class);
startActivity(alarmIntent);
break;
}
item.setChecked(true);
mDrawerLayout.closeDrawers();
return true;
}
});
}
// private void switchToHome() {
// getSupportFragmentManager().beginTransaction().replace(R.id.frame_content, new HomeFragment()).commit();
// mToolbar.setTitle(R.string.app_name);
// }
//
private void switchToPlace() {
// getSupportFragmentManager().beginTransaction().replace(R.id.frame_content, new PlaceFragment()).commit();
// mToolbar.setTitle(R.string.navigation_place);
mToolbar.setTitle(R.string.app_name);
startActivity(new Intent(this, MapActivity.class));
}
//
// private void switchToSettings() {
// getSupportFragmentManager().beginTransaction().replace(R.id.frame_content, new SettingsFragment()).commit();
// mToolbar.setTitle(R.string.navigation_settings);
// }
//
// private void switchToAbout() {
// getSupportFragmentManager().beginTransaction().replace(R.id.frame_content, new AboutFragment()).commit();
// mToolbar.setTitle(R.string.navigation_about);
//
// }
public void showFragment(int index){
FragmentTransaction ft = getFragmentManager().beginTransaction();
//想要显示一个fragment先隐藏所有fragment防止重叠
hideFragment(ft);
switch (index){
case HOME:
if(homeFragment != null){
ft.show(homeFragment);
}else{
homeFragment = new HomeFragment();
ft.add(R.id.frame_content, homeFragment);
}
break;
case SETTINGS:
if(settingsFragment != null){
ft.show(settingsFragment);
}else{
settingsFragment = new SettingsFragment();
ft.add(R.id.frame_content, settingsFragment);
}
break;
}
ft.commit();
}
/*
fragment
*/
public void hideFragment(FragmentTransaction ft){
if(homeFragment != null){
ft.hide(homeFragment);
}
if(settingsFragment != null){
ft.hide(settingsFragment);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
if(item.getItemId() == android.R.id.home)
{
mDrawerLayout.openDrawer(GravityCompat.START);
return true ;
}
if(item.getItemId() == R.id.id_menu_settings){
showFragment(SETTINGS);
}
return super.onOptionsItemSelected(item);
}
@Override
public void onInit(int status) {
// if (status == TextToSpeech.SUCCESS) {
// int result = textToSpeech.setLanguage(Locale.CHINESE);
//
// if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
// Toast.makeText(this, "TTS语音引擎不支持或缺少中文语音数据", Toast.LENGTH_LONG).show();
// } else {
// String welcomeMessage = "欢迎使用老人跌倒监测系统。";
// textToSpeech.speak(welcomeMessage, TextToSpeech.QUEUE_FLUSH, null, null);
// Myapp.textToSpeech = textToSpeech;
// }
// } else {
// Toast.makeText(this, "TTS引擎初始化失败", Toast.LENGTH_LONG).show();
// }
}
@Override
protected void onDestroy() {
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
}
super.onDestroy();
}
private void showGeofenceAlertDialog() {
new AlertDialog.Builder(this)
.setTitle("安全提醒")
.setMessage("您已离开设定的安全区域,请注意安全!")
.setIcon(R.drawable.ic_warning)
.setPositiveButton("我知道了", (dialog, which) -> {
// 播放语音提醒
if (textToSpeech != null) {
textToSpeech.speak("请注意安全,尽快返回安全区域",
TextToSpeech.QUEUE_FLUSH, null, null);
}
})
.setCancelable(false)
.show();
}
}

@ -1,394 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.maps.AMap;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.LocationSource;
import com.amap.api.maps.MapView;
import com.amap.api.maps.MapsInitializer;
import com.amap.api.maps.UiSettings;
import com.google.android.material.navigation.NavigationView;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
public class MapActivity extends AppCompatActivity implements LocationSource, AMapLocationListener, TextToSpeech.OnInitListener, LocationListener {
private MapView mMapView;
private AMap aMap;
private LocationSource.OnLocationChangedListener mListener;
private AMapLocationClient mLocationClient;
private AMapLocationClientOption mLocationOption;
private UiSettings mUiSettings;
private static final int LOCATION_PERMISSION_REQUEST_CODE = 1;
private LocationManager locationManager;
private TextToSpeech textToSpeech;
private String locationAddress;
private ToggleButton tb;
private TextView textView;
private NavigationView mNavigationView;
private Toolbar mToolbar;
public String nowaddress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textToSpeech = new TextToSpeech(this, this);
setContentView(R.layout.map_activity);
textView = (TextView) findViewById(R.id.address);
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mToolbar.setTitle(R.string.navigation_place);
MapsInitializer.updatePrivacyShow(this,true,true);
MapsInitializer.updatePrivacyAgree(this,true);
//为activity窗口设置活动栏
// setSupportActionBar(mToolbar);
final ActionBar actionBar = getSupportActionBar();
//设置返回图标
actionBar.setHomeAsUpIndicator(0);
actionBar.setDisplayHomeAsUpEnabled(true);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
// 检查定位权限
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// 申请定位权限
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
LOCATION_PERMISSION_REQUEST_CODE);
} else {
// 获取LocationManager实例
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// 获取TextToSpeech实例并设置初始化监听器
textToSpeech = new TextToSpeech(this, this);
// 开始监听位置变化
startLocationUpdates();
}
//获取地图控件引用
mMapView = (MapView) findViewById(R.id.map);
//在activity执行onCreate时执行mMapView.onCreate(savedInstanceState),创建地图
//实现地图生命周期管理
mMapView.onCreate(savedInstanceState);
//初始化AMap对象
aMap = mMapView.getMap();
// 设置定位监听,如果不设置此定位资源则定位按钮不可点击
aMap.setLocationSource(this);
// 设置为true表示显示定位层并可触发定位false表示隐藏定位层并不可触发定位默认是false
aMap.setMyLocationEnabled(true);
// 设置定位的类型为定位模式,有定位、跟随或地图根据面向方向旋转几种
aMap.setMyLocationType(AMap.LOCATION_TYPE_LOCATE);
//实例化UiSettings类
mUiSettings = aMap.getUiSettings();
//显示指南针
mUiSettings.setCompassEnabled(true);
// 显示默认的定位按钮
mUiSettings.setMyLocationButtonEnabled(true);
//显示比例尺控件
mUiSettings.setScaleControlsEnabled(true);
tb = (ToggleButton) findViewById(R.id.tb);
tb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
//设置使用卫星地图
aMap.setMapType(AMap.MAP_TYPE_SATELLITE);
} else {
//设置使用普通地图
aMap.setMapType(AMap.MAP_TYPE_NORMAL);
}
}
});
}
private void startLocationUpdates() {
// 设置最小时间间隔和最小距离这里设置为1000毫秒和1米
// 这样当位置发生变化时会在接下来的1000毫秒内获取位置信息
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
10000, 10, this);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
// 检查定位权限授权结果
if (grantResults.length > 0 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 获取LocationManager实例
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// 开始监听位置变化
startLocationUpdates();
} else {
// 处理没有授权的情况
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
@Override
protected void onResume() {
super.onResume();
//在activity执行onResume时执行mMapView.onResume(),重新绘制加载地图
//实现地图生命周期管理
mMapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
//在activity执行onPause时执行mMapView.onPause(),暂停地图的绘制
//实现地图生命周期管理
mMapView.onPause();
}
public void onLocationChanged(Location location) {
// 当位置发生变化时,更新界面上的位置信息
double latitude = location.getLatitude();
double longitude = location.getLongitude();
// TODO: 在界面上显示位置信息
locationAddress = getFormattedAddress(latitude, longitude); // 获取格式化的位置地址
//textView.setText(latitude+"\n"+longitude+locationAddress);
speakLocationInformation(); // 开始语音播报位置信息
}
private String getFormattedAddress(double latitude, double longitude) {
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
List<Address> addresses;
String address = "";
try {
addresses = geocoder.getFromLocation(latitude, longitude, 1);
if (addresses != null && addresses.size() > 0) {
Address returnedAddress = addresses.get(0);
StringBuilder sb = new StringBuilder();
for (int i = 0; i <= returnedAddress.getMaxAddressLineIndex(); i++) {
sb.append(returnedAddress.getAddressLine(i)).append("\n");
}
address = sb.toString();
}
} catch (IOException e) {
e.printStackTrace();
// 处理异常情况
}
return address;
}
private void speakLocationInformation() {
if (textToSpeech != null && textToSpeech.isSpeaking()) {
textToSpeech.stop();
}
if (textToSpeech != null) {
textToSpeech.speak("您现在位于" + locationAddress, TextToSpeech.QUEUE_FLUSH, null, null);
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// 当位置提供者状态变化时,处理逻辑
}
@Override
public void onProviderEnabled(String provider) {
// 当位置提供者启用时,处理逻辑
}
@Override
public void onProviderDisabled(String provider) {
// 当位置提供者禁用时,处理逻辑
}
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = textToSpeech.setLanguage(Locale.CHINESE);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
//Toast.makeText(this, "TTS语音引擎不支持或缺少中文语音数据", Toast.LENGTH_LONG).show();
} else {
speakLocationInformation(); // 当初始化成功后直接开始语音播报位置信息
}
} else {
Toast.makeText(this, "TTS引擎初始化失败", Toast.LENGTH_LONG).show();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 停止位置监听
locationManager.removeUpdates(this);
// 释放TextToSpeech资源
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//在activity执行onSaveInstanceState时执行mMapView.onSaveInstanceState(outState),保存地图当前的状态
//实现地图生命周期管理
mMapView.onSaveInstanceState(outState);
}
/**
*
*/
@Override
public void activate(OnLocationChangedListener onLocationChangedListener) {
mListener = onLocationChangedListener;
if (mLocationClient == null) {
//初始化定位
try {
mLocationClient = new AMapLocationClient(this);
} catch (Exception e) {
e.printStackTrace();
}
//初始化定位参数
mLocationOption = new AMapLocationClientOption();
//设置定位回调监听
mLocationClient.setLocationListener(this);
//设置为高精度定位模式
mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
//设置定位参数
mLocationClient.setLocationOption(mLocationOption);
// 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
// 注意设置合适的定位时间的间隔最小间隔支持为2000ms并且在合适时间调用stopLocation()方法来取消定位请求
// 在定位结束后在合适的生命周期调用onDestroy()方法
// 在单次定位情况下定位无论成功与否都无需调用stopLocation()方法移除请求定位sdk内部会移除
mLocationClient.startLocation();//启动定位
}
}
/**
*
*/
@Override
public void deactivate() {
mListener = null;
if (mLocationClient != null) {
mLocationClient.stopLocation();
mLocationClient.onDestroy();
}
mLocationClient = null;
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (mListener != null && aMapLocation != null) {
if (aMapLocation != null
&& aMapLocation.getErrorCode() == 0) {
mListener.onLocationChanged(aMapLocation);// 显示系统小蓝点
aMap.moveCamera(CameraUpdateFactory.zoomTo(16));//将地图的缩放级别调整到17级
//定位成功回调信息,设置相关消息
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(aMapLocation.getTime());
String time = df.format(date);//定位时
StringBuffer address = new StringBuffer();
/*address.append(aMapLocation.getCountry()
+ aMapLocation.getProvince()
+ aMapLocation.getCity()
+ aMapLocation.getDistrict()
+ aMapLocation.getStreet()
+ aMapLocation.getStreetNum());*/
address.append("纬度: "+ aMapLocation.getLatitude() + "\n");
address.append("经度: "+ aMapLocation.getLongitude() + "\n");
//如果option中设置isNeedAddress为false则没有此结果网络定位结果中会有地址信息GPS定位不返回地址信息。
//address.append("地址: "+ aMapLocation.getAddress() + "\n");
//address.append("当前定位点的AOI信息: "+ aMapLocation.getAoiName() + "\n");
//address.append("当前室内定位的建筑物Id: "+ aMapLocation.getBuildingId() + "\n");
//address.append("当前室内定位的楼层: "+ aMapLocation.getFloor() + "\n");
Log.v("older", "address:" + time + address.toString());
textView.setText(time + "\n" + locationAddress+address.toString());
//39.11083224826389
// 经度: 117.35290635850694
} else {
String errText = "定位失败," + aMapLocation.getErrorCode()+ ": " + aMapLocation.getErrorInfo();
Log.e("AmapErr",errText);
}
}
}
}

@ -1,17 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.app.Application;
import android.speech.tts.TextToSpeech;
public class Myapp extends Application {
public static TextToSpeech textToSpeech;
@Override
public void onCreate() {
super.onCreate();
}
}

@ -1,67 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import edu.gatech.seclass.fall_detection_master.db.UserDao;
import edu.gatech.seclass.fall_detection_master.db.DBHelper;
public class RegisterActivity extends AppCompatActivity {
private EditText etUsername;
private EditText etPassword;
private EditText etConfirmPassword;
private Button btnRegister;
private UserDao userDao;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
// 确保数据库表存在
DBHelper dbHelper = new DBHelper(this);
dbHelper.ensureTableExists();
initViews();
userDao = new UserDao(this);
}
private void initViews() {
etUsername = findViewById(R.id.et_username);
etPassword = findViewById(R.id.et_password);
etConfirmPassword = findViewById(R.id.et_confirm_password);
btnRegister = findViewById(R.id.btn_register);
btnRegister.setOnClickListener(v -> register());
}
private void register() {
String username = etUsername.getText().toString().trim();
String password = etPassword.getText().toString().trim();
String confirmPassword = etConfirmPassword.getText().toString().trim();
if (username.isEmpty() || password.isEmpty() || confirmPassword.isEmpty()) {
Toast.makeText(this, "请填写所有信息", Toast.LENGTH_SHORT).show();
return;
}
if (!password.equals(confirmPassword)) {
Toast.makeText(this, "两次输入的密码不一致", Toast.LENGTH_SHORT).show();
return;
}
if (userDao.isUsernameExists(username)) {
Toast.makeText(this, "用户名已存在", Toast.LENGTH_SHORT).show();
return;
}
if (userDao.register(username, password)) {
Toast.makeText(this, "注册成功", Toast.LENGTH_SHORT).show();
finish();
} else {
Toast.makeText(this, "注册失败", Toast.LENGTH_SHORT).show();
}
}
}

@ -1,74 +0,0 @@
package edu.gatech.seclass.fall_detection_master;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.util.Log;
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener{
public static final String KEY_NAME = "pre_key_name";
public static final String KEY_SEX = "pre_key_sex";
public static final String KEY_AGE = "pre_key_age";
public static final String KEY_ALERT = "pre_key_alert";
public static final String KEY_VIBRATE = "pre_key_vibrate";
public static final String KEY_PHONE = "pre_key_phone";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.d("FallDetection", "SettingsFragment.onsharedPreferenceChanged");
// System.out.print("key是 " + key);
Log.d("FallDetection", key);
// if(key.equals(KEY_AGE)){
// Preference agePre = findPreference(key);
// agePre.setSummary(sharedPreferences.getString(key, "请输入年龄"));
// }
switch (key){
case KEY_NAME:
Preference namePre = findPreference(key);
namePre.setSummary(sharedPreferences.getString(key, ""));
break;
case KEY_SEX:
Preference sexPre = findPreference(key);
sexPre.setSummary(sharedPreferences.getString(key, ""));
break;
case KEY_AGE:
Preference agePre = findPreference(key);
agePre.setSummary(sharedPreferences.getString(key, ""));
break;
case KEY_ALERT:
Preference alertPre = findPreference(key);
alertPre.setSummary(sharedPreferences.getString(key, ""));
break;
case KEY_VIBRATE:
break;
case KEY_PHONE:
Preference phonePre = findPreference(key);
phonePre.setSummary(sharedPreferences.getString(key, ""));
break;
}
}
@Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
getPreferenceManager().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
}

@ -1,97 +0,0 @@
package edu.gatech.seclass.fall_detection_master.adapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Switch;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import edu.gatech.seclass.fall_detection_master.R;
import edu.gatech.seclass.fall_detection_master.model.AlarmInfo;
import java.util.List;
public class AlarmAdapter extends RecyclerView.Adapter<AlarmAdapter.ViewHolder> {
private List<AlarmInfo> alarmList;
private OnItemClickListener listener;
public interface OnItemClickListener {
void onItemClick(AlarmInfo alarm);
void onSwitchChanged(AlarmInfo alarm, boolean isChecked);
void onDeleteClick(AlarmInfo alarm);
}
public AlarmAdapter(List<AlarmInfo> alarmList) {
this.alarmList = alarmList;
}
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_alarm, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
AlarmInfo alarm = alarmList.get(position);
holder.tvTime.setText(String.format("%02d:%02d", alarm.getHour(), alarm.getMinute()));
holder.switchAlarm.setChecked(alarm.isEnabled());
// 设置闹钟描述
if (alarm.getDescription() != null && !alarm.getDescription().isEmpty()) {
holder.tvDescription.setText(alarm.getDescription());
holder.tvDescription.setVisibility(View.VISIBLE);
} else {
holder.tvDescription.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
return alarmList.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView tvTime;
TextView tvDescription;
Switch switchAlarm;
ViewHolder(View itemView) {
super(itemView);
tvTime = itemView.findViewById(R.id.tv_time);
tvDescription = itemView.findViewById(R.id.tv_description);
switchAlarm = itemView.findViewById(R.id.switch_alarm);
itemView.setOnClickListener(v -> {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(alarmList.get(position));
}
}
});
switchAlarm.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onSwitchChanged(alarmList.get(position), isChecked);
}
}
});
itemView.findViewById(R.id.btn_delete).setOnClickListener(v -> {
if (listener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onDeleteClick(alarmList.get(position));
}
}
});
}
}
}

@ -1,66 +0,0 @@
package edu.gatech.seclass.fall_detection_master.db;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import edu.gatech.seclass.fall_detection_master.model.AlarmInfo;
import java.util.ArrayList;
import java.util.List;
public class AlarmDao {
private DBHelper dbHelper;
public AlarmDao(Context context) {
dbHelper = new DBHelper(context);
}
public long insert(AlarmInfo alarm) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("hour", alarm.getHour());
values.put("minute", alarm.getMinute());
values.put("enabled", alarm.isEnabled() ? 1 : 0);
values.put("description", alarm.getDescription());
return db.insert("alarm_info", null, values);
}
public void update(AlarmInfo alarm) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("hour", alarm.getHour());
values.put("minute", alarm.getMinute());
values.put("enabled", alarm.isEnabled() ? 1 : 0);
values.put("description", alarm.getDescription());
db.update("alarm_info", values, "id = ?",
new String[]{String.valueOf(alarm.getId())});
}
public void delete(int id) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete("alarm_info", "id = ?", new String[]{String.valueOf(id)});
}
public List<AlarmInfo> getAllAlarms() {
List<AlarmInfo> alarmList = new ArrayList<>();
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.query("alarm_info", null, null, null, null, null, "hour,minute");
while (cursor.moveToNext()) {
AlarmInfo alarm = new AlarmInfo(
cursor.getInt(cursor.getColumnIndex("hour")),
cursor.getInt(cursor.getColumnIndex("minute"))
);
alarm.setId(cursor.getInt(cursor.getColumnIndex("id")));
alarm.setEnabled(cursor.getInt(cursor.getColumnIndex("enabled")) == 1);
alarm.setDescription(cursor.getString(cursor.getColumnIndex("description")));
alarmList.add(alarm);
}
cursor.close();
return alarmList;
}
}

@ -1,81 +0,0 @@
package edu.gatech.seclass.fall_detection_master.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DBHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "elderly_care.db";
private static final int DATABASE_VERSION = 2;
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
try {
// 创建用户表
db.execSQL("CREATE TABLE IF NOT EXISTS user_info (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"username TEXT UNIQUE," +
"password TEXT)");
// 创建健康信息表
db.execSQL("CREATE TABLE IF NOT EXISTS health_info (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"blood_pressure_high INTEGER," +
"blood_pressure_low INTEGER," +
"heart_rate INTEGER," +
"blood_sugar REAL," +
"record_time INTEGER)");
// 创建闹钟信息表
db.execSQL("CREATE TABLE IF NOT EXISTS alarm_info (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"hour INTEGER," +
"minute INTEGER," +
"enabled INTEGER," +
"description TEXT)");
Log.d("DBHelper", "数据库表创建成功");
} catch (Exception e) {
Log.e("DBHelper", "数据库表创建失败: " + e.getMessage());
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
try {
// 删除旧表
db.execSQL("DROP TABLE IF EXISTS user_info");
db.execSQL("DROP TABLE IF EXISTS health_info");
db.execSQL("DROP TABLE IF EXISTS alarm_info");
// 重新创建表
onCreate(db);
Log.d("DBHelper", "数据库升级成功");
} catch (Exception e) {
Log.e("DBHelper", "数据库升级失败: " + e.getMessage());
}
}
// 添加一个方法来检查表是否存在
public boolean isTableExists(String tableName) {
SQLiteDatabase db = getReadableDatabase();
try {
db.query(tableName, null, null, null, null, null, null);
return true;
} catch (Exception e) {
return false;
}
}
// 添加一个方法来强制创建表
public void ensureTableExists() {
SQLiteDatabase db = getWritableDatabase();
onCreate(db);
}
}

@ -1,52 +0,0 @@
package edu.gatech.seclass.fall_detection_master.db;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import edu.gatech.seclass.fall_detection_master.model.HealthInfo;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class HealthInfoDao {
private DBHelper dbHelper;
public HealthInfoDao(Context context) {
dbHelper = new DBHelper(context);
}
public long insert(HealthInfo healthInfo) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("blood_pressure_high", healthInfo.getBloodPressureHigh());
values.put("blood_pressure_low", healthInfo.getBloodPressureLow());
values.put("heart_rate", healthInfo.getHeartRate());
values.put("blood_sugar", healthInfo.getBloodSugar());
values.put("record_time", healthInfo.getRecordTime().getTime());
return db.insert("health_info", null, values);
}
public List<HealthInfo> getRecentRecords(int limit) {
List<HealthInfo> list = new ArrayList<>();
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.query("health_info", null, null, null, null, null,
"record_time DESC", String.valueOf(limit));
while (cursor.moveToNext()) {
HealthInfo info = new HealthInfo();
info.setId(cursor.getInt(cursor.getColumnIndex("id")));
info.setBloodPressureHigh(cursor.getInt(cursor.getColumnIndex("blood_pressure_high")));
info.setBloodPressureLow(cursor.getInt(cursor.getColumnIndex("blood_pressure_low")));
info.setHeartRate(cursor.getInt(cursor.getColumnIndex("heart_rate")));
info.setBloodSugar(cursor.getFloat(cursor.getColumnIndex("blood_sugar")));
info.setRecordTime(new Date(cursor.getLong(cursor.getColumnIndex("record_time"))));
list.add(info);
}
cursor.close();
return list;
}
}

@ -1,51 +0,0 @@
package edu.gatech.seclass.fall_detection_master.db;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class UserDao {
private DBHelper dbHelper;
public UserDao(Context context) {
dbHelper = new DBHelper(context);
}
public boolean register(String username, String password) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("username", username);
values.put("password", password);
try {
return db.insert("user_info", null, values) != -1;
} catch (Exception e) {
return false;
}
}
public boolean login(String username, String password) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.query("user_info", null,
"username = ? AND password = ?",
new String[]{username, password},
null, null, null);
boolean result = cursor.getCount() > 0;
cursor.close();
return result;
}
public boolean isUsernameExists(String username) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.query("user_info", null,
"username = ?",
new String[]{username},
null, null, null);
boolean result = cursor.getCount() > 0;
cursor.close();
return result;
}
}

@ -1,96 +0,0 @@
package edu.gatech.seclass.fall_detection_master.geofence;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import android.location.Location;
public class GeofenceHelper implements AMapLocationListener {
private Context context;
private AMapLocationClient locationClient;
private AMapLocationClientOption locationOption;
private OnGeofenceListener listener;
private double centerLatitude;
private double centerLongitude;
private int radius;
private boolean isInside = true;
public interface OnGeofenceListener {
void onGeofenceEnter();
void onGeofenceExit();
}
public GeofenceHelper(Context context) {
this.context = context;
loadGeofenceSettings();
initLocation();
}
private void loadGeofenceSettings() {
SharedPreferences sp = context.getSharedPreferences("geofence", Context.MODE_PRIVATE);
centerLatitude = sp.getFloat("latitude", 0);
centerLongitude = sp.getFloat("longitude", 0);
radius = sp.getInt("radius", 100);
}
private void initLocation() {
try {
locationClient = new AMapLocationClient(context);
locationOption = new AMapLocationClientOption();
locationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
locationOption.setInterval(2000);
locationClient.setLocationOption(locationOption);
locationClient.setLocationListener(this);
} catch (Exception e) {
e.printStackTrace();
}
}
public void startMonitoring() {
if (locationClient != null) {
locationClient.startLocation();
}
}
public void stopMonitoring() {
if (locationClient != null) {
locationClient.stopLocation();
}
}
@Override
public void onLocationChanged(AMapLocation aMapLocation) {
if (aMapLocation != null && aMapLocation.getErrorCode() == 0) {
// 计算当前位置与围栏中心的距离
float[] results = new float[1];
Location.distanceBetween(
aMapLocation.getLatitude(), aMapLocation.getLongitude(),
centerLatitude, centerLongitude,
results
);
boolean currentlyInside = results[0] <= radius;
// 检测是否穿越围栏边界
if (currentlyInside != isInside) {
isInside = currentlyInside;
if (listener != null) {
if (isInside) {
listener.onGeofenceEnter();
} else {
listener.onGeofenceExit();
}
}
}
}
}
public void setOnGeofenceListener(OnGeofenceListener listener) {
this.listener = listener;
}
}

@ -1,27 +0,0 @@
package edu.gatech.seclass.fall_detection_master.model;
public class AlarmInfo {
private int id;
private int hour;
private int minute;
private boolean isEnabled;
private String description;
public AlarmInfo(int hour, int minute) {
this.hour = hour;
this.minute = minute;
this.isEnabled = true;
}
// Getters and setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public int getHour() { return hour; }
public void setHour(int hour) { this.hour = hour; }
public int getMinute() { return minute; }
public void setMinute(int minute) { this.minute = minute; }
public boolean isEnabled() { return isEnabled; }
public void setEnabled(boolean enabled) { isEnabled = enabled; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
}

@ -1,30 +0,0 @@
package edu.gatech.seclass.fall_detection_master.model;
import java.util.Date;
public class HealthInfo {
private int id;
private int bloodPressureHigh;
private int bloodPressureLow;
private int heartRate;
private float bloodSugar;
private Date recordTime;
public HealthInfo() {
this.recordTime = new Date();
}
// Getters and setters
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public int getBloodPressureHigh() { return bloodPressureHigh; }
public void setBloodPressureHigh(int bloodPressureHigh) { this.bloodPressureHigh = bloodPressureHigh; }
public int getBloodPressureLow() { return bloodPressureLow; }
public void setBloodPressureLow(int bloodPressureLow) { this.bloodPressureLow = bloodPressureLow; }
public int getHeartRate() { return heartRate; }
public void setHeartRate(int heartRate) { this.heartRate = heartRate; }
public float getBloodSugar() { return bloodSugar; }
public void setBloodSugar(float bloodSugar) { this.bloodSugar = bloodSugar; }
public Date getRecordTime() { return recordTime; }
public void setRecordTime(Date recordTime) { this.recordTime = recordTime; }
}

@ -1,210 +0,0 @@
package edu.gatech.seclass.fall_detection_master.service;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.speech.tts.TextToSpeech;
import androidx.core.app.NotificationCompat;
import edu.gatech.seclass.fall_detection_master.Myapp;
import edu.gatech.seclass.fall_detection_master.R;
import edu.gatech.seclass.fall_detection_master.AlarmActivity;
import java.util.Locale;
public class AlarmService extends Service implements TextToSpeech.OnInitListener {
private MediaPlayer mediaPlayer;
// private TextToSpeech textToSpeech;
private boolean isPlaying = false;
private PowerManager.WakeLock wakeLock;
private static final String CHANNEL_ID = "alarm_channel";
private static final String CHANNEL_NAME = "闹钟提醒";
@Override
public void onCreate() {
super.onCreate();
// 获取 WakeLock
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, "AlarmService::WakeLock");
createNotificationChannel();
mediaPlayer = MediaPlayer.create(this, R.raw.alarm_sound);
mediaPlayer.setLooping(true);
// textToSpeech = new TextToSpeech(this, this);
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH);
channel.setSound(null, null);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
@Override
/*
public int onStartCommand(Intent intent, int flags, int startId) {
// 获取 WakeLock
wakeLock.acquire(10*60*1000L );
if (!isPlaying) {
// 显示通知
showAlarmNotification();
// 播放闹钟声音
mediaPlayer.start();
isPlaying = true;
// 播放语音提醒
speakReminder();
}
return START_STICKY;
}
*/
public int onStartCommand(Intent intent, int flags, int startId) {
// 检查是否为停止闹钟的请求
if (intent != null && "STOP_ALARM".equals(intent.getAction())) {
stopAlarm();
stopSelf(); // 停止服务
return START_NOT_STICKY;
}
// 获取 WakeLock
if (wakeLock != null && !wakeLock.isHeld()) {
wakeLock.acquire(10 * 60 * 1000L /*10 minutes*/);
}
if (!isPlaying) {
// 显示通知
showAlarmNotification();
// 播放闹钟声音
mediaPlayer.start();
isPlaying = true;
// 播放语音提醒
speakReminder();
}
return START_STICKY;
}
// 停止闹钟播放的逻辑
private void stopAlarm() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
}
isPlaying = false;
}
@Override
public void onDestroy() {
stopAlarm(); // 确保在销毁时停止闹钟
stopForeground(true); // 停止前台通知
super.onDestroy();
}
@SuppressLint("ForegroundServiceType")
private void showAlarmNotification() {
Intent stopIntent = new Intent(this, AlarmService.class);
stopIntent.setAction("STOP_ALARM");
PendingIntent stopPendingIntent = PendingIntent.getService(this, 0, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Intent intent = new Intent(this, AlarmActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("闹钟提醒")
.setContentText("闹钟时间到")
.setSmallIcon(R.drawable.ic_drawer)
.setAutoCancel(true)
.setOngoing(true)
.setContentIntent(pendingIntent)
.addAction(R.drawable.ic_about, "关闭闹钟", stopPendingIntent) // 添加停止按钮
.build();
startForeground(1, notification);
}
/*
@SuppressLint("ForegroundServiceType")
private void showAlarmNotification() {
Intent intent = new Intent(this, AlarmActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("闹钟提醒")
.setContentText("闹钟时间到")
.setSmallIcon(R.drawable.ic_drawer)
.setAutoCancel(true)
.setOngoing(true)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
}
*/
private void speakReminder() {
// if (textToSpeech != null) {
// String reminder = "闹钟时间到了,请记得按时吃药";
// Myapp.textToSpeech.speak(reminder, TextToSpeech.QUEUE_FLUSH, null, null);
// }
}
@Override
public void onInit(int status) {
// if (status == TextToSpeech.SUCCESS) {
// textToSpeech.setLanguage(Locale.CHINESE);
// }
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
/*
@Override
public void onDestroy() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
// if (textToSpeech != null) {
// textToSpeech.stop();
// textToSpeech.shutdown();
// }
if (wakeLock.isHeld()) {
wakeLock.release();
}
super.onDestroy();
}
*/
}

@ -1,30 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 835 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 550 B

@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="闹钟提醒"
android:textSize="24sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:layout_margin="16dp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_alarms"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"/>
</LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_add_alarm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/ic_add"
app:fabSize="normal"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.amap.api.maps.MapView
android:id="@+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:background="#80FFFFFF"
android:layout_alignParentBottom="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="电子围栏半径(米):"
android:textSize="16sp"
android:textColor="@android:color/black"/>
<SeekBar
android:id="@+id/seekbar_radius"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:max="1000"
android:progress="100"/>
<TextView
android:id="@+id/tv_radius"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="100米"
android:textColor="@android:color/black"/>
<Button
android:id="@+id/btn_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="保存设置"/>
</LinearLayout>
</RelativeLayout>

@ -1,88 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="健康信息记录"
android:textSize="24sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="24dp"/>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<EditText
android:id="@+id/et_systolic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="高压 (mmHg)"
android:inputType="number"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<EditText
android:id="@+id/et_diastolic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="低压 (mmHg)"
android:inputType="number"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<EditText
android:id="@+id/et_heart_rate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="心率 (次/分)"
android:inputType="number"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<EditText
android:id="@+id/et_blood_sugar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="血糖 (mmol/L)"
android:inputType="numberDecimal"/>
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btn_save"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="保存"/>
<Button
android:id="@+id/btn_view_report"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="查看健康报告"/>
</LinearLayout>
</ScrollView>

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<TextView
android:id="@+id/tv_report"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:lineSpacingExtra="8dp"/>
</ScrollView>

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="老人看护系统"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="32dp"/>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="用户名"
android:inputType="text"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp">
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密码"
android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登录"/>
<Button
android:id="@+id/btn_register"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="注册"/>
</LinearLayout>

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/appbar"
layout="@layout/include_toolbar"/>
<FrameLayout
android:id="@+id/frame_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/appbar"
android:scrollbars="none"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"></FrameLayout>
</RelativeLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/navigation_header"
app:menu="@menu/drawer"></com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>

@ -1,62 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户注册"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginBottom="32dp"/>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<EditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="用户名"
android:inputType="text"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<EditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密码"
android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp">
<EditText
android:id="@+id/et_confirm_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="确认密码"
android:inputType="textPassword"/>
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btn_register"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="注册"/>
</LinearLayout>

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TimePicker
android:id="@+id/time_picker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:timePickerMode="spinner"/>
<EditText
android:id="@+id/et_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:hint="闹钟名称"
android:inputType="text"/>
</LinearLayout>

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@color/about_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/about_content1"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
<TextView
android:padding="30dp"
android:textSize="17sp"
android:layout_marginBottom="150dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="功能介绍:\n
实时监控用户是否发生跌倒。如果用户发生跌倒,手机会发出警报求助,以便获得及时的救助。"/>
<TextView
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="老人跌倒检测"/>
<TextView
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="当前版本1.0.0"/>
</LinearLayout>

@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_marginTop="30dp"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:textColor="@color/primary_text"
android:text="老人看护" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="300dp"
app:srcCompat="@drawable/people" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dp"
android:background="@color/teal_700"
android:orientation="horizontal">
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="80dp"
android:padding="5dp"
android:text="跌倒检测"
android:textColor="@color/primary_text"
android:textSize="18sp" />
<com.suke.widget.SwitchButton
android:id="@+id/switchButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="45dp" />
</LinearLayout>
<!--<TextView-->
<!--android:layout_gravity="center_horizontal"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:text="当前版本1.0.0"/>-->
</LinearLayout>

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<include android:id="@+id/appbar"
layout="@layout/include_toolbar"
android:title="@string/navigation_place"
xmlns:android="http://schemas.android.com/apk/res/android" />
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.amap.api.maps.SupportMapFragment" />
</FrameLayout>

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.appbar.AppBarLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</com.google.android.material.appbar.AppBarLayout>

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
app:cardCornerRadius="8dp"
app:cardElevation="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="24sp"
android:textStyle="bold"/>
<Switch
android:id="@+id/switch_alarm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"/>
<ImageButton
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_delete"/>
</LinearLayout>
<TextView
android:id="@+id/tv_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textSize="14sp"
android:textColor="@android:color/darker_gray"/>
</LinearLayout>
</androidx.cardview.widget.CardView>

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/map_activity"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include android:id="@+id/appbar"
layout="@layout/include_toolbar"
android:title="@string/navigation_place"
xmlns:android="http://schemas.android.com/apk/res/android" />
<com.amap.api.maps.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.amap.api.maps.MapView>
<ToggleButton
android:id="@+id/tb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:textOff="普通地图"
android:textOn="卫星地图"
android:checked="false"/>
<TextView
android:layout_width="250dp"
android:layout_height="wrap_content"
android:id="@+id/address"
android:textSize="20sp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#fff6ed"
android:gravity="center"
android:padding="16dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_app"/>
<TextView
android:layout_marginTop="10dp"
android:textSize="18sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:gravity="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"/>
</LinearLayout>

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/navigation_item_home"
android:icon="@drawable/ic_home"
android:title="@string/navigation_home" />
<item
android:id="@+id/navigation_item_place"
android:icon="@drawable/ic_home"
android:title="@string/navigation_place" />
<item
android:id="@+id/nav_map"
android:icon="@drawable/ic_home"
android:title="电子围栏" />
<item
android:id="@+id/nav_health"
android:icon="@drawable/ic_home"
android:title="健康信息" />
<item
android:id="@+id/nav_report"
android:icon="@drawable/ic_home"
android:title="健康报告" />
<item
android:id="@+id/nav_alarm"
android:icon="@drawable/ic_home"
android:title="闹钟提醒" />
<item
android:id="@+id/navigation_item_settings"
android:icon="@drawable/ic_settings"
android:title="@string/navigation_settings" />
</group>
</menu>

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/id_menu_settings"
android:title="@string/navigation_settings"/>
</menu>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save