Commit 2ccd5d32b67a5f5003d2566112be182a2b2add06
1 parent
ad8287cf
1、进程保活
Showing
31 changed files
with
2106 additions
and
10 deletions
app/build.gradle
| 1 | 1 | apply plugin: 'com.android.application' |
| 2 | +apply plugin: 'com.alibaba.arouter' | |
| 3 | + | |
| 4 | +static def stringValue(def value) { | |
| 5 | + return "\"${value}\"" | |
| 6 | +} | |
| 2 | 7 | |
| 3 | 8 | android { |
| 4 | 9 | compileSdkVersion 28 |
| 5 | 10 | defaultConfig { |
| 6 | - applicationId "com.example.modulepedometer" | |
| 7 | - minSdkVersion 15 | |
| 8 | - targetSdkVersion 28 | |
| 11 | + applicationId "com.cnlive.strike" | |
| 12 | + minSdkVersion 16 | |
| 13 | + targetSdkVersion 27 | |
| 9 | 14 | versionCode 1 |
| 10 | 15 | versionName "1.0" |
| 11 | 16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
| 17 | + multiDexEnabled true | |
| 18 | + javaCompileOptions { | |
| 19 | + annotationProcessorOptions { | |
| 20 | + arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: "enable"] | |
| 21 | + } | |
| 22 | + } | |
| 12 | 23 | } |
| 13 | 24 | buildTypes { |
| 25 | + debug { | |
| 26 | + applicationIdSuffix ".debug" | |
| 27 | + resValue("string", "app_name", "网++ 内测") | |
| 28 | + buildConfigField("String", "APP_ID", stringValue("802_jhbqccxw08")) | |
| 29 | + buildConfigField("String", "APP_KEY", stringValue("9c5619e9be747bb3b925dd215ca5923d86f12c09b9394f")) | |
| 30 | + buildConfigField("String", "APP_SCERET", stringValue("1e6380cb347255e777f72b5aa60f41daa68443a132aaea")) | |
| 31 | + } | |
| 14 | 32 | release { |
| 15 | - minifyEnabled false | |
| 16 | - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | |
| 33 | + resValue("string", "app_name", "网++") | |
| 34 | + buildConfigField("String", "APP_ID", stringValue("769_jetj7bq525")) | |
| 35 | + buildConfigField("String", "APP_KEY", stringValue("0d57b045ec0c3988a682d94c644e66b9b8e0d2b8ef937d")) | |
| 36 | + buildConfigField("String", "APP_SCERET", stringValue("275e8dc29274a1186d82f65bc607c231d02bcb3bfd8976")) | |
| 17 | 37 | } |
| 18 | 38 | } |
| 39 | + | |
| 40 | + compileOptions { | |
| 41 | + sourceCompatibility JavaVersion.VERSION_1_8 | |
| 42 | + targetCompatibility JavaVersion.VERSION_1_8 | |
| 43 | + } | |
| 44 | + dataBinding { | |
| 45 | + enabled true | |
| 46 | + } | |
| 47 | + dexOptions { | |
| 48 | + javaMaxHeapSize '4g' | |
| 49 | + } | |
| 50 | + | |
| 51 | + compileOptions { | |
| 52 | + sourceCompatibility 1.8 | |
| 53 | + targetCompatibility 1.8 | |
| 54 | + } | |
| 19 | 55 | } |
| 20 | 56 | |
| 21 | 57 | dependencies { |
| ... | ... | @@ -25,4 +61,12 @@ dependencies { |
| 25 | 61 | testImplementation 'junit:junit:4.12' |
| 26 | 62 | androidTestImplementation 'com.android.support.test:runner:1.0.2' |
| 27 | 63 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' |
| 64 | + implementation project(':moudle_pedometer') | |
| 65 | + implementation "com.cnlive.libs:base:$rootProject.libBase" | |
| 66 | + implementation "com.qmuiteam:qmui:$rootProject.qmui" | |
| 67 | + implementation "com.cnlive:app_arch:$rootProject.appArch" | |
| 68 | + | |
| 69 | + //ARouter | |
| 70 | + implementation "com.alibaba:arouter-api:$rootProject.arouterApiVersion" | |
| 71 | + annotationProcessor "com.alibaba:arouter-compiler:$rootProject.arouterCompilerVersion" | |
| 28 | 72 | } | ... | ... |
app/src/main/AndroidManifest.xml
| ... | ... | @@ -2,7 +2,11 @@ |
| 2 | 2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 | 3 | package="com.example.modulepedometer"> |
| 4 | 4 | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 5 | 8 | <application |
| 9 | + android:name=".MyApp" | |
| 6 | 10 | android:allowBackup="true" |
| 7 | 11 | android:icon="@mipmap/ic_launcher" |
| 8 | 12 | android:label="@string/app_name" | ... | ... |
app/src/main/java/com/example/modulepedometer/MainActivity.java
| 1 | 1 | package com.example.modulepedometer; |
| 2 | 2 | |
| 3 | +import android.content.Intent; | |
| 3 | 4 | import android.support.v7.app.AppCompatActivity; |
| 4 | 5 | import android.os.Bundle; |
| 5 | 6 | |
| 7 | +import com.alibaba.android.arouter.launcher.ARouter; | |
| 8 | +import com.cnlive.moudle.pedometer.ui.activity.PedometerMainActivity; | |
| 9 | + | |
| 6 | 10 | public class MainActivity extends AppCompatActivity { |
| 7 | 11 | |
| 8 | 12 | @Override |
| 9 | 13 | protected void onCreate(Bundle savedInstanceState) { |
| 10 | 14 | super.onCreate(savedInstanceState); |
| 11 | 15 | setContentView(R.layout.activity_main); |
| 16 | + ARouter.getInstance() | |
| 17 | + .build("/moudle_pedometer/InterestActivity") | |
| 18 | + .navigation(this); | |
| 19 | + finish(); | |
| 12 | 20 | } |
| 13 | 21 | } | ... | ... |
app/src/main/java/com/example/modulepedometer/MyApp.java
0 → 100644
| 1 | +package com.example.modulepedometer; | |
| 2 | + | |
| 3 | +import android.app.Application; | |
| 4 | + | |
| 5 | +import com.alibaba.android.arouter.launcher.ARouter; | |
| 6 | +import com.cnlive.libs.base.application.AppConfig; | |
| 7 | + | |
| 8 | +public class MyApp extends Application { | |
| 9 | + @Override | |
| 10 | + public void onCreate() { | |
| 11 | + super.onCreate(); | |
| 12 | + String userId = ""; | |
| 13 | + AppConfig.init(getApplicationContext(), BuildConfig.APP_ID, BuildConfig.APP_KEY, BuildConfig.APP_SCERET, | |
| 14 | + 0, BuildConfig.DEBUG, "", "", | |
| 15 | + userId, "", "", "", ""); | |
| 16 | + initARouter(); | |
| 17 | + } | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 初始化阿里的路由 | |
| 21 | + */ | |
| 22 | + private void initARouter() { | |
| 23 | + if (BuildConfig.DEBUG) { // 这两行必须写在init之前,否则这些配置在init过程中将无效 | |
| 24 | + ARouter.openLog(); // 打印日志 | |
| 25 | + ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险) | |
| 26 | + ARouter.printStackTrace(); // 打印日志的时候打印线程堆栈 | |
| 27 | + } | |
| 28 | + ARouter.init(this); // 尽可能早,推荐在Application中初始化 | |
| 29 | + } | |
| 30 | +} | ... | ... |
app/src/main/res/values/strings.xml
moudle_pedometer/build.gradle
| ... | ... | @@ -42,7 +42,7 @@ android { |
| 42 | 42 | } |
| 43 | 43 | //greendao配置 |
| 44 | 44 | greendao { |
| 45 | - schemaVersion 1 //版本号,升级时可配置 | |
| 45 | + schemaVersion 1 //版本号,升级时可配置 | |
| 46 | 46 | daoPackage 'com.cnlive.moudle.pedometer.sql.dao' //包名 |
| 47 | 47 | targetGenDir 'src/main/java' //生成目录 |
| 48 | 48 | } |
| ... | ... | @@ -68,6 +68,7 @@ dependencies { |
| 68 | 68 | implementation "com.github.bumptech.glide:glide:$rootProject.glide" |
| 69 | 69 | implementation "jp.wasabeef:glide-transformations:$rootProject.glideTransformations" |
| 70 | 70 | implementation 'com.android.support:support-v4:28.0.0' |
| 71 | + implementation 'com.android.support.constraint:constraint-layout:1.1.3' | |
| 71 | 72 | annotationProcessor "com.github.bumptech.glide:compiler:$rootProject.compiler" |
| 72 | 73 | |
| 73 | 74 | //-------------------------------------------------------- | ... | ... |
moudle_pedometer/src/debug/res/mipmap-hdpi/ic_launcher.png
0 → 100644
4.41 KB
moudle_pedometer/src/debug/res/mipmap-ldpi/ic_launcher.png
0 → 100644
2.17 KB
moudle_pedometer/src/debug/res/mipmap-xhdpi/ic_launcher.png
0 → 100644
5.93 KB
moudle_pedometer/src/debug/res/mipmap-xxhdpi/ic_launcher.png
0 → 100644
9.25 KB
moudle_pedometer/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
0 → 100644
13.2 KB
moudle_pedometer/src/main/AndroidManifest.xml
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 1 | 2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
| 2 | - package="com.example.moudle_pedometer" /> | |
| 3 | + xmlns:tools="http://schemas.android.com/tools" | |
| 4 | + package="com.example.moudle_pedometer"> | |
| 5 | + | |
| 6 | + <!-- 申请权限 --> | |
| 7 | + <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | |
| 8 | + <uses-permission android:name="android.permission.WAKE_LOCK" /> | |
| 9 | + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> | |
| 10 | + <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> | |
| 11 | + <!--计歩需要的权限--> | |
| 12 | + <uses-permission android:name="android.permission.VIBRATE" /> | |
| 13 | + <uses-permission | |
| 14 | + android:name="android.permission.WRITE_SETTINGS" | |
| 15 | + tools:ignore="ProtectedPermissions" /> | |
| 16 | + | |
| 17 | + <uses-feature android:name="android.hardware.sensor.accelerometer" /> | |
| 18 | + | |
| 19 | + <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> | |
| 20 | + <uses-permission | |
| 21 | + android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" | |
| 22 | + tools:ignore="ProtectedPermissions" /> | |
| 23 | + | |
| 24 | + <uses-feature | |
| 25 | + android:name="android.hardware.sensor.stepcounter" | |
| 26 | + android:required="true" /> | |
| 27 | + <uses-feature | |
| 28 | + android:name="android.hardware.sensor.stepdetector" | |
| 29 | + android:required="true" /> | |
| 30 | + | |
| 31 | + <application> | |
| 32 | + <service | |
| 33 | + android:name="com.cnlive.moudle.pedometer.service.KeepLiveService" | |
| 34 | + android:enabled="true" | |
| 35 | + android:exported="true" | |
| 36 | + android:priority="1000" | |
| 37 | + android:process=":remote" /> | |
| 38 | + <service | |
| 39 | + android:name="com.cnlive.moudle.pedometer.service.StepService" | |
| 40 | + android:enabled="true" | |
| 41 | + android:exported="true" | |
| 42 | + android:priority="1000" | |
| 43 | + android:process=":step"> | |
| 44 | + <intent-filter> | |
| 45 | + <!-- 系统启动完成后会调用--> | |
| 46 | + <action android:name="android.intent.action.BOOT_COMPLETED" /> | |
| 47 | + <action android:name="android.intent.action.DATE_CHANGED" /> | |
| 48 | + <action android:name="android.intent.action.MEDIA_MOUNTED" /> | |
| 49 | + <action android:name="android.intent.action.USER_PRESENT" /> | |
| 50 | + <action android:name="android.intent.action.ACTION_TIME_TICK" /> | |
| 51 | + <action android:name="android.intent.action.ACTION_POWER_CONNECTED" /> | |
| 52 | + <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" /> | |
| 53 | + </intent-filter> | |
| 54 | + </service> | |
| 55 | + | |
| 56 | + <activity android:name="com.cnlive.moudle.pedometer.ui.activity.PedometerMainActivity" /> | |
| 57 | + | |
| 58 | + <receiver | |
| 59 | + android:name="com.cnlive.moudle.pedometer.receivers.MyReceiver" | |
| 60 | + android:enabled="true" | |
| 61 | + android:exported="true"> | |
| 62 | + <intent-filter android:priority="1000"> | |
| 63 | + <action android:name="com.cnlive.moudle.pedometer.receivers.MyReceiver" /> | |
| 64 | + <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> | |
| 65 | + <action android:name="android.net.wifi.STATE_CHANGE" /> | |
| 66 | + <action android:name="com.example.myservice.MyReceiver" /> | |
| 67 | + </intent-filter> | |
| 68 | + </receiver> | |
| 69 | + </application> | |
| 70 | + | |
| 71 | +</manifest> | |
| 3 | 72 | \ No newline at end of file | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/model/step/StepCount.java
0 → 100644
| 1 | +package com.cnlive.moudle.pedometer.model.step; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * Created by dylan on 16/9/27. | |
| 5 | + */ | |
| 6 | + | |
| 7 | +/* | |
| 8 | +* 根据StepDetector传入的步点"数"步子 | |
| 9 | +* */ | |
| 10 | +public class StepCount implements StepCountListener { | |
| 11 | + | |
| 12 | + private int count = 0; | |
| 13 | + private int mCount = 0; | |
| 14 | + private StepValuePassListener mStepValuePassListener; | |
| 15 | + private long timeOfLastPeak = 0; | |
| 16 | + private long timeOfThisPeak = 0; | |
| 17 | + private StepDetector stepDetector; | |
| 18 | + | |
| 19 | + public StepCount() { | |
| 20 | + stepDetector = new StepDetector(); | |
| 21 | + stepDetector.initListener(this); | |
| 22 | + } | |
| 23 | + public StepDetector getStepDetector(){ | |
| 24 | + return stepDetector; | |
| 25 | + } | |
| 26 | + | |
| 27 | + /* | |
| 28 | + * 连续走十步才会开始计步 | |
| 29 | + * 连续走了9步以下,停留超过3秒,则计数清空 | |
| 30 | + * */ | |
| 31 | + @Override | |
| 32 | + public void countStep() { | |
| 33 | + this.timeOfLastPeak = this.timeOfThisPeak; | |
| 34 | + this.timeOfThisPeak = System.currentTimeMillis(); | |
| 35 | + if (this.timeOfThisPeak - this.timeOfLastPeak <= 3000L) { | |
| 36 | + if (this.count < 9) { | |
| 37 | + this.count++; | |
| 38 | + } else if (this.count == 9) { | |
| 39 | + this.count++; | |
| 40 | + this.mCount += this.count; | |
| 41 | + notifyListener(); | |
| 42 | + } else { | |
| 43 | + this.mCount++; | |
| 44 | + notifyListener(); | |
| 45 | + } | |
| 46 | + } else {//超时 | |
| 47 | + this.count = 1;//为1,不是0 | |
| 48 | + } | |
| 49 | + | |
| 50 | + } | |
| 51 | + | |
| 52 | + public void initListener(StepValuePassListener listener) { | |
| 53 | + this.mStepValuePassListener = listener; | |
| 54 | + } | |
| 55 | + | |
| 56 | + public void notifyListener() { | |
| 57 | + if (this.mStepValuePassListener != null) | |
| 58 | + this.mStepValuePassListener.stepChanged(this.mCount); | |
| 59 | + } | |
| 60 | + | |
| 61 | + | |
| 62 | + public void setSteps(int initValue) { | |
| 63 | + this.mCount = initValue; | |
| 64 | + this.count = 0; | |
| 65 | + timeOfLastPeak = 0; | |
| 66 | + timeOfThisPeak = 0; | |
| 67 | + notifyListener(); | |
| 68 | + } | |
| 69 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/model/step/StepCountListener.java
0 → 100644
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/model/step/StepDetector.java
0 → 100644
| 1 | +package com.cnlive.moudle.pedometer.model.step; | |
| 2 | + | |
| 3 | + | |
| 4 | +import android.hardware.Sensor; | |
| 5 | +import android.hardware.SensorEvent; | |
| 6 | +import android.hardware.SensorEventListener; | |
| 7 | +/* | |
| 8 | + * 算法的主要部分,检测是否是步点 | |
| 9 | + * */ | |
| 10 | + | |
| 11 | +public class StepDetector implements SensorEventListener { | |
| 12 | + | |
| 13 | + //存放三轴数据 | |
| 14 | + float[] oriValues = new float[3]; | |
| 15 | + final int ValueNum = 4; | |
| 16 | + //用于存放计算阈值的波峰波谷差值 | |
| 17 | + float[] tempValue = new float[ValueNum]; | |
| 18 | + int tempCount = 0; | |
| 19 | + //是否上升的标志位 | |
| 20 | + boolean isDirectionUp = false; | |
| 21 | + //持续上升次数 | |
| 22 | + int continueUpCount = 0; | |
| 23 | + //上一点的持续上升的次数,为了记录波峰的上升次数 | |
| 24 | + int continueUpFormerCount = 0; | |
| 25 | + //上一点的状态,上升还是下降 | |
| 26 | + boolean lastStatus = false; | |
| 27 | + //波峰值 | |
| 28 | + float peakOfWave = 0; | |
| 29 | + //波谷值 | |
| 30 | + float valleyOfWave = 0; | |
| 31 | + //此次波峰的时间 | |
| 32 | + long timeOfThisPeak = 0; | |
| 33 | + //上次波峰的时间 | |
| 34 | + long timeOfLastPeak = 0; | |
| 35 | + //当前的时间 | |
| 36 | + long timeOfNow = 0; | |
| 37 | + //当前传感器的值 | |
| 38 | + float gravityNew = 0; | |
| 39 | + //上次传感器的值 | |
| 40 | + float gravityOld = 0; | |
| 41 | + //动态阈值需要动态的数据,这个值用于这些动态数据的阈值 | |
| 42 | + final float InitialValue = (float) 1.3; | |
| 43 | + //初始阈值 | |
| 44 | + float ThreadValue = (float) 2.0; | |
| 45 | + //波峰波谷时间差 | |
| 46 | + int TimeInterval = 250; | |
| 47 | + private StepCountListener mStepListeners; | |
| 48 | + | |
| 49 | + @Override | |
| 50 | + public void onSensorChanged(SensorEvent event) { | |
| 51 | + for (int i = 0; i < 3; i++) { | |
| 52 | + oriValues[i] = event.values[i]; | |
| 53 | + } | |
| 54 | + gravityNew = (float) Math.sqrt(oriValues[0] * oriValues[0] | |
| 55 | + + oriValues[1] * oriValues[1] + oriValues[2] * oriValues[2]); | |
| 56 | + detectorNewStep(gravityNew); | |
| 57 | + } | |
| 58 | + | |
| 59 | + @Override | |
| 60 | + public void onAccuracyChanged(Sensor sensor, int accuracy) { | |
| 61 | + // | |
| 62 | + } | |
| 63 | + | |
| 64 | + public void initListener(StepCountListener listener) { | |
| 65 | + this.mStepListeners = listener; | |
| 66 | + } | |
| 67 | + | |
| 68 | + /* | |
| 69 | + * 检测步子,并开始计步 | |
| 70 | + * 1.传入sersor中的数据 | |
| 71 | + * 2.如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步 | |
| 72 | + * 3.符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中 | |
| 73 | + * */ | |
| 74 | + public void detectorNewStep(float values) { | |
| 75 | + if (gravityOld == 0) { | |
| 76 | + gravityOld = values; | |
| 77 | + } else { | |
| 78 | + if (detectorPeak(values, gravityOld)) { | |
| 79 | + timeOfLastPeak = timeOfThisPeak; | |
| 80 | + timeOfNow = System.currentTimeMillis(); | |
| 81 | + if (timeOfNow - timeOfLastPeak >= TimeInterval | |
| 82 | + && (peakOfWave - valleyOfWave >= ThreadValue)) { | |
| 83 | + timeOfThisPeak = timeOfNow; | |
| 84 | + /* | |
| 85 | + * 更新界面的处理,不涉及到算法 | |
| 86 | + * 一般在通知更新界面之前,增加下面处理,为了处理无效运动: | |
| 87 | + * 1.连续记录10才开始计步 | |
| 88 | + * 2.例如记录的9步用户停住超过3秒,则前面的记录失效,下次从头开始 | |
| 89 | + * 3.连续记录了9步用户还在运动,之前的数据才有效 | |
| 90 | + * */ | |
| 91 | + mStepListeners.countStep(); | |
| 92 | + } | |
| 93 | + if (timeOfNow - timeOfLastPeak >= TimeInterval | |
| 94 | + && (peakOfWave - valleyOfWave >= InitialValue)) { | |
| 95 | + timeOfThisPeak = timeOfNow; | |
| 96 | + ThreadValue = peakValleyThread(peakOfWave - valleyOfWave); | |
| 97 | + } | |
| 98 | + } | |
| 99 | + } | |
| 100 | + gravityOld = values; | |
| 101 | + } | |
| 102 | + | |
| 103 | + /* | |
| 104 | + * 检测波峰 | |
| 105 | + * 以下四个条件判断为波峰: | |
| 106 | + * 1.目前点为下降的趋势:isDirectionUp为false | |
| 107 | + * 2.之前的点为上升的趋势:lastStatus为true | |
| 108 | + * 3.到波峰为止,持续上升大于等于2次 | |
| 109 | + * 4.波峰值大于20 | |
| 110 | + * 记录波谷值 | |
| 111 | + * 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值 | |
| 112 | + * 2.所以要记录每次的波谷值,为了和下次的波峰做对比 | |
| 113 | + * */ | |
| 114 | + public boolean detectorPeak(float newValue, float oldValue) { | |
| 115 | + lastStatus = isDirectionUp; | |
| 116 | + if (newValue >= oldValue) { | |
| 117 | + isDirectionUp = true; | |
| 118 | + continueUpCount++; | |
| 119 | + } else { | |
| 120 | + continueUpFormerCount = continueUpCount; | |
| 121 | + continueUpCount = 0; | |
| 122 | + isDirectionUp = false; | |
| 123 | + } | |
| 124 | + | |
| 125 | + if (!isDirectionUp && lastStatus | |
| 126 | + && (continueUpFormerCount >= 2 || oldValue >= 20)) { | |
| 127 | + peakOfWave = oldValue; | |
| 128 | + return true; | |
| 129 | + } else if (!lastStatus && isDirectionUp) { | |
| 130 | + valleyOfWave = oldValue; | |
| 131 | + return false; | |
| 132 | + } else { | |
| 133 | + return false; | |
| 134 | + } | |
| 135 | + } | |
| 136 | + | |
| 137 | + /* | |
| 138 | + * 阈值的计算 | |
| 139 | + * 1.通过波峰波谷的差值计算阈值 | |
| 140 | + * 2.记录4个值,存入tempValue[]数组中 | |
| 141 | + * 3.在将数组传入函数averageValue中计算阈值 | |
| 142 | + * */ | |
| 143 | + public float peakValleyThread(float value) { | |
| 144 | + float tempThread = ThreadValue; | |
| 145 | + if (tempCount < ValueNum) { | |
| 146 | + tempValue[tempCount] = value; | |
| 147 | + tempCount++; | |
| 148 | + } else { | |
| 149 | + tempThread = averageValue(tempValue, ValueNum); | |
| 150 | + for (int i = 1; i < ValueNum; i++) { | |
| 151 | + tempValue[i - 1] = tempValue[i]; | |
| 152 | + } | |
| 153 | + tempValue[ValueNum - 1] = value; | |
| 154 | + } | |
| 155 | + return tempThread; | |
| 156 | + | |
| 157 | + } | |
| 158 | + | |
| 159 | + /* | |
| 160 | + * 梯度化阈值 | |
| 161 | + * 1.计算数组的均值 | |
| 162 | + * 2.通过均值将阈值梯度化在一个范围里 | |
| 163 | + * */ | |
| 164 | + public float averageValue(float value[], int n) { | |
| 165 | + float ave = 0; | |
| 166 | + for (int i = 0; i < n; i++) { | |
| 167 | + ave += value[i]; | |
| 168 | + } | |
| 169 | + ave = ave / ValueNum; | |
| 170 | + if (ave >= 8) { | |
| 171 | + ave = (float) 4.3; | |
| 172 | + } else if (ave >= 7 && ave < 8) { | |
| 173 | + ave = (float) 3.3; | |
| 174 | + } else if (ave >= 4 && ave < 7) { | |
| 175 | + ave = (float) 2.3; | |
| 176 | + } else if (ave >= 3 && ave < 4) { | |
| 177 | + ave = (float) 2.0; | |
| 178 | + } else { | |
| 179 | + ave = (float) 1.3; | |
| 180 | + } | |
| 181 | + return ave; | |
| 182 | + } | |
| 183 | + | |
| 184 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/model/step/StepValuePassListener.java
0 → 100644
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/receivers/MyReceiver.java
0 → 100644
| 1 | +package com.cnlive.moudle.pedometer.receivers; | |
| 2 | + | |
| 3 | +import android.annotation.SuppressLint; | |
| 4 | +import android.content.BroadcastReceiver; | |
| 5 | +import android.content.Context; | |
| 6 | +import android.content.Intent; | |
| 7 | +import android.os.PowerManager; | |
| 8 | +import android.util.Log; | |
| 9 | + | |
| 10 | +import com.cnlive.moudle.pedometer.service.KeepLiveService; | |
| 11 | +import com.cnlive.moudle.pedometer.service.StepService; | |
| 12 | +import com.cnlive.moudle.pedometer.utils.ServiceUtils; | |
| 13 | + | |
| 14 | +public class MyReceiver extends BroadcastReceiver { | |
| 15 | + | |
| 16 | + private PowerManager.WakeLock wakeLock = null; | |
| 17 | + | |
| 18 | + public MyReceiver() { | |
| 19 | + | |
| 20 | + } | |
| 21 | + | |
| 22 | + public MyReceiver(PowerManager.WakeLock wakeLock) { | |
| 23 | + super(); | |
| 24 | + this.wakeLock = wakeLock; | |
| 25 | + } | |
| 26 | + | |
| 27 | + @SuppressLint("Wakelock") | |
| 28 | + @Override | |
| 29 | + public void onReceive(Context context, Intent intent) { | |
| 30 | + Log.e("广播", "接收到广播:" + intent.getAction()); | |
| 31 | + if (!ServiceUtils.isServiceRunning(context, "com.cnlive.moudle.pedometer.service.KeepLiveService")) { | |
| 32 | + context.startService(new Intent(context, KeepLiveService.class)); | |
| 33 | + Log.e("启动服务", "启动MyIntentService"); | |
| 34 | + } | |
| 35 | + if (!ServiceUtils.isServiceRunning(context, "com.cnlive.moudle.pedometer.service.StepService")) { | |
| 36 | + context.startService(new Intent(context, StepService.class)); | |
| 37 | + Log.e("启动服务", "启动MyTestService"); | |
| 38 | + } | |
| 39 | + | |
| 40 | + String action = intent.getAction(); | |
| 41 | + | |
| 42 | + if (Intent.ACTION_SCREEN_OFF.equals(action)) { | |
| 43 | + if (null != wakeLock && !(wakeLock.isHeld())) { | |
| 44 | + wakeLock.acquire(); | |
| 45 | + Log.e("启动电量锁", "启动"); | |
| 46 | + } | |
| 47 | + //启动保活服务 | |
| 48 | +// KeepLiveService.getInstance().startPlaySong(); | |
| 49 | + | |
| 50 | +// Log.e("启动保活", "启动"); | |
| 51 | + } else if (Intent.ACTION_SCREEN_ON.equals(action) || Intent.ACTION_USER_PRESENT.equals(action)) { | |
| 52 | + if (null != wakeLock && wakeLock.isHeld()) { | |
| 53 | + wakeLock.release(); | |
| 54 | + Log.e("重置电量锁", "释放"); | |
| 55 | + } | |
| 56 | + //暂停保活服务 | |
| 57 | +// KeepLiveService.getInstance().stopPlaySong(); | |
| 58 | +// Log.e("停止保活", "停止"); | |
| 59 | + } | |
| 60 | + | |
| 61 | + } | |
| 62 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/service/KeepLiveService.java
0 → 100644
| 1 | +package com.cnlive.moudle.pedometer.service; | |
| 2 | + | |
| 3 | +import android.annotation.SuppressLint; | |
| 4 | +import android.app.Activity; | |
| 5 | +import android.app.Notification; | |
| 6 | +import android.app.NotificationChannel; | |
| 7 | +import android.app.NotificationManager; | |
| 8 | +import android.app.PendingIntent; | |
| 9 | +import android.app.Service; | |
| 10 | +import android.content.ComponentName; | |
| 11 | +import android.content.Context; | |
| 12 | +import android.content.Intent; | |
| 13 | +import android.content.IntentFilter; | |
| 14 | +import android.media.MediaPlayer; | |
| 15 | +import android.os.Build; | |
| 16 | +import android.os.IBinder; | |
| 17 | +import android.os.PowerManager; | |
| 18 | +import android.support.v4.app.NotificationCompat; | |
| 19 | +import android.util.Log; | |
| 20 | +import android.widget.RemoteViews; | |
| 21 | + | |
| 22 | +import com.cnlive.libs.base.util.SharedPreferencesHelper; | |
| 23 | +import com.cnlive.moudle.pedometer.receivers.MyReceiver; | |
| 24 | +import com.cnlive.moudle.pedometer.utils.ServiceUtils; | |
| 25 | +import com.example.moudle_pedometer.R; | |
| 26 | + | |
| 27 | +import java.io.IOException; | |
| 28 | + | |
| 29 | +/** | |
| 30 | + * @author ShinnyYang | |
| 31 | + * 维持后台运行的服务 | |
| 32 | + */ | |
| 33 | +public class KeepLiveService extends Service implements MediaPlayer.OnCompletionListener { | |
| 34 | + //唤醒锁 | |
| 35 | + private PowerManager.WakeLock wakeLock = null; | |
| 36 | + //电源管理器 | |
| 37 | + private PowerManager powerManager = null; | |
| 38 | + //音频播放器 | |
| 39 | + public static MediaPlayer mMediaPlayer; | |
| 40 | + //广播 | |
| 41 | + private static MyReceiver myReceiver; | |
| 42 | + private String CHANNEL_ONE_ID = "com.cnlive"; | |
| 43 | + private String CHANNEL_ONE_NAME = "Channel One"; | |
| 44 | + private NotificationManager mNM; | |
| 45 | + private Notification notification = null; | |
| 46 | + //是否在后台运行 | |
| 47 | + public static boolean isKeepService = true; | |
| 48 | + private static KeepLiveService instance; | |
| 49 | + private int startId; | |
| 50 | + | |
| 51 | + public KeepLiveService() { | |
| 52 | + } | |
| 53 | + | |
| 54 | + public static KeepLiveService getInstance() { | |
| 55 | + if (instance == null) { | |
| 56 | + instance = new KeepLiveService(); | |
| 57 | + return instance; | |
| 58 | + } else { | |
| 59 | + return instance; | |
| 60 | + } | |
| 61 | + } | |
| 62 | + | |
| 63 | + @Override | |
| 64 | + public void onCreate() { | |
| 65 | + instance = this; | |
| 66 | +// if (!ServiceUtils.isServiceRunning(getApplicationContext(), "com.cnlive.moudle.pedometer.service.StepService")) { | |
| 67 | +// startService(new Intent(getApplicationContext(), StepService.class)); | |
| 68 | +// } | |
| 69 | + init(); | |
| 70 | + initBroadCastReceiver(); | |
| 71 | + super.onCreate(); | |
| 72 | + } | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * 初始化广播 | |
| 76 | + */ | |
| 77 | + private void initBroadCastReceiver() { | |
| 78 | + if (wakeLock != null) { | |
| 79 | + myReceiver = new MyReceiver(wakeLock); | |
| 80 | + } else { | |
| 81 | + myReceiver = new MyReceiver(); | |
| 82 | + } | |
| 83 | + IntentFilter intentFilter = new IntentFilter(); | |
| 84 | + intentFilter.addAction(Intent.ACTION_SCREEN_OFF); | |
| 85 | + intentFilter.addAction(Intent.ACTION_SCREEN_ON); | |
| 86 | +// intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); | |
| 87 | +// intentFilter.addAction(Intent.ACTION_TIME_CHANGED); | |
| 88 | +// intentFilter.addAction(Intent.ACTION_POWER_CONNECTED); | |
| 89 | +// intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED); | |
| 90 | + intentFilter.addAction("com.cnlive.moudle.pedometer.receivers.MyReceiver"); | |
| 91 | + registerReceiver(myReceiver, intentFilter); | |
| 92 | + } | |
| 93 | + | |
| 94 | + /** | |
| 95 | + * 初始化相关参数 | |
| 96 | + */ | |
| 97 | + @SuppressLint("InvalidWakeLockTag") | |
| 98 | + private void init() { | |
| 99 | + if (null == powerManager) { | |
| 100 | + powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); | |
| 101 | + } | |
| 102 | + if (null == wakeLock) { | |
| 103 | + wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "track upload"); | |
| 104 | + } | |
| 105 | + if (null == mNM) { | |
| 106 | + mNM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); | |
| 107 | + } | |
| 108 | + | |
| 109 | + } | |
| 110 | + | |
| 111 | + @SuppressLint("WrongConstant") | |
| 112 | + @Override | |
| 113 | + public int onStartCommand(Intent intent, int flags, int startId) { | |
| 114 | + this.startId = startId; | |
| 115 | + showHideForegroundNotification(); | |
| 116 | + startPlaySong(); | |
| 117 | + flags = START_STICKY; | |
| 118 | + return super.onStartCommand(intent, flags, startId); | |
| 119 | + } | |
| 120 | + | |
| 121 | + //开始、暂停播放 | |
| 122 | + public void startPlaySong() { | |
| 123 | + if (mMediaPlayer == null) { | |
| 124 | + mMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.no_kill); | |
| 125 | + Log.e("音乐启动播放,播放对象为: ", "" + mMediaPlayer.hashCode()); | |
| 126 | + } else { | |
| 127 | + Log.e("音乐启动播放,播放对象为: ", "" + mMediaPlayer.hashCode()); | |
| 128 | + } | |
| 129 | + mMediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); | |
| 130 | + if (!mMediaPlayer.isPlaying()) { | |
| 131 | + mMediaPlayer.start(); | |
| 132 | + } | |
| 133 | + Log.e("是否播放:", mMediaPlayer.isPlaying() + ""); | |
| 134 | + mMediaPlayer.setOnCompletionListener(this); | |
| 135 | + mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { | |
| 136 | + @Override | |
| 137 | + public void onPrepared(MediaPlayer mediaPlayer) { | |
| 138 | + Log.e("加载完成:", ""); | |
| 139 | + | |
| 140 | + } | |
| 141 | + }); | |
| 142 | + } | |
| 143 | + | |
| 144 | + //停止播放销毁对象 | |
| 145 | + public void stopPlaySong() { | |
| 146 | + if (mMediaPlayer != null) { | |
| 147 | + mMediaPlayer.stop(); | |
| 148 | + Log.e("音乐停止播放,播放对象为:", "" + mMediaPlayer.hashCode()); | |
| 149 | + Log.e("音乐播放器是否在循环:", "" + mMediaPlayer.isLooping()); | |
| 150 | + Log.e("音乐播放器是否还在播放:", "" + mMediaPlayer.isPlaying()); | |
| 151 | + mMediaPlayer.release(); | |
| 152 | + Log.e("播放对象销毁,播放对象为:", "" + mMediaPlayer.hashCode()); | |
| 153 | + mMediaPlayer = null; | |
| 154 | + } | |
| 155 | + } | |
| 156 | + | |
| 157 | + | |
| 158 | + private void showHideForegroundNotification() { | |
| 159 | + NotificationChannel channel = null; | |
| 160 | + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { | |
| 161 | + channel = new NotificationChannel(CHANNEL_ONE_ID, CHANNEL_ONE_NAME, | |
| 162 | + NotificationManager.IMPORTANCE_HIGH); | |
| 163 | + channel.enableLights(false); | |
| 164 | + channel.enableVibration(false); | |
| 165 | + channel.setVibrationPattern(new long[]{0}); | |
| 166 | + channel.setSound(null, null); | |
| 167 | + mNM.createNotificationChannel(channel); | |
| 168 | + } | |
| 169 | + notification = new NotificationCompat.Builder(this, CHANNEL_ONE_ID) | |
| 170 | + .setWhen(System.currentTimeMillis()) | |
| 171 | + .setSound(null) | |
| 172 | + .build(); | |
| 173 | + // 0 隐藏前台服务通知 | |
| 174 | + startForeground(0, notification); | |
| 175 | + } | |
| 176 | + | |
| 177 | + @Override | |
| 178 | + public void onDestroy() { | |
| 179 | + super.onDestroy(); | |
| 180 | + Log.e("keep", "停止后"); | |
| 181 | + if (myReceiver != null) { | |
| 182 | + unregisterReceiver(myReceiver); | |
| 183 | + } | |
| 184 | + stopForeground(true); | |
| 185 | + stopPlaySong(); | |
| 186 | + boolean result = SharedPreferencesHelper.getInstance(getApplicationContext()).getBoolean("isKeepAlive", false); | |
| 187 | + Log.e("状态", result + ""); | |
| 188 | + //判断是否保持服务 | |
| 189 | + if (result) { | |
| 190 | +// // 重启自己 | |
| 191 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | |
| 192 | + startForegroundService(new Intent(getApplicationContext(), KeepLiveService.class)); | |
| 193 | + } else { | |
| 194 | + startService(new Intent(getApplicationContext(), KeepLiveService.class)); | |
| 195 | + } | |
| 196 | + //发送重启广播 | |
| 197 | + sendRestartBroadCast(); | |
| 198 | + } | |
| 199 | + } | |
| 200 | + | |
| 201 | + | |
| 202 | + /** | |
| 203 | + * 发送重启广播 | |
| 204 | + */ | |
| 205 | + private void sendRestartBroadCast() { | |
| 206 | + Intent intent = new Intent(" com.cnlive.moudle.pedometer.receivers.MyReceiver"); | |
| 207 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | |
| 208 | + intent.setComponent(new ComponentName(getPackageName(), " com.cnlive.moudle.pedometer.receivers.MyReceiver"));//高版本Android发送广播需要加这句 | |
| 209 | + } | |
| 210 | + sendBroadcast(intent); | |
| 211 | + } | |
| 212 | + | |
| 213 | + @Override | |
| 214 | + public IBinder onBind(Intent intent) { | |
| 215 | + // TODO: Return the communication channel to the service. | |
| 216 | + throw new UnsupportedOperationException("Not yet implemented"); | |
| 217 | + } | |
| 218 | + | |
| 219 | + | |
| 220 | + /** | |
| 221 | + * 歌曲播放完成 | |
| 222 | + * | |
| 223 | + * @param mediaPlayer | |
| 224 | + */ | |
| 225 | + @Override | |
| 226 | + public void onCompletion(MediaPlayer mediaPlayer) { | |
| 227 | + if (isKeepService) { | |
| 228 | + mediaPlayer.start(); | |
| 229 | + } | |
| 230 | + Intent intent = new Intent(" com.cnlive.moudle.pedometer.receivers.MyReceiver"); | |
| 231 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | |
| 232 | + intent.setComponent(new ComponentName(getPackageName(), " com.cnlive.moudle.pedometer.receivers.MyReceiver"));//高版本Android发送广播需要加这句 | |
| 233 | + } | |
| 234 | + sendBroadcast(intent); | |
| 235 | + Log.e("重新播放", "开始"); | |
| 236 | + } | |
| 237 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/service/StepService.java
0 → 100644
| 1 | +package com.cnlive.moudle.pedometer.service; | |
| 2 | + | |
| 3 | +import android.annotation.SuppressLint; | |
| 4 | +import android.app.Notification; | |
| 5 | +import android.app.NotificationChannel; | |
| 6 | +import android.app.NotificationManager; | |
| 7 | +import android.app.PendingIntent; | |
| 8 | +import android.app.Service; | |
| 9 | +import android.content.BroadcastReceiver; | |
| 10 | +import android.content.ComponentName; | |
| 11 | +import android.content.Context; | |
| 12 | +import android.content.Intent; | |
| 13 | +import android.content.IntentFilter; | |
| 14 | +import android.hardware.Sensor; | |
| 15 | +import android.hardware.SensorEvent; | |
| 16 | +import android.hardware.SensorEventListener; | |
| 17 | +import android.hardware.SensorManager; | |
| 18 | +import android.os.Binder; | |
| 19 | +import android.os.Build; | |
| 20 | +import android.os.CountDownTimer; | |
| 21 | +import android.os.IBinder; | |
| 22 | +import android.support.v4.app.NotificationCompat; | |
| 23 | +import android.util.Log; | |
| 24 | +import android.widget.RemoteViews; | |
| 25 | + | |
| 26 | +import com.cnlive.moudle.pedometer.model.step.StepCount; | |
| 27 | +import com.cnlive.moudle.pedometer.model.step.StepValuePassListener; | |
| 28 | +import com.cnlive.moudle.pedometer.sql.dao.UserStepEntityDao; | |
| 29 | +import com.cnlive.moudle.pedometer.sql.db.DbCore; | |
| 30 | +import com.cnlive.moudle.pedometer.sql.entity.UserStepEntity; | |
| 31 | +import com.cnlive.moudle.pedometer.ui.activity.PedometerMainActivity; | |
| 32 | +import com.cnlive.moudle.pedometer.utils.ServiceUtils; | |
| 33 | +import com.example.moudle_pedometer.R; | |
| 34 | +import com.orhanobut.logger.Logger; | |
| 35 | + | |
| 36 | +import org.greenrobot.greendao.DbUtils; | |
| 37 | + | |
| 38 | +import java.text.SimpleDateFormat; | |
| 39 | +import java.util.Date; | |
| 40 | +import java.util.List; | |
| 41 | +import java.util.UUID; | |
| 42 | + | |
| 43 | +public class StepService extends Service implements SensorEventListener { | |
| 44 | + private String TAG = "StepService"; | |
| 45 | + public static boolean isKeep = true; | |
| 46 | + /** | |
| 47 | + * 通知栏相关 | |
| 48 | + */ | |
| 49 | + private String CHANNEL_ONE_ID = "com.cnlive"; | |
| 50 | + private String CHANNEL_ONE_NAME = "Channel Two"; | |
| 51 | + private NotificationManager mNM; | |
| 52 | + private Notification notification = null; | |
| 53 | + private RemoteViews remoteViews; | |
| 54 | + /** | |
| 55 | + * 默认为30秒进行一次存储 | |
| 56 | + */ | |
| 57 | + private static int duration = 30 * 1000; | |
| 58 | + /** | |
| 59 | + * 当前的日期 | |
| 60 | + */ | |
| 61 | + private static String CURRENT_DATE = ""; | |
| 62 | + /** | |
| 63 | + * 传感器管理对象 | |
| 64 | + */ | |
| 65 | + private SensorManager sensorManager; | |
| 66 | + /** | |
| 67 | + * 广播接受者 | |
| 68 | + */ | |
| 69 | + private BroadcastReceiver mBatInfoReceiver; | |
| 70 | + /** | |
| 71 | + * 保存记步计时器 | |
| 72 | + */ | |
| 73 | + private TimeCount time; | |
| 74 | + /** | |
| 75 | + * 当前所走的步数 | |
| 76 | + */ | |
| 77 | + private int CURRENT_STEP; | |
| 78 | + /** | |
| 79 | + * 计步传感器类型 Sensor.TYPE_STEP_COUNTER或者Sensor.TYPE_STEP_DETECTOR | |
| 80 | + */ | |
| 81 | + private static int stepSensorType = -1; | |
| 82 | + /** | |
| 83 | + * 每次第一次启动记步服务时是否从系统中获取了已有的步数记录 | |
| 84 | + */ | |
| 85 | + private boolean hasRecord = false; | |
| 86 | + /** | |
| 87 | + * 系统中获取到的已有的步数 | |
| 88 | + */ | |
| 89 | + private int hasStepCount = 0; | |
| 90 | + /** | |
| 91 | + * 上一次的步数 | |
| 92 | + */ | |
| 93 | + private int previousStepCount = 0; | |
| 94 | + /** | |
| 95 | + * 加速度传感器中获取的步数 | |
| 96 | + */ | |
| 97 | + private StepCount mStepCount; | |
| 98 | + /** | |
| 99 | + * IBinder对象,向Activity传递数据的桥梁 | |
| 100 | + */ | |
| 101 | + private StepBinder stepBinder = new StepBinder(); | |
| 102 | + private String userId; | |
| 103 | + | |
| 104 | + public StepService() { | |
| 105 | + } | |
| 106 | + | |
| 107 | + @Override | |
| 108 | + public void onCreate() { | |
| 109 | + super.onCreate(); | |
| 110 | + init(); | |
| 111 | + //显示计步通知 | |
| 112 | + showStartForegroundNotification(); | |
| 113 | + userId = "123"; | |
| 114 | + initTodayData(userId); | |
| 115 | + initBroadcastReceiver(); | |
| 116 | + new Thread(new Runnable() { | |
| 117 | + @Override | |
| 118 | + public void run() { | |
| 119 | + startStepDetector(); | |
| 120 | + } | |
| 121 | + }).start(); | |
| 122 | + startTimeCount(); | |
| 123 | + } | |
| 124 | + | |
| 125 | + private void init() { | |
| 126 | + if (remoteViews == null) { | |
| 127 | + remoteViews = new RemoteViews(getPackageName(), R.layout.custom_step_notification); | |
| 128 | + } | |
| 129 | + if (null == mNM) { | |
| 130 | + mNM = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); | |
| 131 | + } | |
| 132 | + } | |
| 133 | + | |
| 134 | + @SuppressLint("WrongConstant") | |
| 135 | + @Override | |
| 136 | + public int onStartCommand(Intent intent, int flags, int startId) { | |
| 137 | + if (!ServiceUtils.isServiceRunning(getApplicationContext(), "com.cnlive.moudle.pedometer.service.KeepLiveService")) { | |
| 138 | + startService(new Intent(getApplicationContext(), KeepLiveService.class)); | |
| 139 | + } | |
| 140 | + flags = START_STICKY; | |
| 141 | + return super.onStartCommand(intent, flags, startId); | |
| 142 | + } | |
| 143 | + | |
| 144 | + private void showStartForegroundNotification() { | |
| 145 | + NotificationChannel channel = null; | |
| 146 | + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { | |
| 147 | + channel = new NotificationChannel(CHANNEL_ONE_ID, CHANNEL_ONE_NAME, | |
| 148 | + NotificationManager.IMPORTANCE_HIGH); | |
| 149 | + channel.enableLights(false); | |
| 150 | + channel.setSound(null, null); | |
| 151 | +// channel.setLightColor(getColor(R.color.colorPrimary)); | |
| 152 | + channel.enableVibration(false); | |
| 153 | + channel.setVibrationPattern(new long[]{0}); | |
| 154 | + channel.setSound(null, null); | |
| 155 | + mNM.createNotificationChannel(channel); | |
| 156 | + } | |
| 157 | + Intent notificationIntent = new Intent(this, PedometerMainActivity.class); | |
| 158 | + notification = new NotificationCompat.Builder(this, CHANNEL_ONE_ID) | |
| 159 | + .setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, 0)) | |
| 160 | + .setSmallIcon(R.drawable.ic_icon) | |
| 161 | +// .setContentText("前台服务正在运行") | |
| 162 | +// .setContentTitle("标题") | |
| 163 | + .setCustomContentView(remoteViews) | |
| 164 | + .setSound(null) | |
| 165 | + .setWhen(System.currentTimeMillis()) | |
| 166 | + .build(); | |
| 167 | + startForeground(1, notification); | |
| 168 | + | |
| 169 | + } | |
| 170 | + | |
| 171 | + @Override | |
| 172 | + public IBinder onBind(Intent intent) { | |
| 173 | + return stepBinder; | |
| 174 | + } | |
| 175 | + | |
| 176 | + | |
| 177 | + @Override | |
| 178 | + public void onDestroy() { | |
| 179 | + super.onDestroy(); | |
| 180 | + //取消前台进程 | |
| 181 | + stopForeground(true); | |
| 182 | + unregisterReceiver(mBatInfoReceiver); | |
| 183 | + stopSelf(); | |
| 184 | + if (isKeep) { | |
| 185 | + sendRestartBroadCast(); | |
| 186 | + } | |
| 187 | + Log.e("杀死", "MyTestService"); | |
| 188 | + } | |
| 189 | + | |
| 190 | + /** | |
| 191 | + * 发送重启广播 | |
| 192 | + */ | |
| 193 | + private void sendRestartBroadCast() { | |
| 194 | + Intent intent = new Intent(" com.cnlive.moudle.pedometer.receivers.MyReceiver"); | |
| 195 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | |
| 196 | + intent.setComponent(new ComponentName(getPackageName(), " com.cnlive.moudle.pedometer.receivers.MyReceiver"));//高版本Android发送广播需要加这句 | |
| 197 | + } | |
| 198 | + sendBroadcast(intent); | |
| 199 | + } | |
| 200 | + | |
| 201 | + | |
| 202 | + @Override | |
| 203 | + public void onAccuracyChanged(Sensor sensor, int i) { | |
| 204 | + | |
| 205 | + } | |
| 206 | + | |
| 207 | + /** | |
| 208 | + * @获取默认的pendingIntent,为了防止2.3及以下版本报错 | |
| 209 | + * @flags属性: 在顶部常驻:Notification.FLAG_ONGOING_EVENT | |
| 210 | + * 点击去除: Notification.FLAG_AUTO_CANCEL | |
| 211 | + */ | |
| 212 | + public PendingIntent getDefalutIntent(int flags) { | |
| 213 | + PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, new Intent(), flags); | |
| 214 | + return pendingIntent; | |
| 215 | + } | |
| 216 | + | |
| 217 | + /** | |
| 218 | + * 获取当天日期 | |
| 219 | + * | |
| 220 | + * @return | |
| 221 | + */ | |
| 222 | + private String getTodayDate() { | |
| 223 | + Date date = new Date(System.currentTimeMillis()); | |
| 224 | + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); | |
| 225 | + return sdf.format(date); | |
| 226 | + } | |
| 227 | + | |
| 228 | + /** | |
| 229 | + * 初始化当天的步数 | |
| 230 | + */ | |
| 231 | + private void initTodayData(String userId) { | |
| 232 | + CURRENT_DATE = getTodayDate(); | |
| 233 | + DbCore.init(getApplicationContext(), "Step.db"); | |
| 234 | +// //获取当天的数据,用于展示 CURRENT_DATE | |
| 235 | + List<UserStepEntity> list = DbCore.getDaoSession().getUserStepEntityDao().queryBuilder().where(UserStepEntityDao.Properties.UserId.eq(userId), UserStepEntityDao.Properties.Date.eq(CURRENT_DATE)).list(); | |
| 236 | + if (list.size() == 0 || list.isEmpty()) { | |
| 237 | + CURRENT_STEP = 0; | |
| 238 | + } else if (list.size() == 1) { | |
| 239 | + Log.v(TAG, "StepData=" + list.get(0).toString()); | |
| 240 | + CURRENT_STEP = Integer.parseInt(list.get(0).getStepCount()); | |
| 241 | + } else { | |
| 242 | + Log.v(TAG, "出错了!"); | |
| 243 | + } | |
| 244 | + if (mStepCount != null) { | |
| 245 | + mStepCount.setSteps(CURRENT_STEP); | |
| 246 | + } | |
| 247 | + updateNotification(); | |
| 248 | + } | |
| 249 | + | |
| 250 | + private void updateNotification() { | |
| 251 | + remoteViews.setTextViewText(R.id.tv_step_count, CURRENT_STEP + ""); | |
| 252 | + mNM.notify(1, notification); | |
| 253 | + | |
| 254 | + } | |
| 255 | + | |
| 256 | + /** | |
| 257 | + * 注册广播 | |
| 258 | + */ | |
| 259 | + private void initBroadcastReceiver() { | |
| 260 | + final IntentFilter filter = new IntentFilter(); | |
| 261 | + // 屏幕灭屏广播 | |
| 262 | + filter.addAction(Intent.ACTION_SCREEN_OFF); | |
| 263 | + //关机广播 | |
| 264 | + filter.addAction(Intent.ACTION_SHUTDOWN); | |
| 265 | + // 屏幕亮屏广播 | |
| 266 | + filter.addAction(Intent.ACTION_SCREEN_ON); | |
| 267 | + // 屏幕解锁广播 | |
| 268 | +// filter.addAction(Intent.ACTION_USER_PRESENT); | |
| 269 | + // 当长按电源键弹出“关机”对话或者锁屏时系统会发出这个广播 | |
| 270 | + // example:有时候会用到系统对话框,权限可能很高,会覆盖在锁屏界面或者“关机”对话框之上, | |
| 271 | + // 所以监听这个广播,当收到时就隐藏自己的对话,如点击pad右下角部分弹出的对话框 | |
| 272 | + filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); | |
| 273 | + //监听日期变化 | |
| 274 | + filter.addAction(Intent.ACTION_DATE_CHANGED); | |
| 275 | + filter.addAction(Intent.ACTION_TIME_CHANGED); | |
| 276 | + filter.addAction(Intent.ACTION_TIME_TICK); | |
| 277 | + | |
| 278 | + mBatInfoReceiver = new BroadcastReceiver() { | |
| 279 | + @Override | |
| 280 | + public void onReceive(final Context context, final Intent intent) { | |
| 281 | + String action = intent.getAction(); | |
| 282 | + if (Intent.ACTION_SCREEN_ON.equals(action)) { | |
| 283 | + Log.d(TAG, "screen on"); | |
| 284 | + } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { | |
| 285 | + Log.d(TAG, "screen off"); | |
| 286 | + //改为60秒一存储 | |
| 287 | + duration = 60000; | |
| 288 | + } else if (Intent.ACTION_USER_PRESENT.equals(action)) { | |
| 289 | + Log.d(TAG, "screen unlock"); | |
| 290 | + save(); | |
| 291 | + //改为30秒一存储 | |
| 292 | + duration = 30000; | |
| 293 | + } else if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) { | |
| 294 | + Log.i(TAG, " receive Intent.ACTION_CLOSE_SYSTEM_DIALOGS"); | |
| 295 | + //保存一次 | |
| 296 | + save(); | |
| 297 | + } else if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { | |
| 298 | + Log.i(TAG, " receive ACTION_SHUTDOWN"); | |
| 299 | + save(); | |
| 300 | + } else if (Intent.ACTION_DATE_CHANGED.equals(action)) {//日期变化步数重置为0 | |
| 301 | +// Logger.d("重置步数" + StepDcretor.CURRENT_STEP); | |
| 302 | + save(); | |
| 303 | + isNewDay(); | |
| 304 | + } else if (Intent.ACTION_TIME_CHANGED.equals(action)) { | |
| 305 | + //时间变化步数重置为0 | |
| 306 | +// isCall(); | |
| 307 | + save(); | |
| 308 | + isNewDay(); | |
| 309 | + } else if (Intent.ACTION_TIME_TICK.equals(action)) {//日期变化步数重置为0 | |
| 310 | +// isCall(); | |
| 311 | +// Logger.d("重置步数" + StepDcretor.CURRENT_STEP); | |
| 312 | + save(); | |
| 313 | + isNewDay(); | |
| 314 | + } | |
| 315 | + } | |
| 316 | + }; | |
| 317 | + registerReceiver(mBatInfoReceiver, filter); | |
| 318 | + } | |
| 319 | + | |
| 320 | + /** | |
| 321 | + * 获取当前步数 | |
| 322 | + * | |
| 323 | + * @return | |
| 324 | + */ | |
| 325 | + public int getStepCount() { | |
| 326 | + return CURRENT_STEP; | |
| 327 | + } | |
| 328 | + | |
| 329 | + /** | |
| 330 | + * 监听晚上0点变化初始化数据 | |
| 331 | + */ | |
| 332 | + private void isNewDay() { | |
| 333 | + String time = "00:00"; | |
| 334 | + if (time.equals(new SimpleDateFormat("HH:mm").format(new Date())) || !CURRENT_DATE.equals(getTodayDate())) { | |
| 335 | + initTodayData(userId); | |
| 336 | + } | |
| 337 | + } | |
| 338 | + | |
| 339 | +// /** | |
| 340 | +// * 监听时间变化提醒用户锻炼 | |
| 341 | +// */ | |
| 342 | +// private void isCall() { | |
| 343 | +// String time = this.getSharedPreferences("share_date", Context.MODE_MULTI_PROCESS).getString("achieveTime", "21:00"); | |
| 344 | +// String plan = this.getSharedPreferences("share_date", Context.MODE_MULTI_PROCESS).getString("planWalk_QTY", "7000"); | |
| 345 | +// String remind = this.getSharedPreferences("share_date", Context.MODE_MULTI_PROCESS).getString("remind", "1"); | |
| 346 | +// Logger.d("time=" + time + "\n" + | |
| 347 | +// "new SimpleDateFormat(\"HH: mm\").format(new Date()))=" + new SimpleDateFormat("HH:mm").format(new Date())); | |
| 348 | +// if (("1".equals(remind)) && | |
| 349 | +// (CURRENT_STEP < Integer.parseInt(plan)) && | |
| 350 | +// (time.equals(new SimpleDateFormat("HH:mm").format(new Date()))) | |
| 351 | +// ) { | |
| 352 | +// remindNotify(); | |
| 353 | +// } | |
| 354 | +// | |
| 355 | +// } | |
| 356 | + /** | |
| 357 | + * 提醒锻炼通知栏 | |
| 358 | + */ | |
| 359 | +// private void remindNotify() { | |
| 360 | +// | |
| 361 | +// //设置点击跳转 | |
| 362 | +// Intent hangIntent = new Intent(this, MainActivity.class); | |
| 363 | +// PendingIntent hangPendingIntent = PendingIntent.getActivity(this, 0, hangIntent, PendingIntent.FLAG_CANCEL_CURRENT); | |
| 364 | +// | |
| 365 | +// String plan = this.getSharedPreferences("share_date", Context.MODE_MULTI_PROCESS).getString("planWalk_QTY", "7000"); | |
| 366 | +// NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this); | |
| 367 | +// mBuilder.setContentTitle("今日步数" + CURRENT_STEP + " 步") | |
| 368 | +// .setContentText("距离目标还差" + (Integer.valueOf(plan) - CURRENT_STEP) + "步,加油!") | |
| 369 | +// .setContentIntent(hangPendingIntent) | |
| 370 | +// .setTicker(getResources().getString(R.string.app_name) + "提醒您开始锻炼了")//通知首次出现在通知栏,带上升动画效果的 | |
| 371 | +// .setWhen(System.currentTimeMillis())//通知产生的时间,会在通知信息里显示 | |
| 372 | +// .setPriority(Notification.PRIORITY_DEFAULT)//设置该通知优先级 | |
| 373 | +// .setAutoCancel(true)//设置这个标志当用户单击面板就可以让通知将自动取消 | |
| 374 | +// .setOngoing(false)//ture,设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接) | |
| 375 | +// .setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)//向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合: | |
| 376 | +// //Notification.DEFAULT_ALL Notification.DEFAULT_SOUND 添加声音 // requires VIBRATE permission | |
| 377 | +// .setSmallIcon(R.mipmap.logo); | |
| 378 | +// NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); | |
| 379 | +// mNotificationManager.notify(notify_remind_id, mBuilder.build()); | |
| 380 | +// } | |
| 381 | + | |
| 382 | + /** | |
| 383 | + * 获取传感器实例 | |
| 384 | + */ | |
| 385 | + private void startStepDetector() { | |
| 386 | + if (sensorManager != null) { | |
| 387 | + sensorManager = null; | |
| 388 | + } | |
| 389 | + // 获取传感器管理器的实例 | |
| 390 | + sensorManager = (SensorManager) this | |
| 391 | + .getSystemService(SENSOR_SERVICE); | |
| 392 | + //android4.4以后可以使用计步传感器 | |
| 393 | + int VERSION_CODES = Build.VERSION.SDK_INT; | |
| 394 | + if (VERSION_CODES >= 19) { | |
| 395 | + addCountStepListener(); | |
| 396 | + } else { | |
| 397 | + addBasePedometerListener(); | |
| 398 | + } | |
| 399 | + } | |
| 400 | + | |
| 401 | + /** | |
| 402 | + * 添加传感器监听 | |
| 403 | + * 1. TYPE_STEP_COUNTER API的解释说返回从开机被激活后统计的步数,当重启手机后该数据归零, | |
| 404 | + * 该传感器是一个硬件传感器所以它是低功耗的。 | |
| 405 | + * 为了能持续的计步,请不要反注册事件,就算手机处于休眠状态它依然会计步。 | |
| 406 | + * 当激活的时候依然会上报步数。该sensor适合在长时间的计步需求。 | |
| 407 | + * <p> | |
| 408 | + * 2.TYPE_STEP_DETECTOR翻译过来就是走路检测, | |
| 409 | + * API文档也确实是这样说的,该sensor只用来监监测走步,每次返回数字1.0。 | |
| 410 | + * 如果需要长事件的计步请使用TYPE_STEP_COUNTER。 | |
| 411 | + */ | |
| 412 | + private void addCountStepListener() { | |
| 413 | + Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER); | |
| 414 | + Sensor detectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR); | |
| 415 | + if (countSensor != null) { | |
| 416 | + stepSensorType = Sensor.TYPE_STEP_COUNTER; | |
| 417 | + Log.v(TAG, "Sensor.TYPE_STEP_COUNTER"); | |
| 418 | + sensorManager.registerListener(StepService.this, countSensor, SensorManager.SENSOR_DELAY_NORMAL); | |
| 419 | + } else if (detectorSensor != null) { | |
| 420 | + stepSensorType = Sensor.TYPE_STEP_DETECTOR; | |
| 421 | + Log.v(TAG, "Sensor.TYPE_STEP_DETECTOR"); | |
| 422 | + sensorManager.registerListener(StepService.this, detectorSensor, SensorManager.SENSOR_DELAY_NORMAL); | |
| 423 | + } else { | |
| 424 | + Log.v(TAG, "Count sensor not available!"); | |
| 425 | + addBasePedometerListener(); | |
| 426 | + } | |
| 427 | + } | |
| 428 | + | |
| 429 | + /** | |
| 430 | + * 通过加速度传感器来记步 | |
| 431 | + */ | |
| 432 | + private void addBasePedometerListener() { | |
| 433 | + mStepCount = new StepCount(); | |
| 434 | + mStepCount.setSteps(CURRENT_STEP); | |
| 435 | + // 获得传感器的类型,这里获得的类型是加速度传感器 | |
| 436 | + // 此方法用来注册,只有注册过才会生效,参数:SensorEventListener的实例,Sensor的实例,更新速率 | |
| 437 | + Sensor sensor = sensorManager | |
| 438 | + .getDefaultSensor(Sensor.TYPE_ACCELEROMETER); | |
| 439 | + boolean isAvailable = sensorManager.registerListener(mStepCount.getStepDetector(), sensor, | |
| 440 | + SensorManager.SENSOR_DELAY_UI); | |
| 441 | + mStepCount.initListener(new StepValuePassListener() { | |
| 442 | + @Override | |
| 443 | + public void stepChanged(int steps) { | |
| 444 | + CURRENT_STEP = steps; | |
| 445 | + updateNotification(); | |
| 446 | + } | |
| 447 | + }); | |
| 448 | + if (isAvailable) { | |
| 449 | + Log.v(TAG, "加速度传感器可以使用"); | |
| 450 | + } else { | |
| 451 | + Log.v(TAG, "加速度传感器无法使用"); | |
| 452 | + } | |
| 453 | + } | |
| 454 | + | |
| 455 | + /** | |
| 456 | + * 传感器监听回调 | |
| 457 | + * 记步的关键代码 | |
| 458 | + * 1. TYPE_STEP_COUNTER API的解释说返回从开机被激活后统计的步数,当重启手机后该数据归零, | |
| 459 | + * 该传感器是一个硬件传感器所以它是低功耗的。 | |
| 460 | + * 为了能持续的计步,请不要反注册事件,就算手机处于休眠状态它依然会计步。 | |
| 461 | + * 当激活的时候依然会上报步数。该sensor适合在长时间的计步需求。 | |
| 462 | + * <p> | |
| 463 | + * 2.TYPE_STEP_DETECTOR翻译过来就是走路检测, | |
| 464 | + * API文档也确实是这样说的,该sensor只用来监监测走步,每次返回数字1.0。 | |
| 465 | + * 如果需要长事件的计步请使用TYPE_STEP_COUNTER。 | |
| 466 | + * | |
| 467 | + * @param event | |
| 468 | + */ | |
| 469 | + @Override | |
| 470 | + public void onSensorChanged(SensorEvent event) { | |
| 471 | + if (stepSensorType == Sensor.TYPE_STEP_COUNTER) { | |
| 472 | + //获取当前传感器返回的临时步数 | |
| 473 | + int tempStep = (int) event.values[0]; | |
| 474 | + //首次如果没有获取手机系统中已有的步数则获取一次系统中APP还未开始记步的步数 | |
| 475 | + if (!hasRecord) { | |
| 476 | + hasRecord = true; | |
| 477 | + hasStepCount = tempStep; | |
| 478 | + } else { | |
| 479 | + //获取APP打开到现在的总步数=本次系统回调的总步数-APP打开之前已有的步数 | |
| 480 | + int thisStepCount = tempStep - hasStepCount; | |
| 481 | + //本次有效步数=(APP打开后所记录的总步数-上一次APP打开后所记录的总步数) | |
| 482 | + int thisStep = thisStepCount - previousStepCount; | |
| 483 | + //总步数=现有的步数+本次有效步数 | |
| 484 | + CURRENT_STEP += (thisStep); | |
| 485 | + //记录最后一次APP打开到现在的总步数 | |
| 486 | + previousStepCount = thisStepCount; | |
| 487 | + } | |
| 488 | + Logger.d("tempStep" + tempStep); | |
| 489 | + } else if (stepSensorType == Sensor.TYPE_STEP_DETECTOR) { | |
| 490 | + if (event.values[0] == 1.0) { | |
| 491 | + CURRENT_STEP++; | |
| 492 | + } | |
| 493 | + } | |
| 494 | + updateNotification(); | |
| 495 | + } | |
| 496 | + | |
| 497 | + /** | |
| 498 | + * 保存记步数据 | |
| 499 | + */ | |
| 500 | + private void save() { | |
| 501 | + int tempStep = CURRENT_STEP; | |
| 502 | + | |
| 503 | + List<UserStepEntity> list = DbCore.getDaoSession().getUserStepEntityDao().queryBuilder().where(UserStepEntityDao.Properties.UserId.eq(userId), UserStepEntityDao.Properties.Date.eq(CURRENT_DATE)).list(); | |
| 504 | + if (list.size() == 0 || list.isEmpty()) { | |
| 505 | + UserStepEntity data = new UserStepEntity(); | |
| 506 | + data.setUuid(UUID.randomUUID().toString()); | |
| 507 | + data.setUserId(userId); | |
| 508 | + data.setDate(CURRENT_DATE); | |
| 509 | + data.setStepCount(tempStep + ""); | |
| 510 | + DbCore.getDaoSession().getUserStepEntityDao().insert(data); | |
| 511 | + } else if (list.size() == 1) { | |
| 512 | + UserStepEntity data = list.get(0); | |
| 513 | + data.setStepCount(tempStep + ""); | |
| 514 | + DbCore.getDaoSession().getUserStepEntityDao().update(data); | |
| 515 | + } else { | |
| 516 | + } | |
| 517 | + } | |
| 518 | + | |
| 519 | + /** | |
| 520 | + * 保存记步数据 | |
| 521 | + */ | |
| 522 | + class TimeCount extends CountDownTimer { | |
| 523 | + public TimeCount(long millisInFuture, long countDownInterval) { | |
| 524 | + super(millisInFuture, countDownInterval); | |
| 525 | + } | |
| 526 | + | |
| 527 | + @Override | |
| 528 | + public void onFinish() { | |
| 529 | + // 如果计时器正常结束,则开始计步 | |
| 530 | + time.cancel(); | |
| 531 | + save(); | |
| 532 | + startTimeCount(); | |
| 533 | + } | |
| 534 | + | |
| 535 | + @Override | |
| 536 | + public void onTick(long millisUntilFinished) { | |
| 537 | + | |
| 538 | + } | |
| 539 | + | |
| 540 | + } | |
| 541 | + | |
| 542 | + /** | |
| 543 | + * 开始保存记步数据 | |
| 544 | + */ | |
| 545 | + private void startTimeCount() { | |
| 546 | + if (time == null) { | |
| 547 | + time = new TimeCount(duration, 1000); | |
| 548 | + } | |
| 549 | + time.start(); | |
| 550 | + } | |
| 551 | + | |
| 552 | + /** | |
| 553 | + * 向Activity传递数据的纽带 | |
| 554 | + */ | |
| 555 | + public class StepBinder extends Binder { | |
| 556 | + | |
| 557 | + /** | |
| 558 | + * 获取当前service对象 | |
| 559 | + * | |
| 560 | + * @return StepService | |
| 561 | + */ | |
| 562 | + public StepService getService() { | |
| 563 | + return StepService.this; | |
| 564 | + } | |
| 565 | + } | |
| 566 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/sql/db/BaseDbHelper.java
0 → 100644
| 1 | +/* | |
| 2 | +******************************* Copyright (c)*********************************\ | |
| 3 | +** | |
| 4 | +** (c) Copyright 2015, 蒋朋, china, qd. sd | |
| 5 | +** All Rights Reserved | |
| 6 | +** | |
| 7 | +** By() | |
| 8 | +** | |
| 9 | +**-----------------------------------版本信息------------------------------------ | |
| 10 | +** 版 本: V0.1 | |
| 11 | +** | |
| 12 | +**------------------------------------------------------------------------------ | |
| 13 | +********************************End of Head************************************\ | |
| 14 | +*/ | |
| 15 | + | |
| 16 | +package com.cnlive.moudle.pedometer.sql.db; | |
| 17 | + | |
| 18 | + | |
| 19 | +import org.greenrobot.greendao.AbstractDao; | |
| 20 | +import org.greenrobot.greendao.query.QueryBuilder; | |
| 21 | + | |
| 22 | +import java.util.List; | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * 文 件 名: BaseDbHelper | |
| 26 | + * 说 明: greedDAO 基础辅助类 | |
| 27 | + * 创 建 人: 蒋朋 | |
| 28 | + * 创建日期: 16-7-19 10:19 | |
| 29 | + * 邮 箱: jp19891017@gmail.com | |
| 30 | + * 博 客: http://jp1017.github.io | |
| 31 | + * 修改时间: | |
| 32 | + * 修改备注: | |
| 33 | + */ | |
| 34 | +public class BaseDbHelper<T, K> { | |
| 35 | + private AbstractDao<T, K> mDao; | |
| 36 | + | |
| 37 | + | |
| 38 | + public BaseDbHelper(AbstractDao dao) { | |
| 39 | + mDao = dao; | |
| 40 | + } | |
| 41 | + | |
| 42 | + | |
| 43 | + public void save(T item) { | |
| 44 | + mDao.insert(item); | |
| 45 | + } | |
| 46 | + | |
| 47 | + public void save(T... items) { | |
| 48 | + mDao.insertInTx(items); | |
| 49 | + } | |
| 50 | + | |
| 51 | + public void save(List<T> items) { | |
| 52 | + mDao.insertInTx(items); | |
| 53 | + } | |
| 54 | + | |
| 55 | + public void saveOrUpdate(T item) { | |
| 56 | + mDao.insertOrReplace(item); | |
| 57 | + } | |
| 58 | + | |
| 59 | + public void saveOrUpdate(T... items) { | |
| 60 | + mDao.insertOrReplaceInTx(items); | |
| 61 | + } | |
| 62 | + | |
| 63 | + public void saveOrUpdate(List<T> items) { | |
| 64 | + mDao.insertOrReplaceInTx(items); | |
| 65 | + } | |
| 66 | + | |
| 67 | + public void deleteByKey(K key) { | |
| 68 | + mDao.deleteByKey(key); | |
| 69 | + } | |
| 70 | + | |
| 71 | + public void delete(T item) { | |
| 72 | + mDao.delete(item); | |
| 73 | + } | |
| 74 | + | |
| 75 | + public void delete(T... items) { | |
| 76 | + mDao.deleteInTx(items); | |
| 77 | + } | |
| 78 | + | |
| 79 | + public void delete(List<T> items) { | |
| 80 | + mDao.deleteInTx(items); | |
| 81 | + } | |
| 82 | + | |
| 83 | + public void deleteAll() { | |
| 84 | + mDao.deleteAll(); | |
| 85 | + } | |
| 86 | + | |
| 87 | + | |
| 88 | + public void update(T item) { | |
| 89 | + mDao.update(item); | |
| 90 | + } | |
| 91 | + | |
| 92 | + public void update(T... items) { | |
| 93 | + mDao.updateInTx(items); | |
| 94 | + } | |
| 95 | + | |
| 96 | + public void update(List<T> items) { | |
| 97 | + mDao.updateInTx(items); | |
| 98 | + } | |
| 99 | + | |
| 100 | + public T query(K key) { | |
| 101 | + return mDao.load(key); | |
| 102 | + } | |
| 103 | + | |
| 104 | + public List<T> queryAll() { | |
| 105 | + return mDao.loadAll(); | |
| 106 | + } | |
| 107 | + | |
| 108 | + public List<T> query(String where, String... params) { | |
| 109 | + | |
| 110 | + return mDao.queryRaw(where, params); | |
| 111 | + } | |
| 112 | + | |
| 113 | + public QueryBuilder<T> queryBuilder() { | |
| 114 | + | |
| 115 | + return mDao.queryBuilder(); | |
| 116 | + } | |
| 117 | + | |
| 118 | + public long count() { | |
| 119 | + return mDao.count(); | |
| 120 | + } | |
| 121 | + | |
| 122 | + public void refresh(T item) { | |
| 123 | + mDao.refresh(item); | |
| 124 | + | |
| 125 | + } | |
| 126 | + | |
| 127 | + public void detach(T item) { | |
| 128 | + mDao.detach(item); | |
| 129 | + } | |
| 130 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/sql/db/DBMigrationHelper.java
0 → 100644
| 1 | +package com.cnlive.moudle.pedometer.sql.db; | |
| 2 | + | |
| 3 | +import android.database.Cursor; | |
| 4 | +import android.database.SQLException; | |
| 5 | +import android.database.sqlite.SQLiteDatabase; | |
| 6 | +import android.support.annotation.NonNull; | |
| 7 | +import android.text.TextUtils; | |
| 8 | +import android.util.Log; | |
| 9 | + | |
| 10 | +import org.greenrobot.greendao.AbstractDao; | |
| 11 | +import org.greenrobot.greendao.database.Database; | |
| 12 | +import org.greenrobot.greendao.database.StandardDatabase; | |
| 13 | +import org.greenrobot.greendao.internal.DaoConfig; | |
| 14 | + | |
| 15 | +import java.lang.reflect.InvocationTargetException; | |
| 16 | +import java.lang.reflect.Method; | |
| 17 | +import java.util.ArrayList; | |
| 18 | +import java.util.Arrays; | |
| 19 | +import java.util.List; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * greenDao升级类 | |
| 23 | + */ | |
| 24 | +public class DBMigrationHelper { | |
| 25 | + public static boolean DEBUG = false; | |
| 26 | + private static String TAG = "MigrationHelper2"; | |
| 27 | + private static final String SQLITE_MASTER = "sqlite_master"; | |
| 28 | + private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master"; | |
| 29 | + | |
| 30 | + public static void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) { | |
| 31 | + printLog("【The Old Database Version】" + db.getVersion()); | |
| 32 | + Database database = new StandardDatabase(db); | |
| 33 | + migrate(database, daoClasses); | |
| 34 | + } | |
| 35 | + | |
| 36 | + public static void migrate(Database database, Class<? extends AbstractDao<?, ?>>... daoClasses) { | |
| 37 | + printLog("【Generate temp table】start"); | |
| 38 | + generateTempTables(database, daoClasses); | |
| 39 | + printLog("【Generate temp table】complete"); | |
| 40 | + | |
| 41 | + dropAllTables(database, true, daoClasses); | |
| 42 | + createAllTables(database, false, daoClasses); | |
| 43 | + | |
| 44 | + printLog("【Restore data】start"); | |
| 45 | + restoreData(database, daoClasses); | |
| 46 | + printLog("【Restore data】complete"); | |
| 47 | + } | |
| 48 | + | |
| 49 | + private static void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { | |
| 50 | + for (int i = 0; i < daoClasses.length; i++) { | |
| 51 | + String tempTableName = null; | |
| 52 | + | |
| 53 | + DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); | |
| 54 | + String tableName = daoConfig.tablename; | |
| 55 | + if (!isTableExists(db, false, tableName)) { | |
| 56 | + printLog("【New Table】" + tableName); | |
| 57 | + continue; | |
| 58 | + } | |
| 59 | + try { | |
| 60 | + tempTableName = daoConfig.tablename.concat("_TEMP"); | |
| 61 | + StringBuilder dropTableStringBuilder = new StringBuilder(); | |
| 62 | + dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";"); | |
| 63 | + db.execSQL(dropTableStringBuilder.toString()); | |
| 64 | + | |
| 65 | + StringBuilder insertTableStringBuilder = new StringBuilder(); | |
| 66 | + insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName); | |
| 67 | + insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";"); | |
| 68 | + db.execSQL(insertTableStringBuilder.toString()); | |
| 69 | + printLog("【Table】" + tableName + "\n ---Columns-->" + getColumnsStr(daoConfig)); | |
| 70 | + printLog("【Generate temp table】" + tempTableName); | |
| 71 | + } catch (SQLException e) { | |
| 72 | + Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e); | |
| 73 | + } | |
| 74 | + } | |
| 75 | + } | |
| 76 | + | |
| 77 | + private static boolean isTableExists(Database db, boolean isTemp, String tableName) { | |
| 78 | + if (db == null || TextUtils.isEmpty(tableName)) { | |
| 79 | + return false; | |
| 80 | + } | |
| 81 | + String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER; | |
| 82 | + String sql = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?"; | |
| 83 | + Cursor cursor = null; | |
| 84 | + int count = 0; | |
| 85 | + try { | |
| 86 | + cursor = db.rawQuery(sql, new String[]{"table", tableName}); | |
| 87 | + if (cursor == null || !cursor.moveToFirst()) { | |
| 88 | + return false; | |
| 89 | + } | |
| 90 | + count = cursor.getInt(0); | |
| 91 | + } catch (Exception e) { | |
| 92 | + e.printStackTrace(); | |
| 93 | + } finally { | |
| 94 | + if (cursor != null) { | |
| 95 | + cursor.close(); | |
| 96 | + } | |
| 97 | + } | |
| 98 | + return count > 0; | |
| 99 | + } | |
| 100 | + | |
| 101 | + | |
| 102 | + private static String getColumnsStr(DaoConfig daoConfig) { | |
| 103 | + if (daoConfig == null) { | |
| 104 | + return "no columns"; | |
| 105 | + } | |
| 106 | + StringBuilder builder = new StringBuilder(); | |
| 107 | + for (int i = 0; i < daoConfig.allColumns.length; i++) { | |
| 108 | + builder.append(daoConfig.allColumns[i]); | |
| 109 | + builder.append(","); | |
| 110 | + } | |
| 111 | + if (builder.length() > 0) { | |
| 112 | + builder.deleteCharAt(builder.length() - 1); | |
| 113 | + } | |
| 114 | + return builder.toString(); | |
| 115 | + } | |
| 116 | + | |
| 117 | + | |
| 118 | + private static void dropAllTables(Database db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) { | |
| 119 | + reflectMethod(db, "dropTable", ifExists, daoClasses); | |
| 120 | + printLog("【Drop all table】"); | |
| 121 | + } | |
| 122 | + | |
| 123 | + private static void createAllTables(Database db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) { | |
| 124 | + reflectMethod(db, "createTable", ifNotExists, daoClasses); | |
| 125 | + printLog("【Create all table】"); | |
| 126 | + } | |
| 127 | + | |
| 128 | + /** | |
| 129 | + * dao class already define the sql exec method, so just invoke it | |
| 130 | + */ | |
| 131 | + private static void reflectMethod(Database db, String methodName, boolean isExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) { | |
| 132 | + if (daoClasses.length < 1) { | |
| 133 | + return; | |
| 134 | + } | |
| 135 | + try { | |
| 136 | + for (Class cls : daoClasses) { | |
| 137 | + Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class); | |
| 138 | + method.invoke(null, db, isExists); | |
| 139 | + } | |
| 140 | + } catch (NoSuchMethodException e) { | |
| 141 | + e.printStackTrace(); | |
| 142 | + } catch (InvocationTargetException e) { | |
| 143 | + e.printStackTrace(); | |
| 144 | + } catch (IllegalAccessException e) { | |
| 145 | + e.printStackTrace(); | |
| 146 | + } | |
| 147 | + } | |
| 148 | + | |
| 149 | + private static void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { | |
| 150 | + for (int i = 0; i < daoClasses.length; i++) { | |
| 151 | + DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); | |
| 152 | + String tableName = daoConfig.tablename; | |
| 153 | + String tempTableName = daoConfig.tablename.concat("_TEMP"); | |
| 154 | + | |
| 155 | + if (!isTableExists(db, true, tempTableName)) { | |
| 156 | + continue; | |
| 157 | + } | |
| 158 | + | |
| 159 | + try { | |
| 160 | + // get all columns from tempTable, take careful to use the columns list | |
| 161 | + List<String> columns = getColumns(db, tempTableName); | |
| 162 | + ArrayList<String> properties = new ArrayList<>(columns.size()); | |
| 163 | + for (int j = 0; j < daoConfig.properties.length; j++) { | |
| 164 | + String columnName = daoConfig.properties[j].columnName; | |
| 165 | + if (columns.contains(columnName)) { | |
| 166 | + properties.add(columnName); | |
| 167 | + } | |
| 168 | + } | |
| 169 | + if (properties.size() > 0) { | |
| 170 | + final String columnSQL = TextUtils.join(",", properties); | |
| 171 | + | |
| 172 | + StringBuilder insertTableStringBuilder = new StringBuilder(); | |
| 173 | + insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" ("); | |
| 174 | + insertTableStringBuilder.append(columnSQL); | |
| 175 | + insertTableStringBuilder.append(") SELECT "); | |
| 176 | + insertTableStringBuilder.append(columnSQL); | |
| 177 | + insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";"); | |
| 178 | + db.execSQL(insertTableStringBuilder.toString()); | |
| 179 | + printLog("【Restore data】 to " + tableName); | |
| 180 | + } | |
| 181 | + StringBuilder dropTableStringBuilder = new StringBuilder(); | |
| 182 | + dropTableStringBuilder.append("DROP TABLE ").append(tempTableName); | |
| 183 | + db.execSQL(dropTableStringBuilder.toString()); | |
| 184 | + printLog("【Drop temp table】" + tempTableName); | |
| 185 | + } catch (SQLException e) { | |
| 186 | + Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e); | |
| 187 | + } | |
| 188 | + } | |
| 189 | + } | |
| 190 | + | |
| 191 | + private static List<String> getColumns(Database db, String tableName) { | |
| 192 | + List<String> columns = null; | |
| 193 | + Cursor cursor = null; | |
| 194 | + try { | |
| 195 | + cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null); | |
| 196 | + if (null != cursor && cursor.getColumnCount() > 0) { | |
| 197 | + columns = Arrays.asList(cursor.getColumnNames()); | |
| 198 | + } | |
| 199 | + } catch (Exception e) { | |
| 200 | + e.printStackTrace(); | |
| 201 | + } finally { | |
| 202 | + if (cursor != null) { | |
| 203 | + cursor.close(); | |
| 204 | + } | |
| 205 | + if (null == columns) { | |
| 206 | + columns = new ArrayList<>(); | |
| 207 | + } | |
| 208 | + } | |
| 209 | + return columns; | |
| 210 | + } | |
| 211 | + | |
| 212 | + private static void printLog(String info) { | |
| 213 | + if (DEBUG) { | |
| 214 | + Log.d(TAG, info); | |
| 215 | + } | |
| 216 | + } | |
| 217 | + | |
| 218 | + | |
| 219 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/sql/db/DbCore.java
0 → 100644
| 1 | +package com.cnlive.moudle.pedometer.sql.db; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.text.TextUtils; | |
| 5 | + | |
| 6 | + | |
| 7 | +import com.cnlive.moudle.pedometer.sql.dao.DaoMaster; | |
| 8 | +import com.cnlive.moudle.pedometer.sql.dao.DaoSession; | |
| 9 | + | |
| 10 | +import org.greenrobot.greendao.query.QueryBuilder; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 文 件 名: DbCore | |
| 14 | + * 说 明: 核心辅助类,用于获取DaoMaster和DaoSession | |
| 15 | + * 参 考:http://blog.inet198.cn/?sbsujjbcy/article/details/48156683 | |
| 16 | + * 创 建 人: 蒋朋 | |
| 17 | + * 创建日期: 16-7-19 10:12 | |
| 18 | + * 邮 箱: jp19891017@gmail.com | |
| 19 | + * 博 客: http://jp1017.github.io | |
| 20 | + * 修改时间: | |
| 21 | + * 修改备注: | |
| 22 | + */ | |
| 23 | +public class DbCore { | |
| 24 | + private static final String DEFAULT_DB_NAME = "-strike-sp-db"; | |
| 25 | + private static DaoMaster daoMaster; | |
| 26 | + private static DaoSession daoSession; | |
| 27 | + | |
| 28 | + private static Context mContext; | |
| 29 | + private static String DB_NAME; | |
| 30 | + private static char[] databasePassword = "com.cnlive.strike_Passw0rd".toCharArray(); | |
| 31 | + | |
| 32 | + public static void init(Context context) { | |
| 33 | + init(context, DEFAULT_DB_NAME); | |
| 34 | + } | |
| 35 | + | |
| 36 | + public static void init(Context context, String dbName) { | |
| 37 | + if (context == null) { | |
| 38 | + throw new IllegalArgumentException("context can't be null"); | |
| 39 | + } | |
| 40 | + if (TextUtils.isEmpty(dbName)) { | |
| 41 | + DB_NAME = DEFAULT_DB_NAME; | |
| 42 | + } else { | |
| 43 | + DB_NAME = dbName; | |
| 44 | + } | |
| 45 | + mContext = context.getApplicationContext(); | |
| 46 | + String pathDatabase = mContext.getDatabasePath(DB_NAME).getAbsolutePath(); | |
| 47 | + | |
| 48 | + } | |
| 49 | + | |
| 50 | + public static DaoMaster getDaoMaster() { | |
| 51 | + if (daoMaster == null) { | |
| 52 | + //此处不可用 DaoMaster.DevOpenHelper, 那是开发辅助类,我们要自定义一个,方便升级 | |
| 53 | + DaoMaster.OpenHelper helper = new MyOpenHelper(mContext, DB_NAME); | |
| 54 | + daoMaster = new DaoMaster(helper.getWritableDb()); | |
| 55 | + } | |
| 56 | + return daoMaster; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public static DaoSession getDaoSession() { | |
| 60 | + if (daoSession == null) { | |
| 61 | + if (daoMaster == null) { | |
| 62 | + daoMaster = getDaoMaster(); | |
| 63 | + } | |
| 64 | + daoSession = daoMaster.newSession(); | |
| 65 | + } | |
| 66 | + return daoSession; | |
| 67 | + } | |
| 68 | + | |
| 69 | + public static void enableQueryBuilderLog() { | |
| 70 | + QueryBuilder.LOG_SQL = true; | |
| 71 | + QueryBuilder.LOG_VALUES = true; | |
| 72 | + } | |
| 73 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/sql/db/MyOpenHelper.java
0 → 100644
| 1 | +/* | |
| 2 | + ******************* Copyright (c) ***********************\ | |
| 3 | + ** | |
| 4 | + ** (c) Copyright 2016, 蒋朋, china, sxkj. sd | |
| 5 | + ** All Rights Reserved | |
| 6 | + ** | |
| 7 | + ** By(青岛世新科技有限公司) | |
| 8 | + ** www.qdsxkj.com | |
| 9 | + ** | |
| 10 | + ** _oo0oo_ | |
| 11 | + ** o8888888o | |
| 12 | + ** 88" . "88 | |
| 13 | + ** (| -_- |) | |
| 14 | + ** 0\ = /0 | |
| 15 | + ** ___/`---'\___ | |
| 16 | + ** .' \\| |// '. | |
| 17 | + ** / \\||| : |||// \ | |
| 18 | + ** / _||||| -:- |||||- \ | |
| 19 | + ** | | \\\ - /// | | | |
| 20 | + ** | \_| ''\---/'' |_/ | | |
| 21 | + ** \ .-\__ '-' ___/-. / | |
| 22 | + ** ___'. .' /--.--\ `. .'___ | |
| 23 | + ** ."" '< `.___\_<|>_/___.' >' "". | |
| 24 | + ** | | : `- \`.;`\ _ /`;.`/ - ` : | | | |
| 25 | + ** \ \ `_. \_ __\ /__ _/ .-` / / | |
| 26 | + ** =====`-.____`.___ \_____/___.-`___.-'===== | |
| 27 | + ** `=---=' | |
| 28 | + ** | |
| 29 | + ** | |
| 30 | + ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 31 | + ** | |
| 32 | + ** 佛祖保佑 永无BUG | |
| 33 | + ** | |
| 34 | + ** | |
| 35 | + ** 南无本师释迦牟尼佛 | |
| 36 | + ** | |
| 37 | + | |
| 38 | + **----------------------版本信息------------------------ | |
| 39 | + ** 版 本: V0.1 | |
| 40 | + ** | |
| 41 | + ******************* End of Head **********************\ | |
| 42 | + */ | |
| 43 | + | |
| 44 | +package com.cnlive.moudle.pedometer.sql.db; | |
| 45 | + | |
| 46 | +import android.content.Context; | |
| 47 | + | |
| 48 | +import com.cnlive.moudle.pedometer.sql.dao.DaoMaster; | |
| 49 | +import com.cnlive.moudle.pedometer.sql.dao.UserStepEntityDao; | |
| 50 | +import com.cnlive.moudle.pedometer.sql.entity.UserStepEntity; | |
| 51 | + | |
| 52 | +import org.greenrobot.greendao.database.Database; | |
| 53 | + | |
| 54 | +/** | |
| 55 | + * 文 件 名: MyOpenHelper | |
| 56 | + * 创 建 人: 蒋朋 | |
| 57 | + * 创建日期: 16-10-11 08:28 | |
| 58 | + * 邮 箱: jp19891017@gmail.com | |
| 59 | + * 博 客: https://jp1017.github.io/ | |
| 60 | + * 描 述: | |
| 61 | + * 修 改 人: | |
| 62 | + * 修改时间: | |
| 63 | + * 修改备注: | |
| 64 | + */ | |
| 65 | + | |
| 66 | +public class MyOpenHelper extends DaoMaster.OpenHelper { | |
| 67 | + public MyOpenHelper(Context context, String name) { | |
| 68 | + super(context, name); | |
| 69 | + } | |
| 70 | + | |
| 71 | + @Override | |
| 72 | + public void onUpgrade(Database db, int oldVersion, int newVersion) { | |
| 73 | + try { | |
| 74 | + //判断版本, 设置需要修改得表 我这边设置一个 FileInfo | |
| 75 | + DBMigrationHelper.migrate(db, UserStepEntityDao.class); | |
| 76 | + } catch (ClassCastException e) { | |
| 77 | + } | |
| 78 | +// KLog.w("db version update from " + oldVersion + " to " + newVersion); | |
| 79 | +// MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() { | |
| 80 | +// | |
| 81 | +// @Override | |
| 82 | +// public void onCreateAllTables(Database db, boolean ifNotExists) { | |
| 83 | +// DaoMaster.createAllTables(db, ifNotExists); | |
| 84 | +// } | |
| 85 | +// | |
| 86 | +// @Override | |
| 87 | +// public void onDropAllTables(Database db, boolean ifExists) { | |
| 88 | +// DaoMaster.dropAllTables(db, ifExists); | |
| 89 | +// } | |
| 90 | +// },G106InfoDao.class);//, GovernanceTechnologyDao.class, TestData3Dao.class | |
| 91 | +// } | |
| 92 | + switch (oldVersion) { | |
| 93 | + case 1: | |
| 94 | + | |
| 95 | + //不能先删除表,否则数据都木了 | |
| 96 | +// StudentDao.dropTable(db, true); | |
| 97 | + | |
| 98 | +// StudentDao.createTable(db, true); | |
| 99 | + | |
| 100 | + // 加入新字段 score | |
| 101 | +// db.execSQL("ALTER TABLE 'STUDENT' ADD 'SCORE' TEXT;"); | |
| 102 | + | |
| 103 | + break; | |
| 104 | + } | |
| 105 | + | |
| 106 | + } | |
| 107 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/sql/entity/UserStepEntity.java
| ... | ... | @@ -2,37 +2,60 @@ package com.cnlive.moudle.pedometer.sql.entity; |
| 2 | 2 | |
| 3 | 3 | import org.greenrobot.greendao.annotation.Entity; |
| 4 | 4 | import org.greenrobot.greendao.annotation.Generated; |
| 5 | +import org.greenrobot.greendao.annotation.Id; | |
| 5 | 6 | |
| 6 | 7 | @Entity |
| 7 | 8 | public class UserStepEntity { |
| 9 | + @Id | |
| 10 | + private String uuid; | |
| 8 | 11 | private String userId; |
| 9 | 12 | private String date; |
| 10 | 13 | private String stepCount; |
| 11 | - @Generated(hash = 1638365954) | |
| 12 | - public UserStepEntity(String userId, String date, String stepCount) { | |
| 14 | + | |
| 15 | + @Generated(hash = 1772281523) | |
| 16 | + public UserStepEntity(String uuid, String userId, String date, | |
| 17 | + String stepCount) { | |
| 18 | + this.uuid = uuid; | |
| 13 | 19 | this.userId = userId; |
| 14 | 20 | this.date = date; |
| 15 | 21 | this.stepCount = stepCount; |
| 16 | 22 | } |
| 23 | + | |
| 17 | 24 | @Generated(hash = 273857141) |
| 18 | 25 | public UserStepEntity() { |
| 19 | 26 | } |
| 27 | + | |
| 20 | 28 | public String getUserId() { |
| 21 | 29 | return this.userId; |
| 22 | 30 | } |
| 31 | + | |
| 23 | 32 | public void setUserId(String userId) { |
| 24 | 33 | this.userId = userId; |
| 25 | 34 | } |
| 35 | + | |
| 26 | 36 | public String getDate() { |
| 27 | 37 | return this.date; |
| 28 | 38 | } |
| 39 | + | |
| 29 | 40 | public void setDate(String date) { |
| 30 | 41 | this.date = date; |
| 31 | 42 | } |
| 43 | + | |
| 32 | 44 | public String getStepCount() { |
| 33 | 45 | return this.stepCount; |
| 34 | 46 | } |
| 47 | + | |
| 35 | 48 | public void setStepCount(String stepCount) { |
| 36 | 49 | this.stepCount = stepCount; |
| 37 | 50 | } |
| 51 | + | |
| 52 | + public String getUuid() { | |
| 53 | + return this.uuid; | |
| 54 | + } | |
| 55 | + | |
| 56 | + public void setUuid(String uuid) { | |
| 57 | + this.uuid = uuid; | |
| 58 | + } | |
| 59 | + | |
| 60 | + | |
| 38 | 61 | } | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/ui/activity/PedometerMainActivity.java
0 → 100644
| 1 | +package com.cnlive.moudle.pedometer.ui.activity; | |
| 2 | + | |
| 3 | +import android.content.ComponentName; | |
| 4 | +import android.content.Intent; | |
| 5 | +import android.content.pm.PackageManager; | |
| 6 | +import android.net.Uri; | |
| 7 | +import android.os.Build; | |
| 8 | +import android.os.Handler; | |
| 9 | +import android.os.PowerManager; | |
| 10 | +import android.provider.Settings; | |
| 11 | +import android.support.v4.app.NotificationManagerCompat; | |
| 12 | +import android.support.v7.app.AppCompatActivity; | |
| 13 | +import android.os.Bundle; | |
| 14 | +import android.util.Log; | |
| 15 | +import android.widget.Toast; | |
| 16 | + | |
| 17 | +import com.alibaba.android.arouter.facade.annotation.Route; | |
| 18 | +import com.cnlive.libs.base.util.SharedPreferencesHelper; | |
| 19 | +import com.cnlive.moudle.pedometer.service.KeepLiveService; | |
| 20 | +import com.cnlive.moudle.pedometer.service.StepService; | |
| 21 | +import com.cnlive.moudle.pedometer.utils.ServiceUtils; | |
| 22 | +import com.example.moudle_pedometer.R; | |
| 23 | + | |
| 24 | +import static android.app.Notification.EXTRA_CHANNEL_ID; | |
| 25 | +import static android.provider.Settings.EXTRA_APP_PACKAGE; | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * 计步器主activity | |
| 29 | + */ | |
| 30 | +@Route(path = "/moudle_pedometer/InterestActivity") | |
| 31 | +public class PedometerMainActivity extends AppCompatActivity { | |
| 32 | + private NotificationManagerCompat notificationManagerCompat; | |
| 33 | + private boolean isOpen; | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + protected void onCreate(Bundle savedInstanceState) { | |
| 37 | + super.onCreate(savedInstanceState); | |
| 38 | + setContentView(R.layout.activity_pedometer_main); | |
| 39 | + SharedPreferencesHelper.getInstance(getApplicationContext()).setValue("isKeepAlive", true); | |
| 40 | +// new Handler().postDelayed(new Runnable() { | |
| 41 | +// @Override | |
| 42 | +// public void run() { | |
| 43 | +// Log.e("停止服务", "停止"); | |
| 44 | +// StepService.isKeep = false; | |
| 45 | +// stopService(new Intent(PedometerMainActivity.this, StepService.class)); | |
| 46 | +// SharedPreferencesHelper.getInstance(getApplicationContext()).setValue("isKeepAlive", false); | |
| 47 | +// new Handler().postDelayed(new Runnable() { | |
| 48 | +// @Override | |
| 49 | +// public void run() { | |
| 50 | +// stopService(new Intent(PedometerMainActivity.this, KeepLiveService.class)); | |
| 51 | +// | |
| 52 | +// } | |
| 53 | +// }, 100); | |
| 54 | +// } | |
| 55 | +// }, 10000); | |
| 56 | + | |
| 57 | +// Intent intent = new Intent(); | |
| 58 | +// ComponentName componentName = new ComponentName("com.android.settings", "com.android.settings.SubSettings"); | |
| 59 | +// intent.setComponent(componentName); | |
| 60 | +// intent.putExtra(EXTRA_APP_PACKAGE, getPackageName()); | |
| 61 | +// intent.putExtra(EXTRA_CHANNEL_ID, getApplicationInfo().uid); | |
| 62 | +// startActivity(intent); | |
| 63 | + } | |
| 64 | + | |
| 65 | + private void check() { | |
| 66 | + //监测通知权限是否打开 | |
| 67 | + notificationManagerCompat = NotificationManagerCompat.from(this); | |
| 68 | + isOpen = notificationManagerCompat.areNotificationsEnabled(); | |
| 69 | + if (isOpen) { | |
| 70 | + startService(new Intent(getApplicationContext(), StepService.class)); | |
| 71 | + } else { | |
| 72 | + goToSettingNo(); | |
| 73 | + } | |
| 74 | + } | |
| 75 | + | |
| 76 | + private void goToSettingNo() { | |
| 77 | + Intent intent1 = new Intent(); | |
| 78 | + try { | |
| 79 | + // 根据isOpened结果,判断是否需要提醒用户跳转AppInfo页面,去打开App通知权限 | |
| 80 | + intent1.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS); | |
| 81 | + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | |
| 82 | + //这种方案适用于 API 26, 即8.0(含8.0)以上可以用 | |
| 83 | + intent1.putExtra(EXTRA_APP_PACKAGE, getPackageName()); | |
| 84 | + intent1.putExtra(EXTRA_CHANNEL_ID, getApplicationInfo().uid); | |
| 85 | + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | |
| 86 | + //这种方案适用于 API21——25,即 5.0——7.1 之间的版本可以使用 | |
| 87 | + intent1.putExtra("app_package", getPackageName()); | |
| 88 | + intent1.putExtra("app_uid", getApplicationInfo().uid); | |
| 89 | + } | |
| 90 | + | |
| 91 | + // 小米6 -MIUI9.6-8.0.0系统,是个特例,通知设置界面只能控制"允许使用通知圆点"——然而这个玩意并没有卵用,我想对雷布斯说:I'm not ok!!! | |
| 92 | + // if ("MI 6".equals(Build.MODEL)) { | |
| 93 | + // intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); | |
| 94 | + // Uri uri = Uri.fromParts("package", getPackageName(), null); | |
| 95 | + // intent.setData(uri); | |
| 96 | + // // intent.setAction("com.android.settings/.SubSettings"); | |
| 97 | + // } | |
| 98 | + startActivity(intent1); | |
| 99 | + } catch (Exception e) { | |
| 100 | + //其他低版本或者异常情况,走该节点。进入APP设置界面 | |
| 101 | + intent1.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); | |
| 102 | + intent1.putExtra("package", getPackageName()); | |
| 103 | + startActivity(intent1); | |
| 104 | + } | |
| 105 | + Toast.makeText(getApplicationContext(), "您尚未开启通知权限,无法进行计步", Toast.LENGTH_LONG).show(); | |
| 106 | + } | |
| 107 | + | |
| 108 | + @Override | |
| 109 | + protected void onRestart() { | |
| 110 | + super.onRestart(); | |
| 111 | + | |
| 112 | + } | |
| 113 | + | |
| 114 | + @Override | |
| 115 | + protected void onResume() { | |
| 116 | + super.onResume(); | |
| 117 | + check(); | |
| 118 | + PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); | |
| 119 | + | |
| 120 | + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { | |
| 121 | + boolean hasIgnored = powerManager.isIgnoringBatteryOptimizations(getPackageName()); | |
| 122 | + if (!hasIgnored) { | |
| 123 | + Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); | |
| 124 | + intent.setData(Uri.parse("package:" + getPackageName())); | |
| 125 | + PackageManager pm = getPackageManager(); | |
| 126 | + if (intent.resolveActivity(pm) != null) { | |
| 127 | + startActivity(intent); | |
| 128 | + } | |
| 129 | + } | |
| 130 | + } | |
| 131 | + } | |
| 132 | +} | ... | ... |
moudle_pedometer/src/main/java/com/cnlive/moudle/pedometer/utils/ServiceUtils.java
0 → 100644
| 1 | +package com.cnlive.moudle.pedometer.utils; | |
| 2 | + | |
| 3 | +import android.app.ActivityManager; | |
| 4 | +import android.content.Context; | |
| 5 | + | |
| 6 | +import com.cnlive.libs.base.util.SharedPreferencesHelper; | |
| 7 | + | |
| 8 | +import java.util.ArrayList; | |
| 9 | + | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 服务工具类 | |
| 13 | + */ | |
| 14 | +public class ServiceUtils { | |
| 15 | + | |
| 16 | + /** | |
| 17 | + * 判断服务是否开启 | |
| 18 | + * | |
| 19 | + * @return | |
| 20 | + */ | |
| 21 | + public static boolean isServiceRunning(Context context, String ServiceName) { | |
| 22 | + if (("").equals(ServiceName) || ServiceName == null) | |
| 23 | + return false; | |
| 24 | + ActivityManager myManager = (ActivityManager) context | |
| 25 | + .getSystemService(Context.ACTIVITY_SERVICE); | |
| 26 | + ArrayList<ActivityManager.RunningServiceInfo> runningService = (ArrayList<ActivityManager.RunningServiceInfo>) myManager | |
| 27 | + .getRunningServices(30); | |
| 28 | + for (int i = 0; i < runningService.size(); i++) { | |
| 29 | + if (runningService.get(i).service.getClassName().toString() | |
| 30 | + .equals(ServiceName)) { | |
| 31 | + return true; | |
| 32 | + } | |
| 33 | + } | |
| 34 | + return false; | |
| 35 | + } | |
| 36 | + | |
| 37 | + public static boolean getIsKeepState(Context context, String value) { | |
| 38 | + boolean result = SharedPreferencesHelper.getInstance(context).getBoolean(value, false); | |
| 39 | + return result; | |
| 40 | + } | |
| 41 | + | |
| 42 | + public static void setIsKeepState(Context context, String value, boolean state) { | |
| 43 | + SharedPreferencesHelper.getInstance(context).setValue(value, state); | |
| 44 | + | |
| 45 | + } | |
| 46 | +} | |
| 0 | 47 | \ No newline at end of file | ... | ... |
moudle_pedometer/src/main/res/drawable/ic_icon.png
0 → 100644
9.25 KB
moudle_pedometer/src/main/res/layout/activity_pedometer_main.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + xmlns:app="http://schemas.android.com/apk/res-auto" | |
| 4 | + xmlns:tools="http://schemas.android.com/tools" | |
| 5 | + android:layout_width="match_parent" | |
| 6 | + android:layout_height="match_parent" | |
| 7 | + tools:context="com.cnlive.moudle.pedometer.ui.activity.PedometerMainActivity"> | |
| 8 | + | |
| 9 | +</android.support.constraint.ConstraintLayout> | ... | ... |
moudle_pedometer/src/main/res/layout/custom_step_notification.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | + | |
| 3 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| 4 | + android:layout_width="match_parent" | |
| 5 | + android:layout_height="wrap_content" | |
| 6 | + android:gravity="center" | |
| 7 | + android:orientation="vertical"> | |
| 8 | + | |
| 9 | + <LinearLayout | |
| 10 | + android:layout_width="match_parent" | |
| 11 | + android:layout_height="wrap_content" | |
| 12 | + android:gravity="center_vertical"> | |
| 13 | + | |
| 14 | + <LinearLayout | |
| 15 | + android:layout_width="wrap_content" | |
| 16 | + android:layout_height="wrap_content" | |
| 17 | + android:layout_weight="1" | |
| 18 | + android:orientation="vertical"> | |
| 19 | + | |
| 20 | + <TextView | |
| 21 | + android:id="@+id/tv_tip" | |
| 22 | + android:layout_width="wrap_content" | |
| 23 | + android:layout_height="wrap_content" | |
| 24 | + android:layout_marginLeft="10dp" | |
| 25 | + android:layout_marginTop="3dp" | |
| 26 | + android:text="今日步数" | |
| 27 | + android:textColor="#707070" | |
| 28 | + android:textSize="14sp" /> | |
| 29 | + | |
| 30 | + <LinearLayout | |
| 31 | + android:layout_width="wrap_content" | |
| 32 | + android:layout_height="wrap_content"> | |
| 33 | + | |
| 34 | + <TextView | |
| 35 | + android:id="@+id/tv_step_count" | |
| 36 | + android:layout_width="wrap_content" | |
| 37 | + android:layout_height="wrap_content" | |
| 38 | + android:layout_centerHorizontal="true" | |
| 39 | + android:layout_marginLeft="15dp" | |
| 40 | + android:text="0" | |
| 41 | + android:textColor="#707070" | |
| 42 | + android:textSize="20sp" /> | |
| 43 | + | |
| 44 | + <TextView | |
| 45 | + android:layout_width="wrap_content" | |
| 46 | + android:layout_height="wrap_content" | |
| 47 | + android:layout_centerHorizontal="true" | |
| 48 | + android:layout_marginLeft="3dp" | |
| 49 | + android:text="步" | |
| 50 | + android:textColor="#707070" | |
| 51 | + android:textSize="14sp" /> | |
| 52 | + </LinearLayout> | |
| 53 | + </LinearLayout> | |
| 54 | + | |
| 55 | + <LinearLayout | |
| 56 | + android:layout_width="0dp" | |
| 57 | + android:layout_height="match_parent" | |
| 58 | + android:layout_weight="1" | |
| 59 | + android:gravity="right|center"> | |
| 60 | + | |
| 61 | + <ImageView | |
| 62 | + android:id="@+id/iv_icon" | |
| 63 | + android:layout_width="35dp" | |
| 64 | + android:layout_height="35dp" | |
| 65 | + android:layout_marginRight="10dp" | |
| 66 | + android:src="@drawable/ic_icon" /> | |
| 67 | + </LinearLayout> | |
| 68 | + </LinearLayout> | |
| 69 | + | |
| 70 | + | |
| 71 | +</LinearLayout> | ... | ... |
moudle_pedometer/src/main/res/raw/keep_live.mp3
0 → 100644
No preview for this file type
moudle_pedometer/src/main/res/raw/no_kill.mp3
0 → 100644
No preview for this file type