├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── today
│ │ └── step
│ │ ├── MainActivity.java
│ │ ├── MyReceiver.java
│ │ └── TSApplication.java
│ └── res
│ ├── layout
│ └── activity_main.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── base-lib-notification
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── andrjhf
│ │ └── notification
│ │ └── api
│ │ └── compat
│ │ └── NotificationApiCompat.java
│ └── res
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── dependencies.gradle
├── gradle.properties
├── lib-jlogger
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── andrjhf
│ │ └── lib
│ │ └── jlogger
│ │ ├── JLoggerConstant.java
│ │ ├── JLoggerWraper.java
│ │ └── Utils.java
│ └── res
│ └── values
│ └── strings.xml
├── lib-todaystepcounter
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── aidl
│ └── com
│ │ └── today
│ │ └── step
│ │ └── lib
│ │ └── ISportStepInterface.aidl
│ ├── java
│ └── com
│ │ └── today
│ │ └── step
│ │ └── lib
│ │ ├── BaseClickBroadcast.java
│ │ ├── ConstantDef.java
│ │ ├── DateUtils.java
│ │ ├── ITodayStepDBHelper.java
│ │ ├── OnStepCounterListener.java
│ │ ├── PreferencesHelper.java
│ │ ├── SportStepJsonUtils.java
│ │ ├── StepUtil.java
│ │ ├── TodayStepBootCompleteReceiver.java
│ │ ├── TodayStepCounter.java
│ │ ├── TodayStepDBHelper.java
│ │ ├── TodayStepData.java
│ │ ├── TodayStepDetector.java
│ │ ├── TodayStepManager.java
│ │ ├── TodayStepService.java
│ │ ├── TodayStepShutdownReceiver.java
│ │ └── WakeLockUtils.java
│ └── res
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ └── strings.xml
├── screenshots
└── screenshots.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android计步模块(类似微信运动,支付宝计步,今日步数)
2 |
3 | [Android计步模块优化(今日步数)](http://www.jianshu.com/p/cfc2a200e46d)
4 |
5 | [Android计步模块优化(今日步数)V2.0.0](https://www.jianshu.com/p/1b53937150ad)
6 |
7 | 
8 |
9 | ### 功能
10 | 1. 返回当天运动步数
11 | 2. 内部自动切换计步算法,适配所有手机
12 | 3. 通过AIDL对外暴露接口
13 | 4. 采用单独进程计步
14 |
15 | ### 优化点
16 | 1. 适配Android8.0系统
17 | 3. TYPE_ACCELEROMETER和TYPE_STEP_COUNTER传感器自动切换
18 | 4. 只提供当天的步数数据
19 | 5. 解决一些bug
20 | 6. 对关键位置增加日志信息(日志系统底层需要自己实现)
21 |
22 | [开源算法](https://github.com/finnfu/stepcount)这个是源码,如果有大神对他进行优化,非常欢迎和我进行讨论。
23 |
24 | #### 问题
25 | 1. 用户后台保活(对于加速度传感器必须后台保活),每个手机都不一样无法提供通用的标准操作
26 | 2. 早上打开一次,计步器会开始计步
27 | 3. 重启手机需要打开app,否则步数丢失
28 | 4. 如果遇到当天步数不准,或者不记步,需要重启手机,android计步协处理器会出现bug
29 | 5. 会有部分清零和极大值出现,这也是由于android计步协处理器出现问题导致的
30 | 6. 卸载app步数会清空,归零。
31 |
32 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion versions.compileSdk
5 | buildToolsVersion '28.0.3'
6 |
7 | defaultConfig {
8 | applicationId versions.applicationId
9 | minSdkVersion versions.minSdk
10 | targetSdkVersion versions.targetSdk
11 | versionCode change.code
12 | versionName change.name
13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
14 | }
15 | buildTypes {
16 | debug{
17 | }
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(include: ['*.jar'], dir: 'libs')
27 | implementation libraries.supportAppCompat
28 | implementation project(':lib-todaystepcounter')
29 | }
30 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/jiahongfei/Documents/DeveloperSoftware/adt-bundle-mac-x86_64-20140702/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/today/step/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.today.step;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.ServiceConnection;
7 | import android.os.Handler;
8 | import android.os.IBinder;
9 | import android.os.Message;
10 | import android.os.RemoteException;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.os.Bundle;
13 | import android.util.Log;
14 | import android.view.View;
15 | import android.widget.TextView;
16 |
17 | import com.today.step.lib.ISportStepInterface;
18 | import com.today.step.lib.TodayStepManager;
19 | import com.today.step.lib.TodayStepService;
20 |
21 | public class MainActivity extends AppCompatActivity {
22 |
23 | private static String TAG = "MainActivity";
24 |
25 | private static final int REFRESH_STEP_WHAT = 0;
26 |
27 | //循环取当前时刻的步数中间的间隔时间
28 | private long TIME_INTERVAL_REFRESH = 3000;
29 |
30 | private Handler mDelayHandler = new Handler(new TodayStepCounterCall());
31 | private int mStepSum;
32 |
33 | private ISportStepInterface iSportStepInterface;
34 |
35 | private TextView mStepArrayTextView;
36 |
37 | private TextView timeTextView;
38 |
39 | @Override
40 | protected void onCreate(Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | setContentView(R.layout.activity_main);
43 |
44 | //初始化计步模块
45 | TodayStepManager.startTodayStepService(getApplication());
46 |
47 | timeTextView = (TextView) findViewById(R.id.timeTextView);
48 | mStepArrayTextView = (TextView) findViewById(R.id.stepArrayTextView);
49 |
50 | //开启计步Service,同时绑定Activity进行aidl通信
51 | Intent intent = new Intent(this, TodayStepService.class);
52 | startService(intent);
53 | bindService(intent, new ServiceConnection() {
54 | @Override
55 | public void onServiceConnected(ComponentName name, IBinder service) {
56 | //Activity和Service通过aidl进行通信
57 | iSportStepInterface = ISportStepInterface.Stub.asInterface(service);
58 | try {
59 | mStepSum = iSportStepInterface.getCurrentTimeSportStep();
60 | updateStepCount();
61 | } catch (RemoteException e) {
62 | e.printStackTrace();
63 | }
64 | mDelayHandler.sendEmptyMessageDelayed(REFRESH_STEP_WHAT, TIME_INTERVAL_REFRESH);
65 |
66 | }
67 |
68 | @Override
69 | public void onServiceDisconnected(ComponentName name) {
70 |
71 | }
72 | }, Context.BIND_AUTO_CREATE);
73 |
74 | //计时器
75 | mhandmhandlele.post(timeRunable);
76 |
77 | }
78 |
79 | class TodayStepCounterCall implements Handler.Callback {
80 |
81 | @Override
82 | public boolean handleMessage(Message msg) {
83 | switch (msg.what) {
84 | case REFRESH_STEP_WHAT: {
85 | //每隔500毫秒获取一次计步数据刷新UI
86 | if (null != iSportStepInterface) {
87 | int step = 0;
88 | try {
89 | step = iSportStepInterface.getCurrentTimeSportStep();
90 | } catch (RemoteException e) {
91 | e.printStackTrace();
92 | }
93 | if (mStepSum != step) {
94 | mStepSum = step;
95 | updateStepCount();
96 | }
97 | }
98 | mDelayHandler.sendEmptyMessageDelayed(REFRESH_STEP_WHAT, TIME_INTERVAL_REFRESH);
99 |
100 | break;
101 | }
102 | }
103 | return false;
104 | }
105 | }
106 |
107 | private void updateStepCount() {
108 | Log.e(TAG, "updateStepCount : " + mStepSum);
109 | TextView stepTextView = (TextView) findViewById(R.id.stepTextView);
110 | stepTextView.setText(mStepSum + "步");
111 |
112 | }
113 |
114 | public void onClick(View view) {
115 | switch (view.getId()) {
116 | case R.id.stepArrayButton: {
117 | //获取所有步数列表
118 | if (null != iSportStepInterface) {
119 | try {
120 | String stepArray = iSportStepInterface.getTodaySportStepArray();
121 | mStepArrayTextView.setText(stepArray);
122 | } catch (RemoteException e) {
123 | e.printStackTrace();
124 | }
125 | }
126 | break;
127 | }
128 | default:
129 | break;
130 | }
131 | }
132 |
133 |
134 | /*****************计时器*******************/
135 | private Runnable timeRunable = new Runnable() {
136 | @Override
137 | public void run() {
138 |
139 | currentSecond = currentSecond + 1000;
140 | timeTextView.setText(getFormatHMS(currentSecond));
141 | if (!isPause) {
142 | //递归调用本runable对象,实现每隔一秒一次执行任务
143 | mhandmhandlele.postDelayed(this, 1000);
144 | }
145 | }
146 | };
147 | //计时器
148 | private Handler mhandmhandlele = new Handler();
149 | private boolean isPause = false;//是否暂停
150 | private long currentSecond = 0;//当前毫秒数
151 | /*****************计时器*******************/
152 |
153 | /**
154 | * 根据毫秒返回时分秒
155 | *
156 | * @param time
157 | * @return
158 | */
159 | public static String getFormatHMS(long time) {
160 | time = time / 1000;//总秒数
161 | int s = (int) (time % 60);//秒
162 | int m = (int) (time / 60);//分
163 | int h = (int) (time / 3600);//秒
164 | return String.format("%02d:%02d:%02d", h, m, s);
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/app/src/main/java/com/today/step/MyReceiver.java:
--------------------------------------------------------------------------------
1 | package com.today.step;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 |
6 | import com.today.step.lib.BaseClickBroadcast;
7 |
8 | public class MyReceiver extends BaseClickBroadcast {
9 |
10 | private static final String TAG = "MyReceiver";
11 |
12 | @Override
13 | public void onReceive(Context context, Intent intent) {
14 | TSApplication tsApplication = (TSApplication) context.getApplicationContext();
15 | if (!tsApplication.isForeground()) {
16 | Intent mainIntent = new Intent(context, MainActivity.class);
17 | mainIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
18 | context.startActivity(mainIntent);
19 | } else {
20 |
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/today/step/TSApplication.java:
--------------------------------------------------------------------------------
1 | package com.today.step;
2 |
3 | import android.app.Activity;
4 | import android.app.Application;
5 | import android.os.Bundle;
6 |
7 |
8 | public class TSApplication extends Application {
9 |
10 | private static TSApplication sApplication;
11 |
12 | private int appCount = 0;
13 |
14 | @Override
15 | public void onCreate() {
16 | super.onCreate();
17 |
18 | sApplication = this;
19 |
20 | registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
21 | @Override
22 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
23 |
24 | }
25 |
26 | @Override
27 | public void onActivityStarted(Activity activity) {
28 | appCount++;
29 | }
30 |
31 | @Override
32 | public void onActivityResumed(Activity activity) {
33 |
34 | }
35 |
36 | @Override
37 | public void onActivityPaused(Activity activity) {
38 |
39 | }
40 |
41 | @Override
42 | public void onActivityStopped(Activity activity) {
43 | appCount--;
44 | }
45 |
46 | @Override
47 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
48 |
49 | }
50 |
51 | @Override
52 | public void onActivityDestroyed(Activity activity) {
53 |
54 | }
55 | });
56 | }
57 |
58 | /**
59 | * app是否在前台
60 | * @return true前台,false后台
61 | */
62 | public boolean isForeground(){
63 | return appCount > 0;
64 | }
65 |
66 | public static TSApplication getApplication() {
67 | return sApplication;
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
27 |
28 |
29 |
38 |
39 |
46 |
47 |
51 |
52 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TodayStepCounter
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/base-lib-notification/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion versions.compileSdk
5 | buildToolsVersion '28.0.3'
6 |
7 | defaultConfig {
8 | minSdkVersion versions.minSdk
9 | targetSdkVersion versions.targetSdk
10 | versionCode change.code
11 | versionName change.name
12 |
13 | }
14 |
15 | buildTypes {
16 | // release {
17 | // multiDexEnabled false
18 | // minifyEnabled false
19 | // proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
20 | // }
21 | }
22 |
23 | resourcePrefix "notification_"
24 | }
25 |
26 | dependencies {
27 | implementation fileTree(dir: 'libs', include: ['*.jar'])
28 |
29 | implementation libraries.supportAppCompat
30 | implementation libraries.supportRecyclerView
31 | }
32 |
--------------------------------------------------------------------------------
/base-lib-notification/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/base-lib-notification/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/base-lib-notification/src/main/java/com/andrjhf/notification/api/compat/NotificationApiCompat.java:
--------------------------------------------------------------------------------
1 | package com.andrjhf.notification.api.compat;
2 |
3 | import android.annotation.TargetApi;
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.Context;
10 | import android.graphics.Bitmap;
11 | import android.os.Build;
12 | import android.support.v7.app.NotificationCompat;
13 | import android.text.TextUtils;
14 |
15 | public class NotificationApiCompat {
16 |
17 | private static final String TAG = "NotificationApiCompat";
18 |
19 | private final NotificationManager manager;
20 | private Notification mNotification;
21 | private final Notification.Builder mBuilder26;
22 | private final android.support.v4.app.NotificationCompat.Builder mBuilder25;
23 |
24 | public NotificationApiCompat(Builder builder) {
25 | manager = builder.manager;
26 | mNotification = builder.mNotification;
27 | mBuilder26 = builder.mBuilder26;
28 | mBuilder25 = builder.mBuilder25;
29 | }
30 |
31 | public Notification getNotificationApiCompat() {
32 | return mNotification;
33 | }
34 |
35 | public void startForeground(Service service, int id) {
36 | service.startForeground(id, mNotification);
37 |
38 | }
39 |
40 | public void stopForeground(Service service) {
41 | service.stopForeground(true);
42 | }
43 |
44 | public void notify(int id) {
45 | manager.notify(id, mNotification);
46 | }
47 |
48 | public void updateNotification( int id, String title, String text) {
49 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
50 | if (!TextUtils.isEmpty(text)) {
51 | mBuilder26.setContentText(text);
52 | }
53 | if (!TextUtils.isEmpty(title)) {
54 | mBuilder26.setContentTitle(title);
55 | }
56 | mNotification = mBuilder26.build();
57 | } else {
58 | if (!TextUtils.isEmpty(text)) {
59 | mBuilder25.setContentText(text);
60 | }
61 | if (!TextUtils.isEmpty(title)) {
62 | mBuilder25.setContentTitle(title);
63 | }
64 | mNotification = mBuilder25.build();
65 | }
66 | manager.notify(id, mNotification);
67 |
68 | }
69 |
70 | public static final class Builder {
71 |
72 | private Context mContext;
73 | private String mChannelId;
74 | private Notification mNotification;
75 | private final NotificationManager manager;
76 | private NotificationChannel mNotificationChannel;
77 | private Notification.Builder mBuilder26;
78 | private android.support.v4.app.NotificationCompat.Builder mBuilder25;
79 |
80 | public Builder(Context context, NotificationManager manager, String channelId, String channelName, int smallIcon) {
81 | mContext = context;
82 | mChannelId = channelId;
83 | this.manager = manager;
84 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
85 | mNotificationChannel = new NotificationChannel(mChannelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
86 | mBuilder26 = getChannelNotification(mContext, channelId);
87 | mBuilder26.setSmallIcon(smallIcon);
88 | } else {
89 | mBuilder25 = getNotification_25(mContext);
90 | mBuilder25.setSmallIcon(smallIcon);
91 | }
92 | }
93 |
94 | public Builder setPriority(int pri) {
95 | // mPriority = pri;
96 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
97 | } else {
98 | mBuilder25.setPriority(pri);
99 | }
100 | return this;
101 | }
102 |
103 | public Builder setLargeIcon(Bitmap icon) {
104 | // mLargeIcon = icon;
105 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
106 | mBuilder26.setLargeIcon(icon);
107 | } else {
108 | mBuilder25.setLargeIcon(icon);
109 | }
110 | return this;
111 | }
112 |
113 | public Builder setContentIntent(PendingIntent intent) {
114 | // mContentIntent = intent;
115 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
116 | mBuilder26.setContentIntent(intent);
117 | } else {
118 | mBuilder25.setContentIntent(intent);
119 | }
120 | return this;
121 | }
122 |
123 | public Builder setTicker(CharSequence tickerText) {
124 | // mTickerText = tickerText;
125 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
126 | mBuilder26.setTicker(tickerText);
127 | } else {
128 | mBuilder25.setTicker(tickerText);
129 | }
130 | return this;
131 | }
132 |
133 | public Builder setContentTitle(CharSequence title) {
134 | // mContentTitle = title;
135 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
136 | mBuilder26.setContentTitle(title);
137 | } else {
138 | mBuilder25.setContentTitle(title);
139 | }
140 | return this;
141 | }
142 |
143 | public Builder setContentText(CharSequence text) {
144 | // mContentText = text;
145 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
146 | mBuilder26.setContentText(text);
147 | } else {
148 | mBuilder25.setContentText(text);
149 | }
150 | return this;
151 | }
152 |
153 | public Builder setOngoing(boolean ongoing) {
154 | // mOngoing = ongoing;
155 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
156 | mBuilder26.setOngoing(ongoing);
157 | } else {
158 | mBuilder25.setOngoing(ongoing);
159 |
160 | }
161 | return this;
162 | }
163 |
164 | public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
165 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
166 | mBuilder26.setOnlyAlertOnce(onlyAlertOnce);
167 | } else {
168 | mBuilder25.setOnlyAlertOnce(onlyAlertOnce);
169 | }
170 | return this;
171 | }
172 |
173 | public Builder setProgress(int max, int progress, boolean indeterminate) {
174 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
175 | mBuilder26.setProgress(max, progress, indeterminate);
176 | } else {
177 | mBuilder25.setProgress(max, progress, indeterminate);
178 | }
179 | return this;
180 | }
181 |
182 | public Builder setWhen(long when) {
183 | // mNotification.when = when;
184 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
185 | mBuilder26.setWhen(when);
186 | } else {
187 | mBuilder25.setWhen(when);
188 | }
189 | return this;
190 | }
191 |
192 | public Builder setDefaults(int defaults) {
193 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
194 | // mBuilder26.setDefaults(defaults);
195 | } else {
196 | mBuilder25.setDefaults(defaults);
197 | }
198 | return this;
199 | }
200 |
201 | public Builder setAutoCancel(boolean autoCancel) {
202 | // setFlag(FLAG_AUTO_CANCEL, autoCancel);
203 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
204 | mBuilder26.setAutoCancel(autoCancel);
205 | } else {
206 | mBuilder25.setAutoCancel(autoCancel);
207 | }
208 | return this;
209 | }
210 |
211 | /**
212 | * 大于等于Android 8.0 api>=26
213 | *
214 | * @param title
215 | * @param content
216 | * @return
217 | */
218 | @TargetApi(Build.VERSION_CODES.O)
219 | private Notification.Builder getChannelNotification(Context context, String channelId) {
220 | return new Notification.Builder(context, channelId);
221 | }
222 |
223 | /**
224 | * 小于Android 8.0 api<26
225 | *
226 | * @param title
227 | * @param content
228 | * @return
229 | */
230 | private android.support.v4.app.NotificationCompat.Builder getNotification_25(Context context) {
231 | return new NotificationCompat.Builder(context);
232 | }
233 |
234 | public NotificationApiCompat builder() {
235 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
236 | manager.createNotificationChannel(mNotificationChannel);
237 | mNotification = mBuilder26.build();
238 | } else {
239 | mNotification = mBuilder25.build();
240 | }
241 | return new NotificationApiCompat(this);
242 | }
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/base-lib-notification/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/base-lib-notification/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | base-lib-notification
3 |
4 |
--------------------------------------------------------------------------------
/base-lib-notification/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | apply from: 'dependencies.gradle'
6 |
7 | repositories {
8 | jcenter()
9 | mavenCentral()
10 | google()
11 | }
12 | dependencies {
13 | classpath gradlePlugins.android
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | google()
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/dependencies.gradle:
--------------------------------------------------------------------------------
1 | ext.change = [
2 |
3 | code : 100,
4 | name : '1.1.0',
5 |
6 | ]
7 |
8 | ext.versions = [
9 |
10 | minSdk : 15,
11 | targetSdk : 26,
12 | compileSdk : 26,
13 |
14 | buildTools : '26.0.2',
15 |
16 | applicationId : "com.today.step",
17 |
18 | androidGradlePlugin : '3.2.1',
19 |
20 | supportLibs : '26.1.0',
21 | ]
22 |
23 | ext.gradlePlugins = [
24 | android : "com.android.tools.build:gradle:$versions.androidGradlePlugin",
25 | ]
26 |
27 | ext.libraries = [
28 | supportAppCompat : "com.android.support:appcompat-v7:$versions.supportLibs",
29 | supportRecyclerView : "com.android.support:recyclerview-v7:$versions.supportLibs",
30 |
31 | ]
32 |
33 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/lib-jlogger/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion versions.compileSdk
5 | buildToolsVersion '28.0.3'
6 |
7 |
8 |
9 | defaultConfig {
10 | minSdkVersion versions.minSdk
11 | targetSdkVersion versions.targetSdk
12 | versionCode change.code
13 | versionName change.name
14 |
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 |
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 |
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: 'libs', include: ['*.jar'])
30 |
31 | implementation libraries.supportAppCompat
32 | }
33 |
--------------------------------------------------------------------------------
/lib-jlogger/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/lib-jlogger/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/lib-jlogger/src/main/java/com/andrjhf/lib/jlogger/JLoggerConstant.java:
--------------------------------------------------------------------------------
1 | package com.andrjhf.lib.jlogger;
2 |
3 | public class JLoggerConstant {
4 |
5 | /**
6 | * app热启动
7 | */
8 | public static final String JLOGGER_APP_HOT_START = "jlogger_app_hot_start";
9 |
10 | /**
11 | * 设备信息
12 | * map.put("BRAND", Build.BRAND); //samsung
13 | * map.put("MANUFACTURER" , Build.MANUFACTURER);//samsung
14 | * map.put("MODEL" , Build.MODEL);//SM-G9500
15 | * map.put("PRODUCT" , Build.PRODUCT);//dreamqltezc
16 | * map.put("RELEASE" , android.os.Build.VERSION.RELEASE);//8.0.0
17 | * map.put("SDK_INT" , String.valueOf(Build.VERSION.SDK_INT));//26
18 | * map.put("APP_Version" , DeviceInfo.getAppVersion(context));
19 | * map.put("APP_Build" , DeviceInfo.getAppVersionCode(context));
20 | */
21 | public static final String JLOGGER_DEVICE_INFO = "jlogger_device_info";
22 |
23 | /**
24 | * Sensor.TYPE_STEP_COUNTER 传感器计步,定时获取传感器监听中的参数
25 | */
26 | public static final String JLOGGER_TYPE_STEP_COUNTER_TIMER = "jlogger_type_step_count_timer";
27 | /**
28 | * Sensor.TYPE_STEP_COUNTER 传感器计步,监听器构造中一些本地数据的展示
29 | */
30 | public static final String JLOGGER_TYPE_STEP_CONSTRUCTOR = "jlogger_type_step_constructor";
31 | /**
32 | * Sensor.TYPE_STEP_COUNTER 在onSensorChanged中回调,mCleanStep=true,调用了计步清零操作
33 | */
34 | public static final String JLOGGER_TYPE_STEP_CLEANSTEP = "jlogger_type_step_cleans_currStep_and_offsetStep";
35 | /**
36 | * Sensor.TYPE_STEP_COUNTER 在onSensorChanged中回调,判断出用户做了关机处理,做偏移量修改
37 | */
38 | public static final String JLOGGER_TYPE_STEP_SHUTDOWN = "jlogger_type_step_shutdown";
39 | /**
40 | * Sensor.TYPE_STEP_COUNTER 在onSensorChanged中回调,判断出sCurrStep < 0,进行容错处理,调用cleanStep()
41 | */
42 | public static final String JLOGGER_TYPE_STEP_TOLERANCE = "jlogger_type_step_tolerance";
43 | /**
44 | * TodayStepService onCreate中,最初的展示到view上的步数
45 | */
46 | public static final String JLOGGER_SERVICE_INITIALIZE_CURRSTEP = "jlogger_service_initialize_currStep";
47 | /**
48 | * TodayStepService onStartCommand中,主进程复活后,首次连接从未挂掉的服务进程,传递的参数和此时服务进程记录的步数
49 | */
50 | public static final String JLOGGER_SERVICE_ONSTARTCOMMAND = "jlogger_service_onStartCommand";
51 | /**
52 | * TodayStepService onBind中,提供给主进程的步数
53 | */
54 | public static final String JLOGGER_SERVICE_ONBIND = "jlogger_service_onBind";
55 | /**
56 | * TodayStepService,主进程复活后,连接未挂掉的服务进程,Sensor.TYPE_STEP_COUNTER已经注册过
57 | */
58 | public static final String JLOGGER_SERVICE_TYPE_STEP_COUNTER_HADREGISTER = "jlogger_service_type_step_counter_hadRegister";
59 | /**
60 | * TodayStepService,注册Sensor.TYPE_STEP_COUNTER监听
61 | */
62 | public static final String JLOGGER_SERVICE_TYPE_STEP_COUNTER_REGISTER = "jlogger_service_type_step_counter_register";
63 | /**
64 | * TodayStepService,主进程复活后,连接未挂掉的服务进程,Sensor.TYPE_ACCELEROMETER已经注册过
65 | */
66 | public static final String JLOGGER_SERVICE_TYPE_ACCELEROMETER_HADREGISTER = "jlogger_service_type_accelerometer_hadregister";
67 | /**
68 | * TodayStepService,注册Sensor.TYPE_ACCELEROMETER监听
69 | */
70 | public static final String JLOGGER_SERVICE_TYPE_ACCELEROMETER_REGISTER = "jlogger_service_type_accelerometer_register";
71 | /**
72 | * TodayStepService,数据库插入数据
73 | */
74 | public static final String JLOGGER_SERVICE_INSERT_DB = "jlogger_service_insert_db";
75 | /**
76 | * TodayStepService,清除数据库数据
77 | */
78 | public static final String JLOGGER_SERVICE_CLEAN_DB = "jlogger_service_clean_db";
79 | /**
80 | * TodayStepService,设置传感器速率
81 | */
82 | public static final String JLOGGER_SERVICE_SENSORRATE_INVOKE = "jlogger_service_sensorrate_invoke";
83 | /**
84 | * TodayStepFragment,通过onBind与Service连接
85 | */
86 | public static final String JLOGGER_FRAGMENT_ONSERVICECONNECTED = "jlogger_fragment_onServiceConnected";
87 | /**
88 | * TodayStepFragment,service手动关闭了
89 | */
90 | public static final String JLOGGER_FRAGMENT_ONSERVICEDISCONNECTED = "jlogger_fragment_onServiceDisconnected";
91 | /**
92 | * TodayStepDetector,Sensor.TYPE_ACCELEROMETER,构造函数中,本地保存的数据
93 | */
94 | public static final String JLOGGER_TYPE_ACCELEROMETER_CONSTRUCTOR = "jlogger_type_accelerometer_constructor";
95 | /**
96 | * TodayStepDetector,Sensor.TYPE_ACCELEROMETER,零点清零
97 | */
98 | public static final String JLOGGER_TYPE_ACCELEROMETER_DATECHANGECLEANSTEP = "jlogger_type_accelerometer_dateChangeCleanStep";
99 | /**
100 | * TodayStepDetector,Sensor.TYPE_ACCELEROMETER,传感器计步,定时获取传感器监听中的参数
101 | */
102 | public static final String JLOGGER_TYPE_ACCELEROMETER_TIMER = "jlogger_type_accelerometer_timer";
103 | /**
104 | * MyOrdersActivity,用户进入保单页面
105 | */
106 | public static final String JLOGGER_USER_INTO_MYORDERSACTIVITY = "jlogger_user_into_MyOrdersActivity";
107 | /**
108 | * ModuleItemTypeHealthTopWidgetAndRun,用户
109 | * */
110 | public static final String JLOGGER_USER_INTO_HEALTHFRAGMENT = "jlogger_user_into_healthFragment";
111 | /**
112 | * 用户上传步数-成功
113 | * */
114 | public static final String JLOGGER_UP_STEP_SUCCESS = "jlogger_up_step_success";
115 | /**
116 | * 用户上传步数-失败
117 | * */
118 | public static final String JLOGGER_UP_STEP_FAILURE = "jlogger_up_step_failure";
119 | /**
120 | * 触发上传步数事件--点击上传按钮
121 | * */
122 | public static final String JLOGGER_UP_STEP_BUTTON = "jlogger_up_step_button";
123 | /**
124 | * 运动历史页面
125 | * */
126 | public static final String JLOGGER_UP_STEP_HISTORY = "jlogger_up_step_history";
127 | /**
128 | * 触发上传步数事件--健康页面下拉刷新
129 | * */
130 | public static final String JLOGGER_UP_STEP_PULLDOWN= "jlogger_up_step_pullDown";
131 | /**
132 | * 触发上传步数事件--边走边赚模块
133 | * */
134 | public static final String JLOGGER_UP_STEP_HEALTHSPORTSTEP= "jlogger_up_step_healthSportStep";
135 | /**
136 | * 触发上传步数事件--边走边赚模块--领取积分
137 | * */
138 | public static final String JLOGGER_UP_STEP_GET_INTEGRAL= "jlogger_up_step_get_integral";
139 | /**
140 | * 触发上传步数事件--健康首页初始化时
141 | * */
142 | public static final String JLOGGER_UP_STEP_FIRST_INTO_HEALTHFRAGMENT= "jlogger_up_step_first_into_healthFragment";
143 | /**
144 | * 触发上传步数事件--TodayStepFragment,5分钟循环上传
145 | * */
146 | public static final String JLOGGER_UP_STEP_CIRCULATION_FIVE= "jlogger_up_step_circulation_five";
147 | /**
148 | * 触发上传步数事件--TodayStepFragment,初始化时,上传
149 | * */
150 | public static final String JLOGGER_UP_STEP_TODAYSTEPFRAGMENT_ONACTIVITYCREATED= "jlogger_up_step_TodayStepFragment_onActivityCreated";
151 | /**
152 | * 触发上传步数事件--TodayStepFragment,event触发
153 | * */
154 | public static final String JLOGGER_UP_STEP_TODAYSTEPFRAGMENT_EVENT= "jlogger_up_step_TodayStepFragment_event";
155 | /**
156 | * SportAwardActivity --进入续保奖励页面
157 | * */
158 | public static final String JLOGGER_USER_INTO_SPORTAWARDACTIVITY= "jlogger_user_into_SportAwardActivity";
159 | /**
160 | * Sensor.TYPE_STEP_COUNTER 传感器计步,时间改变了清零,或者0点分隔回调
161 | * */
162 | public static final String JLOGGER_TYPE_STEP_COUNTER_DATECHANGECLEANSTEP= "jlogger_type_step_counter_dateChangeCleanStep";
163 | /**
164 | * 用户进行了登录操作
165 | * */
166 | public static final String JLOGGER_USER_LOGIN= "jlogger_user_login";
167 | /**
168 | * Sensor.TYPE_STEP_COUNTER 传感器计步,监听器构造中一些本地数据的展示
169 | * */
170 | public static final String JLOGGER_TYPE_STEP_SHUTDOWNBYSYSTEMRUNNINGTIME= "jlogger_type_step_shutdownBySystemRunningTime";
171 | /**
172 | * TodayStepService onDestroy
173 | * */
174 | public static final String JLOGGER_TODAYSTEPSERVICE_ONDESTROY= "jlogger_TodayStepService_onDestroy";
175 | /**
176 | * TodayStepService onUnbind
177 | * */
178 | public static final String JLOGGER_TODAYSTEPSERVICE_ONUNBIND= "jlogger_TodayStepService_onUnbind";
179 | /**
180 | * Sensor.TYPE_STEP_COUNTER 传感器计步,监听器构造中一些本地数据的展示
181 | * */
182 | public static final String JLOGGER_TYPE_STEP_SHUTDOWNBYCOUNTERSTEP= "jlogger_type_step_shutdownByCounterStep";
183 | /**
184 | * TodayStepFragment 上传数据库中的运动轨迹
185 | * */
186 | public static final String JLOGGER_TODAYSTEPFRAGMENT_POSTSPORTSTEPNUM= "jlogger_TodayStepFragment_postSportStepNum";
187 | }
188 |
--------------------------------------------------------------------------------
/lib-jlogger/src/main/java/com/andrjhf/lib/jlogger/JLoggerWraper.java:
--------------------------------------------------------------------------------
1 | package com.andrjhf.lib.jlogger;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.text.TextUtils;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | public class JLoggerWraper {
12 |
13 | public static final void initXLog(Application application, String xlogPath) {
14 | String fileName = Utils.getProcessName(application);
15 | try {
16 | fileName = fileName.replace(":", "_");
17 | } catch (Exception e) {
18 | e.printStackTrace();
19 | fileName = "xlog";
20 | }
21 |
22 | // JLoggerConfig jLoggerConfig = new JLoggerConfig.XlogBuilder(
23 | // application,
24 | // fileName,
25 | // xlogPath
26 | // )
27 | // .builder();
28 | // JLogger.init(jLoggerConfig);
29 | }
30 |
31 | public synchronized static final void onEventInfo(Context context, String eventID, String label) {
32 | if (!TextUtils.isEmpty(label)) {
33 | // JLogger.i(context.getPackageName(), String.format("%s : %s", eventID, label));
34 | } else {
35 | // JLogger.i(context.getPackageName(), eventID);
36 |
37 | }
38 | }
39 |
40 | public synchronized static final void onEventInfo(Context context, String eventID) {
41 | onEventInfo(context, eventID, "");
42 | }
43 |
44 | public synchronized static final void onEventInfo(Context context, String eventID, Map map) {
45 | onEventInfo(context, eventID, map.toString());
46 | }
47 |
48 | public synchronized static final void flush() {
49 | // JLogger.flush();
50 | }
51 |
52 | public synchronized static final void deviceInfo(Context context) {
53 | Map map = new HashMap<>();
54 | map.put("BRAND", Build.BRAND); //samsung
55 | map.put("MANUFACTURER", Build.MANUFACTURER);//samsung
56 | map.put("MODEL", Build.MODEL);//SM-G9500
57 | map.put("PRODUCT", Build.PRODUCT);//dreamqltezc
58 | map.put("RELEASE", android.os.Build.VERSION.RELEASE);//8.0.0
59 | map.put("SDK_INT", String.valueOf(Build.VERSION.SDK_INT));//26
60 | map.put("APP_Version", Utils.getAppVersion(context));
61 | map.put("APP_Build", Utils.getAppVersionCode(context));
62 | //1. 手机具体型号,设备信息
63 | //2. 早上打开,晚上打开
64 | onEventInfo(context, JLoggerConstant.JLOGGER_DEVICE_INFO, map);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib-jlogger/src/main/java/com/andrjhf/lib/jlogger/Utils.java:
--------------------------------------------------------------------------------
1 | package com.andrjhf.lib.jlogger;
2 |
3 | import android.app.ActivityManager;
4 | import android.app.Application;
5 | import android.content.Context;
6 | import android.content.pm.PackageInfo;
7 | import android.content.pm.PackageManager;
8 | import android.util.Log;
9 |
10 | public class Utils {
11 |
12 | public static String getProcessName(Application application) {
13 | int pid = android.os.Process.myPid();
14 | String processName = "";
15 | ActivityManager manager = (ActivityManager) application.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
16 | for (ActivityManager.RunningAppProcessInfo process : manager.getRunningAppProcesses()) {
17 | if (process.pid == pid) {
18 | processName = process.processName;
19 | }
20 | }
21 |
22 | Log.d("", "application start,processName:" + processName);
23 | return processName;
24 | }
25 |
26 | /**
27 | * @brief 获取versionName
28 | *
29 | * @param context
30 | * @return
31 | */
32 | public static String getAppVersion(Context context) {
33 | // 获取packagemanager的实例
34 | PackageManager packageManager = context.getPackageManager();
35 | // getPackageName()是你当前类的包名,0代表是获取版本信息
36 | PackageInfo packInfo = null;
37 | try {
38 | packInfo = packageManager.getPackageInfo(context.getPackageName(),0);
39 | } catch (PackageManager.NameNotFoundException e) {
40 | e.printStackTrace();
41 | }
42 | String version = packInfo.versionName;
43 | return version;
44 | }
45 |
46 | /**
47 | * @brief 获取versionCode
48 | *
49 | * @param context
50 | * @return
51 | */
52 | public static String getAppVersionCode(Context context) {
53 | // 获取packagemanager的实例
54 | PackageManager packageManager = context.getPackageManager();
55 | // getPackageName()是你当前类的包名,0代表是获取版本信息
56 | PackageInfo packInfo = null;
57 | try {
58 | packInfo = packageManager.getPackageInfo(context.getPackageName(),0);
59 | } catch (PackageManager.NameNotFoundException e) {
60 | e.printStackTrace();
61 | }
62 | String version = packInfo.versionCode + "";
63 | return version;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/lib-jlogger/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | lib_jlogger
3 |
4 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion versions.compileSdk
5 | buildToolsVersion '28.0.3'
6 |
7 | defaultConfig {
8 | minSdkVersion versions.minSdk
9 | targetSdkVersion versions.targetSdk
10 | versionCode change.code
11 | versionName change.name
12 |
13 | }
14 | buildTypes {
15 | debug {
16 | buildConfigField "boolean", "TODAY_STEP_DEBUG", "true"
17 | }
18 | release {
19 | buildConfigField "boolean", "TODAY_STEP_DEBUG", "true"
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | }
25 |
26 | dependencies {
27 | compile fileTree(include: ['*.jar'], dir: 'libs')
28 | compile libraries.supportAppCompat
29 | implementation project(':base-lib-notification')
30 | implementation project(':lib-jlogger')
31 | // implementation project(':lib-encrypt')
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/jiahongfei/Documents/DeveloperSoftware/adt-bundle-mac-x86_64-20140702/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
17 |
18 |
19 |
20 |
21 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/aidl/com/today/step/lib/ISportStepInterface.aidl:
--------------------------------------------------------------------------------
1 | // ISportStepInterface.aidl
2 | package com.today.step.lib;
3 |
4 | interface ISportStepInterface {
5 | /**
6 | * 获取当前时间运动步数
7 | */
8 | int getCurrentTimeSportStep();
9 |
10 | /**
11 | * 获取所有步数列表,json格式,如果数据过多建议在线程中获取,否则会阻塞UI线程
12 | */
13 | String getTodaySportStepArray();
14 | }
15 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/BaseClickBroadcast.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.content.BroadcastReceiver;
4 |
5 | /**
6 | * 通知栏点击通知
7 | * Created by jiahongfei on 2017/10/19.
8 | */
9 |
10 | public abstract class BaseClickBroadcast extends BroadcastReceiver {
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/ConstantDef.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | /**
4 | * @author : jiahongfei
5 | * @email : jiahongfeinew@163.com
6 | * @date : 2018/12/25
7 | * @desc : 计步公共常量
8 | */
9 | public class ConstantDef {
10 |
11 | /**
12 | * 打印JLogger日志
13 | */
14 | public static final int HANDLER_WHAT_TEST_JLOGGER = 0;
15 | /**
16 | * 打印JLogger日志时间
17 | */
18 | public static final int WHAT_TEST_JLOGGER_DURATION = 1000*60*5;//5分钟
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/DateUtils.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import java.text.ParseException;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Date;
6 |
7 | /**
8 | * @Description: 时间工具类(时间格式转换方便类)
9 | */
10 | class DateUtils {
11 |
12 | private static ThreadLocal SIMPLE_DATE_FORMAT = new ThreadLocal<>();
13 |
14 | public static SimpleDateFormat getDateFormat() {
15 | SimpleDateFormat df = SIMPLE_DATE_FORMAT.get();
16 | if (df == null) {
17 | df = new SimpleDateFormat();
18 | SIMPLE_DATE_FORMAT.set(df);
19 | }
20 | return df;
21 | }
22 |
23 | /**
24 | * 返回一定格式的当前时间
25 | *
26 | * @param pattern "yyyy-MM-dd HH:mm:ss E"
27 | * @return
28 | */
29 | public static String getCurrentDate(String pattern) {
30 | getDateFormat().applyPattern(pattern);
31 | Date date = new Date(System.currentTimeMillis());
32 | String dateString = getDateFormat().format(date);
33 | return dateString;
34 |
35 | }
36 |
37 | public static long getDateMillis(String dateString, String pattern) {
38 | long millionSeconds = 0;
39 | getDateFormat().applyPattern(pattern);
40 | try {
41 | millionSeconds = getDateFormat().parse(dateString).getTime();
42 | } catch (ParseException e) {
43 | e.printStackTrace();
44 | }// 毫秒
45 |
46 | return millionSeconds;
47 | }
48 |
49 | /**
50 | * 格式化输入的millis
51 | *
52 | * @param millis
53 | * @param pattern yyyy-MM-dd HH:mm:ss E
54 | * @return
55 | */
56 | public static String dateFormat(long millis, String pattern) {
57 | getDateFormat().applyPattern(pattern);
58 | Date date = new Date(millis);
59 | String dateString = getDateFormat().format(date);
60 | return dateString;
61 | }
62 |
63 | /**
64 | * 将dateString原来old格式转换成new格式
65 | *
66 | * @param dateString
67 | * @param oldPattern yyyy-MM-dd HH:mm:ss E
68 | * @param newPattern
69 | * @return oldPattern和dateString形式不一样直接返回dateString
70 | */
71 | public static String dateFormat(String dateString, String oldPattern,
72 | String newPattern) {
73 | long millis = getDateMillis(dateString, oldPattern);
74 | if (0 == millis) {
75 | return dateString;
76 | }
77 | String date = dateFormat(millis, newPattern);
78 | return date;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/ITodayStepDBHelper.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import java.util.List;
4 |
5 |
6 | interface ITodayStepDBHelper {
7 |
8 | void createTable();
9 |
10 | void deleteTable();
11 |
12 | void clearCapacity(String curDate, int limit);
13 |
14 | boolean isExist(TodayStepData todayStepData);
15 |
16 | void insert(TodayStepData todayStepData);
17 |
18 | TodayStepData getMaxStepByDate(long millis);
19 |
20 | List getQueryAll();
21 |
22 | List getStepListByDate(String dateString);
23 |
24 | List getStepListByStartDateAndDays(String startDate, int days);
25 | }
26 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/OnStepCounterListener.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | /**
4 | * Created by jiahongfei on 2017/6/30.
5 | */
6 |
7 | public interface OnStepCounterListener {
8 |
9 | /**
10 | * 用于显示步数
11 | * @param step
12 | */
13 | void onChangeStepCounter(int step);
14 |
15 | /**
16 | * 步数清零监听,由于跨越0点需要重新计步
17 | */
18 | void onStepCounterClean();
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/PreferencesHelper.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 |
6 |
7 | /**
8 | * @ClassName: PreferencesHelper
9 | * @Description: (公用类 , 用于缓存一些key — — value类型的数据)
10 | */
11 |
12 | class PreferencesHelper {
13 |
14 | private static final String TAG = "PreferencesHelper";
15 |
16 | public static final String APP_SHARD = "today_step_share_prefs";
17 |
18 | // 上一次计步器的步数
19 | public static final String LAST_SENSOR_TIME = "last_sensor_time";
20 | // 步数补偿数值,每次传感器返回的步数-offset=当前步数
21 | public static final String STEP_OFFSET = "step_offset";
22 | // 当天,用来判断是否跨天
23 | public static final String STEP_TODAY = "step_today";
24 | // 清除步数
25 | public static final String CLEAN_STEP = "clean_step";
26 | // 当前步数
27 | public static final String CURR_STEP = "curr_step";
28 | //手机关机监听
29 | public static final String SHUTDOWN = "shutdown";
30 | //系统运行时间
31 | public static final String ELAPSED_REALTIMEl = "elapsed_realtime";
32 |
33 | /**
34 | * Get SharedPreferences
35 | */
36 | private static SharedPreferences getSharedPreferences(Context context) {
37 | return context.getSharedPreferences(APP_SHARD, Context.MODE_PRIVATE);
38 | }
39 |
40 | public static void setLastSensorStep(Context context, float lastSensorStep) {
41 | getSharedPreferences(context).edit().putFloat(LAST_SENSOR_TIME, lastSensorStep).commit();
42 | }
43 |
44 | public static float getLastSensorStep(Context context) {
45 | return getSharedPreferences(context).getFloat(LAST_SENSOR_TIME, 0.0f);
46 | }
47 |
48 |
49 | public static void setStepOffset(Context context, float stepOffset) {
50 | getSharedPreferences(context).edit().putFloat(STEP_OFFSET, stepOffset).commit();
51 | }
52 |
53 | public static float getStepOffset(Context context) {
54 | return getSharedPreferences(context).getFloat(STEP_OFFSET, 0.0f);
55 | }
56 |
57 | public static void setStepToday(Context context, String stepToday) {
58 | getSharedPreferences(context).edit().putString(STEP_TODAY, stepToday).commit();
59 | }
60 |
61 | public static String getStepToday(Context context) {
62 | return getSharedPreferences(context).getString(STEP_TODAY, "");
63 | }
64 |
65 | /**
66 | * true清除步数从0开始,false否
67 | *
68 | * @param context
69 | * @param cleanStep
70 | */
71 | public static void setCleanStep(Context context, boolean cleanStep) {
72 | getSharedPreferences(context).edit().putBoolean(CLEAN_STEP, cleanStep).commit();
73 | }
74 |
75 | /**
76 | * true 清除步数,false否
77 | *
78 | * @param context
79 | * @return
80 | */
81 | public static boolean getCleanStep(Context context) {
82 | return getSharedPreferences(context).getBoolean(CLEAN_STEP, true);
83 | }
84 |
85 | public static void setCurrentStep(Context context, float currStep) {
86 | getSharedPreferences(context).edit().putFloat(CURR_STEP, currStep).commit();
87 | }
88 |
89 | public static float getCurrentStep(Context context) {
90 | return getSharedPreferences(context).getFloat(CURR_STEP, 0.0f);
91 | }
92 |
93 | public static void setShutdown(Context context, boolean shutdown) {
94 | getSharedPreferences(context).edit().putBoolean(SHUTDOWN, shutdown).commit();
95 | }
96 |
97 | public static boolean getShutdown(Context context) {
98 | return getSharedPreferences(context).getBoolean(SHUTDOWN, false);
99 | }
100 |
101 | public static void setElapsedRealtime(Context context, long elapsedRealtime) {
102 | getSharedPreferences(context).edit().putLong(ELAPSED_REALTIMEl, elapsedRealtime).commit();
103 | }
104 |
105 | public static long getElapsedRealtime(Context context) {
106 | return getSharedPreferences(context).getLong(ELAPSED_REALTIMEl, 0L);
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/SportStepJsonUtils.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | import java.util.List;
8 |
9 | public class SportStepJsonUtils {
10 |
11 | public static final String SPORT_DATE = "sportDate";
12 | public static final String STEP_NUM = "stepNum";
13 | public static final String DISTANCE = "km";
14 | public static final String CALORIE = "kaluli";
15 | public static final String TODAY = TodayStepDBHelper.TODAY;
16 |
17 | static JSONArray getSportStepJsonArray(List todayStepDataArrayList) {
18 | JSONArray jsonArray = new JSONArray();
19 | if (null == todayStepDataArrayList || 0 == todayStepDataArrayList.size()) {
20 | return jsonArray;
21 | }
22 | for (int i = 0; i < todayStepDataArrayList.size(); i++) {
23 | TodayStepData todayStepData = todayStepDataArrayList.get(i);
24 | try {
25 | JSONObject subObject = getJSONObject(todayStepData);
26 | jsonArray.put(subObject);
27 | } catch (JSONException e) {
28 | e.printStackTrace();
29 | }
30 | }
31 | return jsonArray;
32 | }
33 |
34 | static JSONObject getJSONObject(TodayStepData todayStepData) throws JSONException{
35 | JSONObject subObject = new JSONObject();
36 | subObject.put(TODAY, todayStepData.getToday());
37 | subObject.put(SPORT_DATE, todayStepData.getDate()/1000);
38 | subObject.put(STEP_NUM, todayStepData.getStep());
39 | subObject.put(DISTANCE, getDistanceByStep(todayStepData.getStep()));
40 | subObject.put(CALORIE, getCalorieByStep(todayStepData.getStep()));
41 | return subObject;
42 | }
43 |
44 | // 公里计算公式
45 | static String getDistanceByStep(long steps) {
46 | return String.format("%.2f", steps * 0.6f / 1000);
47 | }
48 |
49 | // 千卡路里计算公式
50 | static String getCalorieByStep(long steps) {
51 | return String.format("%.1f", steps * 0.6f * 60 * 1.036f / 1000);
52 | }
53 |
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/StepUtil.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import java.util.Date;
4 |
5 | public class StepUtil {
6 |
7 | /**
8 | * 是否上传步数,23:55:50~00:05:50分无法上传步数
9 | *
10 | * @return true可以上传,false不能上传
11 | */
12 | public static boolean isUploadStep() {
13 |
14 | Date curDate = new Date(System.currentTimeMillis());
15 |
16 | long mills2355 = DateUtils.getDateMillis(DateUtils.getCurrentDate("yyyy-MM-dd") + " 23:55:50", "yyyy-MM-dd HH:mm:ss");
17 | Date date2355 = new Date(mills2355);
18 |
19 | if (curDate.after(date2355)) {
20 | return false;
21 | }
22 |
23 | long mills0005 = DateUtils.getDateMillis(DateUtils.getCurrentDate("yyyy-MM-dd") + " 00:05:50", "yyyy-MM-dd HH:mm:ss");
24 | Date date0005 = new Date(mills0005);
25 |
26 | if (curDate.before(date0005)) {
27 | return false;
28 | }
29 |
30 | return true;
31 | }
32 |
33 | /**
34 | * 是否先上传步数在跳转,23:59:00~00:01:00分直接跳转不上传步数
35 | *
36 | * @return true上传后跳转,false直接跳转
37 | */
38 | public static boolean isUploadStepGoto() {
39 |
40 | Date curDate = new Date(System.currentTimeMillis());
41 |
42 | long mills2355 = DateUtils.getDateMillis(DateUtils.getCurrentDate("yyyy-MM-dd") + " 23:59:00", "yyyy-MM-dd HH:mm:ss");
43 | Date date2355 = new Date(mills2355);
44 |
45 | if (curDate.after(date2355)) {
46 | return false;
47 | }
48 |
49 | long mills0005 = DateUtils.getDateMillis(DateUtils.getCurrentDate("yyyy-MM-dd") + " 00:01:00", "yyyy-MM-dd HH:mm:ss");
50 | Date date0005 = new Date(mills0005);
51 |
52 | if (curDate.before(date0005)) {
53 | return false;
54 | }
55 |
56 | return true;
57 | }
58 |
59 | /**
60 | * 23:30:00~00:05:00分隐藏tips
61 | *
62 | * @return true上传后跳转,false直接跳转
63 | */
64 | public static boolean isHealthTipsHide() {
65 |
66 | Date curDate = new Date(System.currentTimeMillis());
67 |
68 | long mills2355 = DateUtils.getDateMillis(DateUtils.getCurrentDate("yyyy-MM-dd") + " 23:30:00", "yyyy-MM-dd HH:mm:ss");
69 | Date date2355 = new Date(mills2355);
70 |
71 | if (curDate.after(date2355)) {
72 | return false;
73 | }
74 |
75 | long mills0005 = DateUtils.getDateMillis(DateUtils.getCurrentDate("yyyy-MM-dd") + " 00:05:00", "yyyy-MM-dd HH:mm:ss");
76 | Date date0005 = new Date(mills0005);
77 |
78 | if (curDate.before(date0005)) {
79 | return false;
80 | }
81 |
82 | return true;
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/TodayStepBootCompleteReceiver.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.support.v4.content.ContextCompat;
7 |
8 | /**
9 | * 开机完成广播
10 | */
11 | public class TodayStepBootCompleteReceiver extends BroadcastReceiver {
12 |
13 | private static final String TAG = "TodayStepBootCompleteReceiver";
14 |
15 | @Override
16 | public void onReceive(Context context, Intent intent) {
17 |
18 | try {
19 | Intent todayStepIntent = new Intent(context, TodayStepService.class);
20 | todayStepIntent.putExtra(TodayStepService.INTENT_NAME_BOOT, true);
21 | ContextCompat.startForegroundService(context,todayStepIntent);
22 |
23 | } catch (Exception e) {
24 | e.printStackTrace();
25 | // https://stackoverflow.com/questions/38764497/security-exception-unable-to-start-service-user-0-is-restricted
26 | // 经过和OPPO工程师沟通,这个问题的原因是OPPO手机自动熄屏一段时间后,会启用系统自带的电量优化管理,
27 | // 禁止一切自启动的APP(用户设置的自启动白名单除外)。所以,类似的崩溃常常集中在用户休息之后的夜里或者凌晨,
28 | // 但是并不影响用户平时的正常使用。至于会出现user 0 is restricted,我觉得是coloros系统电量优化管理做得不好的地方。
29 | // 对coloros官方的处理建议:既然禁止自启动,那么干脆直接force stop对应的进程,而不是抛出RuntimeException来让开发者买单。
30 | // 对开发者处理建议:在服务启动的地方进行try catch防止崩溃即可(也是“1元夺宝”APP目前的处理方式)
31 | }
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/TodayStepCounter.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.IntentFilter;
7 | import android.hardware.Sensor;
8 | import android.hardware.SensorEvent;
9 | import android.hardware.SensorEventListener;
10 | import android.os.BatteryManager;
11 | import android.os.Build;
12 | import android.os.Handler;
13 | import android.os.Message;
14 | import android.os.PowerManager;
15 | import android.os.SystemClock;
16 | import android.util.Log;
17 |
18 | import com.andrjhf.lib.jlogger.JLoggerConstant;
19 | import com.andrjhf.lib.jlogger.JLoggerWraper;
20 |
21 | import java.util.HashMap;
22 | import java.util.Map;
23 |
24 | import static com.today.step.lib.ConstantDef.HANDLER_WHAT_TEST_JLOGGER;
25 | import static com.today.step.lib.ConstantDef.WHAT_TEST_JLOGGER_DURATION;
26 |
27 | /**
28 | * Sensor.TYPE_STEP_COUNTER
29 | * 计步传感器计算当天步数,不需要后台Service
30 | * Created by jiahongfei on 2017/6/30.
31 | */
32 |
33 | class TodayStepCounter implements SensorEventListener {
34 |
35 | private static final String TAG = "TodayStepCounter";
36 |
37 | private int sOffsetStep = 0;
38 | private int sCurrStep = 0;
39 | private String mTodayDate;
40 | private boolean mCleanStep = true;
41 | private boolean mShutdown = false;
42 | /**
43 | * 用来标识对象第一次创建,
44 | */
45 | private boolean mCounterStepReset = true;
46 |
47 | private Context mContext;
48 | private OnStepCounterListener mOnStepCounterListener;
49 |
50 | private boolean mSeparate = false;
51 | private boolean mBoot = false;
52 |
53 | private float mJLoggerSensorStep = 0f;
54 | private int mJLoggerCounterStep = 0;
55 | private int mJLoggerCurrStep = 0;
56 | private int mJLoggerOffsetStep = 0;
57 | /**
58 | * 传感器回调次数
59 | */
60 | private long mJLoggerSensorCount = 0;
61 |
62 | private final Handler sHandler = new Handler(new Handler.Callback() {
63 | @Override
64 | public boolean handleMessage(Message msg) {
65 | switch (msg.what){
66 | case HANDLER_WHAT_TEST_JLOGGER:{
67 | HashMap map = new HashMap<>();
68 | map.put("sCurrStep",String.valueOf(mJLoggerCurrStep));
69 | map.put("counterStep",String.valueOf(mJLoggerCounterStep));
70 | map.put("SensorStep",String.valueOf(mJLoggerSensorStep));
71 | map.put("sOffsetStep",String.valueOf(mJLoggerOffsetStep));
72 | map.put("SensorCount",String.valueOf(mJLoggerSensorCount));
73 | //增加电量、息屏状态
74 | int battery = getBattery();
75 | if(battery!=-1){
76 | map.put("battery",String.valueOf(battery));
77 | }
78 | map.put("isScreenOn",String.valueOf(getScreenState()));
79 | Log.e("wcd_map",map.toString());
80 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_STEP_COUNTER_TIMER,map);
81 | sHandler.removeMessages(HANDLER_WHAT_TEST_JLOGGER);
82 | sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_TEST_JLOGGER,WHAT_TEST_JLOGGER_DURATION);
83 | break;
84 | }
85 | }
86 | return false;
87 | }
88 | });
89 |
90 | public TodayStepCounter(Context context, OnStepCounterListener onStepCounterListener, boolean separate, boolean boot) {
91 | this.mContext = context;
92 | this.mSeparate = separate;
93 | this.mBoot = boot;
94 | this.mOnStepCounterListener = onStepCounterListener;
95 |
96 | WakeLockUtils.getLock(mContext);
97 |
98 | sCurrStep = (int) PreferencesHelper.getCurrentStep(mContext);
99 | mCleanStep = PreferencesHelper.getCleanStep(mContext);
100 | mTodayDate = PreferencesHelper.getStepToday(mContext);
101 | sOffsetStep = (int) PreferencesHelper.getStepOffset(mContext);
102 | mShutdown = PreferencesHelper.getShutdown(mContext);
103 | //开机启动监听到,一定是关机开机了
104 | boolean isShutdown = shutdownBySystemRunningTime();
105 | if (mBoot || isShutdown) {
106 | mShutdown = true;
107 | PreferencesHelper.setShutdown(mContext, mShutdown);
108 | }
109 | HashMap map = new HashMap<>();
110 | map.put("sCurrStep",String.valueOf(sCurrStep));
111 | map.put("mCleanStep",String.valueOf(mCleanStep));
112 | map.put("mTodayDate",String.valueOf(mTodayDate));
113 | map.put("sOffsetStep",String.valueOf(sOffsetStep));
114 | map.put("mShutdown",String.valueOf(mShutdown));
115 | map.put("isShutdown",String.valueOf(isShutdown));
116 | map.put("lastSensorStep",String.valueOf(PreferencesHelper.getLastSensorStep(mContext)));
117 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_STEP_CONSTRUCTOR,map);
118 |
119 | dateChangeCleanStep();
120 |
121 | initBroadcastReceiver();
122 |
123 | updateStepCounter();
124 |
125 | //启动JLogger日志打印
126 | sHandler.removeMessages(HANDLER_WHAT_TEST_JLOGGER);
127 | sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_TEST_JLOGGER,WHAT_TEST_JLOGGER_DURATION);
128 | }
129 |
130 | private void initBroadcastReceiver() {
131 | final IntentFilter filter = new IntentFilter();
132 | filter.addAction(Intent.ACTION_TIME_TICK);
133 | filter.addAction(Intent.ACTION_DATE_CHANGED);
134 | BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() {
135 | @Override
136 | public void onReceive(final Context context, final Intent intent) {
137 | if (Intent.ACTION_TIME_TICK.equals(intent.getAction())
138 | || Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
139 | //service存活做0点分隔
140 | dateChangeCleanStep();
141 |
142 | }
143 | }
144 | };
145 | mContext.registerReceiver(mBatInfoReceiver, filter);
146 |
147 | }
148 |
149 | @Override
150 | public void onSensorChanged(SensorEvent event) {
151 |
152 | if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
153 |
154 | int counterStep = (int) event.values[0];
155 |
156 | if (mCleanStep) {
157 | //TODO:只有传感器回调才会记录当前传感器步数,然后对当天步数进行清零,所以步数会少,少的步数等于传感器启动需要的步数,假如传感器需要10步进行启动,那么就少10步
158 | Map map = new HashMap<>();
159 | map.put("clean_before_sCurrStep",String.valueOf(sCurrStep));
160 | map.put("clean_before_sOffsetStep",String.valueOf(sOffsetStep));
161 | map.put("clean_before_mCleanStep",String.valueOf(mCleanStep));
162 | cleanStep(counterStep);
163 | map.put("clean_after_sCurrStep",String.valueOf(sCurrStep));
164 | map.put("clean_after_sOffsetStep",String.valueOf(sOffsetStep));
165 | map.put("clean_after_mCleanStep",String.valueOf(mCleanStep));
166 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_STEP_CLEANSTEP,map);
167 | } else {
168 | //处理关机启动
169 | if (mShutdown || shutdownByCounterStep(counterStep)) {
170 | Map map = new HashMap<>();
171 | map.put("shutdown_before_mShutdown",String.valueOf(mShutdown));
172 | map.put("shutdown_before_mCounterStepReset",String.valueOf(mCounterStepReset));
173 | map.put("shutdown_before_sOffsetStep",String.valueOf(sOffsetStep));
174 | shutdown(counterStep);
175 | map.put("shutdown_after_mShutdown",String.valueOf(mShutdown));
176 | map.put("shutdown_after_mCounterStepReset",String.valueOf(mCounterStepReset));
177 | map.put("shutdown_after_sOffsetStep",String.valueOf(sOffsetStep));
178 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_STEP_SHUTDOWN,map);
179 | }
180 | }
181 | sCurrStep = counterStep - sOffsetStep;
182 |
183 | if (sCurrStep < 0) {
184 | Map map = new HashMap<>();
185 | map.put("tolerance_before_counterStep",String.valueOf(counterStep));
186 | map.put("tolerance_before_sCurrStep",String.valueOf(sCurrStep));
187 | map.put("tolerance_before_sOffsetStep",String.valueOf(sOffsetStep));
188 | //容错处理,无论任何原因步数不能小于0,如果小于0,直接清零
189 | cleanStep(counterStep);
190 | map.put("tolerance_after_counterStep",String.valueOf(counterStep));
191 | map.put("tolerance_after_sCurrStep",String.valueOf(sCurrStep));
192 | map.put("tolerance_after_sOffsetStep",String.valueOf(sOffsetStep));
193 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_STEP_TOLERANCE,map);
194 | }
195 |
196 | PreferencesHelper.setCurrentStep(mContext, sCurrStep);
197 | PreferencesHelper.setElapsedRealtime(mContext, SystemClock.elapsedRealtime());
198 | PreferencesHelper.setLastSensorStep(mContext, counterStep);
199 |
200 | mJLoggerSensorStep = event.values[0];
201 | mJLoggerCounterStep = counterStep;
202 | mJLoggerCurrStep = sCurrStep;
203 | mJLoggerOffsetStep = sOffsetStep;
204 | updateStepCounter();
205 | if(mJLoggerSensorCount==0){
206 | sHandler.removeMessages(HANDLER_WHAT_TEST_JLOGGER);
207 | sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_TEST_JLOGGER,800);
208 | }
209 | //用来判断传感器是否回调
210 | mJLoggerSensorCount++;
211 |
212 | }
213 | }
214 |
215 | private void cleanStep(int counterStep) {
216 | //清除步数,步数归零,优先级最高
217 | sCurrStep = 0;
218 | sOffsetStep = counterStep;
219 | PreferencesHelper.setStepOffset(mContext, sOffsetStep);
220 |
221 | mCleanStep = false;
222 | PreferencesHelper.setCleanStep(mContext, mCleanStep);
223 | mJLoggerCurrStep = sCurrStep;
224 | mJLoggerOffsetStep = sOffsetStep;
225 | }
226 |
227 | private void shutdown(int counterStep) {
228 | int tmpCurrStep = (int) PreferencesHelper.getCurrentStep(mContext);
229 | //重新设置offset
230 | sOffsetStep = counterStep - tmpCurrStep;
231 | //TODO 只有在当天进行过关机,才会进入到这,直接置反??@老大
232 | // sOffsetStep = -tmpCurrStep;
233 | PreferencesHelper.setStepOffset(mContext, sOffsetStep);
234 |
235 | mShutdown = false;
236 | PreferencesHelper.setShutdown(mContext, mShutdown);
237 | }
238 |
239 | private boolean shutdownByCounterStep(int counterStep) {
240 | if (mCounterStepReset) {
241 | //只判断一次
242 | mCounterStepReset = false;
243 | if (counterStep < PreferencesHelper.getLastSensorStep(mContext)) {
244 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_STEP_SHUTDOWNBYCOUNTERSTEP,"当前传感器步数小于上次传感器步数");
245 | //当前传感器步数小于上次传感器步数肯定是重新启动了,只是用来增加精度不是绝对的
246 | // Logger.e(TAG, "当前传感器步数小于上次传感器步数肯定是重新启动了,只是用来增加精度不是绝对的");
247 | return true;
248 | }
249 | }
250 | return false;
251 | }
252 |
253 | private boolean shutdownBySystemRunningTime() {
254 | if (PreferencesHelper.getElapsedRealtime(mContext) > SystemClock.elapsedRealtime()) {
255 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_STEP_SHUTDOWNBYSYSTEMRUNNINGTIME,"本地记录的时间,判断进行了关机操作");
256 | //上次运行的时间大于当前运行时间判断为重启,只是增加精度,极端情况下连续重启,会判断不出来
257 | // Logger.e(TAG, "上次运行的时间大于当前运行时间判断为重启,只是增加精度,极端情况下连续重启,会判断不出来");
258 | return true;
259 | }
260 | return false;
261 | }
262 |
263 | private synchronized void dateChangeCleanStep(){
264 |
265 | //时间改变了清零,或者0点分隔回调
266 | if (!getTodayDate().equals(mTodayDate) || mSeparate) {
267 | HashMap map = new HashMap<>();
268 | map.put("getTodayDate()",String.valueOf(getTodayDate()));
269 | map.put("mTodayDate",mTodayDate);
270 | map.put("mSeparate",String.valueOf(mSeparate));
271 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_STEP_COUNTER_DATECHANGECLEANSTEP,map);
272 | WakeLockUtils.getLock(mContext);
273 |
274 | mCleanStep = true;
275 | PreferencesHelper.setCleanStep(mContext, mCleanStep);
276 |
277 | mTodayDate = getTodayDate();
278 | PreferencesHelper.setStepToday(mContext, mTodayDate);
279 |
280 | mShutdown = false;
281 | PreferencesHelper.setShutdown(mContext, mShutdown);
282 |
283 | mBoot = false;
284 |
285 | mSeparate = false;
286 |
287 | sCurrStep = 0;
288 | PreferencesHelper.setCurrentStep(mContext, sCurrStep);
289 |
290 | mJLoggerSensorCount = 0;
291 | mJLoggerCurrStep = sCurrStep;
292 |
293 | if(null != mOnStepCounterListener){
294 | mOnStepCounterListener.onStepCounterClean();
295 | }
296 | }
297 | }
298 |
299 | private String getTodayDate() {
300 | return DateUtils.getCurrentDate("yyyy-MM-dd");
301 | }
302 |
303 | private void updateStepCounter() {
304 |
305 | //每次回调都判断一下是否跨天
306 | dateChangeCleanStep();
307 |
308 | if (null != mOnStepCounterListener) {
309 | mOnStepCounterListener.onChangeStepCounter(sCurrStep);
310 | }
311 | }
312 |
313 | public int getCurrentStep(){
314 | sCurrStep = (int) PreferencesHelper.getCurrentStep(mContext);
315 | return sCurrStep;
316 | }
317 |
318 | @Override
319 | public void onAccuracyChanged(Sensor sensor, int accuracy) {
320 |
321 | }
322 | private int getBattery(){
323 | BatteryManager batteryManager = (BatteryManager)mContext.getSystemService(Context.BATTERY_SERVICE);
324 | int battery = -1;
325 | if(Build.VERSION.SDK_INT >=Build.VERSION_CODES.LOLLIPOP){
326 | battery = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
327 | }
328 | return battery;
329 | }
330 | private boolean getScreenState(){
331 | PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
332 | return pm.isScreenOn();
333 | }
334 | }
335 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/TodayStepDBHelper.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteDatabase;
7 | import android.database.sqlite.SQLiteOpenHelper;
8 | import android.util.Log;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Calendar;
12 | import java.util.HashSet;
13 | import java.util.List;
14 | import java.util.Set;
15 |
16 | /**
17 | * 用来记录当天步数列表,传感器回调30次记录一条数据
18 | * Created by jiahongfei on 2017/10/9.
19 | */
20 |
21 | class TodayStepDBHelper extends SQLiteOpenHelper implements ITodayStepDBHelper {
22 |
23 | private static final String TAG = "TodayStepDBHelper";
24 |
25 | private static final String DATE_PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
26 |
27 | private static final int VERSION = 1;
28 | private static final String DATABASE_NAME = "TodayStepDB.db";
29 | private static final String TABLE_NAME = "TodayStepData";
30 | private static final String PRIMARY_KEY = "_id";
31 | public static final String TODAY = "today";
32 | public static final String DATE = "date";
33 | public static final String STEP = "step";
34 |
35 | private static final String SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
36 | + PRIMARY_KEY + " INTEGER PRIMARY KEY AUTOINCREMENT, "
37 | + TODAY + " TEXT, "
38 | + DATE + " long, "
39 | + STEP + " long);";
40 | private static final String SQL_DELETE_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;
41 | private static final String SQL_QUERY_ALL = "SELECT * FROM " + TABLE_NAME;
42 | private static final String SQL_QUERY_STEP = "SELECT * FROM " + TABLE_NAME + " WHERE " + TODAY + " = ? AND " + STEP + " = ?";
43 | private static final String SQL_QUERY_STEP_BY_DATE = "SELECT * FROM " + TABLE_NAME + " WHERE " + TODAY + " = ?";
44 | private static final String SQL_DELETE_TODAY = "DELETE FROM " + TABLE_NAME + " WHERE " + TODAY + " = ?";
45 | private static final String SQL_QUERY_STEP_ORDER_BY = "SELECT * FROM " + TABLE_NAME + " WHERE " + TODAY + " = ? ORDER BY " + STEP + " DESC";
46 |
47 | //只保留mLimit天的数据
48 | private int mLimit = -1;
49 |
50 | public static ITodayStepDBHelper factory(Context context) {
51 | return new TodayStepDBHelper(context);
52 | }
53 |
54 | private TodayStepDBHelper(Context context) {
55 | super(context, DATABASE_NAME, null, VERSION);
56 | }
57 |
58 | @Override
59 | public void onCreate(SQLiteDatabase db) {
60 | db.execSQL(SQL_CREATE_TABLE);
61 | }
62 |
63 | @Override
64 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
65 | deleteTable();
66 | onCreate(db);
67 | }
68 |
69 | @Override
70 | public synchronized boolean isExist(TodayStepData todayStepData) {
71 | Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_STEP, new String[]{todayStepData.getToday(), todayStepData.getStep() + ""});
72 | boolean exist = cursor.getCount() > 0 ? true : false;
73 | cursor.close();
74 | return exist;
75 | }
76 |
77 | @Override
78 | public synchronized void createTable() {
79 | getWritableDatabase().execSQL(SQL_CREATE_TABLE);
80 | }
81 |
82 | @Override
83 | public synchronized void insert(TodayStepData todayStepData) {
84 |
85 | ContentValues contentValues = new ContentValues();
86 | contentValues.put(TODAY, todayStepData.getToday());
87 | contentValues.put(DATE, todayStepData.getDate());
88 | contentValues.put(STEP, todayStepData.getStep());
89 | getWritableDatabase().insert(TABLE_NAME, null, contentValues);
90 | }
91 |
92 | @Override
93 | public synchronized List getQueryAll() {
94 | Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_ALL, new String[]{});
95 | List todayStepDatas = getTodayStepDataList(cursor);
96 | cursor.close();
97 | return todayStepDatas;
98 | }
99 |
100 | /**
101 | * 获取最大步数,根据时间
102 | *
103 | * @return
104 | */
105 | @Override
106 | public synchronized TodayStepData getMaxStepByDate(long millis) {
107 | Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_STEP_ORDER_BY, new String[]{DateUtils.dateFormat(millis, "yyyy-MM-dd")});
108 | TodayStepData todayStepData = null;
109 | if (cursor.getCount() > 0) {
110 | cursor.moveToNext();
111 | todayStepData = getTodayStepData(cursor);
112 | }
113 | cursor.close();
114 | return todayStepData;
115 | }
116 |
117 | /**
118 | * 根据时间获取步数列表
119 | *
120 | * @param dateString 格式yyyy-MM-dd
121 | * @return
122 | */
123 | @Override
124 | public synchronized List getStepListByDate(String dateString) {
125 | Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_STEP_BY_DATE, new String[]{dateString});
126 | List todayStepDatas = getTodayStepDataList(cursor);
127 | cursor.close();
128 | return todayStepDatas;
129 | }
130 |
131 | /**
132 | * 根据时间和天数获取步数列表
133 | * 例如:
134 | * startDate = 2018-01-15
135 | * days = 3
136 | * 获取 2018-01-15、2018-01-16、2018-01-17三天的步数
137 | *
138 | * @param startDate 格式yyyy-MM-dd
139 | * @param days
140 | * @return
141 | */
142 | @Override
143 | public synchronized List getStepListByStartDateAndDays(String startDate, int days) {
144 | List todayStepDatas = new ArrayList<>();
145 | for (int i = 0; i < days; i++) {
146 | Calendar calendar = Calendar.getInstance();
147 | calendar.setTimeInMillis(DateUtils.getDateMillis(startDate, DATE_PATTERN_YYYY_MM_DD));
148 | calendar.add(Calendar.DAY_OF_YEAR, i);
149 | Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_STEP_BY_DATE,
150 | new String[]{DateUtils.dateFormat(calendar.getTimeInMillis(), DATE_PATTERN_YYYY_MM_DD)});
151 | todayStepDatas.addAll(getTodayStepDataList(cursor));
152 | cursor.close();
153 | }
154 | return todayStepDatas;
155 | }
156 |
157 | private List getTodayStepDataList(Cursor cursor) {
158 |
159 | List todayStepDatas = new ArrayList<>();
160 | while (cursor.moveToNext()) {
161 | TodayStepData todayStepData = getTodayStepData(cursor);
162 | todayStepDatas.add(todayStepData);
163 | }
164 | return todayStepDatas;
165 | }
166 |
167 | private TodayStepData getTodayStepData(Cursor cursor){
168 | String today = cursor.getString(cursor.getColumnIndex(TODAY));
169 | long date = cursor.getLong(cursor.getColumnIndex(DATE));
170 | long step = cursor.getLong(cursor.getColumnIndex(STEP));
171 | TodayStepData todayStepData = new TodayStepData();
172 | todayStepData.setToday(today);
173 | todayStepData.setDate(date);
174 | todayStepData.setStep(step);
175 | return todayStepData;
176 | }
177 |
178 | /**
179 | * 根据limit来清除数据库
180 | * 例如:
181 | * curDate = 2018-01-10 limit=0;表示只保留2018-01-10
182 | * curDate = 2018-01-10 limit=1;表示保留2018-01-10、2018-01-09等
183 | *
184 | * @param curDate
185 | * @param limit -1失效
186 | */
187 | @Override
188 | public synchronized void clearCapacity(String curDate, int limit) {
189 | mLimit = limit;
190 | if (mLimit <= 0) {
191 | return;
192 | }
193 | try {
194 | Calendar calendar = Calendar.getInstance();
195 | calendar.setTimeInMillis(DateUtils.getDateMillis(curDate, DATE_PATTERN_YYYY_MM_DD));
196 | calendar.add(Calendar.DAY_OF_YEAR, -(mLimit));
197 | String date = DateUtils.dateFormat(calendar.getTimeInMillis(), DATE_PATTERN_YYYY_MM_DD);
198 | Log.e(TAG, date);
199 |
200 | List todayStepDataList = getQueryAll();
201 | Set delDateSet = new HashSet<>();
202 | for (TodayStepData tmpTodayStepData : todayStepDataList) {
203 | long dbTodayDate = DateUtils.getDateMillis(tmpTodayStepData.getToday(), DATE_PATTERN_YYYY_MM_DD);
204 | if (calendar.getTimeInMillis() >= dbTodayDate) {
205 | delDateSet.add(tmpTodayStepData.getToday());
206 | }
207 | }
208 |
209 | for (String delDate : delDateSet) {
210 | getWritableDatabase().execSQL(SQL_DELETE_TODAY, new String[]{delDate});
211 | }
212 |
213 | } catch (Exception e) {
214 | e.printStackTrace();
215 | }
216 | }
217 |
218 | @Override
219 | public synchronized void deleteTable() {
220 | getWritableDatabase().execSQL(SQL_DELETE_TABLE);
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/TodayStepData.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | import java.io.Serializable;
7 |
8 |
9 | public class TodayStepData implements Serializable, Parcelable {
10 |
11 | //当天时间,只显示到天 yyyy-MM-dd
12 | private String today;
13 | //步数时间,显示到毫秒
14 | private long date;
15 | //对应date时间的步数
16 | private long step;
17 |
18 | public TodayStepData() {
19 |
20 | }
21 |
22 | protected TodayStepData(Parcel in) {
23 | today = in.readString();
24 | date = in.readLong();
25 | step = in.readLong();
26 | }
27 |
28 | @Override
29 | public void writeToParcel(Parcel dest, int flags) {
30 | dest.writeString(today);
31 | dest.writeLong(date);
32 | dest.writeLong(step);
33 | }
34 |
35 | @Override
36 | public int describeContents() {
37 | return 0;
38 | }
39 |
40 | public static final Creator CREATOR = new Creator() {
41 | @Override
42 | public TodayStepData createFromParcel(Parcel in) {
43 | return new TodayStepData(in);
44 | }
45 |
46 | @Override
47 | public TodayStepData[] newArray(int size) {
48 | return new TodayStepData[size];
49 | }
50 | };
51 |
52 | public long getDate() {
53 | return date;
54 | }
55 |
56 | public void setDate(long date) {
57 | this.date = date;
58 | }
59 |
60 | public long getStep() {
61 | return step;
62 | }
63 |
64 | public void setStep(long step) {
65 | this.step = step;
66 | }
67 |
68 | public String getToday() {
69 | return today;
70 | }
71 |
72 | public void setToday(String today) {
73 | this.today = today;
74 | }
75 |
76 | @Override
77 | public String toString() {
78 | return "TodayStepData{" +
79 | ", today=" + today +
80 | ", date=" + date +
81 | ", step=" + step +
82 | '}';
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/TodayStepDetector.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.IntentFilter;
7 | import android.hardware.Sensor;
8 | import android.hardware.SensorEvent;
9 | import android.hardware.SensorEventListener;
10 | import android.os.Handler;
11 | import android.os.Message;
12 |
13 |
14 | import com.andrjhf.lib.jlogger.JLoggerConstant;
15 | import com.andrjhf.lib.jlogger.JLoggerWraper;
16 |
17 | import java.util.HashMap;
18 | import java.util.Map;
19 |
20 | import static com.today.step.lib.ConstantDef.HANDLER_WHAT_TEST_JLOGGER;
21 | import static com.today.step.lib.ConstantDef.WHAT_TEST_JLOGGER_DURATION;
22 |
23 | /**
24 | * Sensor.TYPE_ACCELEROMETER
25 | * 加速度传感器计算当天步数,需要保持后台Service
26 | */
27 | public class TodayStepDetector implements SensorEventListener{
28 |
29 | private final String TAG = "TodayStepDetector";
30 |
31 | //存放三轴数据
32 | float[] oriValues = new float[3];
33 | final int ValueNum = 4;
34 | //用于存放计算阈值的波峰波谷差值
35 | float[] tempValue = new float[ValueNum];
36 | int tempCount = 0;
37 | //是否上升的标志位
38 | boolean isDirectionUp = false;
39 | //持续上升次数
40 | int continueUpCount = 0;
41 | //上一点的持续上升的次数,为了记录波峰的上升次数
42 | int continueUpFormerCount = 0;
43 | //上一点的状态,上升还是下降
44 | boolean lastStatus = false;
45 | //波峰值
46 | float peakOfWave = 0;
47 | //波谷值
48 | float valleyOfWave = 0;
49 | //此次波峰的时间
50 | long timeOfThisPeak = 0;
51 | //上次波峰的时间
52 | long timeOfLastPeak = 0;
53 | //当前的时间
54 | long timeOfNow = 0;
55 | //当前传感器的值
56 | float gravityNew = 0;
57 | //上次传感器的值
58 | float gravityOld = 0;
59 | //动态阈值需要动态的数据,这个值用于这些动态数据的阈值
60 | final float InitialValue = (float) 1.3;
61 | //初始阈值
62 | float ThreadValue = (float) 2.0;
63 | //波峰波谷时间差
64 | int TimeInterval = 250;
65 |
66 | private int count = 0;
67 | private int mCount = 0;
68 | private OnStepCounterListener mOnStepCounterListener;
69 | private Context mContext;
70 | private long timeOfLastPeak1 = 0;
71 | private long timeOfThisPeak1 = 0;
72 | private String mTodayDate;
73 |
74 | /**
75 | * 传感器回调次数
76 | */
77 | private int mJLoggerSensorCount = 0;
78 |
79 | private final Handler sHandler = new Handler(new Handler.Callback() {
80 | @Override
81 | public boolean handleMessage(Message msg) {
82 | switch (msg.what){
83 | case HANDLER_WHAT_TEST_JLOGGER:{
84 | Map map = new HashMap<>();
85 | map.put("mCount",String.valueOf(mCount));
86 | map.put("count",String.valueOf(count));
87 | map.put("mJLoggerSensorCount",String.valueOf(mJLoggerSensorCount));
88 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_ACCELEROMETER_TIMER,map);
89 | // JLogger.i(TAG,"onSensorChanged mCount : " + mCount +
90 | // " this.count :" + count +
91 | // " SensorCount : " + mJLoggerSensorCount);
92 |
93 | sHandler.removeMessages(HANDLER_WHAT_TEST_JLOGGER);
94 | sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_TEST_JLOGGER,WHAT_TEST_JLOGGER_DURATION);
95 | break;
96 | }
97 | }
98 | return false;
99 | }
100 | });
101 |
102 | public TodayStepDetector(Context context, OnStepCounterListener onStepCounterListener){
103 | super();
104 | mContext = context;
105 | this.mOnStepCounterListener = onStepCounterListener;
106 |
107 | WakeLockUtils.getLock(mContext);
108 |
109 | mCount = (int) PreferencesHelper.getCurrentStep(mContext);
110 | mTodayDate = PreferencesHelper.getStepToday(mContext);
111 | Map map = new HashMap<>();
112 | map.put("mCount",String.valueOf(mCount));
113 | map.put("mTodayDate",String.valueOf(mTodayDate));
114 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_ACCELEROMETER_CONSTRUCTOR,map);
115 | // JLogger.i(TAG, "TodayStepDetector mCount : " + mCount +
116 | // " mTodayDate:" + mTodayDate);
117 |
118 | dateChangeCleanStep();
119 | initBroadcastReceiver();
120 |
121 | updateStepCounter();
122 |
123 | sHandler.removeMessages(HANDLER_WHAT_TEST_JLOGGER);
124 | sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_TEST_JLOGGER,WHAT_TEST_JLOGGER_DURATION);
125 | }
126 |
127 | private void initBroadcastReceiver() {
128 | final IntentFilter filter = new IntentFilter();
129 | filter.addAction(Intent.ACTION_TIME_TICK);
130 | filter.addAction(Intent.ACTION_DATE_CHANGED);
131 | BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() {
132 | @Override
133 | public void onReceive(final Context context, final Intent intent) {
134 | if (Intent.ACTION_TIME_TICK.equals(intent.getAction())
135 | || Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
136 | //service存活做0点分隔
137 | dateChangeCleanStep();
138 |
139 | }
140 | }
141 | };
142 | mContext.registerReceiver(mBatInfoReceiver, filter);
143 | }
144 |
145 | private synchronized void dateChangeCleanStep() {
146 | //时间改变了清零,或者0点分隔回调
147 | if (!getTodayDate().equals(mTodayDate)) {
148 |
149 | WakeLockUtils.getLock(mContext);
150 |
151 | mCount = 0;
152 | PreferencesHelper.setCurrentStep(mContext, mCount);
153 |
154 | mTodayDate = getTodayDate();
155 | PreferencesHelper.setStepToday(mContext, mTodayDate);
156 |
157 | setSteps(0);
158 | JLoggerWraper.onEventInfo(mContext,JLoggerConstant.JLOGGER_TYPE_ACCELEROMETER_DATECHANGECLEANSTEP);
159 | mJLoggerSensorCount = 0;
160 |
161 | if(null != mOnStepCounterListener){
162 | mOnStepCounterListener.onStepCounterClean();
163 | }
164 | }
165 | }
166 |
167 | private String getTodayDate() {
168 | return DateUtils.getCurrentDate("yyyy-MM-dd");
169 | }
170 |
171 | private void updateStepCounter(){
172 |
173 | //每次回调都判断一下是否跨天
174 | dateChangeCleanStep();
175 |
176 | if (null != mOnStepCounterListener) {
177 | mOnStepCounterListener.onChangeStepCounter(mCount);
178 | }
179 | }
180 |
181 | @Override
182 | public void onSensorChanged(SensorEvent event) {
183 | if(Sensor.TYPE_ACCELEROMETER == event.sensor.getType()) {
184 | for (int i = 0; i < 3; i++) {
185 | oriValues[i] = event.values[i];
186 | }
187 | gravityNew = (float) Math.sqrt(oriValues[0] * oriValues[0]
188 | + oriValues[1] * oriValues[1] + oriValues[2] * oriValues[2]);
189 | detectorNewStep(gravityNew);
190 | }
191 | }
192 |
193 | @Override
194 | public void onAccuracyChanged(Sensor sensor, int accuracy) {
195 | //
196 | }
197 |
198 | /*
199 | * 检测步子,并开始计步
200 | * 1.传入sersor中的数据
201 | * 2.如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步
202 | * 3.符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中
203 | * */
204 | private void detectorNewStep(float values) {
205 | if (gravityOld == 0) {
206 | gravityOld = values;
207 | } else {
208 | if (detectorPeak(values, gravityOld)) {
209 | timeOfLastPeak = timeOfThisPeak;
210 | timeOfNow = System.currentTimeMillis();
211 | if (timeOfNow - timeOfLastPeak >= TimeInterval
212 | && (peakOfWave - valleyOfWave >= ThreadValue)) {
213 | timeOfThisPeak = timeOfNow;
214 | /*
215 | * 更新界面的处理,不涉及到算法
216 | * 一般在通知更新界面之前,增加下面处理,为了处理无效运动:
217 | * 1.连续记录10才开始计步
218 | * 2.例如记录的9步用户停住超过3秒,则前面的记录失效,下次从头开始
219 | * 3.连续记录了9步用户还在运动,之前的数据才有效
220 | * */
221 | countStep();
222 | }
223 | if (timeOfNow - timeOfLastPeak >= TimeInterval
224 | && (peakOfWave - valleyOfWave >= InitialValue)) {
225 | timeOfThisPeak = timeOfNow;
226 | ThreadValue = peakValleyThread(peakOfWave - valleyOfWave);
227 | }
228 | }
229 | }
230 | gravityOld = values;
231 | }
232 |
233 | /*
234 | * 检测波峰
235 | * 以下四个条件判断为波峰:
236 | * 1.目前点为下降的趋势:isDirectionUp为false
237 | * 2.之前的点为上升的趋势:lastStatus为true
238 | * 3.到波峰为止,持续上升大于等于2次
239 | * 4.波峰值大于20
240 | * 记录波谷值
241 | * 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值
242 | * 2.所以要记录每次的波谷值,为了和下次的波峰做对比
243 | * */
244 | private boolean detectorPeak(float newValue, float oldValue) {
245 | lastStatus = isDirectionUp;
246 | if (newValue >= oldValue) {
247 | isDirectionUp = true;
248 | continueUpCount++;
249 | } else {
250 | continueUpFormerCount = continueUpCount;
251 | continueUpCount = 0;
252 | isDirectionUp = false;
253 | }
254 |
255 | if (!isDirectionUp && lastStatus
256 | && (continueUpFormerCount >= 2 || oldValue >= 20)) {
257 | peakOfWave = oldValue;
258 | return true;
259 | } else if (!lastStatus && isDirectionUp) {
260 | valleyOfWave = oldValue;
261 | return false;
262 | } else {
263 | return false;
264 | }
265 | }
266 |
267 | /*
268 | * 阈值的计算
269 | * 1.通过波峰波谷的差值计算阈值
270 | * 2.记录4个值,存入tempValue[]数组中
271 | * 3.在将数组传入函数averageValue中计算阈值
272 | * */
273 | private float peakValleyThread(float value) {
274 | float tempThread = ThreadValue;
275 | if (tempCount < ValueNum) {
276 | tempValue[tempCount] = value;
277 | tempCount++;
278 | } else {
279 | tempThread = averageValue(tempValue, ValueNum);
280 | for (int i = 1; i < ValueNum; i++) {
281 | tempValue[i - 1] = tempValue[i];
282 | }
283 | tempValue[ValueNum - 1] = value;
284 | }
285 | return tempThread;
286 |
287 | }
288 |
289 | /*
290 | * 梯度化阈值
291 | * 1.计算数组的均值
292 | * 2.通过均值将阈值梯度化在一个范围里
293 | * */
294 | private float averageValue(float value[], int n) {
295 | float ave = 0;
296 | for (int i = 0; i < n; i++) {
297 | ave += value[i];
298 | }
299 | ave = ave / ValueNum;
300 | if (ave >= 8)
301 | ave = (float) 4.3;
302 | else if (ave >= 7 && ave < 8)
303 | ave = (float) 3.3;
304 | else if (ave >= 4 && ave < 7)
305 | ave = (float) 2.3;
306 | else if (ave >= 3 && ave < 4)
307 | ave = (float) 2.0;
308 | else {
309 | ave = (float) 1.3;
310 | }
311 | return ave;
312 | }
313 |
314 |
315 |
316 |
317 | /*
318 | * 连续走十步才会开始计步
319 | * 连续走了9步以下,停留超过3秒,则计数清空
320 | * */
321 | private void countStep() {
322 | this.timeOfLastPeak1 = this.timeOfThisPeak1;
323 | this.timeOfThisPeak1 = System.currentTimeMillis();
324 | if (this.timeOfThisPeak1 - this.timeOfLastPeak1 <= 3000L){
325 | if(this.count<9){
326 | this.count++;
327 | }else if(this.count == 9){
328 | this.count++;
329 | this.mCount += this.count;
330 | PreferencesHelper.setCurrentStep(mContext, mCount);
331 | updateStepCounter();
332 | }else{
333 | this.mCount++;
334 | PreferencesHelper.setCurrentStep(mContext, mCount);
335 | updateStepCounter();
336 | }
337 | }else{//超时
338 | this.count = 1;//为1,不是0
339 | }
340 | //测试传感器是否回调
341 | mJLoggerSensorCount++;
342 | }
343 |
344 |
345 | private void setSteps(int initValue) {
346 | this.mCount = initValue;
347 | this.count = 0;
348 | timeOfLastPeak1 = 0;
349 | timeOfThisPeak1 = 0;
350 | }
351 |
352 | public int getCurrentStep() {
353 | return mCount;
354 | }
355 |
356 | public void setCurrentStep(int initStep){
357 |
358 | setSteps(initStep);
359 |
360 | mCount = initStep;
361 | PreferencesHelper.setCurrentStep(mContext, mCount);
362 |
363 | mTodayDate = getTodayDate();
364 | PreferencesHelper.setStepToday(mContext, mTodayDate);
365 |
366 | if(null != mOnStepCounterListener){
367 | mOnStepCounterListener.onChangeStepCounter(mCount);
368 | }
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/TodayStepManager.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.app.Activity;
4 | import android.app.Application;
5 | import android.app.job.JobInfo;
6 | import android.app.job.JobScheduler;
7 | import android.content.ComponentName;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.content.ServiceConnection;
11 | import android.os.Build;
12 | import android.support.annotation.RequiresApi;
13 | import android.support.v4.content.ContextCompat;
14 |
15 | /**
16 | * 计步SDK初始化方法
17 | * Created by jiahongfei on 2017/10/9.
18 | */
19 |
20 | public class TodayStepManager {
21 |
22 | private static final String TAG = "TodayStepManager";
23 |
24 | public static void startTodayStepService(Application application) {
25 | try {
26 | Intent intent = new Intent(application, TodayStepService.class);
27 | ContextCompat.startForegroundService(application, intent);
28 | } catch (Exception e) {
29 | e.printStackTrace();
30 | // https://stackoverflow.com/questions/38764497/security-exception-unable-to-start-service-user-0-is-restricted
31 | // 经过和OPPO工程师沟通,这个问题的原因是OPPO手机自动熄屏一段时间后,会启用系统自带的电量优化管理,
32 | // 禁止一切自启动的APP(用户设置的自启动白名单除外)。所以,类似的崩溃常常集中在用户休息之后的夜里或者凌晨,
33 | // 但是并不影响用户平时的正常使用。至于会出现user 0 is restricted,我觉得是coloros系统电量优化管理做得不好的地方。
34 | // 对coloros官方的处理建议:既然禁止自启动,那么干脆直接force stop对应的进程,而不是抛出RuntimeException来让开发者买单。
35 | // 对开发者处理建议:在服务启动的地方进行try catch防止崩溃即可(也是“1元夺宝”APP目前的处理方式)
36 | }
37 | }
38 |
39 | public static boolean bindService(Activity activity, ServiceConnection conn) {
40 | try {
41 | Intent intent = new Intent(activity, TodayStepService.class);
42 | return activity.bindService(intent, conn, Activity.BIND_AUTO_CREATE);
43 | } catch (Exception e) {
44 | e.printStackTrace();
45 | // https://stackoverflow.com/questions/38764497/security-exception-unable-to-start-service-user-0-is-restricted
46 | // 经过和OPPO工程师沟通,这个问题的原因是OPPO手机自动熄屏一段时间后,会启用系统自带的电量优化管理,
47 | // 禁止一切自启动的APP(用户设置的自启动白名单除外)。所以,类似的崩溃常常集中在用户休息之后的夜里或者凌晨,
48 | // 但是并不影响用户平时的正常使用。至于会出现user 0 is restricted,我觉得是coloros系统电量优化管理做得不好的地方。
49 | // 对coloros官方的处理建议:既然禁止自启动,那么干脆直接force stop对应的进程,而不是抛出RuntimeException来让开发者买单。
50 | // 对开发者处理建议:在服务启动的地方进行try catch防止崩溃即可(也是“1元夺宝”APP目前的处理方式)
51 | }
52 | return false;
53 |
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/TodayStepService.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationManager;
5 | import android.app.PendingIntent;
6 | import android.app.Service;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.pm.ActivityInfo;
10 | import android.content.pm.PackageInfo;
11 | import android.content.pm.PackageManager;
12 | import android.graphics.Bitmap;
13 | import android.graphics.BitmapFactory;
14 | import android.hardware.Sensor;
15 | import android.hardware.SensorManager;
16 | import android.os.Build;
17 | import android.os.Handler;
18 | import android.os.IBinder;
19 | import android.os.Message;
20 | import android.os.RemoteException;
21 | import android.text.TextUtils;
22 |
23 | import com.andrjhf.lib.jlogger.JLoggerConstant;
24 | import com.andrjhf.lib.jlogger.JLoggerWraper;
25 | import com.andrjhf.notification.api.compat.NotificationApiCompat;
26 |
27 | import org.json.JSONArray;
28 |
29 | import java.lang.reflect.InvocationTargetException;
30 | import java.lang.reflect.Method;
31 | import java.util.HashMap;
32 | import java.util.List;
33 | import java.util.Map;
34 |
35 | import static com.today.step.lib.SportStepJsonUtils.getCalorieByStep;
36 | import static com.today.step.lib.SportStepJsonUtils.getDistanceByStep;
37 |
38 | public class TodayStepService extends Service implements Handler.Callback {
39 |
40 | private static final String TAG = "TodayStepService";
41 |
42 | private static final String STEP_CHANNEL_ID = "stepChannelId";
43 |
44 | /**
45 | * 步数通知ID
46 | */
47 | private static final int NOTIFY_ID = 1000;
48 |
49 | /**
50 | * 保存数据库频率
51 | */
52 | private static final int DB_SAVE_COUNTER = 300;
53 |
54 | /**
55 | * 传感器刷新频率
56 | */
57 | private static final int SAMPLING_PERIOD_US = SensorManager.SENSOR_DELAY_FASTEST;
58 |
59 | /**
60 | * 运动停止保存步数
61 | */
62 | private static final int HANDLER_WHAT_SAVE_STEP = 0;
63 |
64 | /**
65 | * 刷新通知栏步数
66 | */
67 | private static final int HANDLER_WHAT_REFRESH_NOTIFY_STEP = 2;
68 |
69 |
70 | /**
71 | * 如果走路如果停止,10秒钟后保存数据库
72 | */
73 | private static final int LAST_SAVE_STEP_DURATION = 10 * 1000;
74 |
75 | /**
76 | * 刷新通知栏步数,3s一次
77 | */
78 | private static final int REFRESH_NOTIFY_STEP_DURATION = 3 * 1000;
79 |
80 | /**
81 | * 点击通知栏广播requestCode
82 | */
83 | private static final int BROADCAST_REQUEST_CODE = 100;
84 |
85 | public static final String INTENT_NAME_0_SEPARATE = "intent_name_0_separate";
86 | public static final String INTENT_NAME_BOOT = "intent_name_boot";
87 | public static final String INTENT_STEP_INIT = "intent_step_init";
88 |
89 | /**
90 | * 当前步数
91 | */
92 | private static int CURRENT_STEP = 0;
93 |
94 | private SensorManager mSensorManager;
95 | /**
96 | * Sensor.TYPE_ACCELEROMETER
97 | * 加速度传感器计算当天步数,需要保持后台Service
98 | */
99 | private TodayStepDetector mStepDetector;
100 | /**
101 | * Sensor.TYPE_STEP_COUNTER
102 | * 计步传感器计算当天步数,不需要后台Service
103 | */
104 | private TodayStepCounter mStepCounter;
105 |
106 | private NotificationManager nm;
107 | private NotificationApiCompat mNotificationApiCompat;
108 |
109 | private boolean mSeparate = false;
110 | private boolean mBoot = false;
111 |
112 | /**
113 | * 保存数据库计数器
114 | */
115 | private int mDbSaveCount = 0;
116 |
117 | /**
118 | * 数据库
119 | */
120 | private ITodayStepDBHelper mTodayStepDBHelper;
121 |
122 | private final Handler sHandler = new Handler(this);
123 |
124 | @Override
125 | public boolean handleMessage(Message msg) {
126 | switch (msg.what) {
127 | case HANDLER_WHAT_SAVE_STEP: {
128 | //走路停止保存数据库
129 | mDbSaveCount = 0;
130 |
131 | saveDb(true, CURRENT_STEP);
132 | break;
133 | }
134 | case HANDLER_WHAT_REFRESH_NOTIFY_STEP: {
135 | //刷新通知栏
136 |
137 | updateTodayStep(CURRENT_STEP);
138 |
139 | sHandler.removeMessages(HANDLER_WHAT_REFRESH_NOTIFY_STEP);
140 | sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_REFRESH_NOTIFY_STEP, REFRESH_NOTIFY_STEP_DURATION);
141 | break;
142 | }
143 | default:
144 | break;
145 | }
146 | return false;
147 | }
148 |
149 | @Override
150 | public void onCreate() {
151 | super.onCreate();
152 |
153 | mTodayStepDBHelper = TodayStepDBHelper.factory(getApplicationContext());
154 |
155 | mSensorManager = (SensorManager) this
156 | .getSystemService(SENSOR_SERVICE);
157 |
158 | initNotification(CURRENT_STEP);
159 |
160 | getSensorRate();
161 |
162 | // JLogger.i(TAG, "onCreate currStep :" + CURRENT_STEP);
163 | Map map = getLogMap();
164 | map.put("current_step", String.valueOf(CURRENT_STEP));
165 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_INITIALIZE_CURRSTEP, map);
166 | }
167 |
168 | @Override
169 | public int onStartCommand(Intent intent, int flags, int startId) {
170 | if (null != intent) {
171 | mSeparate = intent.getBooleanExtra(INTENT_NAME_0_SEPARATE, false);
172 | mBoot = intent.getBooleanExtra(INTENT_NAME_BOOT, false);
173 | String setStep = intent.getStringExtra(INTENT_STEP_INIT);
174 | if (!TextUtils.isEmpty(setStep)) {
175 | try {
176 | setSteps(Integer.parseInt(setStep));
177 | } catch (NumberFormatException e) {
178 | e.printStackTrace();
179 | }
180 | }
181 | }
182 | // JLogger.i(TAG, "onStartCommand CurrStep :" + CURRENT_STEP + " mSeparate:" + mSeparate + " mBoot:" + mBoot);
183 | mDbSaveCount = 0;
184 |
185 | Map map = getLogMap();
186 | map.put("current_step", String.valueOf(CURRENT_STEP));
187 | map.put("mSeparate", String.valueOf(mSeparate));
188 | map.put("mBoot", String.valueOf(mBoot));
189 | map.put("mDbSaveCount", String.valueOf(mDbSaveCount));
190 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_ONSTARTCOMMAND, map);
191 |
192 | updateNotification(CURRENT_STEP);
193 | //注册传感器
194 | startStepDetector();
195 |
196 | sHandler.removeMessages(HANDLER_WHAT_REFRESH_NOTIFY_STEP);
197 | sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_REFRESH_NOTIFY_STEP, REFRESH_NOTIFY_STEP_DURATION);
198 |
199 | return START_STICKY;
200 | }
201 |
202 | private synchronized void initNotification(int currentStep) {
203 |
204 | nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
205 | int smallIcon = getResources().getIdentifier("icon_step_small", "mipmap", getPackageName());
206 | if (0 == smallIcon) {
207 | smallIcon = R.mipmap.ic_launcher;
208 | }
209 | String receiverName = getReceiver(getApplicationContext());
210 | PendingIntent contentIntent = PendingIntent.getBroadcast(this, BROADCAST_REQUEST_CODE, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);
211 | if (!TextUtils.isEmpty(receiverName)) {
212 | try {
213 | contentIntent = PendingIntent.getBroadcast(this, BROADCAST_REQUEST_CODE, new Intent(this, Class.forName(receiverName)), PendingIntent.FLAG_UPDATE_CURRENT);
214 | } catch (Exception e) {
215 | e.printStackTrace();
216 | contentIntent = PendingIntent.getBroadcast(this, BROADCAST_REQUEST_CODE, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);
217 | }
218 | }
219 | String km = getDistanceByStep(currentStep);
220 | String calorie = getCalorieByStep(currentStep);
221 | String contentText = calorie + " 千卡 " + km + " 公里";
222 | int largeIcon = getResources().getIdentifier("ic_launcher", "mipmap", getPackageName());
223 | Bitmap largeIconBitmap = null;
224 | if (0 != largeIcon) {
225 | largeIconBitmap = BitmapFactory.decodeResource(getResources(), largeIcon);
226 | } else {
227 | largeIconBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
228 | }
229 | mNotificationApiCompat = new NotificationApiCompat.Builder(this,
230 | nm,
231 | STEP_CHANNEL_ID,
232 | getString(R.string.step_channel_name),
233 | smallIcon)
234 | .setContentIntent(contentIntent)
235 | .setContentText(contentText)
236 | .setContentTitle(getString(R.string.title_notification_bar, String.valueOf(currentStep)))
237 | .setTicker(getString(R.string.app_name))
238 | .setOngoing(true)
239 | .setPriority(Notification.PRIORITY_MIN)
240 | .setLargeIcon(largeIconBitmap)
241 | .setOnlyAlertOnce(true)
242 | .builder();
243 | mNotificationApiCompat.startForeground(this, NOTIFY_ID);
244 | mNotificationApiCompat.notify(NOTIFY_ID);
245 |
246 | }
247 |
248 | @Override
249 | public IBinder onBind(Intent intent) {
250 | // JLogger.i(TAG, "onBind : CurrStep : " + CURRENT_STEP);
251 | Map map = getLogMap();
252 | map.put("current_step", String.valueOf(CURRENT_STEP));
253 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_ONBIND, map);
254 |
255 |
256 | sHandler.removeMessages(HANDLER_WHAT_REFRESH_NOTIFY_STEP);
257 | sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_REFRESH_NOTIFY_STEP, REFRESH_NOTIFY_STEP_DURATION);
258 |
259 | return mIBinder.asBinder();
260 | }
261 |
262 | private void startStepDetector() {
263 |
264 | //android4.4以后如果有stepcounter可以使用计步传感器
265 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && getStepCounter()) {
266 | addStepCounterListener();
267 | } else {
268 | addBasePedoListener();
269 | }
270 | }
271 |
272 | private void addStepCounterListener() {
273 | if (null != mStepCounter) {
274 | WakeLockUtils.getLock(this);
275 | CURRENT_STEP = mStepCounter.getCurrentStep();
276 | updateNotification(CURRENT_STEP);
277 | Map map = getLogMap();
278 | map.put("current_step", String.valueOf(CURRENT_STEP));
279 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_TYPE_STEP_COUNTER_HADREGISTER, map);
280 | return;
281 | }
282 | Sensor countSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
283 | if (null == countSensor) {
284 | return;
285 | }
286 | mStepCounter = new TodayStepCounter(getApplicationContext(), mOnStepCounterListener, mSeparate, mBoot);
287 | CURRENT_STEP = mStepCounter.getCurrentStep();
288 | boolean registerSuccess = mSensorManager.registerListener(mStepCounter, countSensor, SAMPLING_PERIOD_US);
289 | Map map = getLogMap();
290 | map.put("current_step", String.valueOf(CURRENT_STEP));
291 | map.put("current_step_registerSuccess", String.valueOf(registerSuccess));
292 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_TYPE_STEP_COUNTER_REGISTER, map);
293 | }
294 |
295 | private void addBasePedoListener() {
296 |
297 | if (null != mStepDetector) {
298 | WakeLockUtils.getLock(this);
299 | CURRENT_STEP = mStepDetector.getCurrentStep();
300 | // JLogger.i(TAG, "alreadly register TYPE_ACCELEROMETER : CurrStep : " + CURRENT_STEP);
301 | updateNotification(CURRENT_STEP);
302 | Map map = getLogMap();
303 | map.put("current_step", String.valueOf(CURRENT_STEP));
304 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_TYPE_ACCELEROMETER_HADREGISTER, map);
305 |
306 | return;
307 | }
308 | //没有计步器的时候开启定时器保存数据
309 | Sensor sensor = mSensorManager
310 | .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
311 | if (null == sensor) {
312 | return;
313 | }
314 | mStepDetector = new TodayStepDetector(this, mOnStepCounterListener);
315 | CURRENT_STEP = mStepDetector.getCurrentStep();
316 | // 获得传感器的类型,这里获得的类型是加速度传感器
317 | // 此方法用来注册,只有注册过才会生效,参数:SensorEventListener的实例,Sensor的实例,更新速率
318 | boolean registerSuccess = mSensorManager.registerListener(mStepDetector, sensor, SAMPLING_PERIOD_US);
319 | Map map = getLogMap();
320 | map.put("current_step", String.valueOf(CURRENT_STEP));
321 | map.put("current_step_registerSuccess", String.valueOf(registerSuccess));
322 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_TYPE_ACCELEROMETER_REGISTER, map);
323 | }
324 |
325 | @Override
326 | public void onDestroy() {
327 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_TODAYSTEPSERVICE_ONDESTROY, "CURRENT_STEP=" + CURRENT_STEP);
328 | JLoggerWraper.flush();
329 | super.onDestroy();
330 | }
331 |
332 | @Override
333 | public boolean onUnbind(Intent intent) {
334 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_TODAYSTEPSERVICE_ONUNBIND, "CURRENT_STEP=" + CURRENT_STEP);
335 | return super.onUnbind(intent);
336 | }
337 |
338 | /**
339 | * 步数每次回调的方法
340 | *
341 | * @param currentStep
342 | */
343 | private void updateTodayStep(int currentStep) {
344 |
345 | CURRENT_STEP = currentStep;
346 | updateNotification(CURRENT_STEP);
347 | saveStep(currentStep);
348 | }
349 |
350 | private void saveStep(int currentStep) {
351 | sHandler.removeMessages(HANDLER_WHAT_SAVE_STEP);
352 | sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_SAVE_STEP, LAST_SAVE_STEP_DURATION);
353 |
354 | if (DB_SAVE_COUNTER > mDbSaveCount) {
355 | mDbSaveCount++;
356 |
357 | return;
358 | }
359 | mDbSaveCount = 0;
360 |
361 | saveDb(false, currentStep);
362 | }
363 |
364 | /**
365 | * @param handler true handler回调保存步数,否false
366 | * @param currentStep
367 | */
368 | private void saveDb(boolean handler, int currentStep) {
369 |
370 | TodayStepData todayStepData = new TodayStepData();
371 | todayStepData.setToday(getTodayDate());
372 | todayStepData.setDate(System.currentTimeMillis());
373 | todayStepData.setStep(currentStep);
374 | if (null != mTodayStepDBHelper) {
375 | if (!handler || !mTodayStepDBHelper.isExist(todayStepData)) {
376 | mTodayStepDBHelper.insert(todayStepData);
377 | Map map = getLogMap();
378 | map.put("saveDb_currentStep", String.valueOf(currentStep));
379 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_INSERT_DB, map);
380 | }
381 | }
382 | }
383 |
384 | private void cleanDb() {
385 |
386 | // JLogger.i(TAG, "cleanDb");
387 | Map map = getLogMap();
388 | map.put("cleanDB_current_step", String.valueOf(CURRENT_STEP));
389 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_CLEAN_DB, map);
390 | mDbSaveCount = 0;
391 |
392 | if (null != mTodayStepDBHelper) {
393 | //保存多天的步数
394 | mTodayStepDBHelper.deleteTable();
395 | mTodayStepDBHelper.createTable();
396 | }
397 | }
398 |
399 | private String getTodayDate() {
400 | return DateUtils.getCurrentDate("yyyy-MM-dd");
401 | }
402 |
403 | /**
404 | * 更新通知
405 | */
406 | private synchronized void updateNotification(int stepCount) {
407 | if (null != mNotificationApiCompat) {
408 | String km = getDistanceByStep(stepCount);
409 | String calorie = getCalorieByStep(stepCount);
410 | String contentText = calorie + " 千卡 " + km + " 公里";
411 | mNotificationApiCompat.updateNotification(NOTIFY_ID, getString(R.string.title_notification_bar, String.valueOf(stepCount)), contentText);
412 | }
413 | }
414 |
415 | private boolean getStepCounter() {
416 | Sensor countSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
417 | if (null == countSensor) {
418 | return false;
419 | }
420 | return true;
421 | }
422 |
423 | private OnStepCounterListener mOnStepCounterListener = new OnStepCounterListener() {
424 | @Override
425 | public void onChangeStepCounter(int step) {
426 |
427 | if (StepUtil.isUploadStep()) {
428 | CURRENT_STEP = step;
429 | }
430 | }
431 |
432 | @Override
433 | public void onStepCounterClean() {
434 |
435 | CURRENT_STEP = 0;
436 | updateNotification(CURRENT_STEP);
437 |
438 | cleanDb();
439 | }
440 |
441 | };
442 |
443 | private final ISportStepInterface.Stub mIBinder = new ISportStepInterface.Stub() {
444 |
445 | private JSONArray getSportStepJsonArray(List todayStepDataArrayList) {
446 | return SportStepJsonUtils.getSportStepJsonArray(todayStepDataArrayList);
447 | }
448 |
449 | @Override
450 | public int getCurrentTimeSportStep() throws RemoteException {
451 | return CURRENT_STEP;
452 | }
453 |
454 | @Override
455 | public String getTodaySportStepArray() throws RemoteException {
456 | if (null != mTodayStepDBHelper) {
457 | List todayStepDataArrayList = mTodayStepDBHelper.getQueryAll();
458 | JSONArray jsonArray = getSportStepJsonArray(todayStepDataArrayList);
459 | return jsonArray.toString();
460 | }
461 | return null;
462 | }
463 | };
464 |
465 | public static String getReceiver(Context context) {
466 | try {
467 | PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_RECEIVERS);
468 | ActivityInfo[] activityInfos = packageInfo.receivers;
469 | if (null != activityInfos && activityInfos.length > 0) {
470 | for (int i = 0; i < activityInfos.length; i++) {
471 | String receiverName = activityInfos[i].name;
472 | Class superClazz = Class.forName(receiverName).getSuperclass();
473 | int count = 1;
474 | while (null != superClazz) {
475 | if (superClazz.getName().equals("java.lang.Object")) {
476 | break;
477 | }
478 | if (superClazz.getName().equals(BaseClickBroadcast.class.getName())) {
479 | return receiverName;
480 | }
481 | if (count > 20) {
482 | //用来做容错,如果20个基类还不到Object直接跳出防止while死循环
483 | break;
484 | }
485 | count++;
486 | superClazz = superClazz.getSuperclass();
487 |
488 | }
489 | }
490 | }
491 | } catch (Exception e) {
492 | e.printStackTrace();
493 | }
494 | return null;
495 | }
496 |
497 | /**
498 | * 获取传感器速率
499 | */
500 | private void getSensorRate() {
501 |
502 | Class> personType = SensorManager.class;
503 |
504 | //访问私有方法
505 | //getDeclaredMethod可以获取到所有方法,而getMethod只能获取public
506 | Method method = null;
507 | try {
508 | method = personType.getDeclaredMethod("getDelay", int.class);
509 | //压制Java对访问修饰符的检查
510 | method.setAccessible(true);
511 | //调用方法;person为所在对象
512 | int rate = (int) method.invoke(null, SAMPLING_PERIOD_US);
513 | Map map = getLogMap();
514 | map.put("getSensorRate", String.valueOf(rate));
515 | JLoggerWraper.onEventInfo(this, JLoggerConstant.JLOGGER_SERVICE_SENSORRATE_INVOKE, map);
516 |
517 | } catch (NoSuchMethodException e) {
518 | e.printStackTrace();
519 | } catch (IllegalAccessException e) {
520 | e.printStackTrace();
521 | } catch (InvocationTargetException e) {
522 | e.printStackTrace();
523 | } catch (Exception e) {
524 | e.printStackTrace();
525 | }
526 | }
527 |
528 | /**
529 | * 设置步数初始值,目前只支持设置用加速度传感器进行计步
530 | *
531 | * @param steps
532 | */
533 | private void setSteps(int steps) {
534 | if (null != mStepDetector) {
535 | mStepDetector.setCurrentStep(steps);
536 | }
537 | }
538 |
539 | private Map map;
540 |
541 | private Map getLogMap() {
542 | if (map == null) {
543 | map = new HashMap<>();
544 | } else {
545 | map.clear();
546 | }
547 | return map;
548 | }
549 |
550 |
551 | }
552 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/TodayStepShutdownReceiver.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | /**
8 | * Created by jiahongfei on 2017/9/27.
9 | */
10 |
11 | public class TodayStepShutdownReceiver extends BroadcastReceiver {
12 |
13 | private static final String TAG = "TodayStepShutdownReceiver";
14 |
15 | @Override
16 | public void onReceive(Context context, Intent intent) {
17 | if (intent.getAction().equals(Intent.ACTION_SHUTDOWN)) {
18 | PreferencesHelper.setShutdown(context,true);
19 | }
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/java/com/today/step/lib/WakeLockUtils.java:
--------------------------------------------------------------------------------
1 | package com.today.step.lib;
2 |
3 | import android.content.Context;
4 | import android.os.PowerManager;
5 |
6 | import java.util.Calendar;
7 |
8 | /**
9 | * @author : jiahongfei
10 | * @email : jiahongfeinew@163.com
11 | * @date : 2018/2/12
12 | * @desc :
13 | */
14 |
15 | class WakeLockUtils {
16 |
17 | private static PowerManager.WakeLock mWakeLock;
18 |
19 | synchronized static PowerManager.WakeLock getLock(Context context) {
20 | if (mWakeLock != null) {
21 | if (mWakeLock.isHeld())
22 | mWakeLock.release();
23 | mWakeLock = null;
24 | }
25 |
26 | if (mWakeLock == null) {
27 | PowerManager mgr = (PowerManager) context
28 | .getSystemService(Context.POWER_SERVICE);
29 | mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
30 | TodayStepService.class.getName());
31 | mWakeLock.setReferenceCounted(true);
32 | Calendar c = Calendar.getInstance();
33 | c.setTimeInMillis(System.currentTimeMillis());
34 | mWakeLock.acquire();
35 | }
36 | return (mWakeLock);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/lib-todaystepcounter/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/lib-todaystepcounter/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/lib-todaystepcounter/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | TodayStepCounterLib
3 | 当前步数:%1$s
4 | 计步器通知
5 |
6 |
--------------------------------------------------------------------------------
/screenshots/screenshots.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahongfei/TodayStepCounter/3f9814255fe925dafc0dba13295280fcf8a836c4/screenshots/screenshots.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':lib-todaystepcounter', ':base-lib-notification', ':lib-jlogger'
2 |
--------------------------------------------------------------------------------