Compare commits
No commits in common. 'main' and 'develop' have entirely different histories.
|
Before Width: | Height: | Size: 318 KiB |
@ -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 +0,0 @@
|
||||
/build
|
||||
@ -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,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();
|
||||
}
|
||||
|
||||
/*
|
||||
3s内svm原始数据收集
|
||||
*/
|
||||
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,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,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,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>
|
||||
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 835 KiB |
|
Before Width: | Height: | Size: 646 B |
|
Before Width: | Height: | Size: 406 B |
|
Before Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 230 B |
|
Before Width: | Height: | Size: 500 B |
|
Before Width: | Height: | Size: 2.8 KiB |
|
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>
|
||||
|
Before Width: | Height: | Size: 99 B |
|
Before Width: | Height: | Size: 525 B |
|
Before Width: | Height: | Size: 437 B |
|
Before Width: | Height: | Size: 652 B |
|
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,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>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 982 B |