From 0cf9eef5bf09dc056fc7f918461cd5e62b786ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BC=96=E7=A0=81=E7=8C=BF?= Date: Fri, 27 Sep 2024 01:09:52 +0800 Subject: [PATCH] first commit --- .gitignore | 23 + .pydio | 1 + clientAppOne/.gitignore | 15 + clientAppOne/.pydio | 1 + clientAppOne/app/.gitignore | 1 + clientAppOne/app/.pydio | 1 + clientAppOne/app/build.gradle | 69 +++ clientAppOne/app/libs/.pydio | 1 + clientAppOne/app/proguard-rules.pro | 21 + clientAppOne/app/src/.pydio | 1 + clientAppOne/app/src/androidTest/.pydio | 1 + clientAppOne/app/src/androidTest/java/.pydio | 1 + .../app/src/androidTest/java/com/.pydio | 1 + .../app/src/androidTest/java/com/bmy/.pydio | 1 + .../java/com/bmy/clientappone/.pydio | 1 + .../clientappone/ExampleInstrumentedTest.java | 26 + clientAppOne/app/src/main/.pydio | 1 + clientAppOne/app/src/main/AndroidManifest.xml | 79 +++ clientAppOne/app/src/main/java/.pydio | 1 + clientAppOne/app/src/main/java/com/.pydio | 1 + clientAppOne/app/src/main/java/com/bmy/.pydio | 1 + .../src/main/java/com/bmy/clientappone/.pydio | 1 + .../CheckPermissionsActivity.java | 219 ++++++++ .../com/bmy/clientappone/MainActivity.java | 476 ++++++++++++++++++ .../com/bmy/clientappone/MyApplication.java | 65 +++ .../java/com/bmy/clientappone/utils/.pydio | 1 + .../bmy/clientappone/utils/DistanceUtils.java | 33 ++ .../com/bmy/clientappone/utils/Utils.java | 117 +++++ clientAppOne/app/src/main/res/.pydio | 1 + .../app/src/main/res/drawable-v24/.pydio | 1 + .../drawable-v24/ic_launcher_foreground.xml | 30 ++ clientAppOne/app/src/main/res/drawable/.pydio | 1 + .../app/src/main/res/drawable/ic_launcher.png | Bin 0 -> 4123 bytes .../res/drawable/ic_launcher_background.xml | 170 +++++++ clientAppOne/app/src/main/res/layout/.pydio | 1 + .../app/src/main/res/layout/activity_main.xml | 33 ++ .../app/src/main/res/mipmap-anydpi-v26/.pydio | 1 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../app/src/main/res/mipmap-hdpi/.pydio | 1 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 4123 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5339 bytes .../app/src/main/res/mipmap-mdpi/.pydio | 1 + .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2636 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 3388 bytes .../app/src/main/res/mipmap-xhdpi/.pydio | 1 + .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4926 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7472 bytes .../app/src/main/res/mipmap-xxhdpi/.pydio | 1 + .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7909 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 11873 bytes .../app/src/main/res/mipmap-xxxhdpi/.pydio | 1 + .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10652 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 16570 bytes .../app/src/main/res/values-night/.pydio | 1 + .../app/src/main/res/values-night/themes.xml | 16 + clientAppOne/app/src/main/res/values/.pydio | 1 + .../app/src/main/res/values/colors.xml | 31 ++ .../app/src/main/res/values/dimens.xml | 27 + .../app/src/main/res/values/strings.xml | 172 +++++++ .../app/src/main/res/values/themes.xml | 16 + clientAppOne/app/src/test/.pydio | 1 + clientAppOne/app/src/test/java/.pydio | 1 + clientAppOne/app/src/test/java/com/.pydio | 1 + clientAppOne/app/src/test/java/com/bmy/.pydio | 1 + .../src/test/java/com/bmy/clientappone/.pydio | 1 + .../com/bmy/clientappone/ExampleUnitTest.java | 17 + clientAppOne/build.gradle | 24 + clientAppOne/gradle.properties | 19 + clientAppOne/gradlew | 172 +++++++ clientAppOne/gradlew.bat | 84 ++++ clientAppOne/settings.gradle | 2 + clientAppOne/问题.txt | 1 + clientapptwo/.gitignore | 15 + clientapptwo/.pydio | 1 + clientapptwo/app/.gitignore | 1 + clientapptwo/app/.pydio | 1 + clientapptwo/app/build.gradle | 41 ++ clientapptwo/app/libs/.pydio | 1 + clientapptwo/app/proguard-rules.pro | 21 + clientapptwo/app/src/.pydio | 1 + clientapptwo/app/src/androidTest/.pydio | 1 + clientapptwo/app/src/androidTest/java/.pydio | 1 + .../app/src/androidTest/java/com/.pydio | 1 + .../app/src/androidTest/java/com/bmy/.pydio | 1 + .../java/com/bmy/clientapptwo/.pydio | 1 + .../clientapptwo/ExampleInstrumentedTest.java | 26 + clientapptwo/app/src/main/.pydio | 1 + clientapptwo/app/src/main/AndroidManifest.xml | 62 +++ clientapptwo/app/src/main/java/.pydio | 1 + clientapptwo/app/src/main/java/com/.pydio | 1 + clientapptwo/app/src/main/java/com/bmy/.pydio | 1 + .../src/main/java/com/bmy/clientapptwo/.pydio | 1 + .../com/bmy/clientapptwo/MainActivity.java | 313 ++++++++++++ clientapptwo/app/src/main/res/.pydio | 1 + .../app/src/main/res/drawable-v24/.pydio | 1 + .../drawable-v24/ic_launcher_foreground.xml | 30 ++ clientapptwo/app/src/main/res/drawable/.pydio | 1 + .../res/drawable/ic_launcher_background.xml | 170 +++++++ clientapptwo/app/src/main/res/drawable/xa.png | Bin 0 -> 5141 bytes clientapptwo/app/src/main/res/layout/.pydio | 1 + .../app/src/main/res/layout/activity_main.xml | 79 +++ .../app/src/main/res/mipmap-anydpi-v26/.pydio | 1 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + .../app/src/main/res/mipmap-hdpi/.pydio | 1 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3593 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5339 bytes .../app/src/main/res/mipmap-mdpi/.pydio | 1 + .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2636 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 3388 bytes .../app/src/main/res/mipmap-xhdpi/.pydio | 1 + .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4926 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7472 bytes .../app/src/main/res/mipmap-xxhdpi/.pydio | 1 + .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7909 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 11873 bytes .../app/src/main/res/mipmap-xxxhdpi/.pydio | 1 + .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10652 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 16570 bytes .../app/src/main/res/values-night/.pydio | 1 + .../app/src/main/res/values-night/themes.xml | 16 + clientapptwo/app/src/main/res/values/.pydio | 1 + .../app/src/main/res/values/colors.xml | 10 + .../app/src/main/res/values/strings.xml | 3 + .../app/src/main/res/values/themes.xml | 16 + clientapptwo/app/src/main/res/xml/.pydio | 1 + .../main/res/xml/network_security_config.xml | 4 + clientapptwo/app/src/test/.pydio | 1 + clientapptwo/app/src/test/java/.pydio | 1 + clientapptwo/app/src/test/java/com/.pydio | 1 + clientapptwo/app/src/test/java/com/bmy/.pydio | 1 + .../src/test/java/com/bmy/clientapptwo/.pydio | 1 + .../com/bmy/clientapptwo/ExampleUnitTest.java | 17 + clientapptwo/build.gradle | 24 + clientapptwo/gradle.properties | 19 + clientapptwo/gradlew | 172 +++++++ clientapptwo/gradlew.bat | 84 ++++ clientapptwo/settings.gradle | 2 + http.http | 49 ++ socketEnd.zip | Bin 0 -> 3802 bytes socketEnd/.pydio | 1 + socketEnd/index.html | 41 ++ socketEnd/index.js | 6 + socketEnd/package.json | 20 + socketEnd/utils/.pydio | 1 + socketEnd/utils/WebSocket.js | 92 ++++ socketEnd/utils/utils.js | 34 ++ 思路.txt | 64 +++ 149 files changed, 3476 insertions(+) create mode 100644 .gitignore create mode 100644 .pydio create mode 100644 clientAppOne/.gitignore create mode 100644 clientAppOne/.pydio create mode 100644 clientAppOne/app/.gitignore create mode 100644 clientAppOne/app/.pydio create mode 100644 clientAppOne/app/build.gradle create mode 100644 clientAppOne/app/libs/.pydio create mode 100644 clientAppOne/app/proguard-rules.pro create mode 100644 clientAppOne/app/src/.pydio create mode 100644 clientAppOne/app/src/androidTest/.pydio create mode 100644 clientAppOne/app/src/androidTest/java/.pydio create mode 100644 clientAppOne/app/src/androidTest/java/com/.pydio create mode 100644 clientAppOne/app/src/androidTest/java/com/bmy/.pydio create mode 100644 clientAppOne/app/src/androidTest/java/com/bmy/clientappone/.pydio create mode 100644 clientAppOne/app/src/androidTest/java/com/bmy/clientappone/ExampleInstrumentedTest.java create mode 100644 clientAppOne/app/src/main/.pydio create mode 100644 clientAppOne/app/src/main/AndroidManifest.xml create mode 100644 clientAppOne/app/src/main/java/.pydio create mode 100644 clientAppOne/app/src/main/java/com/.pydio create mode 100644 clientAppOne/app/src/main/java/com/bmy/.pydio create mode 100644 clientAppOne/app/src/main/java/com/bmy/clientappone/.pydio create mode 100644 clientAppOne/app/src/main/java/com/bmy/clientappone/CheckPermissionsActivity.java create mode 100644 clientAppOne/app/src/main/java/com/bmy/clientappone/MainActivity.java create mode 100644 clientAppOne/app/src/main/java/com/bmy/clientappone/MyApplication.java create mode 100644 clientAppOne/app/src/main/java/com/bmy/clientappone/utils/.pydio create mode 100644 clientAppOne/app/src/main/java/com/bmy/clientappone/utils/DistanceUtils.java create mode 100644 clientAppOne/app/src/main/java/com/bmy/clientappone/utils/Utils.java create mode 100644 clientAppOne/app/src/main/res/.pydio create mode 100644 clientAppOne/app/src/main/res/drawable-v24/.pydio create mode 100644 clientAppOne/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 clientAppOne/app/src/main/res/drawable/.pydio create mode 100644 clientAppOne/app/src/main/res/drawable/ic_launcher.png create mode 100644 clientAppOne/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 clientAppOne/app/src/main/res/layout/.pydio create mode 100644 clientAppOne/app/src/main/res/layout/activity_main.xml create mode 100644 clientAppOne/app/src/main/res/mipmap-anydpi-v26/.pydio create mode 100644 clientAppOne/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 clientAppOne/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 clientAppOne/app/src/main/res/mipmap-hdpi/.pydio create mode 100644 clientAppOne/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 clientAppOne/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 clientAppOne/app/src/main/res/mipmap-mdpi/.pydio create mode 100644 clientAppOne/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 clientAppOne/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 clientAppOne/app/src/main/res/mipmap-xhdpi/.pydio create mode 100644 clientAppOne/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 clientAppOne/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 clientAppOne/app/src/main/res/mipmap-xxhdpi/.pydio create mode 100644 clientAppOne/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 clientAppOne/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 clientAppOne/app/src/main/res/mipmap-xxxhdpi/.pydio create mode 100644 clientAppOne/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 clientAppOne/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 clientAppOne/app/src/main/res/values-night/.pydio create mode 100644 clientAppOne/app/src/main/res/values-night/themes.xml create mode 100644 clientAppOne/app/src/main/res/values/.pydio create mode 100755 clientAppOne/app/src/main/res/values/colors.xml create mode 100755 clientAppOne/app/src/main/res/values/dimens.xml create mode 100755 clientAppOne/app/src/main/res/values/strings.xml create mode 100644 clientAppOne/app/src/main/res/values/themes.xml create mode 100644 clientAppOne/app/src/test/.pydio create mode 100644 clientAppOne/app/src/test/java/.pydio create mode 100644 clientAppOne/app/src/test/java/com/.pydio create mode 100644 clientAppOne/app/src/test/java/com/bmy/.pydio create mode 100644 clientAppOne/app/src/test/java/com/bmy/clientappone/.pydio create mode 100644 clientAppOne/app/src/test/java/com/bmy/clientappone/ExampleUnitTest.java create mode 100644 clientAppOne/build.gradle create mode 100644 clientAppOne/gradle.properties create mode 100755 clientAppOne/gradlew create mode 100644 clientAppOne/gradlew.bat create mode 100644 clientAppOne/settings.gradle create mode 100644 clientAppOne/问题.txt create mode 100644 clientapptwo/.gitignore create mode 100644 clientapptwo/.pydio create mode 100644 clientapptwo/app/.gitignore create mode 100644 clientapptwo/app/.pydio create mode 100644 clientapptwo/app/build.gradle create mode 100644 clientapptwo/app/libs/.pydio create mode 100644 clientapptwo/app/proguard-rules.pro create mode 100644 clientapptwo/app/src/.pydio create mode 100644 clientapptwo/app/src/androidTest/.pydio create mode 100644 clientapptwo/app/src/androidTest/java/.pydio create mode 100644 clientapptwo/app/src/androidTest/java/com/.pydio create mode 100644 clientapptwo/app/src/androidTest/java/com/bmy/.pydio create mode 100644 clientapptwo/app/src/androidTest/java/com/bmy/clientapptwo/.pydio create mode 100644 clientapptwo/app/src/androidTest/java/com/bmy/clientapptwo/ExampleInstrumentedTest.java create mode 100644 clientapptwo/app/src/main/.pydio create mode 100644 clientapptwo/app/src/main/AndroidManifest.xml create mode 100644 clientapptwo/app/src/main/java/.pydio create mode 100644 clientapptwo/app/src/main/java/com/.pydio create mode 100644 clientapptwo/app/src/main/java/com/bmy/.pydio create mode 100644 clientapptwo/app/src/main/java/com/bmy/clientapptwo/.pydio create mode 100644 clientapptwo/app/src/main/java/com/bmy/clientapptwo/MainActivity.java create mode 100644 clientapptwo/app/src/main/res/.pydio create mode 100644 clientapptwo/app/src/main/res/drawable-v24/.pydio create mode 100644 clientapptwo/app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 clientapptwo/app/src/main/res/drawable/.pydio create mode 100644 clientapptwo/app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 clientapptwo/app/src/main/res/drawable/xa.png create mode 100644 clientapptwo/app/src/main/res/layout/.pydio create mode 100644 clientapptwo/app/src/main/res/layout/activity_main.xml create mode 100644 clientapptwo/app/src/main/res/mipmap-anydpi-v26/.pydio create mode 100644 clientapptwo/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 clientapptwo/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 clientapptwo/app/src/main/res/mipmap-hdpi/.pydio create mode 100644 clientapptwo/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 clientapptwo/app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 clientapptwo/app/src/main/res/mipmap-mdpi/.pydio create mode 100644 clientapptwo/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 clientapptwo/app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 clientapptwo/app/src/main/res/mipmap-xhdpi/.pydio create mode 100644 clientapptwo/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 clientapptwo/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 clientapptwo/app/src/main/res/mipmap-xxhdpi/.pydio create mode 100644 clientapptwo/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 clientapptwo/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 clientapptwo/app/src/main/res/mipmap-xxxhdpi/.pydio create mode 100644 clientapptwo/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 clientapptwo/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 clientapptwo/app/src/main/res/values-night/.pydio create mode 100644 clientapptwo/app/src/main/res/values-night/themes.xml create mode 100644 clientapptwo/app/src/main/res/values/.pydio create mode 100644 clientapptwo/app/src/main/res/values/colors.xml create mode 100644 clientapptwo/app/src/main/res/values/strings.xml create mode 100644 clientapptwo/app/src/main/res/values/themes.xml create mode 100644 clientapptwo/app/src/main/res/xml/.pydio create mode 100644 clientapptwo/app/src/main/res/xml/network_security_config.xml create mode 100644 clientapptwo/app/src/test/.pydio create mode 100644 clientapptwo/app/src/test/java/.pydio create mode 100644 clientapptwo/app/src/test/java/com/.pydio create mode 100644 clientapptwo/app/src/test/java/com/bmy/.pydio create mode 100644 clientapptwo/app/src/test/java/com/bmy/clientapptwo/.pydio create mode 100644 clientapptwo/app/src/test/java/com/bmy/clientapptwo/ExampleUnitTest.java create mode 100644 clientapptwo/build.gradle create mode 100644 clientapptwo/gradle.properties create mode 100755 clientapptwo/gradlew create mode 100644 clientapptwo/gradlew.bat create mode 100644 clientapptwo/settings.gradle create mode 100644 http.http create mode 100644 socketEnd.zip create mode 100644 socketEnd/.pydio create mode 100644 socketEnd/index.html create mode 100644 socketEnd/index.js create mode 100644 socketEnd/package.json create mode 100644 socketEnd/utils/.pydio create mode 100644 socketEnd/utils/WebSocket.js create mode 100644 socketEnd/utils/utils.js create mode 100644 思路.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..403adbc --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules +/dist + + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.pydio b/.pydio new file mode 100644 index 0000000..b0f2d2c --- /dev/null +++ b/.pydio @@ -0,0 +1 @@ +a90f4fde-ad34-40fa-914b-67114b882576 \ No newline at end of file diff --git a/clientAppOne/.gitignore b/clientAppOne/.gitignore new file mode 100644 index 0000000..aa724b7 --- /dev/null +++ b/clientAppOne/.gitignore @@ -0,0 +1,15 @@ +*.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 diff --git a/clientAppOne/.pydio b/clientAppOne/.pydio new file mode 100644 index 0000000..2f886ef --- /dev/null +++ b/clientAppOne/.pydio @@ -0,0 +1 @@ +4fff03da-7cd6-48ab-8de2-c5cc6e8b1d30 \ No newline at end of file diff --git a/clientAppOne/app/.gitignore b/clientAppOne/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/clientAppOne/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/clientAppOne/app/.pydio b/clientAppOne/app/.pydio new file mode 100644 index 0000000..282c5f1 --- /dev/null +++ b/clientAppOne/app/.pydio @@ -0,0 +1 @@ +3ce68cbd-aada-42ea-be25-09702e2dba89 \ No newline at end of file diff --git a/clientAppOne/app/build.gradle b/clientAppOne/app/build.gradle new file mode 100644 index 0000000..6182894 --- /dev/null +++ b/clientAppOne/app/build.gradle @@ -0,0 +1,69 @@ +plugins { + id 'com.android.application' +} + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.2" + + defaultConfig { + applicationId "com.bmy.clientappone" + minSdkVersion 16 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + ndk { + //设置支持的SO库架构(开发者可以根据需要,选择一个或多个平台的so) + abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86","arm64-v8a","x86_64" + } + } + + signingConfigs { + //调试版的keystore + debug { + storeFile file("/Users/bmy/Tools/key.jks") + storePassword "lb714500" + keyAlias "key" + keyPassword "lb714500" + } + //发布版的keystore + release { + storeFile file("/Users/bmy/Tools/key.jks") + storePassword "lb714500" + keyAlias "key" + keyPassword "lb714500" + } + } + + 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 'androidx.appcompat:appcompat:1.1.0' + implementation 'com.google.android.material:material:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + //定位功能 + compile 'com.amap.api:location:latest.integration' + //搜索功能 + compile 'com.amap.api:search:latest.integration' + //3D地图so及jar + compile 'com.amap.api:3dmap:latest.integration' + implementation 'com.squareup.okhttp3:okhttp:4.9.0' + implementation 'com.ejlchina:okhttps-gson:3.1.3' +} \ No newline at end of file diff --git a/clientAppOne/app/libs/.pydio b/clientAppOne/app/libs/.pydio new file mode 100644 index 0000000..3a4be68 --- /dev/null +++ b/clientAppOne/app/libs/.pydio @@ -0,0 +1 @@ +c1f7038f-b16b-4ff8-819f-f15b872e7700 \ No newline at end of file diff --git a/clientAppOne/app/proguard-rules.pro b/clientAppOne/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/clientAppOne/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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 \ No newline at end of file diff --git a/clientAppOne/app/src/.pydio b/clientAppOne/app/src/.pydio new file mode 100644 index 0000000..db3d6cd --- /dev/null +++ b/clientAppOne/app/src/.pydio @@ -0,0 +1 @@ +179845e2-1a2c-4c8c-a11b-11ecf129ca58 \ No newline at end of file diff --git a/clientAppOne/app/src/androidTest/.pydio b/clientAppOne/app/src/androidTest/.pydio new file mode 100644 index 0000000..9125350 --- /dev/null +++ b/clientAppOne/app/src/androidTest/.pydio @@ -0,0 +1 @@ +e0b1245e-ba24-4029-b069-690130b454f0 \ No newline at end of file diff --git a/clientAppOne/app/src/androidTest/java/.pydio b/clientAppOne/app/src/androidTest/java/.pydio new file mode 100644 index 0000000..6d36468 --- /dev/null +++ b/clientAppOne/app/src/androidTest/java/.pydio @@ -0,0 +1 @@ +ad34b3cd-d558-4021-b1e6-2266c23d59c1 \ No newline at end of file diff --git a/clientAppOne/app/src/androidTest/java/com/.pydio b/clientAppOne/app/src/androidTest/java/com/.pydio new file mode 100644 index 0000000..099dad5 --- /dev/null +++ b/clientAppOne/app/src/androidTest/java/com/.pydio @@ -0,0 +1 @@ +066a58c3-d308-4296-b779-94e3056412ba \ No newline at end of file diff --git a/clientAppOne/app/src/androidTest/java/com/bmy/.pydio b/clientAppOne/app/src/androidTest/java/com/bmy/.pydio new file mode 100644 index 0000000..7d15280 --- /dev/null +++ b/clientAppOne/app/src/androidTest/java/com/bmy/.pydio @@ -0,0 +1 @@ +f6d0b689-abce-4481-b206-baa2e824e0fd \ No newline at end of file diff --git a/clientAppOne/app/src/androidTest/java/com/bmy/clientappone/.pydio b/clientAppOne/app/src/androidTest/java/com/bmy/clientappone/.pydio new file mode 100644 index 0000000..e5909ad --- /dev/null +++ b/clientAppOne/app/src/androidTest/java/com/bmy/clientappone/.pydio @@ -0,0 +1 @@ +eadded64-405e-4e64-abaa-7c7005cb10e5 \ No newline at end of file diff --git a/clientAppOne/app/src/androidTest/java/com/bmy/clientappone/ExampleInstrumentedTest.java b/clientAppOne/app/src/androidTest/java/com/bmy/clientappone/ExampleInstrumentedTest.java new file mode 100644 index 0000000..58e66ba --- /dev/null +++ b/clientAppOne/app/src/androidTest/java/com/bmy/clientappone/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.bmy.clientappone; + +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 Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.bmy.clientappone", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/clientAppOne/app/src/main/.pydio b/clientAppOne/app/src/main/.pydio new file mode 100644 index 0000000..46e0d91 --- /dev/null +++ b/clientAppOne/app/src/main/.pydio @@ -0,0 +1 @@ +2c64e9ab-a201-4ab0-afbb-2efd2f2c0879 \ No newline at end of file diff --git a/clientAppOne/app/src/main/AndroidManifest.xml b/clientAppOne/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..34689d1 --- /dev/null +++ b/clientAppOne/app/src/main/AndroidManifest.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/clientAppOne/app/src/main/java/.pydio b/clientAppOne/app/src/main/java/.pydio new file mode 100644 index 0000000..eb1d3a2 --- /dev/null +++ b/clientAppOne/app/src/main/java/.pydio @@ -0,0 +1 @@ +bd7acbc0-b44f-4a5d-94b5-de6a2fa969ba \ No newline at end of file diff --git a/clientAppOne/app/src/main/java/com/.pydio b/clientAppOne/app/src/main/java/com/.pydio new file mode 100644 index 0000000..675b85d --- /dev/null +++ b/clientAppOne/app/src/main/java/com/.pydio @@ -0,0 +1 @@ +78024cdb-10c3-4845-adb2-09284dfb14b9 \ No newline at end of file diff --git a/clientAppOne/app/src/main/java/com/bmy/.pydio b/clientAppOne/app/src/main/java/com/bmy/.pydio new file mode 100644 index 0000000..f8327c7 --- /dev/null +++ b/clientAppOne/app/src/main/java/com/bmy/.pydio @@ -0,0 +1 @@ +32c8dd8a-c84e-49d1-bbaa-5a6042053576 \ No newline at end of file diff --git a/clientAppOne/app/src/main/java/com/bmy/clientappone/.pydio b/clientAppOne/app/src/main/java/com/bmy/clientappone/.pydio new file mode 100644 index 0000000..2ac2f71 --- /dev/null +++ b/clientAppOne/app/src/main/java/com/bmy/clientappone/.pydio @@ -0,0 +1 @@ +a3a8e869-4a2b-4697-9a69-5dabe0c59315 \ No newline at end of file diff --git a/clientAppOne/app/src/main/java/com/bmy/clientappone/CheckPermissionsActivity.java b/clientAppOne/app/src/main/java/com/bmy/clientappone/CheckPermissionsActivity.java new file mode 100644 index 0000000..139116a --- /dev/null +++ b/clientAppOne/app/src/main/java/com/bmy/clientappone/CheckPermissionsActivity.java @@ -0,0 +1,219 @@ +package com.bmy.clientappone; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import android.Manifest; +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.view.KeyEvent; + +/** + * 继承了Activity,实现Android6.0的运行时权限检测 + * 需要进行运行时权限检测的Activity可以继承这个类 + * + * @创建时间:2016年5月27日 下午3:01:31 + * @项目名称: AMapLocationDemo + * @author hongming.wang + * @文件名称:PermissionsChecker.java + * @类型名称:PermissionsChecker + * @since 2.5.0 + */ +public class CheckPermissionsActivity extends Activity { + //是否需要检测后台定位权限,设置为true时,如果用户没有给予后台定位权限会弹窗提示 + private boolean needCheckBackLocation = false; + //如果设置了target > 28,需要增加这个权限,否则不会弹出"始终允许"这个选择框 + private static String BACKGROUND_LOCATION_PERMISSION = "android.permission.ACCESS_BACKGROUND_LOCATION"; + /** + * 需要进行检测的权限数组 + */ + protected String[] needPermissions = { + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.READ_PHONE_STATE + }; + + private static final int PERMISSON_REQUESTCODE = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if(Build.VERSION.SDK_INT > 28 + && getApplicationContext().getApplicationInfo().targetSdkVersion > 28) { + needPermissions = new String[] { + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.READ_PHONE_STATE, + BACKGROUND_LOCATION_PERMISSION + }; + } + } + + /** + * 判断是否需要检测,防止不停的弹框 + */ + private boolean isNeedCheck = true; + + @Override + protected void onResume() { + super.onResume(); + if (Build.VERSION.SDK_INT >= 23 + && getApplicationInfo().targetSdkVersion >= 23) { + if (isNeedCheck) { + checkPermissions(needPermissions); + } + } + } + + /** + * + * @param permissions + * @since 2.5.0 + * + */ + private void checkPermissions(String... permissions) { + try { + if (Build.VERSION.SDK_INT >= 23 + && getApplicationInfo().targetSdkVersion >= 23) { + List needRequestPermissonList = findDeniedPermissions(permissions); + if (null != needRequestPermissonList + && needRequestPermissonList.size() > 0) { + String[] array = needRequestPermissonList.toArray(new String[needRequestPermissonList.size()]); + Method method = getClass().getMethod("requestPermissions", new Class[]{String[].class, + int.class}); + + method.invoke(this, array, PERMISSON_REQUESTCODE); + } + } + } catch (Throwable e) { + } + } + + /** + * 获取权限集中需要申请权限的列表 + * + * @param permissions + * @return + * @since 2.5.0 + * + */ + private List findDeniedPermissions(String[] permissions) { + List needRequestPermissonList = new ArrayList(); + if (Build.VERSION.SDK_INT >= 23 + && getApplicationInfo().targetSdkVersion >= 23){ + try { + for (String perm : permissions) { + Method checkSelfMethod = getClass().getMethod("checkSelfPermission", String.class); + Method shouldShowRequestPermissionRationaleMethod = getClass().getMethod("shouldShowRequestPermissionRationale", + String.class); + if ((Integer)checkSelfMethod.invoke(this, perm) != PackageManager.PERMISSION_GRANTED + || (Boolean)shouldShowRequestPermissionRationaleMethod.invoke(this, perm)) { + if(!needCheckBackLocation + && BACKGROUND_LOCATION_PERMISSION.equals(perm)) { + continue; + } + needRequestPermissonList.add(perm); + } + } + } catch (Throwable e) { + + } + } + return needRequestPermissonList; + } + + /** + * 检测是否所有的权限都已经授权 + * @param grantResults + * @return + * @since 2.5.0 + * + */ + private boolean verifyPermissions(int[] grantResults) { + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } + + @TargetApi(23) + public void onRequestPermissionsResult(int requestCode, + String[] permissions, int[] paramArrayOfInt) { + if (requestCode == PERMISSON_REQUESTCODE) { + if (!verifyPermissions(paramArrayOfInt)) { + showMissingPermissionDialog(); + isNeedCheck = false; + } + } + } + + /** + * 显示提示信息 + * + * @since 2.5.0 + * + */ + private void showMissingPermissionDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("提示"); + builder.setMessage("前应用缺少必要权限。\\n\\n请点击\\\"设置\\\"-\\\"权限\\\"-打开所需权限。"); + + // 拒绝, 退出应用 + builder.setNegativeButton("取消", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + builder.setPositiveButton("设置", + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startAppSettings(); + } + }); + + builder.setCancelable(false); + + builder.show(); + } + + /** + * 启动应用的设置 + * + * @since 2.5.0 + * + */ + private void startAppSettings() { + Intent intent = new Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + getPackageName())); + startActivity(intent); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if(keyCode == KeyEvent.KEYCODE_BACK){ + this.finish(); + return true; + } + return super.onKeyDown(keyCode, event); + } + +} diff --git a/clientAppOne/app/src/main/java/com/bmy/clientappone/MainActivity.java b/clientAppOne/app/src/main/java/com/bmy/clientappone/MainActivity.java new file mode 100644 index 0000000..5b869c4 --- /dev/null +++ b/clientAppOne/app/src/main/java/com/bmy/clientappone/MainActivity.java @@ -0,0 +1,476 @@ +package com.bmy.clientappone; + +import android.annotation.SuppressLint; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.Color; +import android.os.Bundle; +import android.os.Message; +import android.os.PowerManager; +import android.speech.tts.TextToSpeech; +import android.util.Log; +import android.view.Gravity; +import android.view.View; +import android.widget.Button; +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 com.amap.api.location.AMapLocationQualityReport; +import com.amap.api.maps.AMapUtils; +import com.amap.api.maps.model.LatLng; +import com.amap.api.services.route.DistanceResult; +import com.amap.api.services.route.DistanceSearch; +import com.bmy.clientappone.utils.Utils; +import com.bmy.clientappone.utils.DistanceUtils; +import com.ejlchina.okhttps.GsonMsgConvertor; +import com.ejlchina.okhttps.HTTP; +import com.ejlchina.okhttps.WebSocket; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import okhttp3.OkHttpClient; + +public class MainActivity extends CheckPermissionsActivity implements View.OnClickListener { + private TextView tvResult; + private Button btLocation; + + private AMapLocationClient locationClient = null; + private AMapLocationClientOption locationOption = null; + + private PowerManager.WakeLock mWakeLock = null; + + private int Nums = 1; + + private TextToSpeech mSpeech; + + private HTTP http = null; + private WebSocket ws = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + setTitle(R.string.title_locationBackground); + initView(); + initOkHttps(); + initLocation(); + } + + + //初始化控件 + private void initView(){ + tvResult = (TextView) findViewById(R.id.tv_result); + btLocation = (Button) findViewById(R.id.bt_location); + btLocation.setOnClickListener(this); + mSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status == TextToSpeech.SUCCESS) { + mSpeech.setLanguage(Locale.CHINESE); + mSpeech.setPitch(1.5f);// 设置音调,值越大声音越尖(女生),值越小则变成男声,1.0是常规 + mSpeech.setSpeechRate(0.5f);//设置速度 + } + } + }); + } + + // 初始化 + private void initOkHttps() { + // 构建实例 + http = HTTP.builder() + .baseUrl("ws://120.27.144.174:8080") + .build(); + ws = http.webSocket("/html") + .listen(); + // 获取当前的连接状态 + int status = ws.status(); + if (status == WebSocket.STATUS_CONNECTING) { + Log.d("1: ", "WebSocket正在连接..."); + ShowToast("1:WebSocket正在连接..."); + } + if (status == WebSocket.STATUS_CONNECTED) { + Log.d("2: ", "WebSocket已建立连接..."); + ShowToast("2:WebSocket已建立连接..."); + } + if (status == WebSocket.STATUS_DISCONNECTED) { + Log.d("3: ", "WebSocket已断开连接(正常断开)..."); + ShowToast("3:WebSocket已断开连接(正常断开)..."); + } + if (status == WebSocket.STATUS_CANCELED) { + Log.d("4: ", "WebSocket已取消连接..."); + ShowToast("4:WebSocket已取消连接..."); + } + if (status == WebSocket.STATUS_TIMEOUT) { + Log.d("5: ", "WebSocket已连接超时..."); + ShowToast("5:WebSocket已连接超时..."); + } + if (status == WebSocket.STATUS_NETWORK_ERROR) { + Log.d("6: ", "WebSocket连接网络错误..."); + ShowToast("6:WebSocket连接网络错误..."); + } + if (status == WebSocket.STATUS_EXCEPTION) { + Log.d("7: ", "WebSocket连接发生异常..."); + ShowToast("7:WebSocket连接发生异常..."); + } + } + + private void sendMessage() { + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("type", 1); + } catch (JSONException e) { + e.printStackTrace(); + } + ws.send(jsonObject.toString()); + } + + private void ShowToast(String text) { + Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.show(); + } + + + @Override + public void onClick(View v) { + if (v.getId() == R.id.bt_location) { + if (btLocation.getText().equals(getResources().getString(R.string.startLocation))) { + Nums = 1; + btLocation.setText(getResources().getString(R.string.stopLocation)); + tvResult.setText("正在定位..."); + startLocation(); + } else { + btLocation.setText(getResources().getString( + R.string.startLocation)); + stopLocation(); + tvResult.setText("定位停止"); + } + } + } + + /** + * 初始化定位 + * + * @since 2.8.0 + * @author hongming.wang + * + */ + private void initLocation(){ + //初始化client + locationClient = new AMapLocationClient(this.getApplicationContext()); + locationOption = getDefaultOption(); + //设置定位参数 + locationClient.setLocationOption(locationOption); + // 设置定位监听 + locationClient.setLocationListener(locationListener); + } + + /** + * 默认的定位参数 + * @since 2.8.0 + * @author hongming.wang + * + */ + private AMapLocationClientOption getDefaultOption(){ + AMapLocationClientOption mOption = new AMapLocationClientOption(); + mOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Sport); + mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式 + mOption.setGpsFirst(true);//可选,设置是否gps优先,只在高精度模式下有效。默认关闭 + mOption.setHttpTimeOut(30000);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效 + mOption.setInterval(5000);//可选,设置定位间隔。默认为5秒 + mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是true + mOption.setOnceLocation(false);//可选,设置是否单次定位。默认是false + mOption.setOnceLocationLatest(false);//可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用 + AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP + mOption.setSensorEnable(true);//可选,设置是否使用传感器。默认是false + mOption.setWifiScan(true); //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差 + mOption.setLocationCacheEnable(true); //可选,设置是否使用缓存定位,默认为true + return mOption; + } + + /** + * 定位监听 + */ + AMapLocationListener locationListener = new AMapLocationListener() { + @Override + public void onLocationChanged(AMapLocation location) { + if (null != location) { + + Log.d("经度=========", String.valueOf(location.getLongitude())); + Log.d("纬度=========", String.valueOf(location.getLatitude())); + + StringBuffer sb = new StringBuffer(); + //errCode等于0代表定位成功,其他的为定位失败 + if(location.getErrorCode() == 0){ + // 当前实时的地理位置 + LatLng CurrentLocation = new LatLng(location.getLatitude(),location.getLongitude()); + // 家的位置 + LatLng MyHome = new LatLng(31.792928,117.325573); + float distance = AMapUtils.calculateLineDistance(CurrentLocation,MyHome); + // 触发开灯开空调的条件有: + // 1: 离家距离小于等于500米(通过两个经纬度坐标计算差值得出) + // 2: 定位精度误差小于等于100米的时候,属于定位较为精准 && location.getAccuracy() <= 100 + // 3: 排除 基站定位 误差很大的情况,只考虑 GPS,前次定位,缓存定位,WIFI定位等高精度地位 + // 4: 通知服务器次数没有超过三次,这里设置多次通知的原因是防止单次提醒准确度不够的问题 + // 多次通知后,关闭GPS定位,停止后台定位,重置计数器,方便下次重新开始! + if (distance <= 500 && location.getLocationType() <= 5 && Nums <= 1 ) { + mSpeech.speak("您即将到家的第"+Nums+"次提醒,为您提前打开空调和灯!", TextToSpeech.QUEUE_FLUSH, null); + Log.d("快到家了:", String.valueOf(distance)); + + ShowToast("正在自动打开家里空调和灯!"); + + // 发送WebSocket请求通知服务器 + sendMessage(); + + // 第三次通知,那么停止定位,修改按钮状态 + if (Nums == 1) { + btLocation.setText(getResources().getString(R.string.startLocation)); + stopLocation(); + tvResult.setText("提醒结束,停止定位!"); + Nums = 1; + Log.d("", "提醒结束,停止定位!"); + } else { + TextResult(sb, location); + } + Nums += 1; + // 没到家或者已经到家并完成了开灯开空调的操作! + } else { + ShowToast("还没到家,距离加还有 "+String.valueOf(distance/1000)+" 公里!"); + Log.d("还没到家,还剩:", String.valueOf(distance)); + TextResult(sb, location); + } + } else { + //定位失败 + sb.append("定位失败" + "\n"); + sb.append("错误码:" + location.getErrorCode() + "\n"); + sb.append("错误信息:" + location.getErrorInfo() + "\n"); + sb.append("错误描述:" + location.getLocationDetail() + "\n"); + } + + } else { + tvResult.setText("定位失败,loc is null"); + } + } + }; + + private void TextResult (StringBuffer sb, AMapLocation location) { + sb.append("定位成功" + "\n"); + sb.append("定位类型: " + location.getLocationType() + "\n"); + sb.append("经 度 : " + location.getLongitude() + "\n"); + sb.append("纬 度 : " + location.getLatitude() + "\n"); + sb.append("精 度 : " + location.getAccuracy() + "米" + "\n"); + //定位完成的时间 + sb.append("定位时间: " + Utils.formatUTC(location.getTime(), "yyyy-MM-dd HH:mm:ss") + "\n"); + //定位之后的回调时间 + sb.append("回调时间: " + Utils.formatUTC(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") + "\n\n"); + sb.append("***定位质量报告***").append("\n"); + sb.append("* WIFI开关:").append(location.getLocationQualityReport().isWifiAble() ? "开启":"关闭").append("\n"); + sb.append("* GPS状态:").append(getGPSStatusString(location.getLocationQualityReport().getGPSStatus())).append("\n"); + sb.append("* GPS星数:").append(location.getLocationQualityReport().getGPSSatellites()).append("\n"); + sb.append("****************").append("\n"); + //解析定位结果, + String result = sb.toString(); + tvResult.setText(result); + } + + /** + * 获取唤醒锁 + */ + @SuppressLint("InvalidWakeLockTag") + private void acquireWakeLock() { + if(mWakeLock == null) { + PowerManager mPM = (PowerManager) this.getSystemService(Context.POWER_SERVICE); + mWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,"PlayService"); + if(mWakeLock!=null) { + mWakeLock.acquire(); + } + } + } + + + /** + * 获取GPS状态的字符串 + * @param statusCode GPS状态码 + * @return + */ + private String getGPSStatusString(int statusCode){ + String str = ""; + switch (statusCode){ + case AMapLocationQualityReport.GPS_STATUS_OK: + str = "GPS状态正常"; + break; + case AMapLocationQualityReport.GPS_STATUS_NOGPSPROVIDER: + str = "手机中没有GPS Provider,无法进行GPS定位"; + break; + case AMapLocationQualityReport.GPS_STATUS_OFF: + str = "GPS关闭,建议开启GPS,提高定位质量"; + break; + case AMapLocationQualityReport.GPS_STATUS_MODE_SAVING: + str = "选择的定位模式中不包含GPS定位,建议选择包含GPS定位的模式,提高定位质量"; + break; + case AMapLocationQualityReport.GPS_STATUS_NOGPSPERMISSION: + str = "没有GPS定位权限,建议开启gps定位权限"; + break; + } + return str; + } + + // App放到前台后 + @Override + protected void onResume() { + super.onResume(); + if(null != locationClient) { + Log.d("切入前台后关闭后台定位功能", "切入前台后关闭后台定位功能"); + releaseWakeLock(); + locationClient.disableBackgroundLocation(true); + } + } + + // App放到后台后 + @Override + protected void onStop() { + super.onStop(); + boolean isBackground = ((MyApplication)getApplication()).isBackground(); + if(isBackground){ + acquireWakeLock(); + Log.d("如果app已经切入到后台,启动后台定位功能", "如果app已经切入到后台,启动后台定位功能"); + if(null != locationClient) { + locationClient.enableBackgroundLocation(2001, buildNotification("实时读取定位上报服务器中...")); + } + } + } + + @Override + protected void onDestroy() { + destroySpeech(); + releaseWakeLock(); + destroyLocation(); + super.onDestroy(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + // 开始定位 + private void startLocation(){ + // 设置定位参数 + locationClient.setLocationOption(locationOption); + // 启动定位 + locationClient.startLocation(); + //启动后台定位 +// locationClient.enableBackgroundLocation(2001, buildNotification()); + } + + // 停止定位 + private void stopLocation(){ + // 停止定位 + locationClient.stopLocation(); + //关闭后台定位 + locationClient.disableBackgroundLocation(true); + } + + // 销毁定位 + private void destroyLocation(){ + if (null != locationClient) { + /** + * 如果AMapLocationClient是在当前Activity实例化的, + * 在Activity的onDestroy中一定要执行AMapLocationClient的onDestroy + */ + locationClient.onDestroy(); + locationClient = null; + locationOption = null; + } + } + + // 释放锁 + private void releaseWakeLock() { + if(mWakeLock!=null) { + mWakeLock.release(); + mWakeLock = null; + } + } + + // 销毁TTS语音 + private void destroySpeech () { + if (mSpeech != null) { + mSpeech.stop(); + mSpeech.shutdown(); + } + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + } + + private void createNotificationChannel(){ + + } + + + private static final String NOTIFICATION_CHANNEL_NAME = "BackgroundLocation"; + private NotificationManager notificationManager = null; + boolean isCreateChannel = false; + @SuppressLint("NewApi") + private Notification buildNotification(String content) { + + Notification.Builder builder = null; + Notification notification = null; + if(android.os.Build.VERSION.SDK_INT >= 26) { + //Android O上对Notification进行了修改,如果设置的targetSDKVersion>=26建议使用此种方式创建通知栏 + if (null == notificationManager) { + notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + } + String channelId = getPackageName(); + if(!isCreateChannel) { + NotificationChannel notificationChannel = new NotificationChannel( + channelId, + NOTIFICATION_CHANNEL_NAME, + NotificationManager.IMPORTANCE_DEFAULT + ); + notificationChannel.enableLights(true);//是否在桌面icon右上角展示小圆点 + // 设置通知出现时的震动(如果 android 设备支持的话) + notificationChannel.enableVibration(true); + notificationChannel.setLightColor(Color.BLUE); //小圆点颜色 + + notificationChannel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知 + notificationManager.createNotificationChannel(notificationChannel); + isCreateChannel = true; + } + builder = new Notification.Builder(getApplicationContext(), channelId); + } else { + builder = new Notification.Builder(getApplicationContext()); + } + + Intent intent = new Intent(this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); + builder.setContentIntent(PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); + + builder.setSmallIcon(R.drawable.ic_launcher) + .setContentTitle(Utils.getAppName(this)) + .setContentText(content) + .setWhen(System.currentTimeMillis()); + + if (android.os.Build.VERSION.SDK_INT >= 16) { + notification = builder.build(); + } else { + return builder.getNotification(); + } + return notification; + } +} \ No newline at end of file diff --git a/clientAppOne/app/src/main/java/com/bmy/clientappone/MyApplication.java b/clientAppOne/app/src/main/java/com/bmy/clientappone/MyApplication.java new file mode 100644 index 0000000..ec19cb1 --- /dev/null +++ b/clientAppOne/app/src/main/java/com/bmy/clientappone/MyApplication.java @@ -0,0 +1,65 @@ +package com.bmy.clientappone; + +import android.app.Activity; +import android.app.Application; +import android.os.Bundle; +import android.util.Log; + +/** + * Created by hongming.wang on 2018/1/23. + */ + +public class MyApplication extends Application{ + private int count = 0; + + @Override + public void onCreate() { + super.onCreate(); + registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + } + + @Override + public void onActivityStarted(Activity activity) { + count ++; + } + + @Override + public void onActivityResumed(Activity activity) { + } + + @Override + public void onActivityPaused(Activity activity) { + } + + @Override + public void onActivityStopped(Activity activity) { + if(count > 0) { + count--; + } + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + } + }); + } + + /** + * 判断app是否在后台 + * @return + */ + public boolean isBackground(){ + if(count <= 0){ + return true; + } else { + return false; + } + } +} diff --git a/clientAppOne/app/src/main/java/com/bmy/clientappone/utils/.pydio b/clientAppOne/app/src/main/java/com/bmy/clientappone/utils/.pydio new file mode 100644 index 0000000..4cd937d --- /dev/null +++ b/clientAppOne/app/src/main/java/com/bmy/clientappone/utils/.pydio @@ -0,0 +1 @@ +23aa0c3f-84f9-413d-93ca-e8e9e72aaf26 \ No newline at end of file diff --git a/clientAppOne/app/src/main/java/com/bmy/clientappone/utils/DistanceUtils.java b/clientAppOne/app/src/main/java/com/bmy/clientappone/utils/DistanceUtils.java new file mode 100644 index 0000000..1da331d --- /dev/null +++ b/clientAppOne/app/src/main/java/com/bmy/clientappone/utils/DistanceUtils.java @@ -0,0 +1,33 @@ +package com.bmy.clientappone.utils; + +public class DistanceUtils { + /** + * 地球半径,单位 km + */ + private static final double EARTH_RADIUS = 6378137; + + /** + * 根据经纬度,计算两点间的距离 + * + * @param longitude1 第一个点的经度 + * @param latitude1 第一个点的纬度 + * @param longitude2 第二个点的经度 + * @param latitude2 第二个点的纬度 + * @return 返回距离 单位米 + */ + public static double getDistance(double longitude1, double latitude1, double longitude2, double latitude2) { + + double latDistance = Math.toRadians(longitude1 - longitude2); + double lngDistance = Math.toRadians(latitude1 - latitude2); + + double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) + + Math.cos(Math.toRadians(longitude1)) * Math.cos(Math.toRadians(longitude2)) + * Math.sin(lngDistance / 2) * Math.sin(lngDistance / 2); + + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + + c = c * EARTH_RADIUS; + return Math.round(c * 10000) / 10000; + + } +} diff --git a/clientAppOne/app/src/main/java/com/bmy/clientappone/utils/Utils.java b/clientAppOne/app/src/main/java/com/bmy/clientappone/utils/Utils.java new file mode 100644 index 0000000..873dfec --- /dev/null +++ b/clientAppOne/app/src/main/java/com/bmy/clientappone/utils/Utils.java @@ -0,0 +1,117 @@ +package com.bmy.clientappone.utils; + + +import java.text.SimpleDateFormat; +import java.util.Locale; + +import com.amap.api.location.AMapLocation; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.text.TextUtils; + +/** + * 辅助工具类 + * @创建时间: 2015年11月24日 上午11:46:50 + * @项目名称: AMapLocationDemo2.x + * @author hongming.wang + * @文件名称: Utils.java + * @类型名称: Utils + */ +public class Utils { + /** + * 开始定位 + */ + public final static int MSG_LOCATION_START = 0; + /** + * 定位完成 + */ + public final static int MSG_LOCATION_FINISH = 1; + /** + * 停止定位 + */ + public final static int MSG_LOCATION_STOP= 2; + + public final static String KEY_URL = "URL"; + public final static String URL_H5LOCATION = "file:///android_asset/sdkLoc.html"; + /** + * 根据定位结果返回定位信息的字符串 + * @param location + * @return + */ + public synchronized static String getLocationStr(AMapLocation location){ + if(null == location){ + return null; + } + StringBuffer sb = new StringBuffer(); + //errCode等于0代表定位成功,其他的为定位失败,具体的可以参照官网定位错误码说明 + if(location.getErrorCode() == 0){ + sb.append("定位成功" + "\n"); + sb.append("定位类型: " + location.getLocationType() + "\n"); + sb.append("经 度 : " + location.getLongitude() + "\n"); + sb.append("纬 度 : " + location.getLatitude() + "\n"); + sb.append("精 度 : " + location.getAccuracy() + "米" + "\n"); + sb.append("提供者 : " + location.getProvider() + "\n"); + + sb.append("速 度 : " + location.getSpeed() + "米/秒" + "\n"); + sb.append("角 度 : " + location.getBearing() + "\n"); + // 获取当前提供定位服务的卫星个数 + sb.append("星 数 : " + location.getSatellites() + "\n"); + sb.append("国 家 : " + location.getCountry() + "\n"); + sb.append("省 : " + location.getProvince() + "\n"); + sb.append("市 : " + location.getCity() + "\n"); + sb.append("城市编码 : " + location.getCityCode() + "\n"); + sb.append("区 : " + location.getDistrict() + "\n"); + sb.append("区域 码 : " + location.getAdCode() + "\n"); + sb.append("地 址 : " + location.getAddress() + "\n"); + sb.append("兴趣点 : " + location.getPoiName() + "\n"); + //定位完成的时间 + sb.append("定位时间: " + formatUTC(location.getTime(), "yyyy-MM-dd HH:mm:ss") + "\n"); + } else { + //定位失败 + sb.append("定位失败" + "\n"); + sb.append("错误码:" + location.getErrorCode() + "\n"); + sb.append("错误信息:" + location.getErrorInfo() + "\n"); + sb.append("错误描述:" + location.getLocationDetail() + "\n"); + } + //定位之后的回调时间 + sb.append("回调时间: " + formatUTC(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss") + "\n"); + return sb.toString(); + } + + private static SimpleDateFormat sdf = null; + public static String formatUTC(long l, String strPattern) { + if (TextUtils.isEmpty(strPattern)) { + strPattern = "yyyy-MM-dd HH:mm:ss"; + } + if (sdf == null) { + try { + sdf = new SimpleDateFormat(strPattern, Locale.CHINA); + } catch (Throwable e) { + } + } else { + sdf.applyPattern(strPattern); + } + return sdf == null ? "NULL" : sdf.format(l); + } + + /** + * 获取app的名称 + * @param context + * @return + */ + public static String getAppName(Context context) { + String appName = ""; + try { + PackageManager packageManager = context.getPackageManager(); + PackageInfo packageInfo = packageManager.getPackageInfo( + context.getPackageName(), 0); + int labelRes = packageInfo.applicationInfo.labelRes; + appName = context.getResources().getString(labelRes); + } catch (Throwable e) { + e.printStackTrace(); + } + return appName; + } +} \ No newline at end of file diff --git a/clientAppOne/app/src/main/res/.pydio b/clientAppOne/app/src/main/res/.pydio new file mode 100644 index 0000000..f16a6e2 --- /dev/null +++ b/clientAppOne/app/src/main/res/.pydio @@ -0,0 +1 @@ +c2cba96c-ce24-4a2a-811b-43b7de4e9a31 \ No newline at end of file diff --git a/clientAppOne/app/src/main/res/drawable-v24/.pydio b/clientAppOne/app/src/main/res/drawable-v24/.pydio new file mode 100644 index 0000000..7f55113 --- /dev/null +++ b/clientAppOne/app/src/main/res/drawable-v24/.pydio @@ -0,0 +1 @@ +40d28bf6-8ade-4493-bfe1-471a9c2a4af1 \ No newline at end of file diff --git a/clientAppOne/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/clientAppOne/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/clientAppOne/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/clientAppOne/app/src/main/res/drawable/.pydio b/clientAppOne/app/src/main/res/drawable/.pydio new file mode 100644 index 0000000..c114ecd --- /dev/null +++ b/clientAppOne/app/src/main/res/drawable/.pydio @@ -0,0 +1 @@ +dd33a8df-11bd-48e6-b8c7-8a3f4d25675a \ No newline at end of file diff --git a/clientAppOne/app/src/main/res/drawable/ic_launcher.png b/clientAppOne/app/src/main/res/drawable/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6cd664e36a295c7711caef1b2ac62b5ccb1627 GIT binary patch literal 4123 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 Z{{e#-$&}K$1)~4}002ovPDHLkV1g_A=1Bkm literal 0 HcmV?d00001 diff --git a/clientAppOne/app/src/main/res/drawable/ic_launcher_background.xml b/clientAppOne/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/clientAppOne/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/clientAppOne/app/src/main/res/layout/.pydio b/clientAppOne/app/src/main/res/layout/.pydio new file mode 100644 index 0000000..66995b1 --- /dev/null +++ b/clientAppOne/app/src/main/res/layout/.pydio @@ -0,0 +1 @@ +a8ca0c64-8515-4c59-878b-01352049a492 \ No newline at end of file diff --git a/clientAppOne/app/src/main/res/layout/activity_main.xml b/clientAppOne/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..2600ea6 --- /dev/null +++ b/clientAppOne/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,33 @@ + + + + + + + + + diff --git a/socketEnd/index.js b/socketEnd/index.js new file mode 100644 index 0000000..228d074 --- /dev/null +++ b/socketEnd/index.js @@ -0,0 +1,6 @@ +const WebSocket = require("./utils/WebSocket"); + + +new WebSocket({ port: 8080 }); + + diff --git a/socketEnd/package.json b/socketEnd/package.json new file mode 100644 index 0000000..dfc1aff --- /dev/null +++ b/socketEnd/package.json @@ -0,0 +1,20 @@ +{ + "name": "socketEnd", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "dev": "node-dev index.js", + "start": "pm2 start ./index.js --name auto --watch -i max" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "ws": "^8.0.0" + }, + "optionalDependencies": { + "bufferutil": "^4.0.3", + "utf-8-validate": "^5.0.5" + } +} diff --git a/socketEnd/utils/.pydio b/socketEnd/utils/.pydio new file mode 100644 index 0000000..d74075f --- /dev/null +++ b/socketEnd/utils/.pydio @@ -0,0 +1 @@ +2c1850c2-c06e-472a-8537-aa75068498d9 \ No newline at end of file diff --git a/socketEnd/utils/WebSocket.js b/socketEnd/utils/WebSocket.js new file mode 100644 index 0000000..0955b5d --- /dev/null +++ b/socketEnd/utils/WebSocket.js @@ -0,0 +1,92 @@ +const Socket = require("ws"); +const utils = require("./utils"); + +class WebSocket { + constructor(options) { + this.SocketList = {}; + this.options = {}; + this.WS = null; + + this.options = options; + + this.createServer() + } + + + createServer() { + const WS = new Socket.Server(this.options); + WS.on('connection', (ws, req) => this.connection(ws, req)) + } + + async connection(ws, req) { + console.log('建立连接:', req.url); + const id = req.url.split('/')[1]; + if (!id) return ws.close(); + + this.SocketList[id] = ws; + ws.id = id; + this.filter(); + + ws.on('message', this.message.bind(this)); + ws.on('close', (msg) => this.close(msg, ws.id)); + } + + async message(msg) { + msg = msg.toString('utf-8'); + try { + const message = JSON.parse(msg); + switch (message.type) { + // 收到客户端1 android 的消息 + // 需要 拿到到GPS的经纬度 进行距离判断 + // 然后服务器 向客户端2 推送消息 + case 1: + + console.log("收到客户端1 android 的消息"); + this.sendMessage({ data: "start" }, "clent2") + break; + + // 收到客户端2的消息 + case 2: + // this.send("flutter客户端2测试") + console.log("收到客户端2的消息", message); + break; + + default: + break; + } + } catch (error) { + console.log(error); + console.log("消息格式必须为Object"); + } + } + + async filter() { + for(let key in this.SocketList) { + if (!this.SocketList[key].readyState === 1) delete this.SocketList[key] + } + } + + close(msg, id) { + console.log('关闭连接', id, msg); + } + + sendMessage(msg, id) { + // console.log("=================="); + if(id) { + // console.log("if ==== ", msg, id); + // console.log("this.SocketList ==== : ", this.SocketList); + if (this.SocketList[id].readyState === 1) { + this.SocketList[id].send(JSON.stringify(msg)); + } + } else { + // console.log("else"); + // console.log("this.SocketList: ", this.SocketList); + for (let ws of Object.values(this.SocketList)) { + if (ws.readyState === 1) ws.send(JSON.stringify(msg)); + } + } + } + +} + +module.exports = WebSocket; \ No newline at end of file diff --git a/socketEnd/utils/utils.js b/socketEnd/utils/utils.js new file mode 100644 index 0000000..e65406c --- /dev/null +++ b/socketEnd/utils/utils.js @@ -0,0 +1,34 @@ +class utils { + + /** + * 计算两经纬度点之间的距离(单位:米) + * @param {*} lat1 纬度1 + * @param {*} lng1 经度1 + * + * @param {*} lat2 纬度2 + * @param {*} lng2 经度2 + * @returns + */ + + caculateLL(lng1, lat1, lng2 = 117.325426, lat2 = 31.794477) { + var radLat1 = (lat1 * Math.PI) / 180.0; + var radLat2 = (lat2 * Math.PI) / 180.0; + var a = radLat1 - radLat2; + var b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0; + var s = + 2 * + Math.asin( + Math.sqrt( + Math.pow(Math.sin(a / 2), 2) + + Math.cos(radLat1) * + Math.cos(radLat2) * + Math.pow(Math.sin(b / 2), 2) + ) + ); + s = s * 6378.137; + s = Math.round(s * 10000) / 10; + return s; + } +} + +module.exports = new utils(); \ No newline at end of file diff --git a/思路.txt b/思路.txt new file mode 100644 index 0000000..a56d367 --- /dev/null +++ b/思路.txt @@ -0,0 +1,64 @@ +实现的功能: + + 当我离家还有500米的时候,提前打开家里的空调 和 客厅灯 等设备。 + +实现的思路: + +数据格式: + +1:客户端 Android App 上报GPS数据格式: + socketId: clent1 +{ + type: 1, // 表示客户端App1,2 表示客户端App2,3 表示服务器 + data: { + Longitude: "", + Latitude: "" + } +} + +2:服务器推送通知给 客户端 Flutter App的数据格式 + socketId: clent2 +{ + type: 3, + data: "start" +} + + +家的经纬度: + +117.326156 +31.792494 + +需要三个角色: + + 1:clientApp_1(GPS经纬度上报端 Android开发) + 就是我随身用的手机,需要用flutter开发一个app,安装在手机里,运行期间发现GPS位置改变,就通过 + 接口 提交最新的经纬度坐标给 服务器 + + 问题:App放入后台后,为了防止被手机系统杀掉,需要加入手机白名单,在后台每隔两秒不断请求最新GPS位置上报服务器 + 状态:已实现 + + 2:服务器(距离判断,消息转发 Node.js + Redis) + 接受 clientApp_1 给的最新坐标,判断离家(家是有固定GPS经纬度的),所以可以计算距离。 + 如果小于等于 500 米范围,发送WebSocket 通知给 clientApp_2 + + 问题:为家里的路由器,专门编译 Node.js 部署本后端。路由器需要开通公网IP或花生壳 + 替代方案:用客户服务器部署后端 + 状态:未开始 + + 3:clientApp_2(执行端 Flutter) + 固定在小爱音箱附近,常年通电后台运行的手机,主要用来接收 服务器的 通知 + 然后播放指定语音唤醒小爱,并播放 小爱 训练计划 中自定义的命令指令! + + 问题:如何系统级保活是个大问题? + 思路:需要加入手机厂商的系统白名单 + 状态:未开始 + + 自定义的命令指令: + + 命令:我快要到家了 + 动作: + 1:打开空调,设置温度 28度,风速最大 + 2:打开客厅灯 + 3:打开书房灯 +