Commit 2ccd5d32b67a5f5003d2566112be182a2b2add06

Authored by 杨帅
1 parent ad8287cf

1、进程保活

Showing 31 changed files with 2106 additions and 10 deletions
app/build.gradle
1 apply plugin: 'com.android.application' 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 android { 8 android {
4 compileSdkVersion 28 9 compileSdkVersion 28
5 defaultConfig { 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 versionCode 1 14 versionCode 1
10 versionName "1.0" 15 versionName "1.0"
11 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 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 buildTypes { 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 release { 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 dependencies { 57 dependencies {
@@ -25,4 +61,12 @@ dependencies { @@ -25,4 +61,12 @@ dependencies {
25 testImplementation 'junit:junit:4.12' 61 testImplementation 'junit:junit:4.12'
26 androidTestImplementation 'com.android.support.test:runner:1.0.2' 62 androidTestImplementation 'com.android.support.test:runner:1.0.2'
27 androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 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,7 +2,11 @@
2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.example.modulepedometer"> 3 package="com.example.modulepedometer">
4 4
  5 +
  6 +
  7 +
5 <application 8 <application
  9 + android:name=".MyApp"
6 android:allowBackup="true" 10 android:allowBackup="true"
7 android:icon="@mipmap/ic_launcher" 11 android:icon="@mipmap/ic_launcher"
8 android:label="@string/app_name" 12 android:label="@string/app_name"
app/src/main/java/com/example/modulepedometer/MainActivity.java
1 package com.example.modulepedometer; 1 package com.example.modulepedometer;
2 2
  3 +import android.content.Intent;
3 import android.support.v7.app.AppCompatActivity; 4 import android.support.v7.app.AppCompatActivity;
4 import android.os.Bundle; 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 public class MainActivity extends AppCompatActivity { 10 public class MainActivity extends AppCompatActivity {
7 11
8 @Override 12 @Override
9 protected void onCreate(Bundle savedInstanceState) { 13 protected void onCreate(Bundle savedInstanceState) {
10 super.onCreate(savedInstanceState); 14 super.onCreate(savedInstanceState);
11 setContentView(R.layout.activity_main); 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
1 <resources> 1 <resources>
2 - <string name="app_name">ModulePedometer</string> 2 + <!--<string name="app_name">ModulePedometer</string>-->
3 </resources> 3 </resources>
moudle_pedometer/build.gradle
@@ -42,7 +42,7 @@ android { @@ -42,7 +42,7 @@ android {
42 } 42 }
43 //greendao配置 43 //greendao配置
44 greendao { 44 greendao {
45 - schemaVersion 1 //版本号,升级时可配置 45 + schemaVersion 1 //版本号,升级时可配置
46 daoPackage 'com.cnlive.moudle.pedometer.sql.dao' //包名 46 daoPackage 'com.cnlive.moudle.pedometer.sql.dao' //包名
47 targetGenDir 'src/main/java' //生成目录 47 targetGenDir 'src/main/java' //生成目录
48 } 48 }
@@ -68,6 +68,7 @@ dependencies { @@ -68,6 +68,7 @@ dependencies {
68 implementation "com.github.bumptech.glide:glide:$rootProject.glide" 68 implementation "com.github.bumptech.glide:glide:$rootProject.glide"
69 implementation "jp.wasabeef:glide-transformations:$rootProject.glideTransformations" 69 implementation "jp.wasabeef:glide-transformations:$rootProject.glideTransformations"
70 implementation 'com.android.support:support-v4:28.0.0' 70 implementation 'com.android.support:support-v4:28.0.0'
  71 + implementation 'com.android.support.constraint:constraint-layout:1.1.3'
71 annotationProcessor "com.github.bumptech.glide:compiler:$rootProject.compiler" 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 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 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 \ No newline at end of file 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
  1 +package com.cnlive.moudle.pedometer.model.step;
  2 +
  3 +
  4 +public interface StepCountListener {
  5 + void countStep();
  6 +}
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
  1 +package com.cnlive.moudle.pedometer.model.step;
  2 +
  3 +
  4 +public interface StepValuePassListener {
  5 + void stepChanged(int steps);
  6 +}
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,37 +2,60 @@ package com.cnlive.moudle.pedometer.sql.entity;
2 2
3 import org.greenrobot.greendao.annotation.Entity; 3 import org.greenrobot.greendao.annotation.Entity;
4 import org.greenrobot.greendao.annotation.Generated; 4 import org.greenrobot.greendao.annotation.Generated;
  5 +import org.greenrobot.greendao.annotation.Id;
5 6
6 @Entity 7 @Entity
7 public class UserStepEntity { 8 public class UserStepEntity {
  9 + @Id
  10 + private String uuid;
8 private String userId; 11 private String userId;
9 private String date; 12 private String date;
10 private String stepCount; 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 this.userId = userId; 19 this.userId = userId;
14 this.date = date; 20 this.date = date;
15 this.stepCount = stepCount; 21 this.stepCount = stepCount;
16 } 22 }
  23 +
17 @Generated(hash = 273857141) 24 @Generated(hash = 273857141)
18 public UserStepEntity() { 25 public UserStepEntity() {
19 } 26 }
  27 +
20 public String getUserId() { 28 public String getUserId() {
21 return this.userId; 29 return this.userId;
22 } 30 }
  31 +
23 public void setUserId(String userId) { 32 public void setUserId(String userId) {
24 this.userId = userId; 33 this.userId = userId;
25 } 34 }
  35 +
26 public String getDate() { 36 public String getDate() {
27 return this.date; 37 return this.date;
28 } 38 }
  39 +
29 public void setDate(String date) { 40 public void setDate(String date) {
30 this.date = date; 41 this.date = date;
31 } 42 }
  43 +
32 public String getStepCount() { 44 public String getStepCount() {
33 return this.stepCount; 45 return this.stepCount;
34 } 46 }
  47 +
35 public void setStepCount(String stepCount) { 48 public void setStepCount(String stepCount) {
36 this.stepCount = stepCount; 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 \ No newline at end of file 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