计步ok了
This commit is contained in:
70
todaystepcounterlib/src/main/AndroidManifest.xml
Normal file
70
todaystepcounterlib/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,70 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.today.step.lib">
|
||||
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
|
||||
|
||||
<!-- 协处理器计步权限 -->
|
||||
<uses-feature
|
||||
android:name="android.hardware.sensor.stepcounter"
|
||||
android:required="true" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.sensor.stepdetector"
|
||||
android:required="true" />
|
||||
|
||||
<application>
|
||||
|
||||
<!--计步Service-->
|
||||
<service
|
||||
android:name=".TodayStepService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":todaystep"
|
||||
android:launchMode="singleInstance"
|
||||
android:priority="1000">
|
||||
<intent-filter>
|
||||
|
||||
<!-- 系统启动完成后会调用 -->
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.DATE_CHANGED" />
|
||||
<action android:name="android.intent.action.MEDIA_MOUNTED" />
|
||||
<action android:name="android.intent.action.USER_PRESENT" />
|
||||
<action android:name="android.intent.action.ACTION_TIME_TICK" />
|
||||
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
|
||||
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!--开机自启动-->
|
||||
<receiver
|
||||
android:name=".TodayStepBootCompleteReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- 关机广播 -->
|
||||
<receiver android:name=".TodayStepShutdownReceiver" >
|
||||
<intent-filter>
|
||||
<!-- 关机广播 -->
|
||||
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!--0点分隔alertmanager-->
|
||||
<receiver
|
||||
android:name=".TodayStepAlertReceive"
|
||||
android:enabled="true"
|
||||
android:exported="false"></receiver>
|
||||
|
||||
<service android:name=".JobSchedulerService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,35 @@
|
||||
// ISportStepInterface.aidl
|
||||
package com.today.step.lib;
|
||||
|
||||
interface ISportStepInterface {
|
||||
/**
|
||||
* 获取当前时间运动步数
|
||||
*/
|
||||
int getCurrentTimeSportStep();
|
||||
|
||||
/**
|
||||
* 获取所有步数列表,json格式,如果数据过多建议在线程中获取,否则会阻塞UI线程
|
||||
*/
|
||||
String getTodaySportStepArray();
|
||||
|
||||
/**
|
||||
* 根据时间获取步数列表
|
||||
*
|
||||
* @param dateString 格式yyyy-MM-dd
|
||||
* @return
|
||||
*/
|
||||
String getTodaySportStepArrayByDate(String date);
|
||||
|
||||
/**
|
||||
* 根据时间和天数获取步数列表
|
||||
* 例如:
|
||||
* startDate = 2018-01-15
|
||||
* days = 3
|
||||
* 获取 2018-01-15、2018-01-16、2018-01-17三天的步数
|
||||
*
|
||||
* @param startDate 格式yyyy-MM-dd
|
||||
* @param days
|
||||
* @return
|
||||
*/
|
||||
String getTodaySportStepArrayByStartDateAndDays(String date, int days);
|
||||
}
|
||||
4
todaystepcounterlib/src/main/assets/microlog.properties
Normal file
4
todaystepcounterlib/src/main/assets/microlog.properties
Normal file
@@ -0,0 +1,4 @@
|
||||
# This is a simple Microlog configuration file
|
||||
microlog.level=DEBUG
|
||||
microlog.appender=LogCatAppender;FileAppender
|
||||
microlog.formatter=SimpleFormatter
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
|
||||
/**
|
||||
* 通知栏点击通知
|
||||
* Created by jiahongfei on 2017/10/19.
|
||||
*/
|
||||
|
||||
public abstract class BaseClickBroadcast extends BroadcastReceiver {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @Description: 时间工具类(时间格式转换方便类)
|
||||
*/
|
||||
class DateUtils {
|
||||
|
||||
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat();
|
||||
|
||||
/**
|
||||
* 返回一定格式的当前时间
|
||||
*
|
||||
* @param pattern "yyyy-MM-dd HH:mm:ss E"
|
||||
* @return
|
||||
*/
|
||||
public static String getCurrentDate(String pattern) {
|
||||
SIMPLE_DATE_FORMAT.applyPattern(pattern);
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
String dateString = SIMPLE_DATE_FORMAT.format(date);
|
||||
return dateString;
|
||||
|
||||
}
|
||||
|
||||
public static long getDateMillis(String dateString, String pattern) {
|
||||
long millionSeconds = 0;
|
||||
SIMPLE_DATE_FORMAT.applyPattern(pattern);
|
||||
try {
|
||||
millionSeconds = SIMPLE_DATE_FORMAT.parse(dateString).getTime();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}// 毫秒
|
||||
|
||||
return millionSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化输入的millis
|
||||
*
|
||||
* @param millis
|
||||
* @param pattern yyyy-MM-dd HH:mm:ss E
|
||||
* @return
|
||||
*/
|
||||
public static String dateFormat(long millis, String pattern) {
|
||||
SIMPLE_DATE_FORMAT.applyPattern(pattern);
|
||||
Date date = new Date(millis);
|
||||
String dateString = SIMPLE_DATE_FORMAT.format(date);
|
||||
return dateString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将dateString原来old格式转换成new格式
|
||||
*
|
||||
* @param dateString
|
||||
* @param oldPattern yyyy-MM-dd HH:mm:ss E
|
||||
* @param newPattern
|
||||
* @return oldPattern和dateString形式不一样直接返回dateString
|
||||
*/
|
||||
public static String dateFormat(String dateString, String oldPattern,
|
||||
String newPattern) {
|
||||
long millis = getDateMillis(dateString, oldPattern);
|
||||
if (0 == millis) {
|
||||
return dateString;
|
||||
}
|
||||
String date = dateFormat(millis, newPattern);
|
||||
return date;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : jiahongfei
|
||||
* @email : jiahongfeinew@163.com
|
||||
* @date : 2018/1/22
|
||||
* @desc :
|
||||
*/
|
||||
|
||||
interface ITodayStepDBHelper {
|
||||
|
||||
void createTable();
|
||||
|
||||
void deleteTable();
|
||||
|
||||
void clearCapacity(String curDate, int limit);
|
||||
|
||||
boolean isExist(TodayStepData todayStepData);
|
||||
|
||||
void insert(TodayStepData todayStepData);
|
||||
|
||||
List<TodayStepData> getQueryAll();
|
||||
|
||||
List<TodayStepData> getStepListByDate(String dateString);
|
||||
|
||||
List<TodayStepData> getStepListByStartDateAndDays(String startDate, int days);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.app.job.JobParameters;
|
||||
import android.app.job.JobService;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
/**
|
||||
*
|
||||
* Created by jiahongfei on 2017/10/13.
|
||||
*/
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public class JobSchedulerService extends JobService {
|
||||
|
||||
private static final String TAG = "JobSchedulerService";
|
||||
|
||||
@Override
|
||||
public boolean onStartJob(JobParameters params) {
|
||||
Intent intent = new Intent(getApplication(), TodayStepService.class);
|
||||
getApplication().startService(intent);
|
||||
|
||||
// Toast.makeText(getApplicationContext(), "onStartJob", Toast.LENGTH_SHORT).show();
|
||||
|
||||
Logger.e(TAG,"onStartJob");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onStopJob(JobParameters params) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* 日志打印工具类,封装到一起,是为了调用时方便
|
||||
*
|
||||
* @author Administrator
|
||||
*/
|
||||
class Logger {
|
||||
private static final String TAG = "Logger";
|
||||
|
||||
public static boolean sIsDebug = BuildConfig.TODAY_STEP_DEBUG;
|
||||
|
||||
public static void v(String message) {
|
||||
if (sIsDebug)
|
||||
Log.v(TAG, message);
|
||||
}
|
||||
|
||||
public static void v(String tag, String message) {
|
||||
if (sIsDebug)
|
||||
Log.v(tag, message);
|
||||
}
|
||||
|
||||
public static void d(String message) {
|
||||
if (sIsDebug)
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
|
||||
public static void i(String message) {
|
||||
if (sIsDebug)
|
||||
Log.i(TAG, message);
|
||||
}
|
||||
|
||||
public static void i(String tag, String message) {
|
||||
if (sIsDebug)
|
||||
Log.i(tag, message);
|
||||
}
|
||||
|
||||
public static void w(String message) {
|
||||
if (sIsDebug)
|
||||
Log.w(TAG, message);
|
||||
}
|
||||
|
||||
public static void w(String tag, String message) {
|
||||
if (sIsDebug)
|
||||
Log.w(tag, message);
|
||||
}
|
||||
|
||||
public static void e(String message) {
|
||||
if (sIsDebug)
|
||||
Log.e(TAG, message);
|
||||
}
|
||||
|
||||
public static void e(String tag, String message) {
|
||||
if (sIsDebug)
|
||||
Log.e(tag, message);
|
||||
}
|
||||
|
||||
public static void d(String tag, String message) {
|
||||
if (!TextUtils.isEmpty(message) && sIsDebug) {
|
||||
Log.d(TextUtils.isEmpty(tag) ? TAG : tag, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.code.microlog4android.LoggerFactory;
|
||||
import com.google.code.microlog4android.appender.FileAppender;
|
||||
import com.google.code.microlog4android.config.PropertyConfigurator;
|
||||
|
||||
/**
|
||||
* @author : jiahongfei
|
||||
* @email : jiahongfeinew@163.com
|
||||
* @date : 2018/2/6
|
||||
* @desc :
|
||||
*/
|
||||
|
||||
public class Microlog4Android {
|
||||
|
||||
private static final com.google.code.microlog4android.Logger logger = LoggerFactory.getLogger();
|
||||
|
||||
public void configure(Context context){
|
||||
if(null != logger) {
|
||||
PropertyConfigurator.getConfigurator(context).configure();
|
||||
FileAppender appender = (FileAppender) logger.getAppender(1);
|
||||
appender.setAppend(true);
|
||||
logger.addAppender(appender);
|
||||
}
|
||||
}
|
||||
|
||||
public void error(Object message){
|
||||
if(null != logger) {
|
||||
logger.error(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
/**
|
||||
* Created by jiahongfei on 2017/6/30.
|
||||
*/
|
||||
|
||||
interface OnStepCounterListener {
|
||||
|
||||
/**
|
||||
* 用于显示步数
|
||||
* @param step
|
||||
*/
|
||||
void onChangeStepCounter(int step);
|
||||
|
||||
/**
|
||||
* 步数清零监听,由于跨越0点需要重新计步
|
||||
*/
|
||||
void onStepCounterClean();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
|
||||
/**
|
||||
* @ClassName: PreferencesHelper
|
||||
* @Description: (公用类,用于缓存一些key——value类型的数据)
|
||||
*/
|
||||
|
||||
class PreferencesHelper {
|
||||
|
||||
private static final String TAG = "PreferencesHelper";
|
||||
|
||||
public static final String APP_SHARD = "today_step_share_prefs";
|
||||
|
||||
// 上一次计步器的步数
|
||||
public static final String LAST_SENSOR_TIME = "last_sensor_time";
|
||||
// 步数补偿数值,每次传感器返回的步数-offset=当前步数
|
||||
public static final String STEP_OFFSET = "step_offset";
|
||||
// 当天,用来判断是否跨天
|
||||
public static final String STEP_TODAY = "step_today";
|
||||
// 清除步数
|
||||
public static final String CLEAN_STEP = "clean_step";
|
||||
// 当前步数
|
||||
public static final String CURR_STEP = "curr_step";
|
||||
//手机关机监听
|
||||
public static final String SHUTDOWN = "shutdown";
|
||||
//系统运行时间
|
||||
public static final String ELAPSED_REALTIMEl = "elapsed_realtime";
|
||||
|
||||
/**
|
||||
* Get SharedPreferences
|
||||
*/
|
||||
private static SharedPreferences getSharedPreferences(Context context) {
|
||||
return context.getSharedPreferences(APP_SHARD, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public static void setLastSensorStep(Context context, float lastSensorStep){
|
||||
Logger.e(TAG, "setLastSensorStep");
|
||||
getSharedPreferences(context).edit().putFloat(LAST_SENSOR_TIME,lastSensorStep).commit();
|
||||
}
|
||||
|
||||
public static float getLastSensorStep(Context context){
|
||||
Logger.e(TAG, "getLastSensorStep");
|
||||
return getSharedPreferences(context).getFloat(LAST_SENSOR_TIME,0.0f);
|
||||
}
|
||||
|
||||
public static void setStepOffset(Context context, float stepOffset){
|
||||
Logger.e(TAG, "setStepOffset");
|
||||
getSharedPreferences(context).edit().putFloat(STEP_OFFSET,stepOffset).commit();
|
||||
}
|
||||
|
||||
public static float getStepOffset(Context context){
|
||||
Logger.e(TAG, "getStepOffset");
|
||||
return getSharedPreferences(context).getFloat(STEP_OFFSET,0.0f);
|
||||
}
|
||||
|
||||
public static void setStepToday(Context context, String stepToday){
|
||||
Logger.e(TAG, "setStepToday");
|
||||
getSharedPreferences(context).edit().putString(STEP_TODAY,stepToday).commit();
|
||||
}
|
||||
|
||||
public static String getStepToday(Context context){
|
||||
Logger.e(TAG, "getStepToday");
|
||||
return getSharedPreferences(context).getString(STEP_TODAY,"");
|
||||
}
|
||||
|
||||
/**
|
||||
* true清除步数从0开始,false否
|
||||
* @param context
|
||||
* @param cleanStep
|
||||
*/
|
||||
public static void setCleanStep(Context context, boolean cleanStep){
|
||||
Logger.e(TAG, "setCleanStep");
|
||||
getSharedPreferences(context).edit().putBoolean(CLEAN_STEP,cleanStep).commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* true 清除步数,false否
|
||||
* @param context
|
||||
* @return
|
||||
*/
|
||||
public static boolean getCleanStep(Context context){
|
||||
Logger.e(TAG, "getCleanStep");
|
||||
return getSharedPreferences(context).getBoolean(CLEAN_STEP,true);
|
||||
}
|
||||
|
||||
public static void setCurrentStep(Context context, float currStep){
|
||||
Logger.e(TAG, "setCurrentStep");
|
||||
getSharedPreferences(context).edit().putFloat(CURR_STEP,currStep).commit();
|
||||
}
|
||||
|
||||
public static float getCurrentStep(Context context){
|
||||
Logger.e(TAG, "getCurrentStep");
|
||||
return getSharedPreferences(context).getFloat(CURR_STEP,0.0f);
|
||||
}
|
||||
|
||||
public static void setShutdown(Context context, boolean shutdown){
|
||||
Logger.e(TAG, "setShutdown");
|
||||
getSharedPreferences(context).edit().putBoolean(SHUTDOWN,shutdown).commit();
|
||||
}
|
||||
|
||||
public static boolean getShutdown(Context context){
|
||||
Logger.e(TAG, "getShutdown");
|
||||
return getSharedPreferences(context).getBoolean(SHUTDOWN, false);
|
||||
}
|
||||
|
||||
public static void setElapsedRealtime(Context context, long elapsedRealtime){
|
||||
Logger.e(TAG, "setElapsedRealtime");
|
||||
getSharedPreferences(context).edit().putLong(ELAPSED_REALTIMEl,elapsedRealtime).commit();
|
||||
}
|
||||
|
||||
public static long getElapsedRealtime(Context context){
|
||||
Logger.e(TAG, "getElapsedRealtime");
|
||||
return getSharedPreferences(context).getLong(ELAPSED_REALTIMEl, 0L);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : jiahongfei
|
||||
* @email : jiahongfeinew@163.com
|
||||
* @date : 2018/1/31
|
||||
* @desc : 用于解析和生成运动步数Json字符串
|
||||
*/
|
||||
|
||||
public class SportStepJsonUtils {
|
||||
|
||||
public static final String SPORT_DATE = "sportDate";
|
||||
public static final String STEP_NUM = "stepNum";
|
||||
public static final String DISTANCE = "km";
|
||||
public static final String CALORIE = "kaluli";
|
||||
public static final String TODAY = TodayStepDBHelper.TODAY;
|
||||
|
||||
static JSONArray getSportStepJsonArray(List<TodayStepData> todayStepDataArrayList) {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
if (null == todayStepDataArrayList || 0 == todayStepDataArrayList.size()) {
|
||||
return jsonArray;
|
||||
}
|
||||
for (int i = 0; i < todayStepDataArrayList.size(); i++) {
|
||||
TodayStepData todayStepData = todayStepDataArrayList.get(i);
|
||||
try {
|
||||
JSONObject subObject = new JSONObject();
|
||||
subObject.put(TODAY, todayStepData.getToday());
|
||||
subObject.put(SPORT_DATE, todayStepData.getDate());
|
||||
subObject.put(STEP_NUM, todayStepData.getStep());
|
||||
subObject.put(DISTANCE, getDistanceByStep(todayStepData.getStep()));
|
||||
subObject.put(CALORIE, getCalorieByStep(todayStepData.getStep()));
|
||||
jsonArray.put(subObject);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
// 公里计算公式
|
||||
static String getDistanceByStep(long steps) {
|
||||
return String.format("%.2f", steps * 0.6f / 1000);
|
||||
}
|
||||
|
||||
// 千卡路里计算公式
|
||||
static String getCalorieByStep(long steps) {
|
||||
return String.format("%.1f", steps * 0.6f * 60 * 1.036f / 1000);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import static android.content.Context.ALARM_SERVICE;
|
||||
|
||||
/**
|
||||
* Created by jiahongfei on 2017/6/18.
|
||||
*/
|
||||
class StepAlertManagerUtils {
|
||||
|
||||
private static final String TAG = "StepAlertManagerUtils";
|
||||
|
||||
/**
|
||||
* 设置0点分隔Alert,当前天+1天的0点启动
|
||||
*
|
||||
* @param application
|
||||
*/
|
||||
public static void set0SeparateAlertManager(Context application) {
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(System.currentTimeMillis());
|
||||
calendar.add(Calendar.DAY_OF_YEAR,1);
|
||||
String tomorrow = DateUtils.dateFormat(calendar.getTimeInMillis(),"yyyy-MM-dd");
|
||||
long timeInMillis = DateUtils.getDateMillis(tomorrow+ " 00:00:00","yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
Logger.e(TAG, DateUtils.dateFormat(timeInMillis,"yyyy-MM-dd HH:mm:ss"));
|
||||
|
||||
AlarmManager alarmManager = (AlarmManager) application.getSystemService(ALARM_SERVICE);
|
||||
Intent i1 = new Intent(application, TodayStepAlertReceive.class);
|
||||
i1.putExtra(TodayStepService.INTENT_NAME_0_SEPARATE, true);
|
||||
i1.setAction(TodayStepAlertReceive.ACTION_STEP_ALERT);
|
||||
PendingIntent operation = PendingIntent.getBroadcast(application, 0, i1, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeInMillis, operation);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeInMillis, operation);
|
||||
} else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, timeInMillis, operation);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* 0点启动app处理步数
|
||||
* Created by jiahongfei on 2017/6/18.
|
||||
*/
|
||||
|
||||
public class TodayStepAlertReceive extends BroadcastReceiver {
|
||||
|
||||
public static final String ACTION_STEP_ALERT = "action_step_alert";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (ACTION_STEP_ALERT.equals(intent.getAction())) {
|
||||
boolean separate = intent.getBooleanExtra(TodayStepService.INTENT_NAME_0_SEPARATE, false);
|
||||
Intent stepInent = new Intent(context, TodayStepService.class);
|
||||
stepInent.putExtra(TodayStepService.INTENT_NAME_0_SEPARATE, separate);
|
||||
context.startService(stepInent);
|
||||
|
||||
StepAlertManagerUtils.set0SeparateAlertManager(context.getApplicationContext());
|
||||
|
||||
Logger.e("TodayStepAlertReceive","TodayStepAlertReceive");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* 开机完成广播
|
||||
*
|
||||
*/
|
||||
public class TodayStepBootCompleteReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "TodayStepBootCompleteReceiver";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
Intent todayStepIntent = new Intent(context, TodayStepService.class);
|
||||
todayStepIntent.putExtra(TodayStepService.INTENT_NAME_BOOT,true);
|
||||
context.startService(todayStepIntent);
|
||||
|
||||
Logger.e(TAG,"TodayStepBootCompleteReceiver");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.os.PowerManager;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* android4.4 Sensor.TYPE_STEP_COUNTER
|
||||
* 计步传感器计算当天步数,不需要后台Service
|
||||
* Created by jiahongfei on 2017/6/30.
|
||||
*/
|
||||
|
||||
class TodayStepCounter implements SensorEventListener {
|
||||
|
||||
private static final String TAG = "TodayStepCounter";
|
||||
|
||||
private int sOffsetStep = 0;
|
||||
private int sCurrStep = 0;
|
||||
private String mTodayDate;
|
||||
private boolean mCleanStep = true;
|
||||
private boolean mShutdown = false;
|
||||
/**
|
||||
* 用来标识对象第一次创建,
|
||||
*/
|
||||
private boolean mCounterStepReset = true;
|
||||
|
||||
private Context mContext;
|
||||
private OnStepCounterListener mOnStepCounterListener;
|
||||
|
||||
private boolean mSeparate = false;
|
||||
private boolean mBoot = false;
|
||||
|
||||
public TodayStepCounter(Context context, OnStepCounterListener onStepCounterListener, boolean separate, boolean boot) {
|
||||
this.mContext = context;
|
||||
this.mSeparate = separate;
|
||||
this.mBoot = boot;
|
||||
this.mOnStepCounterListener = onStepCounterListener;
|
||||
|
||||
WakeLockUtils.getLock(mContext);
|
||||
|
||||
sCurrStep = (int) PreferencesHelper.getCurrentStep(mContext);
|
||||
mCleanStep = PreferencesHelper.getCleanStep(mContext);
|
||||
mTodayDate = PreferencesHelper.getStepToday(mContext);
|
||||
sOffsetStep = (int) PreferencesHelper.getStepOffset(mContext);
|
||||
mShutdown = PreferencesHelper.getShutdown(mContext);
|
||||
Logger.e(TAG, "mShutdown : " + mShutdown);
|
||||
//开机启动监听到,一定是关机开机了
|
||||
if (mBoot || shutdownBySystemRunningTime()) {
|
||||
mShutdown = true;
|
||||
PreferencesHelper.setShutdown(mContext, mShutdown);
|
||||
Logger.e(TAG, "开机启动监听到");
|
||||
}
|
||||
|
||||
dateChangeCleanStep();
|
||||
|
||||
initBroadcastReceiver();
|
||||
|
||||
updateStepCounter();
|
||||
|
||||
}
|
||||
|
||||
private void initBroadcastReceiver() {
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_TIME_TICK);
|
||||
filter.addAction(Intent.ACTION_DATE_CHANGED);
|
||||
BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
if (Intent.ACTION_TIME_TICK.equals(intent.getAction())
|
||||
|| Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
|
||||
|
||||
Logger.e(TAG, "ACTION_TIME_TICK");
|
||||
//service存活做0点分隔
|
||||
dateChangeCleanStep();
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
mContext.registerReceiver(mBatInfoReceiver, filter);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
|
||||
if (event.sensor.getType() == Sensor.TYPE_STEP_COUNTER) {
|
||||
|
||||
int counterStep = (int) event.values[0];
|
||||
|
||||
if (mCleanStep) {
|
||||
//TODO:只有传感器回调才会记录当前传感器步数,然后对当天步数进行清零,所以步数会少,少的步数等于传感器启动需要的步数,假如传感器需要10步进行启动,那么就少10步
|
||||
cleanStep(counterStep);
|
||||
} else {
|
||||
//处理关机启动
|
||||
if (mShutdown || shutdownByCounterStep(counterStep)) {
|
||||
Logger.e(TAG, "onSensorChanged shutdown");
|
||||
shutdown(counterStep);
|
||||
}
|
||||
}
|
||||
sCurrStep = counterStep - sOffsetStep;
|
||||
|
||||
if (sCurrStep < 0) {
|
||||
//容错处理,无论任何原因步数不能小于0,如果小于0,直接清零
|
||||
Logger.e(TAG, "容错处理,无论任何原因步数不能小于0,如果小于0,直接清零");
|
||||
cleanStep(counterStep);
|
||||
}
|
||||
|
||||
PreferencesHelper.setCurrentStep(mContext, sCurrStep);
|
||||
PreferencesHelper.setElapsedRealtime(mContext, SystemClock.elapsedRealtime());
|
||||
PreferencesHelper.setLastSensorStep(mContext, counterStep);
|
||||
|
||||
Logger.e(TAG, "counterStep : " + counterStep + " --- " + "sOffsetStep : " + sOffsetStep + " --- " + "sCurrStep : " + sCurrStep);
|
||||
|
||||
updateStepCounter();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanStep(int counterStep) {
|
||||
//清除步数,步数归零,优先级最高
|
||||
sCurrStep = 0;
|
||||
sOffsetStep = counterStep;
|
||||
PreferencesHelper.setStepOffset(mContext, sOffsetStep);
|
||||
|
||||
mCleanStep = false;
|
||||
PreferencesHelper.setCleanStep(mContext, mCleanStep);
|
||||
|
||||
Logger.e(TAG, "mCleanStep : " + "清除步数,步数归零");
|
||||
}
|
||||
|
||||
private void shutdown(int counterStep) {
|
||||
int tmpCurrStep = (int) PreferencesHelper.getCurrentStep(mContext);
|
||||
//重新设置offset
|
||||
sOffsetStep = counterStep - tmpCurrStep;
|
||||
PreferencesHelper.setStepOffset(mContext, sOffsetStep);
|
||||
|
||||
mShutdown = false;
|
||||
PreferencesHelper.setShutdown(mContext, mShutdown);
|
||||
}
|
||||
|
||||
private boolean shutdownByCounterStep(int counterStep) {
|
||||
if (mCounterStepReset) {
|
||||
//只判断一次
|
||||
if (counterStep < PreferencesHelper.getLastSensorStep(mContext)) {
|
||||
//当前传感器步数小于上次传感器步数肯定是重新启动了,只是用来增加精度不是绝对的
|
||||
Logger.e(TAG, "当前传感器步数小于上次传感器步数肯定是重新启动了,只是用来增加精度不是绝对的");
|
||||
return true;
|
||||
}
|
||||
mCounterStepReset = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean shutdownBySystemRunningTime() {
|
||||
if (PreferencesHelper.getElapsedRealtime(mContext) > SystemClock.elapsedRealtime()) {
|
||||
//上次运行的时间大于当前运行时间判断为重启,只是增加精度,极端情况下连续重启,会判断不出来
|
||||
Logger.e(TAG, "上次运行的时间大于当前运行时间判断为重启,只是增加精度,极端情况下连续重启,会判断不出来");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private synchronized void dateChangeCleanStep() {
|
||||
//时间改变了清零,或者0点分隔回调
|
||||
if (!getTodayDate().equals(mTodayDate) || mSeparate) {
|
||||
|
||||
WakeLockUtils.getLock(mContext);
|
||||
|
||||
mCleanStep = true;
|
||||
PreferencesHelper.setCleanStep(mContext, mCleanStep);
|
||||
|
||||
mTodayDate = getTodayDate();
|
||||
PreferencesHelper.setStepToday(mContext, mTodayDate);
|
||||
|
||||
mShutdown = false;
|
||||
PreferencesHelper.setShutdown(mContext, mShutdown);
|
||||
|
||||
mBoot = false;
|
||||
|
||||
mSeparate = false;
|
||||
|
||||
sCurrStep = 0;
|
||||
PreferencesHelper.setCurrentStep(mContext, sCurrStep);
|
||||
|
||||
if (null != mOnStepCounterListener) {
|
||||
mOnStepCounterListener.onStepCounterClean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getTodayDate() {
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
private void updateStepCounter() {
|
||||
|
||||
//每次回调都判断一下是否跨天
|
||||
dateChangeCleanStep();
|
||||
|
||||
if (null != mOnStepCounterListener) {
|
||||
mOnStepCounterListener.onChangeStepCounter(sCurrStep);
|
||||
}
|
||||
}
|
||||
|
||||
public int getCurrentStep() {
|
||||
sCurrStep = (int) PreferencesHelper.getCurrentStep(mContext);
|
||||
return sCurrStep;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用来记录当天步数列表,传感器回调30次记录一条数据
|
||||
* Created by jiahongfei on 2017/10/9.
|
||||
*/
|
||||
|
||||
class TodayStepDBHelper extends SQLiteOpenHelper implements ITodayStepDBHelper{
|
||||
|
||||
private static final String TAG = "TodayStepDBHelper";
|
||||
|
||||
private static final String DATE_PATTERN_YYYY_MM_DD = "yyyy-MM-dd";
|
||||
|
||||
private static final int VERSION = 1;
|
||||
private static final String DATABASE_NAME = "TodayStepDB.db";
|
||||
private static final String TABLE_NAME = "TodayStepData";
|
||||
private static final String PRIMARY_KEY = "_id";
|
||||
public static final String TODAY = "today";
|
||||
public static final String DATE = "date";
|
||||
public static final String STEP = "step";
|
||||
|
||||
private static final String SQL_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
|
||||
+ PRIMARY_KEY + " INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||
+ TODAY + " TEXT, "
|
||||
+ DATE + " long, "
|
||||
+ STEP + " long);";
|
||||
private static final String SQL_DELETE_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME;
|
||||
private static final String SQL_QUERY_ALL = "SELECT * FROM " + TABLE_NAME;
|
||||
private static final String SQL_QUERY_STEP = "SELECT * FROM " + TABLE_NAME + " WHERE " + TODAY + " = ? AND " + STEP + " = ?";
|
||||
private static final String SQL_QUERY_STEP_BY_DATE = "SELECT * FROM " + TABLE_NAME + " WHERE " + TODAY + " = ?";
|
||||
private static final String SQL_DELETE_TODAY = "DELETE FROM " + TABLE_NAME + " WHERE " + TODAY + " = ?";
|
||||
|
||||
//只保留mLimit天的数据
|
||||
private int mLimit = -1;
|
||||
|
||||
public static ITodayStepDBHelper factory(Context context){
|
||||
return new TodayStepDBHelper(context);
|
||||
}
|
||||
|
||||
private TodayStepDBHelper(Context context) {
|
||||
super(context, DATABASE_NAME, null, VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
|
||||
Logger.e(TAG, SQL_CREATE_TABLE);
|
||||
db.execSQL(SQL_CREATE_TABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
deleteTable();
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean isExist(TodayStepData todayStepData) {
|
||||
Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_STEP, new String[]{todayStepData.getToday(), todayStepData.getStep() + ""});
|
||||
boolean exist = cursor.getCount() > 0 ? true : false;
|
||||
cursor.close();
|
||||
return exist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void createTable() {
|
||||
getWritableDatabase().execSQL(SQL_CREATE_TABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void insert(TodayStepData todayStepData) {
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(TODAY, todayStepData.getToday());
|
||||
contentValues.put(DATE, todayStepData.getDate());
|
||||
contentValues.put(STEP, todayStepData.getStep());
|
||||
getWritableDatabase().insert(TABLE_NAME, null, contentValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<TodayStepData> getQueryAll() {
|
||||
Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_ALL, new String[]{});
|
||||
List<TodayStepData> todayStepDatas = getTodayStepDataList(cursor);
|
||||
cursor.close();
|
||||
return todayStepDatas;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据时间获取步数列表
|
||||
*
|
||||
* @param dateString 格式yyyy-MM-dd
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public synchronized List<TodayStepData> getStepListByDate(String dateString) {
|
||||
Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_STEP_BY_DATE, new String[]{dateString});
|
||||
List<TodayStepData> todayStepDatas = getTodayStepDataList(cursor);
|
||||
cursor.close();
|
||||
return todayStepDatas;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据时间和天数获取步数列表
|
||||
* 例如:
|
||||
* startDate = 2018-01-15
|
||||
* days = 3
|
||||
* 获取 2018-01-15、2018-01-16、2018-01-17三天的步数
|
||||
*
|
||||
* @param startDate 格式yyyy-MM-dd
|
||||
* @param days
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public synchronized List<TodayStepData> getStepListByStartDateAndDays(String startDate, int days) {
|
||||
List<TodayStepData> todayStepDatas = new ArrayList<>();
|
||||
for (int i = 0; i < days; i++) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(DateUtils.getDateMillis(startDate, DATE_PATTERN_YYYY_MM_DD));
|
||||
calendar.add(Calendar.DAY_OF_YEAR, i);
|
||||
Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_STEP_BY_DATE,
|
||||
new String[]{DateUtils.dateFormat(calendar.getTimeInMillis(), DATE_PATTERN_YYYY_MM_DD)});
|
||||
todayStepDatas.addAll(getTodayStepDataList(cursor));
|
||||
cursor.close();
|
||||
}
|
||||
return todayStepDatas;
|
||||
}
|
||||
|
||||
private List<TodayStepData> getTodayStepDataList(Cursor cursor) {
|
||||
|
||||
List<TodayStepData> todayStepDatas = new ArrayList<>();
|
||||
while (cursor.moveToNext()) {
|
||||
String today = cursor.getString(cursor.getColumnIndex(TODAY));
|
||||
long date = cursor.getLong(cursor.getColumnIndex(DATE));
|
||||
long step = cursor.getLong(cursor.getColumnIndex(STEP));
|
||||
TodayStepData todayStepData = new TodayStepData();
|
||||
todayStepData.setToday(today);
|
||||
todayStepData.setDate(date);
|
||||
todayStepData.setStep(step);
|
||||
todayStepDatas.add(todayStepData);
|
||||
}
|
||||
return todayStepDatas;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据limit来清除数据库
|
||||
* 例如:
|
||||
* curDate = 2018-01-10 limit=0;表示只保留2018-01-10
|
||||
* curDate = 2018-01-10 limit=1;表示保留2018-01-10、2018-01-09等
|
||||
* @param curDate
|
||||
* @param limit -1失效
|
||||
*/
|
||||
@Override
|
||||
public synchronized void clearCapacity(String curDate, int limit) {
|
||||
mLimit = limit;
|
||||
if (mLimit <= 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(DateUtils.getDateMillis(curDate, DATE_PATTERN_YYYY_MM_DD));
|
||||
calendar.add(Calendar.DAY_OF_YEAR, -(mLimit));
|
||||
String date = DateUtils.dateFormat(calendar.getTimeInMillis(), DATE_PATTERN_YYYY_MM_DD);
|
||||
Log.e(TAG, date);
|
||||
|
||||
List<TodayStepData> todayStepDataList = getQueryAll();
|
||||
Set<String> delDateSet = new HashSet<>();
|
||||
for (TodayStepData tmpTodayStepData : todayStepDataList) {
|
||||
long dbTodayDate = DateUtils.getDateMillis(tmpTodayStepData.getToday(), DATE_PATTERN_YYYY_MM_DD);
|
||||
if (calendar.getTimeInMillis() >= dbTodayDate) {
|
||||
delDateSet.add(tmpTodayStepData.getToday());
|
||||
}
|
||||
}
|
||||
|
||||
for (String delDate : delDateSet) {
|
||||
getWritableDatabase().execSQL(SQL_DELETE_TODAY, new String[]{delDate});
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void deleteTable() {
|
||||
getWritableDatabase().execSQL(SQL_DELETE_TABLE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
public class TodayStepData implements Serializable, Parcelable {
|
||||
|
||||
//当天时间,只显示到天 yyyy-MM-dd
|
||||
private String today;
|
||||
//步数时间,显示到毫秒
|
||||
private long date;
|
||||
//对应date时间的步数
|
||||
private long step;
|
||||
|
||||
public TodayStepData() {
|
||||
|
||||
}
|
||||
|
||||
protected TodayStepData(Parcel in) {
|
||||
today = in.readString();
|
||||
date = in.readLong();
|
||||
step = in.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(today);
|
||||
dest.writeLong(date);
|
||||
dest.writeLong(step);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final Creator<TodayStepData> CREATOR = new Creator<TodayStepData>() {
|
||||
@Override
|
||||
public TodayStepData createFromParcel(Parcel in) {
|
||||
return new TodayStepData(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TodayStepData[] newArray(int size) {
|
||||
return new TodayStepData[size];
|
||||
}
|
||||
};
|
||||
|
||||
public long getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(long date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public long getStep() {
|
||||
return step;
|
||||
}
|
||||
|
||||
public void setStep(long step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
public String getToday() {
|
||||
return today;
|
||||
}
|
||||
|
||||
public void setToday(String today) {
|
||||
this.today = today;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TodayStepData{" +
|
||||
", today=" + today +
|
||||
", date=" + date +
|
||||
", step=" + step +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Sensor.TYPE_ACCELEROMETER
|
||||
* 加速度传感器计算当天步数,需要保持后台Service
|
||||
*/
|
||||
class TodayStepDetector implements SensorEventListener{
|
||||
|
||||
private final String TAG = "TodayStepDetector";
|
||||
|
||||
//存放三轴数据
|
||||
float[] oriValues = new float[3];
|
||||
final int ValueNum = 4;
|
||||
//用于存放计算阈值的波峰波谷差值
|
||||
float[] tempValue = new float[ValueNum];
|
||||
int tempCount = 0;
|
||||
//是否上升的标志位
|
||||
boolean isDirectionUp = false;
|
||||
//持续上升次数
|
||||
int continueUpCount = 0;
|
||||
//上一点的持续上升的次数,为了记录波峰的上升次数
|
||||
int continueUpFormerCount = 0;
|
||||
//上一点的状态,上升还是下降
|
||||
boolean lastStatus = false;
|
||||
//波峰值
|
||||
float peakOfWave = 0;
|
||||
//波谷值
|
||||
float valleyOfWave = 0;
|
||||
//此次波峰的时间
|
||||
long timeOfThisPeak = 0;
|
||||
//上次波峰的时间
|
||||
long timeOfLastPeak = 0;
|
||||
//当前的时间
|
||||
long timeOfNow = 0;
|
||||
//当前传感器的值
|
||||
float gravityNew = 0;
|
||||
//上次传感器的值
|
||||
float gravityOld = 0;
|
||||
//动态阈值需要动态的数据,这个值用于这些动态数据的阈值
|
||||
final float InitialValue = (float) 1.3;
|
||||
//初始阈值
|
||||
float ThreadValue = (float) 2.0;
|
||||
//波峰波谷时间差
|
||||
int TimeInterval = 400;
|
||||
|
||||
private int count = 0;
|
||||
private int mCount = 0;
|
||||
private OnStepCounterListener mOnStepCounterListener;
|
||||
private Context mContext;
|
||||
private long timeOfLastPeak1 = 0;
|
||||
private long timeOfThisPeak1 = 0;
|
||||
private String mTodayDate;
|
||||
|
||||
public TodayStepDetector(Context context, OnStepCounterListener onStepCounterListener){
|
||||
super();
|
||||
mContext = context;
|
||||
this.mOnStepCounterListener = onStepCounterListener;
|
||||
|
||||
WakeLockUtils.getLock(mContext);
|
||||
|
||||
mCount = (int) PreferencesHelper.getCurrentStep(mContext);
|
||||
mTodayDate = PreferencesHelper.getStepToday(mContext);
|
||||
dateChangeCleanStep();
|
||||
initBroadcastReceiver();
|
||||
|
||||
updateStepCounter();
|
||||
|
||||
}
|
||||
|
||||
private void initBroadcastReceiver() {
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_TIME_TICK);
|
||||
filter.addAction(Intent.ACTION_DATE_CHANGED);
|
||||
BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
if (Intent.ACTION_TIME_TICK.equals(intent.getAction())
|
||||
|| Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
|
||||
Logger.e(TAG, "ACTION_TIME_TICK");
|
||||
//service存活做0点分隔
|
||||
dateChangeCleanStep();
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
mContext.registerReceiver(mBatInfoReceiver, filter);
|
||||
}
|
||||
|
||||
private synchronized void dateChangeCleanStep() {
|
||||
//时间改变了清零,或者0点分隔回调
|
||||
if (!getTodayDate().equals(mTodayDate)) {
|
||||
|
||||
WakeLockUtils.getLock(mContext);
|
||||
|
||||
mCount = 0;
|
||||
PreferencesHelper.setCurrentStep(mContext, mCount);
|
||||
|
||||
mTodayDate = getTodayDate();
|
||||
PreferencesHelper.setStepToday(mContext, mTodayDate);
|
||||
|
||||
setSteps(0);
|
||||
|
||||
if(null != mOnStepCounterListener){
|
||||
mOnStepCounterListener.onStepCounterClean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getTodayDate() {
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
private void updateStepCounter(){
|
||||
|
||||
//每次回调都判断一下是否跨天
|
||||
dateChangeCleanStep();
|
||||
|
||||
if (null != mOnStepCounterListener) {
|
||||
mOnStepCounterListener.onChangeStepCounter(mCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
oriValues[i] = event.values[i];
|
||||
}
|
||||
gravityNew = (float) Math.sqrt(oriValues[0] * oriValues[0]
|
||||
+ oriValues[1] * oriValues[1] + oriValues[2] * oriValues[2]);
|
||||
detectorNewStep(gravityNew);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
//
|
||||
}
|
||||
|
||||
/*
|
||||
* 检测步子,并开始计步
|
||||
* 1.传入sersor中的数据
|
||||
* 2.如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步
|
||||
* 3.符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中
|
||||
* */
|
||||
private void detectorNewStep(float values) {
|
||||
if (gravityOld == 0) {
|
||||
gravityOld = values;
|
||||
} else {
|
||||
if (detectorPeak(values, gravityOld)) {
|
||||
timeOfLastPeak = timeOfThisPeak;
|
||||
timeOfNow = System.currentTimeMillis();
|
||||
if (timeOfNow - timeOfLastPeak >= TimeInterval
|
||||
&& (peakOfWave - valleyOfWave >= ThreadValue)) {
|
||||
timeOfThisPeak = timeOfNow;
|
||||
/*
|
||||
* 更新界面的处理,不涉及到算法
|
||||
* 一般在通知更新界面之前,增加下面处理,为了处理无效运动:
|
||||
* 1.连续记录10才开始计步
|
||||
* 2.例如记录的9步用户停住超过3秒,则前面的记录失效,下次从头开始
|
||||
* 3.连续记录了9步用户还在运动,之前的数据才有效
|
||||
* */
|
||||
countStep();
|
||||
}
|
||||
if (timeOfNow - timeOfLastPeak >= TimeInterval
|
||||
&& (peakOfWave - valleyOfWave >= InitialValue)) {
|
||||
timeOfThisPeak = timeOfNow;
|
||||
ThreadValue = peakValleyThread(peakOfWave - valleyOfWave);
|
||||
}
|
||||
}
|
||||
}
|
||||
gravityOld = values;
|
||||
}
|
||||
|
||||
/*
|
||||
* 检测波峰
|
||||
* 以下四个条件判断为波峰:
|
||||
* 1.目前点为下降的趋势:isDirectionUp为false
|
||||
* 2.之前的点为上升的趋势:lastStatus为true
|
||||
* 3.到波峰为止,持续上升大于等于2次
|
||||
* 4.波峰值大于20
|
||||
* 记录波谷值
|
||||
* 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值
|
||||
* 2.所以要记录每次的波谷值,为了和下次的波峰做对比
|
||||
* */
|
||||
private boolean detectorPeak(float newValue, float oldValue) {
|
||||
lastStatus = isDirectionUp;
|
||||
if (newValue >= oldValue) {
|
||||
isDirectionUp = true;
|
||||
continueUpCount++;
|
||||
} else {
|
||||
continueUpFormerCount = continueUpCount;
|
||||
continueUpCount = 0;
|
||||
isDirectionUp = false;
|
||||
}
|
||||
|
||||
if (!isDirectionUp && lastStatus
|
||||
&& (continueUpFormerCount >= 2 || oldValue >= 20)) {
|
||||
peakOfWave = oldValue;
|
||||
return true;
|
||||
} else if (!lastStatus && isDirectionUp) {
|
||||
valleyOfWave = oldValue;
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 阈值的计算
|
||||
* 1.通过波峰波谷的差值计算阈值
|
||||
* 2.记录4个值,存入tempValue[]数组中
|
||||
* 3.在将数组传入函数averageValue中计算阈值
|
||||
* */
|
||||
private float peakValleyThread(float value) {
|
||||
float tempThread = ThreadValue;
|
||||
if (tempCount < ValueNum) {
|
||||
tempValue[tempCount] = value;
|
||||
tempCount++;
|
||||
} else {
|
||||
tempThread = averageValue(tempValue, ValueNum);
|
||||
for (int i = 1; i < ValueNum; i++) {
|
||||
tempValue[i - 1] = tempValue[i];
|
||||
}
|
||||
tempValue[ValueNum - 1] = value;
|
||||
}
|
||||
return tempThread;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* 梯度化阈值
|
||||
* 1.计算数组的均值
|
||||
* 2.通过均值将阈值梯度化在一个范围里
|
||||
* */
|
||||
private float averageValue(float value[], int n) {
|
||||
float ave = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
ave += value[i];
|
||||
}
|
||||
ave = ave / ValueNum;
|
||||
if (ave >= 8)
|
||||
ave = (float) 4.3;
|
||||
else if (ave >= 7 && ave < 8)
|
||||
ave = (float) 3.3;
|
||||
else if (ave >= 4 && ave < 7)
|
||||
ave = (float) 2.3;
|
||||
else if (ave >= 3 && ave < 4)
|
||||
ave = (float) 2.0;
|
||||
else {
|
||||
ave = (float) 1.7;
|
||||
}
|
||||
return ave;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 连续走十步才会开始计步
|
||||
* 连续走了9步以下,停留超过3秒,则计数清空
|
||||
* */
|
||||
private void countStep() {
|
||||
this.timeOfLastPeak1 = this.timeOfThisPeak1;
|
||||
this.timeOfThisPeak1 = System.currentTimeMillis();
|
||||
if (this.timeOfThisPeak1 - this.timeOfLastPeak1 <= 3000L){
|
||||
if(this.count<9){
|
||||
this.count++;
|
||||
}else if(this.count == 9){
|
||||
this.count++;
|
||||
this.mCount += this.count;
|
||||
PreferencesHelper.setCurrentStep(mContext, mCount);
|
||||
updateStepCounter();
|
||||
}else{
|
||||
this.mCount++;
|
||||
PreferencesHelper.setCurrentStep(mContext, mCount);
|
||||
updateStepCounter();
|
||||
}
|
||||
}else{//超时
|
||||
this.count = 1;//为1,不是0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void setSteps(int initValue) {
|
||||
this.mCount = initValue;
|
||||
this.count = 0;
|
||||
timeOfLastPeak1 = 0;
|
||||
timeOfThisPeak1 = 0;
|
||||
}
|
||||
|
||||
public int getCurrentStep() {
|
||||
return mCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
/**
|
||||
* 计步SDK初始化方法
|
||||
* Created by jiahongfei on 2017/10/9.
|
||||
*/
|
||||
|
||||
public class TodayStepManager {
|
||||
|
||||
private static final String TAG = "TodayStepManager";
|
||||
private static final int JOB_ID = 100;
|
||||
|
||||
/**
|
||||
* 在程序的最开始调用,最好在自定义的application oncreate中调用
|
||||
*
|
||||
* @param application
|
||||
*/
|
||||
public static void init(Application application) {
|
||||
|
||||
StepAlertManagerUtils.set0SeparateAlertManager(application);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// initJobScheduler(application);
|
||||
}
|
||||
|
||||
|
||||
startTodayStepService(application);
|
||||
}
|
||||
|
||||
public static void startTodayStepService(Application application) {
|
||||
Intent intent = new Intent(application, TodayStepService.class);
|
||||
application.startService(intent);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
private static void initJobScheduler(Application application) {
|
||||
Logger.e(TAG, "initJobScheduler");
|
||||
|
||||
JobScheduler jobScheduler = (JobScheduler)
|
||||
application.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
JobInfo.Builder builder = new JobInfo.Builder(
|
||||
JOB_ID,
|
||||
new ComponentName(application.getPackageName(), JobSchedulerService.class.getName()));
|
||||
builder.setMinimumLatency(5000)// 设置任务运行最少延迟时间
|
||||
.setOverrideDeadline(60000)// 设置deadline,若到期还没有达到规定的条件则会开始执行
|
||||
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)// 设置网络条件
|
||||
.setRequiresCharging(true)// 设置是否充电的条件
|
||||
.setRequiresDeviceIdle(false);// 设置手机是否空闲的条件
|
||||
int resultCode = jobScheduler.schedule(builder.build());
|
||||
if (JobScheduler.RESULT_FAILURE == resultCode) {
|
||||
Logger.e(TAG, "jobScheduler 失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v7.app.NotificationCompat;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static com.today.step.lib.SportStepJsonUtils.getCalorieByStep;
|
||||
import static com.today.step.lib.SportStepJsonUtils.getDistanceByStep;
|
||||
|
||||
public class TodayStepService extends Service implements Handler.Callback {
|
||||
|
||||
private static final String TAG = "TodayStepService";
|
||||
|
||||
/**
|
||||
* 数据库中保存多少天的运动数据
|
||||
*/
|
||||
private static final int DB_LIMIT = 2;
|
||||
|
||||
//保存数据库频率
|
||||
private static final int DB_SAVE_COUNTER = 50;
|
||||
|
||||
//传感器的采样周期,这里使用SensorManager.SENSOR_DELAY_FASTEST,如果使用SENSOR_DELAY_UI会导致部分手机后台清理内存之后传感器不记步
|
||||
private static final int SAMPLING_PERIOD_US = SensorManager.SENSOR_DELAY_FASTEST;
|
||||
|
||||
private static final int HANDLER_WHAT_SAVE_STEP = 0;
|
||||
//如果走路如果停止,10秒钟后保存数据库
|
||||
private static final int LAST_SAVE_STEP_DURATION = 10*1000;
|
||||
|
||||
private static final int BROADCAST_REQUEST_CODE = 100;
|
||||
|
||||
public static final String INTENT_NAME_0_SEPARATE = "intent_name_0_separate";
|
||||
public static final String INTENT_NAME_BOOT = "intent_name_boot";
|
||||
public static final String INTENT_JOB_SCHEDULER = "intent_job_scheduler";
|
||||
|
||||
public static int CURRENT_SETP = 0;
|
||||
|
||||
private SensorManager sensorManager;
|
||||
// private TodayStepDcretor stepDetector;
|
||||
private TodayStepDetector mStepDetector;
|
||||
private TodayStepCounter stepCounter;
|
||||
|
||||
private NotificationManager nm;
|
||||
Notification notification;
|
||||
private NotificationCompat.Builder builder;
|
||||
|
||||
private boolean mSeparate = false;
|
||||
private boolean mBoot = false;
|
||||
|
||||
private int mDbSaveCount = 0;
|
||||
|
||||
private ITodayStepDBHelper mTodayStepDBHelper;
|
||||
|
||||
private final Handler sHandler = new Handler(this);
|
||||
|
||||
private Microlog4Android mMicrolog4Android = new Microlog4Android();
|
||||
|
||||
@Override
|
||||
public boolean handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case HANDLER_WHAT_SAVE_STEP: {
|
||||
Logger.e(TAG, "HANDLER_WHAT_SAVE_STEP");
|
||||
|
||||
microlog4AndroidError("HANDLER_WHAT_SAVE_STEP");
|
||||
|
||||
mDbSaveCount = 0;
|
||||
|
||||
saveDb(true, CURRENT_SETP);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
Logger.e(TAG, "onCreate:" + CURRENT_SETP);
|
||||
super.onCreate();
|
||||
|
||||
mTodayStepDBHelper = TodayStepDBHelper.factory(getApplicationContext());
|
||||
|
||||
sensorManager = (SensorManager) this
|
||||
.getSystemService(SENSOR_SERVICE);
|
||||
|
||||
initNotification(CURRENT_SETP);
|
||||
|
||||
if(null != mMicrolog4Android) {
|
||||
mMicrolog4Android.configure(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Logger.e(TAG, "onStartCommand:" + CURRENT_SETP);
|
||||
|
||||
if (null != intent) {
|
||||
mSeparate = intent.getBooleanExtra(INTENT_NAME_0_SEPARATE, false);
|
||||
mBoot = intent.getBooleanExtra(INTENT_NAME_BOOT, false);
|
||||
}
|
||||
|
||||
mDbSaveCount = 0;
|
||||
|
||||
updateNotification(CURRENT_SETP);
|
||||
|
||||
//注册传感器
|
||||
startStepDetector();
|
||||
|
||||
//TODO:测试数据Start
|
||||
// if(Logger.sIsDebug) {
|
||||
// if (!isStepCounter()) {
|
||||
// Toast.makeText(getApplicationContext(), "Lib 当前手机没有计步传感器", Toast.LENGTH_LONG).show();
|
||||
// } else {
|
||||
// Toast.makeText(getApplicationContext(), "Lib 当前手机使用计步传感器", Toast.LENGTH_LONG).show();
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//TODO:测试数据End
|
||||
|
||||
microlog4AndroidError("onStartCommand");
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
private void initNotification(int currentStep) {
|
||||
|
||||
builder = new NotificationCompat.Builder(this);
|
||||
builder.setPriority(Notification.PRIORITY_MIN);
|
||||
|
||||
String receiverName = getReceiver(getApplicationContext());
|
||||
PendingIntent contentIntent = PendingIntent.getBroadcast(this, BROADCAST_REQUEST_CODE, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
if (!TextUtils.isEmpty(receiverName)) {
|
||||
try {
|
||||
contentIntent = PendingIntent.getBroadcast(this, BROADCAST_REQUEST_CODE, new Intent(this, Class.forName(receiverName)), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
contentIntent = PendingIntent.getBroadcast(this, BROADCAST_REQUEST_CODE, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
}
|
||||
builder.setContentIntent(contentIntent);
|
||||
int smallIcon = getResources().getIdentifier("icon_step_small", "mipmap", getPackageName());
|
||||
if (0 != smallIcon) {
|
||||
Logger.e(TAG, "smallIcon");
|
||||
builder.setSmallIcon(smallIcon);
|
||||
} else {
|
||||
builder.setSmallIcon(R.mipmap.ic_notification_default);// 设置通知小ICON
|
||||
}
|
||||
int largeIcon = getResources().getIdentifier("icon_step_large", "mipmap", getPackageName());
|
||||
if (0 != largeIcon) {
|
||||
Logger.e(TAG, "largeIcon");
|
||||
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), largeIcon));
|
||||
} else {
|
||||
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_notification_default));
|
||||
|
||||
}
|
||||
builder.setTicker(getString(R.string.app_name));
|
||||
builder.setContentTitle(getString(R.string.title_notification_bar, String.valueOf(currentStep)));
|
||||
String km = getDistanceByStep(currentStep);
|
||||
String calorie = getCalorieByStep(currentStep);
|
||||
builder.setContentText(calorie + " 千卡 " + km + " 公里");
|
||||
|
||||
//设置不可清除
|
||||
builder.setOngoing(true);
|
||||
notification = builder.build();
|
||||
//将Service设置前台,这里的id和notify的id一定要相同否则会出现后台清理内存Service被杀死通知还存在的bug
|
||||
startForeground(R.string.app_name, notification);
|
||||
nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.notify(R.string.app_name, notification);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
Logger.e(TAG, "onBind:" + CURRENT_SETP);
|
||||
return mIBinder.asBinder();
|
||||
}
|
||||
|
||||
private void startStepDetector() {
|
||||
|
||||
// getLock(this);
|
||||
|
||||
//android4.4以后如果有stepcounter可以使用计步传感器
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && isStepCounter()) {
|
||||
addStepCounterListener();
|
||||
} else {
|
||||
addBasePedoListener();
|
||||
}
|
||||
}
|
||||
|
||||
private void addStepCounterListener() {
|
||||
Logger.e(TAG, "addStepCounterListener");
|
||||
if (null != stepCounter) {
|
||||
Logger.e(TAG, "已经注册TYPE_STEP_COUNTER");
|
||||
WakeLockUtils.getLock(this);
|
||||
CURRENT_SETP = stepCounter.getCurrentStep();
|
||||
updateNotification(CURRENT_SETP);
|
||||
return;
|
||||
}
|
||||
Sensor countSensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
|
||||
if (null == countSensor) {
|
||||
return;
|
||||
}
|
||||
stepCounter = new TodayStepCounter(getApplicationContext(), mOnStepCounterListener, mSeparate, mBoot);
|
||||
Logger.e(TAG, "countSensor");
|
||||
sensorManager.registerListener(stepCounter, countSensor, SAMPLING_PERIOD_US);
|
||||
}
|
||||
|
||||
private void addBasePedoListener() {
|
||||
Logger.e(TAG, "addBasePedoListener");
|
||||
if (null != mStepDetector) {
|
||||
WakeLockUtils.getLock(this);
|
||||
Logger.e(TAG, "已经注册TYPE_ACCELEROMETER");
|
||||
CURRENT_SETP = mStepDetector.getCurrentStep();
|
||||
updateNotification(CURRENT_SETP);
|
||||
return;
|
||||
}
|
||||
//没有计步器的时候开启定时器保存数据
|
||||
Sensor sensor = sensorManager
|
||||
.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
if (null == sensor) {
|
||||
return;
|
||||
}
|
||||
mStepDetector = new TodayStepDetector(this, mOnStepCounterListener);
|
||||
Log.e(TAG, "TodayStepDcretor");
|
||||
// 获得传感器的类型,这里获得的类型是加速度传感器
|
||||
// 此方法用来注册,只有注册过才会生效,参数:SensorEventListener的实例,Sensor的实例,更新速率
|
||||
sensorManager.registerListener(mStepDetector, sensor, SAMPLING_PERIOD_US);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Logger.e(TAG, "onDestroy:" + CURRENT_SETP);
|
||||
|
||||
Intent intent = new Intent(this, TodayStepService.class);
|
||||
startService(intent);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onUnbind(Intent intent) {
|
||||
Logger.e(TAG, "onUnbind:" + CURRENT_SETP);
|
||||
return super.onUnbind(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* 步数每次回调的方法
|
||||
*
|
||||
* @param currentStep
|
||||
*/
|
||||
private void updateTodayStep(int currentStep) {
|
||||
|
||||
microlog4AndroidError(" currentStep : " + currentStep);
|
||||
|
||||
CURRENT_SETP = currentStep;
|
||||
updateNotification(CURRENT_SETP);
|
||||
saveStep(currentStep);
|
||||
}
|
||||
|
||||
private void saveStep(int currentStep) {
|
||||
sHandler.removeMessages(HANDLER_WHAT_SAVE_STEP);
|
||||
sHandler.sendEmptyMessageDelayed(HANDLER_WHAT_SAVE_STEP, LAST_SAVE_STEP_DURATION);
|
||||
|
||||
microlog4AndroidError(" mDbSaveCount : " + mDbSaveCount);
|
||||
|
||||
if (DB_SAVE_COUNTER > mDbSaveCount) {
|
||||
mDbSaveCount++;
|
||||
return;
|
||||
}
|
||||
mDbSaveCount = 0;
|
||||
|
||||
saveDb(false, currentStep);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param handler true handler回调保存步数,否false
|
||||
* @param currentStep
|
||||
*/
|
||||
private void saveDb(boolean handler, int currentStep) {
|
||||
|
||||
TodayStepData todayStepData = new TodayStepData();
|
||||
todayStepData.setToday(getTodayDate());
|
||||
todayStepData.setDate(System.currentTimeMillis());
|
||||
todayStepData.setStep(currentStep);
|
||||
if (null != mTodayStepDBHelper) {
|
||||
Logger.e(TAG, "saveDb handler : " + handler);
|
||||
if (!handler || !mTodayStepDBHelper.isExist(todayStepData)) {
|
||||
Logger.e(TAG, "saveDb currentStep : " + currentStep);
|
||||
|
||||
microlog4AndroidError("saveDb currentStep : " + currentStep);
|
||||
|
||||
mTodayStepDBHelper.insert(todayStepData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanDb() {
|
||||
|
||||
Logger.e(TAG, "cleanDb");
|
||||
|
||||
mDbSaveCount = 0;
|
||||
|
||||
if (null != mTodayStepDBHelper) {
|
||||
mTodayStepDBHelper.clearCapacity(DateUtils.dateFormat(System.currentTimeMillis(), "yyyy-MM-dd"), DB_LIMIT);
|
||||
}
|
||||
|
||||
// if (null != mTodayStepDBHelper) {
|
||||
//保存多天的步数
|
||||
// mTodayStepDBHelper.deleteTable();
|
||||
// mTodayStepDBHelper.createTable();
|
||||
// }
|
||||
}
|
||||
|
||||
private String getTodayDate() {
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新通知
|
||||
*/
|
||||
private void updateNotification(int stepCount) {
|
||||
if (null == builder || null == nm) {
|
||||
return;
|
||||
}
|
||||
builder.setContentTitle(getString(R.string.title_notification_bar, String.valueOf(stepCount)));
|
||||
String km = getDistanceByStep(stepCount);
|
||||
String calorie = getCalorieByStep(stepCount);
|
||||
builder.setContentText(calorie + " 千卡 " + km + " 公里");
|
||||
notification = builder.build();
|
||||
nm.notify(R.string.app_name, notification);
|
||||
}
|
||||
|
||||
private boolean isStepCounter() {
|
||||
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_COUNTER);
|
||||
}
|
||||
|
||||
private boolean isStepDetector() {
|
||||
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_STEP_DETECTOR);
|
||||
}
|
||||
|
||||
private OnStepCounterListener mOnStepCounterListener = new OnStepCounterListener() {
|
||||
@Override
|
||||
public void onChangeStepCounter(int step) {
|
||||
updateTodayStep(step);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStepCounterClean() {
|
||||
|
||||
CURRENT_SETP = 0;
|
||||
updateNotification(CURRENT_SETP);
|
||||
|
||||
cleanDb();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final ISportStepInterface.Stub mIBinder = new ISportStepInterface.Stub() {
|
||||
|
||||
@Override
|
||||
public int getCurrentTimeSportStep() throws RemoteException {
|
||||
return CURRENT_SETP;
|
||||
}
|
||||
|
||||
private JSONArray getSportStepJsonArray(List<TodayStepData> todayStepDataArrayList) {
|
||||
return SportStepJsonUtils.getSportStepJsonArray(todayStepDataArrayList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTodaySportStepArray() throws RemoteException {
|
||||
if (null != mTodayStepDBHelper) {
|
||||
List<TodayStepData> todayStepDataArrayList = mTodayStepDBHelper.getQueryAll();
|
||||
JSONArray jsonArray = getSportStepJsonArray(todayStepDataArrayList);
|
||||
Logger.e(TAG, jsonArray.toString());
|
||||
return jsonArray.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTodaySportStepArrayByDate(String date) throws RemoteException {
|
||||
if (null != mTodayStepDBHelper) {
|
||||
List<TodayStepData> todayStepDataArrayList = mTodayStepDBHelper.getStepListByDate(date);
|
||||
JSONArray jsonArray = getSportStepJsonArray(todayStepDataArrayList);
|
||||
Logger.e(TAG, jsonArray.toString());
|
||||
return jsonArray.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTodaySportStepArrayByStartDateAndDays(String date, int days) throws RemoteException {
|
||||
if (null != mTodayStepDBHelper) {
|
||||
List<TodayStepData> todayStepDataArrayList = mTodayStepDBHelper.getStepListByStartDateAndDays(date, days);
|
||||
JSONArray jsonArray = getSportStepJsonArray(todayStepDataArrayList);
|
||||
Logger.e(TAG, jsonArray.toString());
|
||||
return jsonArray.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public static String getReceiver(Context context) {
|
||||
try {
|
||||
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_RECEIVERS);
|
||||
ActivityInfo[] activityInfos = packageInfo.receivers;
|
||||
if (null != activityInfos && activityInfos.length > 0) {
|
||||
for (int i = 0; i < activityInfos.length; i++) {
|
||||
String receiverName = activityInfos[i].name;
|
||||
Class superClazz = Class.forName(receiverName).getSuperclass();
|
||||
int count = 1;
|
||||
while (null != superClazz) {
|
||||
if (superClazz.getName().equals("java.lang.Object")) {
|
||||
break;
|
||||
}
|
||||
if (superClazz.getName().equals(BaseClickBroadcast.class.getName())) {
|
||||
Log.e(TAG, "receiverName : " + receiverName);
|
||||
return receiverName;
|
||||
}
|
||||
if (count > 20) {
|
||||
//用来做容错,如果20个基类还不到Object直接跳出防止while死循环
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
superClazz = superClazz.getSuperclass();
|
||||
Log.e(TAG, "superClazz : " + superClazz);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void microlog4AndroidError(String msg){
|
||||
if (null != mMicrolog4Android) {
|
||||
mMicrolog4Android.error(DateUtils.getCurrentDate("yyyy-MM-dd HH:mm:ss") + " " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/**
|
||||
* Created by jiahongfei on 2017/9/27.
|
||||
*/
|
||||
|
||||
public class TodayStepShutdownReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "TodayStepShutdownReceiver";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Intent.ACTION_SHUTDOWN)) {
|
||||
Logger.e(TAG,"TodayStepShutdownReceiver");
|
||||
PreferencesHelper.setShutdown(context,true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* @author : jiahongfei
|
||||
* @email : jiahongfeinew@163.com
|
||||
* @date : 2018/2/12
|
||||
* @desc :
|
||||
*/
|
||||
|
||||
class WakeLockUtils {
|
||||
|
||||
private static PowerManager.WakeLock mWakeLock;
|
||||
|
||||
synchronized static PowerManager.WakeLock getLock(Context context) {
|
||||
if (mWakeLock != null) {
|
||||
if (mWakeLock.isHeld())
|
||||
mWakeLock.release();
|
||||
mWakeLock = null;
|
||||
}
|
||||
|
||||
if (mWakeLock == null) {
|
||||
PowerManager mgr = (PowerManager) context
|
||||
.getSystemService(Context.POWER_SERVICE);
|
||||
mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
|
||||
TodayStepService.class.getName());
|
||||
mWakeLock.setReferenceCounted(true);
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(System.currentTimeMillis());
|
||||
mWakeLock.acquire();
|
||||
}
|
||||
return (mWakeLock);
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
4
todaystepcounterlib/src/main/res/values/strings.xml
Normal file
4
todaystepcounterlib/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<resources>
|
||||
<string name="app_name">TodayStepCounterLib</string>
|
||||
<string name="title_notification_bar">当前步数:%1$s</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.manifest.AndroidManifest;
|
||||
import org.robolectric.res.Fs;
|
||||
|
||||
/**
|
||||
* @author : jiahongfei
|
||||
* @email : jiahongfeinew@163.com
|
||||
* @date : 2018/1/22
|
||||
* @desc :
|
||||
*/
|
||||
|
||||
public class MyRobolectricTestRunner extends RobolectricTestRunner {
|
||||
/**
|
||||
* Creates a runner to run {@code testClass}. Looks in your working directory for your AndroidManifest.xml file
|
||||
* and res directory by default. Use the {@link Config} annotation to configure.
|
||||
*
|
||||
* @param testClass the test class to be run
|
||||
* @throws InitializationError if junit says so
|
||||
*/
|
||||
public MyRobolectricTestRunner(Class<?> testClass) throws InitializationError {
|
||||
super(testClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AndroidManifest getAppManifest(Config config) {
|
||||
String projectName = "TodayStepCounter";
|
||||
int nameLength = projectName.length();
|
||||
String rootPath = System.getProperty("user.dir", "./");
|
||||
int index = rootPath.indexOf(projectName);
|
||||
if (index == -1) {
|
||||
throw new RuntimeException("project name not found in user.dir");
|
||||
}
|
||||
//获取项目的根目录
|
||||
rootPath = rootPath.substring(0, index + nameLength);
|
||||
String manifestProperty = rootPath + "/todaystepcounterlib/src/main/AndroidManifest.xml";
|
||||
String resProperty = rootPath + "/todaystepcounterlib/src/main/res";
|
||||
String assetsProperty = rootPath + "/todaystepcounterlib/src/main/assets";
|
||||
return new AndroidManifest(
|
||||
Fs.fileFromPath(manifestProperty),
|
||||
Fs.fileFromPath(resProperty),
|
||||
Fs.fileFromPath(assetsProperty)) {
|
||||
@Override
|
||||
public int getTargetSdkVersion() {
|
||||
return 21;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.today.step.lib;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author : jiahongfei
|
||||
* @email : jiahongfeinew@163.com
|
||||
* @date : 2018/1/22
|
||||
* @desc :
|
||||
*/
|
||||
@RunWith(MyRobolectricTestRunner.class)
|
||||
@Config(constants = BuildConfig.class, sdk = 21)
|
||||
public class TodayStepDBHelperTest {
|
||||
|
||||
private static final String SPORT_DATE = "sportDate";
|
||||
private static final String STEP_NUM = "stepNum";
|
||||
|
||||
private ITodayStepDBHelper mTodayStepDBHelper;
|
||||
|
||||
@Before
|
||||
public void before(){
|
||||
|
||||
Application application = RuntimeEnvironment.application;
|
||||
|
||||
System.out.println(application);
|
||||
|
||||
mTodayStepDBHelper = TodayStepDBHelper.factory(application);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insert(){
|
||||
|
||||
//10天
|
||||
for (int i = 0; i<10; i++){
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTimeInMillis(DateUtils.getDateMillis("2018-01-01","yyyy-MM-dd"));
|
||||
if(4 == i || 5 == i || 7 == i || 8 == i){
|
||||
continue;
|
||||
}
|
||||
calendar.add(Calendar.DAY_OF_YEAR,i);
|
||||
//每天存储5次步数
|
||||
for (int j = 0; j<5; j++){
|
||||
TodayStepData todayStepData = new TodayStepData();
|
||||
todayStepData.setToday(DateUtils.dateFormat(calendar.getTimeInMillis(),"yyyy-MM-dd"));
|
||||
todayStepData.setStep(100*j);
|
||||
Calendar hourCalendar = Calendar.getInstance();
|
||||
hourCalendar.setTimeInMillis(DateUtils.getDateMillis("2018-01-01 08:00","yyyy-MM-dd HH:mm"));
|
||||
hourCalendar.add(Calendar.HOUR_OF_DAY,j);
|
||||
todayStepData.setDate(hourCalendar.getTimeInMillis());
|
||||
mTodayStepDBHelper.insert(todayStepData);
|
||||
}
|
||||
}
|
||||
|
||||
List<TodayStepData> todayStepDataList = mTodayStepDBHelper.getQueryAll();
|
||||
JSONArray jsonArray = getSportStepJsonArray(todayStepDataList);
|
||||
System.out.println(jsonArray.toString());
|
||||
|
||||
todayStepDataList = mTodayStepDBHelper.getStepListByDate("2018-01-01");
|
||||
jsonArray = getSportStepJsonArray(todayStepDataList);
|
||||
System.out.println(jsonArray.toString());
|
||||
|
||||
todayStepDataList = mTodayStepDBHelper.getStepListByStartDateAndDays("2018-01-03",3);
|
||||
jsonArray = getSportStepJsonArray(todayStepDataList);
|
||||
System.out.println(jsonArray.toString());
|
||||
|
||||
|
||||
|
||||
// mTodayStepDBHelper.clearCapacity("2018-01-10",7);
|
||||
//
|
||||
// todayStepDataList = mTodayStepDBHelper.getQueryAll();
|
||||
// jsonArray = getSportStepJsonArray(todayStepDataList);
|
||||
// Systemhttp://pa.mokous.com/share/renewal/esb_plus_award_notice.html.out.println(jsonArray.toString());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private JSONArray getSportStepJsonArray(List<TodayStepData> todayStepDataArrayList){
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
if (null == todayStepDataArrayList || 0 == todayStepDataArrayList.size()) {
|
||||
return jsonArray;
|
||||
}
|
||||
for (int i = 0; i < todayStepDataArrayList.size(); i++) {
|
||||
TodayStepData todayStepData = todayStepDataArrayList.get(i);
|
||||
try {
|
||||
JSONObject subObject = new JSONObject();
|
||||
subObject.put(TodayStepDBHelper.TODAY, todayStepData.getToday());
|
||||
subObject.put(SPORT_DATE, DateUtils.dateFormat(todayStepData.getDate(),"yyyy-MM-dd HH:mm"));
|
||||
subObject.put(STEP_NUM, todayStepData.getStep());
|
||||
jsonArray.put(subObject);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user