From 78be752b6b85fb1adcf85e650e17c01accfc30cd Mon Sep 17 00:00:00 2001 From: kfl_614 Date: Sun, 22 Mar 2020 18:44:59 +0800 Subject: [PATCH] =?utf8?q?1.=E6=9C=8D=E5=8A=A1APP=EF=BC=8C=E4=B8=BB?= =?utf8?q?=E8=A6=81=E5=8C=85=E5=90=AB=E5=AF=B9=E5=A4=A9=E6=B0=94=E3=80=82?= =?utf8?q?=E8=AE=A1=E6=AD=A5=EF=BC=8C=E8=A1=80=E5=8E=8B=E7=9A=84=E5=A4=84?= =?utf8?q?=E7=90=86=E3=80=82=E6=AD=A4=E6=9C=8D=E5=8A=A1=E9=95=BF=E6=9C=9F?= =?utf8?q?=E5=AD=98=E5=9C=A8=E5=9C=A8=E5=90=8E=E5=8F=B0=E3=80=82=E7=94=B1L?= =?utf8?q?auncher=E5=90=AF=E5=8A=A8=E6=88=96=E8=80=85=E5=BC=80=E6=9C=BA?= =?utf8?q?=E5=90=AF=E5=8A=A8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .gitignore | 14 ++ .idea/codeStyles/Project.xml | 116 +++++++++++ .idea/gradle.xml | 16 ++ .idea/misc.xml | 9 + .idea/runConfigurations.xml | 12 ++ .idea/vcs.xml | 7 + app/.gitignore | 1 + app/EQC_G5.jks | Bin 0 -> 4688 bytes app/build.gradle | 82 ++++++++ app/proguard-rules.pro | 21 ++ .../com/ic/work/ExampleInstrumentedTest.java | 27 +++ app/src/main/AndroidManifest.xml | 65 ++++++ .../aidl/com/ic/aidl/blood/BloodState.java | 16 ++ .../ic/aidl/blood/IBloodAidlInterface.aidl | 14 ++ .../ic/aidl/blood/IBloodRemoteService.aidl | 18 ++ .../com/ic/aidl/ped/IPedAidlInterface.aidl | 15 ++ .../com/ic/aidl/ped/IPedRemoteService.aidl | 20 ++ .../com/ic/aidl/ped/RecordParcelable.aidl | 3 + .../com/ic/aidl/ped/RecordParcelable.java | 88 +++++++++ .../aidl/weather/IWeatherAidlInterface.aidl | 14 ++ .../aidl/weather/IWeatherRemoteService.aidl | 17 ++ .../ic/aidl/weather/WeatherParcelable.aidl | 3 + .../ic/aidl/weather/WeatherParcelable.java | 144 ++++++++++++++ app/src/main/java/com/ic/jni/ICJniUtils.java | 60 ++++++ .../main/java/com/ic/work/MainActivity.java | 40 ++++ .../java/com/ic/work/ThreadPoolManager.java | 46 +++++ .../main/java/com/ic/work/WorkService.java | 187 ++++++++++++++++++ .../main/java/com/ic/work/WorkServiceApp.java | 32 +++ .../main/java/com/ic/work/db/AppDatabase.java | 40 ++++ .../java/com/ic/work/db/PedInjection.java | 69 +++++++ .../com/ic/work/db/TiviTypeConverters.java | 29 +++ .../java/com/ic/work/db/WeatherInjection.java | 47 +++++ .../main/java/com/ic/work/db/dao/PedDao.java | 39 ++++ .../java/com/ic/work/db/dao/WeatherDao.java | 25 +++ .../java/com/ic/work/db/entity/PedEntity.java | 59 ++++++ .../com/ic/work/db/entity/WeatherEntity.java | 94 +++++++++ .../ic/work/event/BloodCheckResultEvent.java | 27 +++ .../ic/work/event/BloodCheckTipsEvent.java | 27 +++ .../ic/work/event/LocationResultEvent.java | 14 ++ .../java/com/ic/work/event/PedCountEvent.java | 13 ++ .../ic/work/event/PedRecordResultEvent.java | 17 ++ .../com/ic/work/event/PedSettingEvent.java | 19 ++ .../com/ic/work/event/WeatherAgainEvent.java | 4 + .../com/ic/work/event/WeatherResultEvent.java | 15 ++ .../com/ic/work/hardware/BloodRunnable.java | 82 ++++++++ .../ic/work/hardware/PedRecordRunnable.java | 40 ++++ .../com/ic/work/hardware/PedRunnable.java | 123 ++++++++++++ .../com/ic/work/process/BloodProcess.java | 98 +++++++++ .../java/com/ic/work/process/PedProcess.java | 126 ++++++++++++ .../com/ic/work/process/WeatherProcess.java | 73 +++++++ .../java/com/ic/work/utils/AppExecutors.java | 50 +++++ .../java/com/ic/work/utils/HardwareUtils.java | 87 ++++++++ .../main/java/com/ic/work/utils/IcLog.java | 59 ++++++ .../main/java/com/ic/work/utils/PedUtil.java | 53 +++++ .../main/java/com/ic/work/utils/SPUtils.java | 38 ++++ .../java/com/ic/work/utils/ServiceUtil.java | 42 ++++ .../com/ic/work/weather/LocationHelper.java | 85 ++++++++ .../com/ic/work/weather/WeatherDBRun.java | 52 +++++ .../com/ic/work/weather/WeatherHelper.java | 47 +++++ .../ic/work/weather/melon/SocketThread.java | 173 ++++++++++++++++ .../ic/work/weather/melon/SocketUtils.java | 49 +++++ .../main/jniLibs/arm64-v8a/libICJniUtils.so | Bin 0 -> 14240 bytes .../main/jniLibs/armeabi-v7a/libICJniUtils.so | Bin 0 -> 22188 bytes app/src/main/jniLibs/x86/libICJniUtils.so | Bin 0 -> 13884 bytes app/src/main/jniLibs/x86_64/libICJniUtils.so | Bin 0 -> 14512 bytes .../drawable-v24/ic_launcher_foreground.xml | 34 ++++ .../res/drawable/ic_launcher_background.xml | 170 ++++++++++++++++ app/src/main/res/layout/activity_main.xml | 19 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/styles.xml | 11 ++ .../java/com/ic/work/ExampleUnitTest.java | 17 ++ build.gradle | 27 +++ gradle.properties | 20 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 172 ++++++++++++++++ gradlew.bat | 84 ++++++++ settings.gradle | 2 + 91 files changed, 3483 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml create mode 100644 app/.gitignore create mode 100644 app/EQC_G5.jks create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/ic/work/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/aidl/com/ic/aidl/blood/BloodState.java create mode 100644 app/src/main/aidl/com/ic/aidl/blood/IBloodAidlInterface.aidl create mode 100644 app/src/main/aidl/com/ic/aidl/blood/IBloodRemoteService.aidl create mode 100644 app/src/main/aidl/com/ic/aidl/ped/IPedAidlInterface.aidl create mode 100644 app/src/main/aidl/com/ic/aidl/ped/IPedRemoteService.aidl create mode 100644 app/src/main/aidl/com/ic/aidl/ped/RecordParcelable.aidl create mode 100644 app/src/main/aidl/com/ic/aidl/ped/RecordParcelable.java create mode 100644 app/src/main/aidl/com/ic/aidl/weather/IWeatherAidlInterface.aidl create mode 100644 app/src/main/aidl/com/ic/aidl/weather/IWeatherRemoteService.aidl create mode 100644 app/src/main/aidl/com/ic/aidl/weather/WeatherParcelable.aidl create mode 100644 app/src/main/aidl/com/ic/aidl/weather/WeatherParcelable.java create mode 100644 app/src/main/java/com/ic/jni/ICJniUtils.java create mode 100644 app/src/main/java/com/ic/work/MainActivity.java create mode 100644 app/src/main/java/com/ic/work/ThreadPoolManager.java create mode 100644 app/src/main/java/com/ic/work/WorkService.java create mode 100644 app/src/main/java/com/ic/work/WorkServiceApp.java create mode 100644 app/src/main/java/com/ic/work/db/AppDatabase.java create mode 100644 app/src/main/java/com/ic/work/db/PedInjection.java create mode 100644 app/src/main/java/com/ic/work/db/TiviTypeConverters.java create mode 100644 app/src/main/java/com/ic/work/db/WeatherInjection.java create mode 100644 app/src/main/java/com/ic/work/db/dao/PedDao.java create mode 100644 app/src/main/java/com/ic/work/db/dao/WeatherDao.java create mode 100644 app/src/main/java/com/ic/work/db/entity/PedEntity.java create mode 100644 app/src/main/java/com/ic/work/db/entity/WeatherEntity.java create mode 100644 app/src/main/java/com/ic/work/event/BloodCheckResultEvent.java create mode 100644 app/src/main/java/com/ic/work/event/BloodCheckTipsEvent.java create mode 100644 app/src/main/java/com/ic/work/event/LocationResultEvent.java create mode 100644 app/src/main/java/com/ic/work/event/PedCountEvent.java create mode 100644 app/src/main/java/com/ic/work/event/PedRecordResultEvent.java create mode 100644 app/src/main/java/com/ic/work/event/PedSettingEvent.java create mode 100644 app/src/main/java/com/ic/work/event/WeatherAgainEvent.java create mode 100644 app/src/main/java/com/ic/work/event/WeatherResultEvent.java create mode 100644 app/src/main/java/com/ic/work/hardware/BloodRunnable.java create mode 100644 app/src/main/java/com/ic/work/hardware/PedRecordRunnable.java create mode 100644 app/src/main/java/com/ic/work/hardware/PedRunnable.java create mode 100644 app/src/main/java/com/ic/work/process/BloodProcess.java create mode 100644 app/src/main/java/com/ic/work/process/PedProcess.java create mode 100644 app/src/main/java/com/ic/work/process/WeatherProcess.java create mode 100644 app/src/main/java/com/ic/work/utils/AppExecutors.java create mode 100644 app/src/main/java/com/ic/work/utils/HardwareUtils.java create mode 100644 app/src/main/java/com/ic/work/utils/IcLog.java create mode 100644 app/src/main/java/com/ic/work/utils/PedUtil.java create mode 100644 app/src/main/java/com/ic/work/utils/SPUtils.java create mode 100644 app/src/main/java/com/ic/work/utils/ServiceUtil.java create mode 100644 app/src/main/java/com/ic/work/weather/LocationHelper.java create mode 100644 app/src/main/java/com/ic/work/weather/WeatherDBRun.java create mode 100644 app/src/main/java/com/ic/work/weather/WeatherHelper.java create mode 100644 app/src/main/java/com/ic/work/weather/melon/SocketThread.java create mode 100644 app/src/main/java/com/ic/work/weather/melon/SocketUtils.java create mode 100644 app/src/main/jniLibs/arm64-v8a/libICJniUtils.so create mode 100644 app/src/main/jniLibs/armeabi-v7a/libICJniUtils.so create mode 100644 app/src/main/jniLibs/x86/libICJniUtils.so create mode 100644 app/src/main/jniLibs/x86_64/libICJniUtils.so create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/com/ic/work/ExampleUnitTest.java create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..603b140 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.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 diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..681f41a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,116 @@ + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..d291b3d --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..7bfef59 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..1711e9b --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/EQC_G5.jks b/app/EQC_G5.jks new file mode 100644 index 0000000000000000000000000000000000000000..2229d46ba5935ac0f52c19d953a9cdcb2069dcae GIT binary patch literal 4688 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 documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.ic.work", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c017541 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/aidl/com/ic/aidl/blood/BloodState.java b/app/src/main/aidl/com/ic/aidl/blood/BloodState.java new file mode 100644 index 0000000..82ed7f7 --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/blood/BloodState.java @@ -0,0 +1,16 @@ +package com.ic.aidl.blood; + +public class BloodState { + + public static final int BLOOD_NULL_TIPS = -1; + public static final int BLOOD_NOT_DEVICE = 1001; + + public static final int BLOOD_PLEASE_QUIET = 1002; + public static final int BLOOD_START_CHECK= 1003; + + public static final int BLOOD_NOT_WEAR=1004; + public static final int BLOOD_ING_CHECK=1005; + + public static final int BLOOD_STOP_CHECK=1006; + public static final int BLOOD_NOT_DATA_CHECK=1007; +} diff --git a/app/src/main/aidl/com/ic/aidl/blood/IBloodAidlInterface.aidl b/app/src/main/aidl/com/ic/aidl/blood/IBloodAidlInterface.aidl new file mode 100644 index 0000000..092c192 --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/blood/IBloodAidlInterface.aidl @@ -0,0 +1,14 @@ +// IWeatherAidlInterface.aidl +package com.ic.aidl.blood; + +// Declare any non-default types here with import statements + +interface IBloodAidlInterface { + /** + * Demonstrates some basic types that you can use as parameters + * and return values in AIDL. + */ + + void updateBloodCheckResult(int high,int low,int heart); + void updateBloodCheckTips(int top,int bottom); +} diff --git a/app/src/main/aidl/com/ic/aidl/blood/IBloodRemoteService.aidl b/app/src/main/aidl/com/ic/aidl/blood/IBloodRemoteService.aidl new file mode 100644 index 0000000..00546c2 --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/blood/IBloodRemoteService.aidl @@ -0,0 +1,18 @@ +// IWeatherRemoteService.aidl +package com.ic.aidl.blood; + +// Declare any non-default types here with import statements + +import com.ic.aidl.blood.IBloodAidlInterface; + +interface IBloodRemoteService { + /** + * Demonstrates some basic types that you can use as parameters + * and return values in AIDL. + */ + void registerCallback(IBloodAidlInterface cb); + void unregisterCallback(IBloodAidlInterface cb); + + void startCheckBlood(); + void stopCheckBlood(); +} diff --git a/app/src/main/aidl/com/ic/aidl/ped/IPedAidlInterface.aidl b/app/src/main/aidl/com/ic/aidl/ped/IPedAidlInterface.aidl new file mode 100644 index 0000000..b9615f6 --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/ped/IPedAidlInterface.aidl @@ -0,0 +1,15 @@ +// IWeatherAidlInterface.aidl +package com.ic.aidl.ped; + +// Declare any non-default types here with import statements +import com.ic.aidl.ped.RecordParcelable; + +interface IPedAidlInterface { + /** + * Demonstrates some basic types that you can use as parameters + * and return values in AIDL. + */ + void updatePedCount(int count); + void updatePedRecord(in List record); + +} diff --git a/app/src/main/aidl/com/ic/aidl/ped/IPedRemoteService.aidl b/app/src/main/aidl/com/ic/aidl/ped/IPedRemoteService.aidl new file mode 100644 index 0000000..60b57a3 --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/ped/IPedRemoteService.aidl @@ -0,0 +1,20 @@ +// IWeatherRemoteService.aidl +package com.ic.aidl.ped; + +// Declare any non-default types here with import statements + +import com.ic.aidl.ped.IPedAidlInterface; + +interface IPedRemoteService { + /** + * Demonstrates some basic types that you can use as parameters + * and return values in AIDL. + */ + void registerCallback(IPedAidlInterface cb); + void unregisterCallback(IPedAidlInterface cb); + + void queryPedCount(); + void queryPedRecord(); + void syncPedHeightSetting(int height); + void syncPedWeightSetting(int weight); +} diff --git a/app/src/main/aidl/com/ic/aidl/ped/RecordParcelable.aidl b/app/src/main/aidl/com/ic/aidl/ped/RecordParcelable.aidl new file mode 100644 index 0000000..7f54af8 --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/ped/RecordParcelable.aidl @@ -0,0 +1,3 @@ +package com.ic.aidl.ped; + +parcelable RecordParcelable; \ No newline at end of file diff --git a/app/src/main/aidl/com/ic/aidl/ped/RecordParcelable.java b/app/src/main/aidl/com/ic/aidl/ped/RecordParcelable.java new file mode 100644 index 0000000..bcdef77 --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/ped/RecordParcelable.java @@ -0,0 +1,88 @@ +package com.ic.aidl.ped; + +import android.os.Parcel; +import android.os.Parcelable; + +public class RecordParcelable implements Parcelable { + private int number; + private String distance; + private String calorie; + private String date; + + public RecordParcelable() { + number = 0; + distance = null; + calorie = null; + date = ""; + } + + public RecordParcelable(int number, String distance, String calorie, String date) { + this.number = number; + this.distance = distance; + this.calorie = calorie; + this.date = date; + } + + public RecordParcelable(Parcel p) { + this.number = p.readInt(); + this.distance = p.readString(); + this.calorie = p.readString(); + this.date = p.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(number); + dest.writeString(distance); + dest.writeString(calorie); + dest.writeString(date); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public RecordParcelable createFromParcel(Parcel in) { + return new RecordParcelable(in); + } + + public RecordParcelable[] newArray(int size) { + return new RecordParcelable[size]; + } + }; + + public int getNumber() { + return number; + } + + public void setNumber(int number) { + this.number = number; + } + + public String getDistance() { + return distance; + } + + public void setDistance(String distance) { + this.distance = distance; + } + + public String getCalorie() { + return calorie; + } + + public void setCalorie(String calorie) { + this.calorie = calorie; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } +} diff --git a/app/src/main/aidl/com/ic/aidl/weather/IWeatherAidlInterface.aidl b/app/src/main/aidl/com/ic/aidl/weather/IWeatherAidlInterface.aidl new file mode 100644 index 0000000..219c69e --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/weather/IWeatherAidlInterface.aidl @@ -0,0 +1,14 @@ +// IWeatherAidlInterface.aidl +package com.ic.aidl.weather; + +// Declare any non-default types here with import statements +import com.ic.aidl.weather.WeatherParcelable; + +interface IWeatherAidlInterface { + /** + * Demonstrates some basic types that you can use as parameters + * and return values in AIDL. + */ + void updateCurrWeather(in WeatherParcelable weather); + +} diff --git a/app/src/main/aidl/com/ic/aidl/weather/IWeatherRemoteService.aidl b/app/src/main/aidl/com/ic/aidl/weather/IWeatherRemoteService.aidl new file mode 100644 index 0000000..2f33b2b --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/weather/IWeatherRemoteService.aidl @@ -0,0 +1,17 @@ +// IWeatherRemoteService.aidl +package com.ic.aidl.weather; + +// Declare any non-default types here with import statements + +import com.ic.aidl.weather.IWeatherAidlInterface; + +interface IWeatherRemoteService { + /** + * Demonstrates some basic types that you can use as parameters + * and return values in AIDL. + */ + void registerCallback(IWeatherAidlInterface cb); + void unregisterCallback(IWeatherAidlInterface cb); + + void queryWeatherInfo(); +} diff --git a/app/src/main/aidl/com/ic/aidl/weather/WeatherParcelable.aidl b/app/src/main/aidl/com/ic/aidl/weather/WeatherParcelable.aidl new file mode 100644 index 0000000..59b6fd3 --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/weather/WeatherParcelable.aidl @@ -0,0 +1,3 @@ +package com.ic.aidl.weather; + +parcelable WeatherParcelable; \ No newline at end of file diff --git a/app/src/main/aidl/com/ic/aidl/weather/WeatherParcelable.java b/app/src/main/aidl/com/ic/aidl/weather/WeatherParcelable.java new file mode 100644 index 0000000..e7c9bbb --- /dev/null +++ b/app/src/main/aidl/com/ic/aidl/weather/WeatherParcelable.java @@ -0,0 +1,144 @@ +package com.ic.aidl.weather; + +import android.os.Parcel; +import android.os.Parcelable; + +public class WeatherParcelable implements Parcelable { + private String city; + private String statusDay; // 白天状态,如:晴 + private String statusNight; // 晚上状态 + private String figureDay; // 状态索引 + private String figureNight; + private String temperatureDay; // 白天温度 或 最低温度 + private String temperatureNight; // 晚上温度 或 最低温度 + private String updateTime; // 更新时间 + + public WeatherParcelable() { + city = ""; + statusDay = ""; + statusNight = ""; + figureDay = ""; + figureNight = ""; + temperatureDay = ""; + temperatureNight = ""; + updateTime = ""; + } + + public WeatherParcelable(String city, + String statusDay, String statusNight, + String figureDay, String figureNight, + String temperatureDay, String temperatureNight, + String updateTime) { + this.city = city; + this.statusDay = statusDay; + this.statusNight = statusNight; + this.figureDay = figureDay; + this.figureNight =figureNight; + this.temperatureDay = temperatureDay; + this.temperatureNight = temperatureNight; + this.updateTime =updateTime; + } + + public WeatherParcelable(Parcel p) { + this.city = p.readString(); + this.statusDay = p.readString(); + this.statusNight = p.readString(); + this.figureDay = p.readString(); + this.figureNight = p.readString(); + this.temperatureDay = p.readString(); + this.temperatureNight = p.readString(); + this.updateTime = p.readString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(city); + dest.writeString(statusDay); + dest.writeString(statusNight); + dest.writeString(figureDay); + dest.writeString(figureNight); + dest.writeString(temperatureDay); + dest.writeString(temperatureNight); + dest.writeString(updateTime); + } + + public static final Creator CREATOR + = new Creator() { + public WeatherParcelable createFromParcel(Parcel in) { + return new WeatherParcelable(in); + } + + public WeatherParcelable[] newArray(int size) { + return new WeatherParcelable[size]; + } + }; + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getStatusDay() { + return statusDay; + } + + public void setStatusDay(String statusDay) { + this.statusDay = statusDay; + } + + public String getStatusNight() { + return statusNight; + } + + public void setStatusNight(String statusNight) { + this.statusNight = statusNight; + } + + public String getFigureDay() { + return figureDay; + } + + public void setFigureDay(String figureDay) { + this.figureDay = figureDay; + } + + public String getFigureNight() { + return figureNight; + } + + public void setFigureNight(String figureNight) { + this.figureNight = figureNight; + } + + public String getTemperatureDay() { + return temperatureDay; + } + + public void setTemperatureDay(String temperatureDay) { + this.temperatureDay = temperatureDay; + } + + public String getTemperatureNight() { + return temperatureNight; + } + + public void setTemperatureNight(String temperatureNight) { + this.temperatureNight = temperatureNight; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } +} diff --git a/app/src/main/java/com/ic/jni/ICJniUtils.java b/app/src/main/java/com/ic/jni/ICJniUtils.java new file mode 100644 index 0000000..cb2aac2 --- /dev/null +++ b/app/src/main/java/com/ic/jni/ICJniUtils.java @@ -0,0 +1,60 @@ +package com.ic.jni; + + +public class ICJniUtils { + + public ICJniUtils(){ + + } + + static { + System.loadLibrary("ICJniUtils"); + } + + /***************计步控制************************************/ + /*运行此函数清除 系统计步为0*/ + public static native int resetStepCount(); + + /*获取当前步数*/ + public static native int getStepCount(); + /*开启计步 不必判断返回值*/ + public static native int enablePedometer(); + /*停止计步 不必判断返回值*/ + public static native int disablePedometer(); + + /*检测计步当前是否开启 1开启,0 关闭*/ + public static native int isPedometerEnabled(); + + /*保存当前步数(getStepCount取得的值)到磁盘 不必判断返回值*/ + public static native int saveStepCount(); + + /*恢复保存时的步数数据,下次getStepCount会在恢复的值上增加 不必判断返回值*/ + public static native int recoverStepCount(); + + + /******心率,血压****************************************/ + /*检查 PPG硬件是否存在,返回 1 存在,0 不存在*/ + public static native int isPPGavailable(); + + /*开启心率血压检测*/ + public static native int enablePPG(); + + /*停止心率血压检测*/ + public static native int disablePPG(); + /*返回 心率值 每分钟跳动次数, 通过这个心率>0 判断是否已经有检测结果, + 有就可以直接通过getHighBloodPressure 和 getLowBloodPressure 获取血压高压低压值*/ + public static native int getPPG(); + /* 返回PPG 运行状态, 0 停止, 1,运行中*/ + public static native int isPPGStarted(); + /*返回是否佩戴 0 未佩戴,1 佩戴*/ + public static native int isWeared(); + + /*获取血压高压值*/ + public static native int getHighBloodPressure(); + + /*获取血压低压值*/ + public static native int getLowBloodPressure(); + + /*获取血氧值*/ + public static native int getSPO2(); +} diff --git a/app/src/main/java/com/ic/work/MainActivity.java b/app/src/main/java/com/ic/work/MainActivity.java new file mode 100644 index 0000000..691fc01 --- /dev/null +++ b/app/src/main/java/com/ic/work/MainActivity.java @@ -0,0 +1,40 @@ +package com.ic.work; + +import androidx.appcompat.app.AppCompatActivity; + +import android.os.Bundle; +import android.widget.Button; + +import com.ic.work.utils.IcLog; +import com.ic.work.utils.PedUtil; +import com.ic.work.utils.ServiceUtil; + +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.format.DateTimeFormatter; + +import java.math.BigDecimal; + +public class MainActivity extends AppCompatActivity { + private static final String TAG="MainActivity"; + + private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Button mBt = (Button) findViewById(R.id.start_service_bt); + mBt.setOnClickListener(view -> { + ServiceUtil.startServiceUtil(getApplicationContext(), + "com.ic.action.WORK_SERVICE", + getPackageName()); + }); + + OffsetDateTime today = OffsetDateTime.now(); + IcLog.i(TAG,today.format(formatter)); + + BigDecimal bg = new BigDecimal(PedUtil.calcDistanceBySteps(170, 1000)); + IcLog.i(TAG,""+bg.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue()); + } +} diff --git a/app/src/main/java/com/ic/work/ThreadPoolManager.java b/app/src/main/java/com/ic/work/ThreadPoolManager.java new file mode 100644 index 0000000..8a5486e --- /dev/null +++ b/app/src/main/java/com/ic/work/ThreadPoolManager.java @@ -0,0 +1,46 @@ +package com.ic.work; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +public class ThreadPoolManager { + private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); + + private static ThreadPoolManager mInstance; + + private ThreadPoolExecutor mTheadPool; + + public static final synchronized ThreadPoolManager getInstance() { + if (mInstance == null) { + mInstance = new ThreadPoolManager(); + } + return mInstance; + } + + private ThreadPoolManager() { + mTheadPool = new ThreadPoolExecutor( + 0, + CPU_COUNT * 2 + 1, + 120L, TimeUnit.SECONDS, + new SynchronousQueue()); + } + + public void execute(Runnable runnable) { + if (runnable == null) + return; + + mTheadPool.execute(runnable); + } + + /** + * 从线程池中移除任务 + */ + public void remove(Runnable runnable) { + if (runnable == null) + return; + + mTheadPool.remove(runnable); + } +} diff --git a/app/src/main/java/com/ic/work/WorkService.java b/app/src/main/java/com/ic/work/WorkService.java new file mode 100644 index 0000000..1a1fdb4 --- /dev/null +++ b/app/src/main/java/com/ic/work/WorkService.java @@ -0,0 +1,187 @@ +package com.ic.work; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +import com.ic.work.event.BloodCheckResultEvent; +import com.ic.work.event.BloodCheckTipsEvent; +import com.ic.work.event.LocationResultEvent; +import com.ic.work.event.PedCountEvent; +import com.ic.work.event.PedRecordResultEvent; +import com.ic.work.event.PedSettingEvent; +import com.ic.work.event.WeatherAgainEvent; +import com.ic.work.event.WeatherResultEvent; +import com.ic.work.process.BloodProcess; +import com.ic.work.process.PedProcess; +import com.ic.work.process.WeatherProcess; +import com.ic.work.utils.IcLog; +import com.ic.work.utils.SPUtils; +import com.ic.work.weather.WeatherHelper; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +public class WorkService extends Service { + + private static final String TAG = "WorkService"; + + private WeatherProcess weatherProcess; + private BloodProcess bloodProcess; + private PedProcess pedProcess; + + private WeatherHelper mWeatherHelper; + + private WorkServiceApp mApp; + + @Override + public IBinder onBind(Intent intent) { + if (intent != null) { + int reqType = intent.getIntExtra("REQ_TYPE", -1); + IcLog.i(TAG,"Bind reqType"+reqType); + switch (reqType) { + case 101: + //天气 + return weatherProcess.getWeatherBinder(); + case 102: + //血压 + return bloodProcess.getBloodBinder(); + case 103: + //计步 + return pedProcess.getPedBinder(); + default: + return null; + } + } + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + mApp = (WorkServiceApp) getApplication(); + + weatherProcess = new WeatherProcess(mApp); + bloodProcess = new BloodProcess(); + + pedProcess = new PedProcess( + (WorkServiceApp) getApplication(), + SPUtils.getPedHeightSP(getApplicationContext()), + SPUtils.getPedWighttSP(getApplicationContext())); + + mWeatherHelper = new WeatherHelper(); + + EventBus.getDefault().register(this); + + mWeatherHelper.startLocation(getApplicationContext()); + + IcLog.i(TAG, "work service is start"); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + IcLog.i(TAG,"WorkService onStartCommand"); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + super.onDestroy(); + IcLog.i(TAG,"WorkService onDestroy"); + bloodProcess = null; + + mApp = null; + EventBus.getDefault().unregister(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(LocationResultEvent event) { + mWeatherHelper.queryWeatherServerInfo(mApp.getWeatherRepository(),event.getmCity()); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(BloodCheckTipsEvent event) { + if (bloodProcess != null) { + bloodProcess.sendBloodCheckTips(event.getTopTips(), + event.getBottomTips()); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(BloodCheckResultEvent event) { + if (bloodProcess != null) { + bloodProcess.sendBloodCheckResult(event.getHigh(), + event.getLow(), event.getHeart()); + } + + //发送一次广播给 心率 launcher + sendHeartBroadcast(event.getHeart()); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(PedSettingEvent event) { + + if(pedProcess != null){ + return; + } + + switch (event.getType()){ + case 1: + int height = event.getValue(); + SPUtils.setPedHeightSP(getApplicationContext(),height); + pedProcess.updateHeight(height); + break; + case 2: + int weight = event.getValue(); + SPUtils.setPedWighttSP(getApplicationContext(),weight); + pedProcess.updateWeight(weight); + break; + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(PedRecordResultEvent event) { + if(pedProcess != null){ + pedProcess.sendPedRecord(event.getRecordList()); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(PedCountEvent event) { + if(pedProcess != null){ + pedProcess.sendPedCount(event.getPedCount()); + } + + //发送一次广播给launcher + sendPedCountBroadcast(event.getPedCount()); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(WeatherResultEvent event) { + if(weatherProcess != null){ + weatherProcess.sendCurrWeather(event.getParcelable()); + } + } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(WeatherAgainEvent event) { + if(mWeatherHelper != null){ + mWeatherHelper.startLocation(getApplicationContext()); + } + } + + private void sendPedCountBroadcast(int count){ + Intent pedIntent = new Intent(); + pedIntent.setAction("com.ic.action.PED_COUNT"); + pedIntent.putExtra("PED_COUNT",count); + sendBroadcast(pedIntent); + } + + private void sendHeartBroadcast(int count){ + Intent pedIntent = new Intent(); + pedIntent.setAction("com.ic.action.BLOOD_HEART"); + pedIntent.putExtra("BLOOD_HEART",count); + sendBroadcast(pedIntent); + } + +} diff --git a/app/src/main/java/com/ic/work/WorkServiceApp.java b/app/src/main/java/com/ic/work/WorkServiceApp.java new file mode 100644 index 0000000..2c9af47 --- /dev/null +++ b/app/src/main/java/com/ic/work/WorkServiceApp.java @@ -0,0 +1,32 @@ +package com.ic.work; + +import android.app.Application; + +import com.ic.work.db.AppDatabase; +import com.ic.work.db.PedInjection; +import com.ic.work.db.WeatherInjection; +import com.ic.work.utils.IcLog; +import com.jakewharton.threetenabp.AndroidThreeTen; + +public class WorkServiceApp extends Application { + + @Override + public void onCreate() { + super.onCreate(); + IcLog.setLogHead("IcWorkService"); + + AndroidThreeTen.init(this); + } + + public AppDatabase getDatabase() { + return AppDatabase.getInstance(this); + } + + public PedInjection getRepository() { + return PedInjection.getInstance(getDatabase()); + } + + public WeatherInjection getWeatherRepository() { + return WeatherInjection.getInstance(getDatabase()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ic/work/db/AppDatabase.java b/app/src/main/java/com/ic/work/db/AppDatabase.java new file mode 100644 index 0000000..3ada192 --- /dev/null +++ b/app/src/main/java/com/ic/work/db/AppDatabase.java @@ -0,0 +1,40 @@ +package com.ic.work.db; + +import android.content.Context; + +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; +import androidx.room.TypeConverters; + +import com.ic.work.db.dao.PedDao; +import com.ic.work.db.dao.WeatherDao; +import com.ic.work.db.entity.PedEntity; +import com.ic.work.db.entity.WeatherEntity; + +@Database(entities = {PedEntity.class, WeatherEntity.class}, version = 2,exportSchema = false) +@TypeConverters(TiviTypeConverters.class) +public abstract class AppDatabase extends RoomDatabase { + + private static AppDatabase sInstance; + + public static final String DATABASE_NAME = "ic-work-db"; + + public abstract PedDao loadPedDao(); + public abstract WeatherDao loadWeatherDao(); + + public static AppDatabase getInstance(final Context context) { + if (sInstance == null) { + synchronized (AppDatabase.class) { + if (sInstance == null) { + sInstance = buildDatabase(context.getApplicationContext()); + } + } + } + return sInstance; + } + + private static AppDatabase buildDatabase(final Context appContext) { + return Room.databaseBuilder(appContext, AppDatabase.class, DATABASE_NAME).build(); + } +} diff --git a/app/src/main/java/com/ic/work/db/PedInjection.java b/app/src/main/java/com/ic/work/db/PedInjection.java new file mode 100644 index 0000000..a0254a3 --- /dev/null +++ b/app/src/main/java/com/ic/work/db/PedInjection.java @@ -0,0 +1,69 @@ +package com.ic.work.db; + +import android.content.Context; + +import com.ic.work.db.dao.PedDao; +import com.ic.work.db.entity.PedEntity; + +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; + +import java.util.Date; +import java.util.List; + +public class PedInjection { + + private static PedInjection sInstance; + + private final AppDatabase mDatabase; + + private PedInjection(final AppDatabase database) { + mDatabase = database; + } + + public static PedInjection getInstance(final AppDatabase database) { + if (sInstance == null) { + synchronized (PedInjection.class) { + if (sInstance == null) { + sInstance = new PedInjection(database); + } + } + } + return sInstance; + } + + private PedDao getPedDao() { + return mDatabase.loadPedDao(); + } + + public List queryDBPedDate(LocalDate date) { + return getPedDao().loadDatePedList(date); + } + + public void insertDBPedDate(PedEntity entity) { + getPedDao().insertPedEntity(entity); + } + + public void updateDBPedDate(PedEntity entity) { + getPedDao().updatePedEntity(entity.getId(), + entity.getPedNumber(), + entity.getPedDistance(), + entity.getPedDistance()); + } + + public int queryDBPedCount() { + return getPedDao().queryCountPed(); + } + + public List queryDBPedAllList() { + return getPedDao().loadAllDatePedList(); + } + + public List queryDBPedOldestList() { + return getPedDao().loadOldestDatePedList(); + } + + public void deletePedEntity(int id) { + getPedDao().deletePedEntity(id); + } +} diff --git a/app/src/main/java/com/ic/work/db/TiviTypeConverters.java b/app/src/main/java/com/ic/work/db/TiviTypeConverters.java new file mode 100644 index 0000000..63207d0 --- /dev/null +++ b/app/src/main/java/com/ic/work/db/TiviTypeConverters.java @@ -0,0 +1,29 @@ +package com.ic.work.db; + +import android.text.TextUtils; + +import androidx.room.TypeConverter; + +import org.threeten.bp.LocalDate; +import org.threeten.bp.format.DateTimeFormatter; + +public class TiviTypeConverters { + + private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; + + @TypeConverter + public static LocalDate toLocalDate(String value) { + if (TextUtils.isEmpty(value)) { + return null; + } + return formatter.parse(value,LocalDate.FROM); + } + + @TypeConverter + public static String fromLocalDate(LocalDate date) { + if (date == null) { + return null; + } + return date.format(formatter); + } +} diff --git a/app/src/main/java/com/ic/work/db/WeatherInjection.java b/app/src/main/java/com/ic/work/db/WeatherInjection.java new file mode 100644 index 0000000..a990d86 --- /dev/null +++ b/app/src/main/java/com/ic/work/db/WeatherInjection.java @@ -0,0 +1,47 @@ +package com.ic.work.db; + +import com.ic.work.db.dao.WeatherDao; +import com.ic.work.db.entity.WeatherEntity; + +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; + +import java.util.List; + +public class WeatherInjection { + + private static WeatherInjection sInstance; + + private final AppDatabase mDatabase; + + private WeatherInjection(final AppDatabase database) { + mDatabase = database; + } + + public static WeatherInjection getInstance(final AppDatabase database) { + if (sInstance == null) { + synchronized (PedInjection.class) { + if (sInstance == null) { + sInstance = new WeatherInjection(database); + } + } + } + return sInstance; + } + + private WeatherDao getWeatherDao() { + return mDatabase.loadWeatherDao(); + } + + public List queryDBWeatherDate(LocalDate date) { + return getWeatherDao().loadAllDateWeatherList(date); + } + + public void deleteDBWeatherDate() { + getWeatherDao().deleteWeatherList(); + } + + public void insertWeatherEntity(WeatherEntity entity){ + getWeatherDao().insertWeatherEntity(entity); + } +} diff --git a/app/src/main/java/com/ic/work/db/dao/PedDao.java b/app/src/main/java/com/ic/work/db/dao/PedDao.java new file mode 100644 index 0000000..7cb31cd --- /dev/null +++ b/app/src/main/java/com/ic/work/db/dao/PedDao.java @@ -0,0 +1,39 @@ +package com.ic.work.db.dao; + +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.Query; + +import com.ic.work.db.entity.PedEntity; + +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; + +import java.util.List; + +@Dao +public interface PedDao { + + //查询时间对应的记录,可能为空。 + @Query("SELECT * FROM icPedDb WHERE pedDate = :currDate ") + List loadDatePedList(LocalDate currDate); + + @Query("SELECT COUNT(id) FROM icPedDb") + int queryCountPed(); + + @Query("SELECT * FROM icPedDb ORDER BY datetime(pedDate) limit 1") + List loadOldestDatePedList(); + + @Query("SELECT * FROM icPedDb") + List loadAllDatePedList(); + + @Insert + void insertPedEntity(PedEntity entity); + + //更新记录 + @Query("UPDATE icPedDb SET pedNumber = :number , pedDistance = :distance , pedCalorie = :calorie WHERE id = :id") + void updatePedEntity(int id, int number, float distance, float calorie); + + @Query("DELETE FROM icPedDb WHERE id = :id") + void deletePedEntity(int id); +} diff --git a/app/src/main/java/com/ic/work/db/dao/WeatherDao.java b/app/src/main/java/com/ic/work/db/dao/WeatherDao.java new file mode 100644 index 0000000..7be1051 --- /dev/null +++ b/app/src/main/java/com/ic/work/db/dao/WeatherDao.java @@ -0,0 +1,25 @@ +package com.ic.work.db.dao; + +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.Query; + +import com.ic.work.db.entity.WeatherEntity; + +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; + +import java.util.List; + +@Dao +public interface WeatherDao { + + @Query("SELECT * FROM icWeatherDb WHERE updateTime= :currDate") + List loadAllDateWeatherList(LocalDate currDate); + + @Query("DELETE from icWeatherDb") + void deleteWeatherList(); + + @Insert + void insertWeatherEntity(WeatherEntity entity); +} diff --git a/app/src/main/java/com/ic/work/db/entity/PedEntity.java b/app/src/main/java/com/ic/work/db/entity/PedEntity.java new file mode 100644 index 0000000..9b65131 --- /dev/null +++ b/app/src/main/java/com/ic/work/db/entity/PedEntity.java @@ -0,0 +1,59 @@ +package com.ic.work.db.entity; + +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; + +@Entity(tableName = "icPedDb", + indices = {@Index("id")}) +public class PedEntity { + @PrimaryKey(autoGenerate = true) + private int id; + private int pedNumber; + private float pedDistance; + private float pedCalorie; + private LocalDate pedDate; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getPedNumber() { + return pedNumber; + } + + public void setPedNumber(int pedNumber) { + this.pedNumber = pedNumber; + } + + public float getPedDistance() { + return pedDistance; + } + + public void setPedDistance(float pedDistance) { + this.pedDistance = pedDistance; + } + + public float getPedCalorie() { + return pedCalorie; + } + + public void setPedCalorie(float pedCalorie) { + this.pedCalorie = pedCalorie; + } + + public LocalDate getPedDate() { + return pedDate; + } + + public void setPedDate(LocalDate pedDate) { + this.pedDate = pedDate; + } +} diff --git a/app/src/main/java/com/ic/work/db/entity/WeatherEntity.java b/app/src/main/java/com/ic/work/db/entity/WeatherEntity.java new file mode 100644 index 0000000..fbb1993 --- /dev/null +++ b/app/src/main/java/com/ic/work/db/entity/WeatherEntity.java @@ -0,0 +1,94 @@ +package com.ic.work.db.entity; + +import androidx.room.Entity; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +import org.threeten.bp.LocalDate; + +@Entity(tableName = "icWeatherDb", + indices = {@Index("id")}) +public class WeatherEntity { + @PrimaryKey(autoGenerate = true) + private int id; + private String city; + private String statusDay; // 白天状态,如:晴 + private String statusNight; // 晚上状态 + private String figureDay; // 状态索引 + private String figureNight; + private String temperatureDay; // 白天温度 或 最低温度 + private String temperatureNight; // 晚上温度 或 最低温度 + private LocalDate updateTime; // 更新时间 + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getStatusDay() { + return statusDay; + } + + public void setStatusDay(String statusDay) { + this.statusDay = statusDay; + } + + public String getStatusNight() { + return statusNight; + } + + public void setStatusNight(String statusNight) { + this.statusNight = statusNight; + } + + public String getFigureDay() { + return figureDay; + } + + public void setFigureDay(String figureDay) { + this.figureDay = figureDay; + } + + public String getFigureNight() { + return figureNight; + } + + public void setFigureNight(String figureNight) { + this.figureNight = figureNight; + } + + public String getTemperatureDay() { + return temperatureDay; + } + + public void setTemperatureDay(String temperatureDay) { + this.temperatureDay = temperatureDay; + } + + public String getTemperatureNight() { + return temperatureNight; + } + + public void setTemperatureNight(String temperatureNight) { + this.temperatureNight = temperatureNight; + } + + public LocalDate getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(LocalDate updateTime) { + this.updateTime = updateTime; + } +} diff --git a/app/src/main/java/com/ic/work/event/BloodCheckResultEvent.java b/app/src/main/java/com/ic/work/event/BloodCheckResultEvent.java new file mode 100644 index 0000000..e4cee9e --- /dev/null +++ b/app/src/main/java/com/ic/work/event/BloodCheckResultEvent.java @@ -0,0 +1,27 @@ +package com.ic.work.event; + +public class BloodCheckResultEvent { + private int high; + private int low; + private int heart; + + + public BloodCheckResultEvent(int high, int low, int heart) { + this.high = high; + this.low = low; + this.heart = heart; + } + + public int getHigh() { + return high; + } + + public int getLow() { + return low; + } + + public int getHeart() { + return heart; + } + +} diff --git a/app/src/main/java/com/ic/work/event/BloodCheckTipsEvent.java b/app/src/main/java/com/ic/work/event/BloodCheckTipsEvent.java new file mode 100644 index 0000000..850f103 --- /dev/null +++ b/app/src/main/java/com/ic/work/event/BloodCheckTipsEvent.java @@ -0,0 +1,27 @@ +package com.ic.work.event; + +public class BloodCheckTipsEvent { + private int topTips; + private int bottomTips; + + public BloodCheckTipsEvent(int topTips, int bottomTips) { + this.topTips = topTips; + this.bottomTips = bottomTips; + } + + public int getTopTips() { + return topTips; + } + + public void setTopTips(int topTips) { + this.topTips = topTips; + } + + public int getBottomTips() { + return bottomTips; + } + + public void setBottomTips(int bottomTips) { + this.bottomTips = bottomTips; + } +} diff --git a/app/src/main/java/com/ic/work/event/LocationResultEvent.java b/app/src/main/java/com/ic/work/event/LocationResultEvent.java new file mode 100644 index 0000000..9b61e33 --- /dev/null +++ b/app/src/main/java/com/ic/work/event/LocationResultEvent.java @@ -0,0 +1,14 @@ +package com.ic.work.event; + +public class LocationResultEvent { + + private String mCity; + + public LocationResultEvent(String city) { + this.mCity = city; + } + + public String getmCity() { + return mCity; + } +} diff --git a/app/src/main/java/com/ic/work/event/PedCountEvent.java b/app/src/main/java/com/ic/work/event/PedCountEvent.java new file mode 100644 index 0000000..bae08de --- /dev/null +++ b/app/src/main/java/com/ic/work/event/PedCountEvent.java @@ -0,0 +1,13 @@ +package com.ic.work.event; + +public class PedCountEvent { + private int pedCount; + + public PedCountEvent(int count) { + this.pedCount = count; + } + + public int getPedCount() { + return pedCount; + } +} diff --git a/app/src/main/java/com/ic/work/event/PedRecordResultEvent.java b/app/src/main/java/com/ic/work/event/PedRecordResultEvent.java new file mode 100644 index 0000000..14699d8 --- /dev/null +++ b/app/src/main/java/com/ic/work/event/PedRecordResultEvent.java @@ -0,0 +1,17 @@ +package com.ic.work.event; + +import com.ic.aidl.ped.RecordParcelable; + +import java.util.List; + +public class PedRecordResultEvent { + private List recordList; + + public List getRecordList() { + return recordList; + } + + public PedRecordResultEvent(List recordList) { + this.recordList = recordList; + } +} diff --git a/app/src/main/java/com/ic/work/event/PedSettingEvent.java b/app/src/main/java/com/ic/work/event/PedSettingEvent.java new file mode 100644 index 0000000..11b0891 --- /dev/null +++ b/app/src/main/java/com/ic/work/event/PedSettingEvent.java @@ -0,0 +1,19 @@ +package com.ic.work.event; + +public class PedSettingEvent { + private int type; + private int value; + + public PedSettingEvent(int type, int value) { + this.type = type; + this.value = value; + } + + public int getType() { + return type; + } + + public int getValue() { + return value; + } +} diff --git a/app/src/main/java/com/ic/work/event/WeatherAgainEvent.java b/app/src/main/java/com/ic/work/event/WeatherAgainEvent.java new file mode 100644 index 0000000..0fc0cb5 --- /dev/null +++ b/app/src/main/java/com/ic/work/event/WeatherAgainEvent.java @@ -0,0 +1,4 @@ +package com.ic.work.event; + +public class WeatherAgainEvent { +} diff --git a/app/src/main/java/com/ic/work/event/WeatherResultEvent.java b/app/src/main/java/com/ic/work/event/WeatherResultEvent.java new file mode 100644 index 0000000..b00277d --- /dev/null +++ b/app/src/main/java/com/ic/work/event/WeatherResultEvent.java @@ -0,0 +1,15 @@ +package com.ic.work.event; + +import com.ic.aidl.weather.WeatherParcelable; + +public class WeatherResultEvent { + private WeatherParcelable parcelable; + + public WeatherResultEvent(WeatherParcelable parcelable) { + this.parcelable = parcelable; + } + + public WeatherParcelable getParcelable() { + return parcelable; + } +} diff --git a/app/src/main/java/com/ic/work/hardware/BloodRunnable.java b/app/src/main/java/com/ic/work/hardware/BloodRunnable.java new file mode 100644 index 0000000..3486560 --- /dev/null +++ b/app/src/main/java/com/ic/work/hardware/BloodRunnable.java @@ -0,0 +1,82 @@ +package com.ic.work.hardware; + +import com.ic.work.event.BloodCheckResultEvent; +import com.ic.work.event.BloodCheckTipsEvent; +import com.ic.work.utils.HardwareUtils; +import com.ic.work.utils.IcLog; + +import org.greenrobot.eventbus.EventBus; + +import static com.ic.aidl.blood.BloodState.BLOOD_ING_CHECK; +import static com.ic.aidl.blood.BloodState.BLOOD_NOT_DATA_CHECK; +import static com.ic.aidl.blood.BloodState.BLOOD_NOT_DEVICE; +import static com.ic.aidl.blood.BloodState.BLOOD_NOT_WEAR; +import static com.ic.aidl.blood.BloodState.BLOOD_NULL_TIPS; +import static com.ic.aidl.blood.BloodState.BLOOD_PLEASE_QUIET; +import static com.ic.aidl.blood.BloodState.BLOOD_START_CHECK; +import static com.ic.aidl.blood.BloodState.BLOOD_STOP_CHECK; + +public class BloodRunnable implements Runnable{ + + private static final String TAG="BloodRunnable"; + + @Override + public void run() { + int ndkHeart = 0; + int ndkHigh = 0; + int ndkLow = 0; + int count = 0; + + if (HardwareUtils.isPPGavailable()) { + sendTipsEventBus(BLOOD_NULL_TIPS,BLOOD_NOT_DEVICE); + return; + } + + //开启 + HardwareUtils.onNdkEnablePPG(); + + sendTipsEventBus(BLOOD_PLEASE_QUIET,BLOOD_START_CHECK); + + try { + while (!Thread.currentThread().isInterrupted()) { + ndkHeart = HardwareUtils.getNdkPPGValue(); + if (HardwareUtils.isWeared()) { + //未佩戴 + sendTipsEventBus(BLOOD_NULL_TIPS,BLOOD_NOT_WEAR); + if (count > 15) break; + count++; + } else { + if (ndkHeart > 0) { + //佩戴好,并且已经或到心率的值,则获取低压和高压的值 + ndkHigh = HardwareUtils.getNdkHighBloodValue(); + ndkLow = HardwareUtils.getNdkLowBloodValue(); + //跳出循环,不在获取 + break; + } else { + //正在测量中,请稍等 + sendTipsEventBus(BLOOD_PLEASE_QUIET,BLOOD_ING_CHECK); + } + } + + Thread.sleep(1000); + } + + if (count > 15 || ndkHeart == 0) { + sendTipsEventBus(BLOOD_STOP_CHECK, BLOOD_NOT_DATA_CHECK); + } else { + EventBus.getDefault().post(new BloodCheckResultEvent(ndkHigh,ndkLow,ndkHeart)); + } + + HardwareUtils.onNdkDisablePPG(); + + } catch (InterruptedException e) { + IcLog.e(TAG, "Stop Get Heart Value"); + }finally { + HardwareUtils.onNdkDisablePPG(); + } + } + + private void sendTipsEventBus(int top,int bottom){ + EventBus.getDefault().post(new BloodCheckTipsEvent(top, bottom)); + } +} diff --git a/app/src/main/java/com/ic/work/hardware/PedRecordRunnable.java b/app/src/main/java/com/ic/work/hardware/PedRecordRunnable.java new file mode 100644 index 0000000..35eae9d --- /dev/null +++ b/app/src/main/java/com/ic/work/hardware/PedRecordRunnable.java @@ -0,0 +1,40 @@ +package com.ic.work.hardware; + +import com.ic.aidl.ped.RecordParcelable; +import com.ic.work.db.PedInjection; +import com.ic.work.db.entity.PedEntity; +import com.ic.work.event.PedRecordResultEvent; + +import org.greenrobot.eventbus.EventBus; +import org.threeten.bp.format.DateTimeFormatter; + +import java.util.ArrayList; +import java.util.List; + +public class PedRecordRunnable implements Runnable { + private PedInjection mPedDb; + + private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; + + public PedRecordRunnable(PedInjection pedDB) { + mPedDb = pedDB; + } + + @Override + public void run() { + List query = mPedDb.queryDBPedAllList(); + List recordList = new ArrayList<>(); + for (int i=0; i< query.size(); i++){ + RecordParcelable recordP = new RecordParcelable(); + recordP.setNumber(query.get(i).getPedNumber()); + recordP.setCalorie(String.valueOf(query.get(i).getPedCalorie())); + recordP.setDistance(String.valueOf(query.get(i).getPedDistance())); + recordP.setDate(query.get(i).getPedDate().format(formatter)); + + recordList.add(recordP); + } + + //发送数据到主线程 + EventBus.getDefault().post(new PedRecordResultEvent(recordList)); + } +} diff --git a/app/src/main/java/com/ic/work/hardware/PedRunnable.java b/app/src/main/java/com/ic/work/hardware/PedRunnable.java new file mode 100644 index 0000000..d127058 --- /dev/null +++ b/app/src/main/java/com/ic/work/hardware/PedRunnable.java @@ -0,0 +1,123 @@ +package com.ic.work.hardware; + +import com.ic.work.db.PedInjection; +import com.ic.work.db.entity.PedEntity; +import com.ic.work.event.PedCountEvent; +import com.ic.work.utils.HardwareUtils; +import com.ic.work.utils.IcLog; +import com.ic.work.utils.PedUtil; + +import org.greenrobot.eventbus.EventBus; +import org.threeten.bp.LocalDate; + +import java.math.BigDecimal; +import java.util.List; + +public class PedRunnable implements Runnable { + + private static final String TAG = "PedRunnable"; + + private PedInjection mPedDb; + + private int mHeight; + private int mWeight; + + public PedRunnable(PedInjection pedDB, int height, int weight) { + mPedDb = pedDB; + mHeight = height; + mWeight = weight; + } + + public void setHeight(int mHeight) { + this.mHeight = mHeight; + } + + public void setWeight(int mWeight) { + this.mWeight = mWeight; + } + + @Override + public void run() { + //1.先获取一次当前的计步数 + int currCount = HardwareUtils.getNdkStepCountValue(); + IcLog.i(TAG, "Ped Count" + currCount); + + int size = mPedDb.queryDBPedCount(); + if (size == 0) { + //如果数据库中无记录,把当前数据插入到数据库中 + insertDBPedEntity(currCount, LocalDate.now(),size); + } else { + //2.去查询数据中是否有当天的记录。 + List todayPed = mPedDb.queryDBPedDate(LocalDate.now()); + if (todayPed != null && todayPed.size() > 0) { + //3.如果数据中有当天的数据,并更新数据 + if (currCount > 0 && currCount > todayPed.get(0).getPedNumber()) { + todayPed.get(0).setPedNumber(currCount); + updateDBPedEntity(todayPed.get(0)); + } + } else { + //4.如果数据库中没有当天的数据,则把当前的数据更新前一天的数据中 + // 并且重置计步,并在数据库中新建一条数据 + //重置计步 + HardwareUtils.resetNdkStepCountValue(); + //获取前一天的数据 + List beforePed = mPedDb.queryDBPedDate(LocalDate.now().minusDays(1)); + if (beforePed != null && beforePed.size() > 0) { + beforePed.get(0).setPedNumber(currCount); + updateDBPedEntity(beforePed.get(0)); + + insertDBPedEntity(0, LocalDate.now(),size); + //发送给主线程。主线更新数据UI + EventBus.getDefault().post(new PedCountEvent(0)); + return; + } else { + //如果没有前一天没有数据。则直接 插入今天的数据 + insertDBPedEntity(currCount, LocalDate.now(),size); + } + } + } + + //发送给主线程。主线更新数据UI + EventBus.getDefault().post(new PedCountEvent(currCount)); + } + + private PedEntity createEntity(int number, LocalDate date) { + + PedEntity entity = new PedEntity(); + entity.setPedNumber(number); + entity.setPedDistance(getDistanceValue(number)); + entity.setPedCalorie(getCalorieValue(number)); + entity.setPedDate(date); + + return entity; + } + + private void insertDBPedEntity(int number, LocalDate date,int size) { + //判断 size 超过 + if(size >= 60){ + //删除一条最早的数据 + List entities = mPedDb.queryDBPedOldestList(); + if(entities != null && entities.size() == 1){ + mPedDb.deletePedEntity(entities.get(0).getId()); + } + } + mPedDb.insertDBPedDate(createEntity(number, date)); + } + + private void updateDBPedEntity(PedEntity entity) { + int number = entity.getPedNumber(); + entity.setPedDistance(getDistanceValue(number)); + entity.setPedCalorie(getCalorieValue(number)); + mPedDb.updateDBPedDate(entity); + } + + private float getCalorieValue(int number) { + BigDecimal bg = new BigDecimal(PedUtil.calcConsumeEnergy(mHeight, mWeight, number)); + return bg.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue(); + } + + private float getDistanceValue(int number) { + BigDecimal bg = new BigDecimal(PedUtil.calcDistanceBySteps(mHeight, number)); + return bg.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue(); + } +} diff --git a/app/src/main/java/com/ic/work/process/BloodProcess.java b/app/src/main/java/com/ic/work/process/BloodProcess.java new file mode 100644 index 0000000..af88312 --- /dev/null +++ b/app/src/main/java/com/ic/work/process/BloodProcess.java @@ -0,0 +1,98 @@ +package com.ic.work.process; + +import android.os.IBinder; +import android.os.RemoteCallbackList; +import android.os.RemoteException; + +import com.ic.aidl.blood.IBloodAidlInterface; +import com.ic.aidl.blood.IBloodRemoteService; +import com.ic.work.ThreadPoolManager; +import com.ic.work.hardware.BloodRunnable; +import com.ic.work.utils.IcLog; + + +public class BloodProcess { + private static final String TAG = "BloodProcess"; + + private RemoteCallbackList mCallbacks = new RemoteCallbackList<>(); + + private BloodRunnable mBloodRun; + + public BloodProcess() { + mBloodRun = new BloodRunnable(); + } + + public IBinder getBloodBinder() { + return bloodBinder; + } + + private IBloodRemoteService.Stub bloodBinder = new IBloodRemoteService.Stub() { + @Override + public void registerCallback(IBloodAidlInterface cb) throws RemoteException { + if (cb != null) { + mCallbacks.register(cb); + } + } + + @Override + public void unregisterCallback(IBloodAidlInterface cb) throws RemoteException { + if (cb != null) { + mCallbacks.unregister(cb); + } + } + + @Override + public void startCheckBlood() throws RemoteException { + ThreadPoolManager.getInstance().execute(mBloodRun); + } + + @Override + public void stopCheckBlood() throws RemoteException { + ThreadPoolManager.getInstance().remove(mBloodRun); + } + }; + + public void sendBloodCheckResult(int heih, int low, int heart) { + int N = 0; + try { + N = mCallbacks.beginBroadcast(); + for (int i = 0; i < N; i++) { + mCallbacks.getBroadcastItem(i).updateBloodCheckResult(heih, low, heart); + } + } catch (NullPointerException e) { + IcLog.e(TAG, e.getMessage()); + } catch (RemoteException er) { + IcLog.e(TAG, er.getMessage()); + } finally { + try { + if (N > 0) { + mCallbacks.finishBroadcast(); + } + } catch (IllegalArgumentException ll) { + IcLog.e(TAG, ll.getMessage()); + } + } + } + + public void sendBloodCheckTips(int top, int bottom) { + int N = 0; + try { + N = mCallbacks.beginBroadcast(); + for (int i = 0; i < N; i++) { + mCallbacks.getBroadcastItem(i).updateBloodCheckTips(top, bottom); + } + } catch (NullPointerException e) { + IcLog.e(TAG, e.getMessage()); + } catch (RemoteException er) { + IcLog.e(TAG, er.getMessage()); + } finally { + try { + if (N > 0) { + mCallbacks.finishBroadcast(); + } + } catch (IllegalArgumentException ll) { + IcLog.e(TAG, ll.getMessage()); + } + } + } +} diff --git a/app/src/main/java/com/ic/work/process/PedProcess.java b/app/src/main/java/com/ic/work/process/PedProcess.java new file mode 100644 index 0000000..6c3f817 --- /dev/null +++ b/app/src/main/java/com/ic/work/process/PedProcess.java @@ -0,0 +1,126 @@ +package com.ic.work.process; + +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteCallbackList; +import android.os.RemoteException; + +import com.ic.aidl.ped.IPedAidlInterface; +import com.ic.aidl.ped.IPedRemoteService; +import com.ic.aidl.ped.RecordParcelable; +import com.ic.work.ThreadPoolManager; +import com.ic.work.WorkServiceApp; +import com.ic.work.event.PedSettingEvent; +import com.ic.work.hardware.PedRecordRunnable; +import com.ic.work.hardware.PedRunnable; +import com.ic.work.utils.IcLog; + +import org.greenrobot.eventbus.EventBus; + +import java.util.List; + +public class PedProcess { + private static final String TAG = "PedProcess"; + + private RemoteCallbackList mCallbacks = new RemoteCallbackList<>(); + + private PedRunnable mPedRun; + private PedRecordRunnable mRecordRun; + + public PedProcess(WorkServiceApp app, int height, int weight) { + mPedRun = new PedRunnable(app.getRepository(), height, weight); + mRecordRun = new PedRecordRunnable(app.getRepository()); + } + + public IBinder getPedBinder() { + return pedBinder; + } + + private IPedRemoteService.Stub pedBinder = new IPedRemoteService.Stub() { + @Override + public void registerCallback(IPedAidlInterface cb) throws RemoteException { + if (cb != null) { + mCallbacks.register(cb); + } + } + + @Override + public void unregisterCallback(IPedAidlInterface cb) throws RemoteException { + if (cb != null) { + mCallbacks.unregister(cb); + } + } + + @Override + public void queryPedCount() throws RemoteException { + ThreadPoolManager.getInstance().execute(mPedRun); + } + + @Override + public void queryPedRecord() throws RemoteException { + ThreadPoolManager.getInstance().execute(mRecordRun); + } + + @Override + public void syncPedHeightSetting(int height) throws RemoteException { + EventBus.getDefault().post(new PedSettingEvent(1, height)); + } + + @Override + public void syncPedWeightSetting(int weight) throws RemoteException { + EventBus.getDefault().post(new PedSettingEvent(2, weight)); + } + }; + + public void updateHeight(int height){ + mPedRun.setHeight(height); + } + + public void updateWeight(int weight){ + mPedRun.setWeight(weight); + } + + public void sendPedCount(int count) { + int N = 0; + try { + N = mCallbacks.beginBroadcast(); + for (int i = 0; i < N; i++) { + mCallbacks.getBroadcastItem(i).updatePedCount(count); + } + } catch (NullPointerException e) { + IcLog.e(TAG, e.getMessage()); + } catch (RemoteException er) { + IcLog.e(TAG, er.getMessage()); + } finally { + try { + if (N > 0) { + mCallbacks.finishBroadcast(); + } + } catch (IllegalArgumentException ll) { + IcLog.e(TAG, ll.getMessage()); + } + } + } + + public void sendPedRecord(List record) { + int N = 0; + try { + N = mCallbacks.beginBroadcast(); + for (int i = 0; i < N; i++) { + mCallbacks.getBroadcastItem(i).updatePedRecord(record); + } + } catch (NullPointerException e) { + IcLog.e(TAG, e.getMessage()); + } catch (RemoteException er) { + IcLog.e(TAG, er.getMessage()); + } finally { + try { + if (N > 0) { + mCallbacks.finishBroadcast(); + } + } catch (IllegalArgumentException ll) { + IcLog.e(TAG, ll.getMessage()); + } + } + } +} diff --git a/app/src/main/java/com/ic/work/process/WeatherProcess.java b/app/src/main/java/com/ic/work/process/WeatherProcess.java new file mode 100644 index 0000000..77058ff --- /dev/null +++ b/app/src/main/java/com/ic/work/process/WeatherProcess.java @@ -0,0 +1,73 @@ +package com.ic.work.process; + +import android.os.IBinder; +import android.os.RemoteCallbackList; +import android.os.RemoteException; + +import com.ic.aidl.weather.IWeatherAidlInterface; +import com.ic.aidl.weather.IWeatherRemoteService; +import com.ic.aidl.weather.WeatherParcelable; +import com.ic.work.ThreadPoolManager; +import com.ic.work.WorkServiceApp; +import com.ic.work.utils.IcLog; +import com.ic.work.weather.WeatherDBRun; + +public class WeatherProcess { + + private static final String TAG = "WeatherProcess"; + + private RemoteCallbackList mCallbacks = new RemoteCallbackList<>(); + + private WeatherDBRun weatherRun; + + public WeatherProcess(WorkServiceApp app) { + weatherRun = new WeatherDBRun(app.getWeatherRepository()); + } + + public IBinder getWeatherBinder(){ + return weatherBinder; + } + + private IWeatherRemoteService.Stub weatherBinder = new IWeatherRemoteService.Stub() { + @Override + public void registerCallback(IWeatherAidlInterface cb) throws RemoteException { + if (cb != null) { + mCallbacks.register(cb); + } + } + + @Override + public void unregisterCallback(IWeatherAidlInterface cb) throws RemoteException { + if (cb != null) { + mCallbacks.unregister(cb); + } + } + + @Override + public void queryWeatherInfo() throws RemoteException { + ThreadPoolManager.getInstance().execute(weatherRun); + } + }; + + public void sendCurrWeather(WeatherParcelable parcelable) { + int N = 0; + try { + N = mCallbacks.beginBroadcast(); + for (int i = 0; i < N; i++) { + mCallbacks.getBroadcastItem(i).updateCurrWeather(parcelable); + } + } catch (NullPointerException e) { + IcLog.e(TAG, e.getMessage()); + } catch (RemoteException er) { + IcLog.e(TAG, er.getMessage()); + } finally { + try { + if (N > 0) { + mCallbacks.finishBroadcast(); + } + } catch (IllegalArgumentException ll) { + IcLog.e(TAG, ll.getMessage()); + } + } + } +} diff --git a/app/src/main/java/com/ic/work/utils/AppExecutors.java b/app/src/main/java/com/ic/work/utils/AppExecutors.java new file mode 100644 index 0000000..a1f57fc --- /dev/null +++ b/app/src/main/java/com/ic/work/utils/AppExecutors.java @@ -0,0 +1,50 @@ +package com.ic.work.utils; + +import android.os.Handler; +import android.os.Looper; + +import androidx.annotation.NonNull; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +public class AppExecutors { + + private final Executor mDiskIO; + + private final Executor mNetworkIO; + + private final Executor mMainThread; + + private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) { + this.mDiskIO = diskIO; + this.mNetworkIO = networkIO; + this.mMainThread = mainThread; + } + + public AppExecutors() { + this(Executors.newSingleThreadExecutor(), Executors.newFixedThreadPool(3), + new MainThreadExecutor()); + } + + public Executor diskIO() { + return mDiskIO; + } + + public Executor networkIO() { + return mNetworkIO; + } + + public Executor mainThread() { + return mMainThread; + } + + private static class MainThreadExecutor implements Executor { + private Handler mainThreadHandler = new Handler(Looper.getMainLooper()); + + @Override + public void execute(@NonNull Runnable command) { + mainThreadHandler.post(command); + } + } +} diff --git a/app/src/main/java/com/ic/work/utils/HardwareUtils.java b/app/src/main/java/com/ic/work/utils/HardwareUtils.java new file mode 100644 index 0000000..13e029a --- /dev/null +++ b/app/src/main/java/com/ic/work/utils/HardwareUtils.java @@ -0,0 +1,87 @@ +package com.ic.work.utils; + +import com.ic.jni.ICJniUtils; + +public class HardwareUtils { + + private static final String TAG = "HardwareUtils"; + + public static boolean isPPGavailable() { + try { + return ICJniUtils.isPPGavailable() == 0; + } catch (Exception e) { + IcLog.e(TAG, e.getMessage()); + return true; + } + } + + public static void onNdkEnablePPG() { + try { + ICJniUtils.enablePPG(); + } catch (Exception e) { + IcLog.e(TAG, e.getMessage()); + } + } + + public static void onNdkDisablePPG() { + try { + ICJniUtils.disablePPG(); + } catch (Exception e) { + IcLog.e(TAG, e.getMessage()); + } + } + + public static boolean isWeared() { + try { + return ICJniUtils.isWeared() == 0; + } catch (Exception e) { + IcLog.e(TAG, e.getMessage()); + return true; + } + } + + public static int getNdkPPGValue() { + try { + return ICJniUtils.getPPG(); + } catch (Exception e) { + IcLog.e(TAG, e.getMessage()); + return 0; + } + } + + public static int getNdkHighBloodValue() { + try { + return ICJniUtils.getHighBloodPressure(); + } catch (Exception e) { + IcLog.e(TAG, e.getMessage()); + return 0; + } + } + + public static int getNdkLowBloodValue() { + try { + return ICJniUtils.getLowBloodPressure(); + } catch (Exception e) { + IcLog.e(TAG, e.getMessage()); + return 0; + } + } + + public static int getNdkStepCountValue() { + try { + return ICJniUtils.getStepCount(); + } catch (Exception e) { + IcLog.e(TAG, e.getMessage()); + return 0; + } + } + + public static int resetNdkStepCountValue() { + try { + return ICJniUtils.resetStepCount(); + } catch (Exception e) { + IcLog.e(TAG, e.getMessage()); + return 0; + } + } +} diff --git a/app/src/main/java/com/ic/work/utils/IcLog.java b/app/src/main/java/com/ic/work/utils/IcLog.java new file mode 100644 index 0000000..a7bb72c --- /dev/null +++ b/app/src/main/java/com/ic/work/utils/IcLog.java @@ -0,0 +1,59 @@ +package com.ic.work.utils; + +import android.util.Log; + +import com.ic.work.BuildConfig; + +/** + * @author RyanLee + * @date 2018/2/2 + */ + +public class IcLog { + + private static final String DOT = "."; + private static boolean isDebug = BuildConfig.DEBUG; + private static String tagHead = ""; + + public static void v(String tag, String msg) { + if (isDebug) { + Log.v(mergeHeadTag(tag), msg); + } + } + + public static void d(String tag, String msg) { + if (isDebug) { + Log.d(mergeHeadTag(tag), msg); + } + } + + public static void i(String tag, String msg) { + if (isDebug) { + Log.i(mergeHeadTag(tag), msg); + } + } + + public static void w(String tag, String msg) { + if (isDebug) { + Log.w(mergeHeadTag(tag), msg); + } + } + + public static void e(String tag, String msg) { + if (isDebug) { + Log.e(mergeHeadTag(tag), msg); + } + } + + public static void setDebug(boolean debug) { + isDebug = debug; + } + + public static void setLogHead(String head) { + tagHead = head + DOT; + } + + private static String mergeHeadTag(final String tag) { + return tagHead + tag; + } +} diff --git a/app/src/main/java/com/ic/work/utils/PedUtil.java b/app/src/main/java/com/ic/work/utils/PedUtil.java new file mode 100644 index 0000000..e4d87ae --- /dev/null +++ b/app/src/main/java/com/ic/work/utils/PedUtil.java @@ -0,0 +1,53 @@ +package com.ic.work.utils; + +public class PedUtil { + + private static final float LB_KG_CONVERSION_RATE = 0.45359237f; + private static final float KM_TO_MILE_CONVERSION_RATE = 0.62147119f; + private static final float INCH_CM_CONVERSION_RATE = 2.54f; + private static final int FOOT_INCH_CONVERSION_RATE = 12; + + //根据身高、步数计算路程 + public static float calcDistanceBySteps(int height, int steps) { + float var = 0f; + if (height < 154) { + var = (float) 16 / 42; + } else if (height > 174) { + var = (float) 17 / 42; + } else { + var = (float) 11 / 28; + } + + return (steps * height * var + height / 7) / 100000; // km + } + + public static float calcConsumeEnergy(int height, int weight, int steps) { + float consumeEnergy = 0f; + if (steps > 0) { + consumeEnergy = (0.53f * height + 0.58f * weight + 0.04f * steps) - 135; + consumeEnergy = (int) (consumeEnergy * 10) / 10f; + consumeEnergy = Math.max(consumeEnergy, 0.1f); + } + return consumeEnergy; + } + + //单位转换 Inch 英寸 -> cm + public static float inchToCm(float inch) { + return (inch * INCH_CM_CONVERSION_RATE); + } + + //单位转换 km -> mile 英里 + public static float kmToMile(float km) { + return (km * KM_TO_MILE_CONVERSION_RATE); + } + + //单位转换 kg -> lb 磅 + public static float kgTolb(float kg) { + return (kg / LB_KG_CONVERSION_RATE); + } + + //单位转换 lb 磅 -> kg + public static float lbTokg(float lb) { + return (lb * LB_KG_CONVERSION_RATE); + } +} diff --git a/app/src/main/java/com/ic/work/utils/SPUtils.java b/app/src/main/java/com/ic/work/utils/SPUtils.java new file mode 100644 index 0000000..2cc5ccb --- /dev/null +++ b/app/src/main/java/com/ic/work/utils/SPUtils.java @@ -0,0 +1,38 @@ +package com.ic.work.utils; + +import android.content.Context; +import android.content.SharedPreferences; + +public class SPUtils { + + private static final String Ped_Height = "Ped_Height"; + private static final String Ped_Weight = "Ped_Weight"; + + public static SharedPreferences getSP(Context context) { + return context.getSharedPreferences("IcPedSet", Context.MODE_PRIVATE); + } + + public static int getPedHeightSP(Context context) { + return getSP(context).getInt(Ped_Height, 170); + } + + public static int getPedWighttSP(Context context) { + return getSP(context).getInt(Ped_Weight, 75); + } + + public static void setPedHeightSP(Context context,int height) { + SharedPreferences.Editor editor = getSP(context).edit(); + if (editor != null) { + editor.putInt(Ped_Weight, height); + editor.apply(); + } + } + + public static void setPedWighttSP(Context context,int weight) { + SharedPreferences.Editor editor = getSP(context).edit(); + if (editor != null) { + editor.putInt(Ped_Weight, weight); + editor.apply(); + } + } +} diff --git a/app/src/main/java/com/ic/work/utils/ServiceUtil.java b/app/src/main/java/com/ic/work/utils/ServiceUtil.java new file mode 100644 index 0000000..a0942ba --- /dev/null +++ b/app/src/main/java/com/ic/work/utils/ServiceUtil.java @@ -0,0 +1,42 @@ +package com.ic.work.utils; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; + +import java.util.List; + +public class ServiceUtil { + + public static void startServiceUtil(Context context , String serviceAction, String packageName) { + Intent intent = getExplicitIntent(context, new Intent(serviceAction)); + if(intent != null){ + intent.setPackage(packageName); + context.startService(intent); + } + } + + public static void bindServiceUtil(Context context , String action, ServiceConnection connection,int type) { + Intent in = getExplicitIntent(context, new Intent(action)); + if(in != null){ + in.putExtra("REQ_TYPE",type); + context.bindService(in, connection, 0); + } + } + + private static Intent getExplicitIntent(Context context, Intent impl) { + List resolveInfo = context.getPackageManager().queryIntentServices(impl, 0); + + if (resolveInfo.size() != 1) return null; + + Intent intent = new Intent(impl); + ServiceInfo info = resolveInfo.get(0).serviceInfo; + if (info == null) return null; + intent.setComponent(new ComponentName(info.packageName, info.name)); + + return intent; + } +} diff --git a/app/src/main/java/com/ic/work/weather/LocationHelper.java b/app/src/main/java/com/ic/work/weather/LocationHelper.java new file mode 100644 index 0000000..250369c --- /dev/null +++ b/app/src/main/java/com/ic/work/weather/LocationHelper.java @@ -0,0 +1,85 @@ +package com.ic.work.weather; + +import android.content.Context; + +import com.amap.api.location.AMapLocationClient; +import com.amap.api.location.AMapLocationClientOption; +import com.amap.api.location.AMapLocationListener; +import com.ic.work.event.LocationResultEvent; +import com.ic.work.utils.IcLog; + +import org.greenrobot.eventbus.EventBus; + +public class LocationHelper { + + private static final String TAG ="LocationHelper"; + + public AMapLocationClient mLocationClient; + + public LocationHelper(Context context) { + mLocationClient = new AMapLocationClient(context); + //定位失败时,可通过ErrCode(错误码)信息来确定失败的原因,errInfo是错误信息,详见错误码表。 + AMapLocationListener mLocationListener = aMapLocation -> { + if (aMapLocation != null) { + if (aMapLocation.getErrorCode() == 0) { + IcLog.i(TAG,"Loaction City:"+aMapLocation.getCity()); + EventBus.getDefault().post(new LocationResultEvent(aMapLocation.getCity())); + } else { + //定位失败时,可通过ErrCode(错误码)信息来确定失败的原因,errInfo是错误信息,详见错误码表。 + IcLog.e(TAG, "location Error, ErrCode:" + + aMapLocation.getErrorCode() + ", errInfo:" + + aMapLocation.getErrorInfo()); + EventBus.getDefault().post(new LocationResultEvent("")); + } + } + }; + mLocationClient.setLocationListener(mLocationListener); + mLocationClient.setLocationOption(getDefaultOption()); + } + + public void startLocationService(){ + if(mLocationClient != null){ + mLocationClient.startLocation(); + } + } + + public void stopLocationService(){ + if(mLocationClient != null){ + mLocationClient.stopLocation(); + mLocationClient.onDestroy(); + + mLocationClient = null; + } + } + + private AMapLocationClientOption getDefaultOption() { + AMapLocationClientOption mOption = new AMapLocationClientOption(); + + // 高德地图默认值 + mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式 + mOption.setGpsFirst(false);//可选,设置是否gps优先,只在高精度模式下有效。默认关闭 + mOption.setHttpTimeOut(30000);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效 + mOption.setInterval(2000);//可选,设置定位间隔。默认为2秒 + mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是true + mOption.setOnceLocation(false);//可选,设置是否单次定位。默认是false + mOption.setOnceLocationLatest(false);//可选,设置是否等待wifi刷新,默认为false.如果设置为true,会自动变为单次定位,持续定位时不要使用 + AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);//可选, 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP + mOption.setSensorEnable(false);//可选,设置是否使用传感器。默认是false + mOption.setWifiScan(true); //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差 + mOption.setLocationCacheEnable(true); //可选,设置是否使用缓存定位,默认为true + + + // 自定义 + mOption.setHttpTimeOut(10000); + mOption.setInterval(10000); + + // 一次定位设置 + // 该方法默认为false。 + mOption.setOnceLocation(true); + // 关闭缓存机制 + mOption.setLocationCacheEnable(false); + + return mOption; + } + +} diff --git a/app/src/main/java/com/ic/work/weather/WeatherDBRun.java b/app/src/main/java/com/ic/work/weather/WeatherDBRun.java new file mode 100644 index 0000000..3e882b9 --- /dev/null +++ b/app/src/main/java/com/ic/work/weather/WeatherDBRun.java @@ -0,0 +1,52 @@ +package com.ic.work.weather; + +import com.ic.aidl.weather.WeatherParcelable; +import com.ic.work.db.WeatherInjection; +import com.ic.work.db.entity.WeatherEntity; +import com.ic.work.event.WeatherAgainEvent; +import com.ic.work.event.WeatherResultEvent; + +import org.greenrobot.eventbus.EventBus; +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.format.DateTimeFormatter; + +import java.util.List; + +public class WeatherDBRun implements Runnable { + + private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; + + private WeatherInjection weatherDb; + + public WeatherDBRun(WeatherInjection weather){ + this.weatherDb = weather; + } + + @Override + public void run() { + + List weatherList = weatherDb.queryDBWeatherDate(LocalDate.now()); + if(weatherList == null || weatherList.size() ==0){ + //通知主线程 开始定位 并通过Socket 获取天气 + EventBus.getDefault().post(new WeatherAgainEvent()); + //删除表中所有数据 + weatherDb.deleteDBWeatherDate(); + }else { + WeatherEntity entity = weatherList.get(0); + + WeatherParcelable parcelable = new WeatherParcelable(); + parcelable.setCity(entity.getCity()); + parcelable.setFigureDay(entity.getFigureDay()); + parcelable.setFigureNight(entity.getFigureNight()); + parcelable.setStatusDay(entity.getStatusDay()); + parcelable.setStatusNight(entity.getStatusNight()); + parcelable.setTemperatureDay(entity.getTemperatureDay()); + parcelable.setTemperatureNight(entity.getTemperatureNight()); + parcelable.setUpdateTime(entity.getUpdateTime().format(formatter)); + + //通知主线程 更新UI + EventBus.getDefault().post(new WeatherResultEvent(parcelable)); + } + } +} diff --git a/app/src/main/java/com/ic/work/weather/WeatherHelper.java b/app/src/main/java/com/ic/work/weather/WeatherHelper.java new file mode 100644 index 0000000..41d33e9 --- /dev/null +++ b/app/src/main/java/com/ic/work/weather/WeatherHelper.java @@ -0,0 +1,47 @@ +package com.ic.work.weather; + +import android.content.Context; +import android.text.TextUtils; + +import com.alibaba.fastjson.JSONObject; +import com.ic.work.ThreadPoolManager; +import com.ic.work.db.WeatherInjection; +import com.ic.work.weather.melon.SocketThread; + +public class WeatherHelper { + + private LocationHelper mLocation = null; + + public void startLocation(Context context) { + mLocation = new LocationHelper(context); + mLocation.startLocationService(); + } + + private void stopLocation() { + if (mLocation != null) { + mLocation.stopLocationService(); + mLocation = null; + } + } + + + public void queryWeatherServerInfo(WeatherInjection weatherDb,String city) { + + stopLocation(); + + if(TextUtils.isEmpty(city)){ + return; + } + + final String serverHost = "118.190.120.79"; + final int port = 11645; + + JSONObject paramJson = new JSONObject(); + paramJson.put("cmd", "getserviceip"); + paramJson.put("channel", "西瓜皮-西瓜皮"); + final String param = paramJson.toJSONString(); + + SocketThread socket = new SocketThread(weatherDb,serverHost, port, param,city); + ThreadPoolManager.getInstance().execute(socket); + } +} diff --git a/app/src/main/java/com/ic/work/weather/melon/SocketThread.java b/app/src/main/java/com/ic/work/weather/melon/SocketThread.java new file mode 100644 index 0000000..f770dc7 --- /dev/null +++ b/app/src/main/java/com/ic/work/weather/melon/SocketThread.java @@ -0,0 +1,173 @@ +package com.ic.work.weather.melon; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.ic.aidl.weather.WeatherParcelable; +import com.ic.work.BuildConfig; +import com.ic.work.db.WeatherInjection; +import com.ic.work.db.entity.WeatherEntity; +import com.ic.work.event.WeatherResultEvent; +import com.ic.work.utils.IcLog; + +import org.greenrobot.eventbus.EventBus; +import org.threeten.bp.LocalDate; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.format.DateTimeFormatter; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class SocketThread implements Runnable { + private static final String TAG = "SocketThread"; + + private static final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE; + + private String mIp; + private int mPort; + private String param; + + private String mCity; + + private SocketUtils mSocketUtils; + + private WeatherInjection weatherInjection; + + public SocketThread(WeatherInjection weatherDb, String ip, int port, String param, String city) { + mSocketUtils = new SocketUtils(); + + weatherInjection = weatherDb; + + this.mIp = ip; + this.mPort = port; + this.param = param; + this.mCity = city; + } + + @Override + public void run() { + + byte[] response = null; + int count = 0; + boolean isQueryWeather = false; + + while (true) { + count++; + + try { + mSocketUtils.connectSocket(mIp, mPort); + mSocketUtils.write(param.getBytes(UTF_8)); + response = mSocketUtils.read(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + mSocketUtils.disconnect(); + } + + if (response != null || count == 3) { + if (response != null) { + if (!isQueryWeather) { + parseWeatherServerInfo(new String(response, UTF_8)); + count = 0; + isQueryWeather = true; + response=null; + continue; + } else { + parseWeatherJSONString(new String(response, UTF_8)); + } + } + break; + } + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } + } + } + + + private void parseWeatherServerInfo(String stringJson) { + IcLog.i(TAG, stringJson); + + JSONObject responseJsonObj = JSONObject.parseObject(stringJson); + JSONObject serverInfo = responseJsonObj.getJSONObject("result"); + mIp = serverInfo.getString("weather_ip"); + mPort = serverInfo.getIntValue("weather_port"); + + JSONObject paramJson = new JSONObject(); + paramJson.put("cmd", "getheweatherbycity"); + paramJson.put("city", transformCityName(mCity)); + param = paramJson.toJSONString(); + } + + private void parseWeatherJSONString(String stringJson) { + IcLog.i(TAG, "Response is weather" + stringJson); + + JSONObject responseJsonObj = JSONObject.parseObject(stringJson); + JSONArray jsonArray = responseJsonObj.getJSONArray("HeWeather data service 3.0"); + if (jsonArray.size() > 0) { + JSONObject jsonObjectRoot = jsonArray.getJSONObject(0); + String stringStatus = jsonObjectRoot.getString("status"); + if (stringStatus.equalsIgnoreCase("ok")) { + JSONArray jsonObjectForecast = jsonObjectRoot.getJSONArray("daily_forecast"); + + JSONObject fJson = jsonObjectForecast.getJSONObject(0); + + JSONObject jObjectCond = fJson.getJSONObject("cond"); + JSONObject jObjectTemp = fJson.getJSONObject("tmp"); + + WeatherParcelable weather = new WeatherParcelable(); + WeatherEntity db = new WeatherEntity(); + weather.setCity(mCity); + db.setCity(mCity); + + weather.setStatusDay(jObjectCond.getString("txt_d")); // 白天天气描述 + db.setStatusDay(weather.getStatusDay()); + weather.setStatusNight(jObjectCond.getString("txt_n")); // 夜间天气描述 + db.setStatusNight(weather.getStatusNight()); + + weather.setFigureDay(jObjectCond.getString("code_d")); // 天气索引 + db.setFigureDay(weather.getFigureDay()); + weather.setFigureNight(jObjectCond.getString("code_n")); + db.setFigureNight(weather.getFigureNight()); + + weather.setTemperatureDay(jObjectTemp.getString("min")); // 白天温度-对应“和风天气”的最低温度 + db.setTemperatureDay(weather.getTemperatureDay()); + weather.setTemperatureNight(jObjectTemp.getString("max")); // 夜间温度-对应“和风天气”的最高温度 + db.setTemperatureNight(weather.getTemperatureNight()); + + weather.setUpdateTime(LocalDate.now().format(formatter)); + db.setUpdateTime(LocalDate.now()); + + if (BuildConfig.DEBUG) { + StringBuffer stringBuffer = new StringBuffer(); + stringBuffer.append(weather.getStatusDay()).append("-").append(weather.getStatusNight()) + .append("|") + .append(weather.getTemperatureDay()).append("-").append(weather.getTemperatureNight()) + .append("|") + .append(weather.getUpdateTime()); + IcLog.i(TAG, "Response is weather:" + stringBuffer.toString()); + } + + EventBus.getDefault().post(new WeatherResultEvent(weather)); + //插入数据库 + weatherInjection.deleteDBWeatherDate(); + weatherInjection.insertWeatherEntity(db); + } + } + } + + private static String transformCityName(String cityName) { + String retValue = cityName; + if (cityName != null && !cityName.isEmpty()) { + if (retValue.endsWith("地区")) { + retValue = retValue.substring(0, retValue.length() - 2); + } else if (retValue.endsWith("市") || retValue.endsWith("县") || retValue.endsWith("州") || retValue.endsWith("盟") + || retValue.endsWith("区")) { + retValue = retValue.substring(0, retValue.length() - 1); + } + } + + return retValue; + } +} diff --git a/app/src/main/java/com/ic/work/weather/melon/SocketUtils.java b/app/src/main/java/com/ic/work/weather/melon/SocketUtils.java new file mode 100644 index 0000000..a26ffb8 --- /dev/null +++ b/app/src/main/java/com/ic/work/weather/melon/SocketUtils.java @@ -0,0 +1,49 @@ +package com.ic.work.weather.melon; + +import java.io.IOException; +import java.net.Socket; + +import okio.BufferedSink; +import okio.BufferedSource; +import okio.Okio; + +public class SocketUtils { + private Socket socket; + private BufferedSource source; + private BufferedSink sink; + + public void connectSocket(String host,int port) throws IOException { + socket = new Socket(host,port); + socket.setSoTimeout(15000); + sink = Okio.buffer(Okio.sink(socket.getOutputStream())); + source = Okio.buffer(Okio.source(socket.getInputStream())); + } + + public void write(byte[] param) throws IOException { + sink.writeInt(param.length); + sink.write(param); + sink.flush(); + } + + public byte[] read() throws IOException { + int byteCount = source.readInt(); + if (byteCount>10485760){ + throw new RuntimeException("超出最大可接收字节数"+byteCount); + } + return source.readByteArray(byteCount); + } + + public void disconnect() { + if (socket!=null){ + try { + socket.close(); + } catch (IOException e) { + e.printStackTrace(); + }finally { + socket = null; + sink = null; + source = null; + } + } + } +} diff --git a/app/src/main/jniLibs/arm64-v8a/libICJniUtils.so b/app/src/main/jniLibs/arm64-v8a/libICJniUtils.so new file mode 100644 index 0000000000000000000000000000000000000000..78b371a12cfca44abb0a4640021a5f43acce984d GIT binary patch literal 14240 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 literal 0 HcmV?d00001 diff --git a/app/src/main/jniLibs/x86/libICJniUtils.so b/app/src/main/jniLibs/x86/libICJniUtils.so new file mode 100644 index 0000000000000000000000000000000000000000..9f22c851cafd0bf2c35ea94bb5bdce9583f09e3e GIT binary patch literal 13884 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 KM4sDa`hNhS^*~Sn literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1f6bb29 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..0d025f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..20a7f50 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,19 @@ + + + + +