diff --git a/app/build.gradle b/app/build.gradle
index 938470f..5864302 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -24,7 +24,7 @@ android {
}
dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
@@ -50,5 +50,20 @@ dependencies {
//个人信息的那个条条
compile 'com.akexorcist:RoundCornerProgressBar:2.0.3'
//wave
- compile 'com.gelitenight.waveview:waveview:1.0.0'
+ implementation 'me.itangqi.waveloadingview:library:0.3.5'
+ //计步
+ implementation project(':todaystepcounterlib')
+ //打分ui
+ compile 'com.github.CB-ysx:CBRatingBar:3.0.1'
+// //蛛网
+// implementation 'me.panpf:spider-web-score-view:1.0.1'
+ //折线
+ implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3'
+ //searchview
+ compile 'com.miguelcatalan:materialsearchview:1.4.0'
+ //floatbuttom
+ compile 'com.nightonke:boommenu:2.1.1'
+ //recycler and card
+ implementation 'com.android.support:recyclerview-v7:26.1.0'
+ implementation 'com.android.support:cardview-v7:26.1.0'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 978e5b9..8bb7fa1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -17,9 +17,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/NutritionMaster.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/NutritionMaster.java
index ec33f70..ff65488 100644
--- a/app/src/main/java/com/example/ninefourone/nutritionmaster/NutritionMaster.java
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/NutritionMaster.java
@@ -1,6 +1,8 @@
package com.example.ninefourone.nutritionmaster;
+import android.app.Activity;
import android.app.Application;
+import android.os.Bundle;
import com.orhanobut.logger.AndroidLogAdapter;
import com.orhanobut.logger.Logger;
@@ -12,6 +14,7 @@ import com.orhanobut.logger.Logger;
public class NutritionMaster extends Application {
public static NutritionMaster mInstance;
+ private int appCount = 0;
@Override
public void onCreate() {
@@ -25,10 +28,55 @@ public class NutritionMaster extends Application {
*/
private void init() {
Logger.addLogAdapter(new AndroidLogAdapter());
- Logger.d("Logger初始化成功");
+ registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ appCount++;
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ appCount--;
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+
+ }
+ });
}
public static NutritionMaster getInstance() {
return mInstance;
}
+
+ /**
+ * app是否在前台
+ *
+ * @return true前台,false后台
+ */
+ public boolean isForeground() {
+ return appCount > 0;
+ }
+
}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/CardAdapter.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/CardAdapter.java
new file mode 100644
index 0000000..a2dd942
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/CardAdapter.java
@@ -0,0 +1,63 @@
+package com.example.ninefourone.nutritionmaster.adapter;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.example.ninefourone.nutritionmaster.R;
+import com.example.ninefourone.nutritionmaster.bean.DailyCard;
+import com.orhanobut.logger.Logger;
+
+import java.util.ArrayList;
+
+/**
+ * Created by ScorpioMiku on 2018/9/2.
+ */
+
+public class CardAdapter extends RecyclerView.Adapter {
+ private Context context;
+ private ArrayList mList;
+
+
+ public CardAdapter(Context context, ArrayList mList) {
+ this.context = context;
+ this.mList = mList;
+ }
+
+
+ @Override
+ public CardHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(context).inflate(R.layout.card_item, parent, false);
+ CardHolder cardHolder = new CardHolder(view);
+ return cardHolder;
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public void onBindViewHolder(CardHolder holder, int position) {
+ holder.bindView(mList.get(position).getPictureId(), mList.get(position).getTitle(), context);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mList.size();
+ }
+
+ /**
+ * 右划
+ */
+ public void swipe2Right() {
+ Logger.d("右划");
+ }
+
+ /**
+ * 左划
+ */
+ public void swipe2left() {
+ Logger.d("左划");
+ }
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/CardHolder.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/CardHolder.java
new file mode 100644
index 0000000..43d40d0
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/CardHolder.java
@@ -0,0 +1,44 @@
+package com.example.ninefourone.nutritionmaster.adapter;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.example.ninefourone.nutritionmaster.R;
+
+import java.util.ArrayList;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
+/**
+ * Created by ScorpioMiku on 2018/9/2.
+ */
+
+public class CardHolder extends RecyclerView.ViewHolder {
+ @BindView(R.id.iv_photo)
+ ImageView ivPhoto;
+ @BindView(R.id.tv_name)
+ TextView tvName;
+ @BindView(R.id.tv_sign)
+ TextView tvSign;
+
+
+ public CardHolder(View itemView) {
+ super(itemView);
+ ButterKnife.bind(this, itemView);
+ }
+
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ public void bindView(int picId, String text, Context context) {
+ tvName.setText(text);
+ ivPhoto.setImageDrawable(context.getDrawable(picId));
+
+ }
+
+
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/HomePagerAdapter.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/HomePagerAdapter.java
index b2cced9..f705e2e 100644
--- a/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/HomePagerAdapter.java
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/adapter/HomePagerAdapter.java
@@ -6,7 +6,7 @@ import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.example.ninefourone.nutritionmaster.R;
-import com.example.ninefourone.nutritionmaster.modules.viewpagerfragments.page1.Page1;
+import com.example.ninefourone.nutritionmaster.modules.viewpagerfragments.customization.CustomizationFragment;
import com.example.ninefourone.nutritionmaster.modules.viewpagerfragments.bodyinformation.BodyInformationFragment;
import com.example.ninefourone.nutritionmaster.modules.viewpagerfragments.page3.Page3;
@@ -30,7 +30,7 @@ public class HomePagerAdapter extends FragmentPagerAdapter {
if (fragments[position] == null) {
switch (position) {
case 0:
- fragments[position] = Page1.getInstance();
+ fragments[position] = CustomizationFragment.getInstance();
break;
case 1:
fragments[position] = BodyInformationFragment.getInstance();
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/base/BaseActivity.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/base/BaseActivity.java
index d9f9592..d1f44e1 100644
--- a/app/src/main/java/com/example/ninefourone/nutritionmaster/base/BaseActivity.java
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/base/BaseActivity.java
@@ -23,6 +23,8 @@ public abstract class BaseActivity extends AppCompatActivity {
initToolBar();
}
+
+
/**
* 设置布局layout
*
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/bean/DailyCard.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/bean/DailyCard.java
new file mode 100644
index 0000000..b689b43
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/bean/DailyCard.java
@@ -0,0 +1,44 @@
+package com.example.ninefourone.nutritionmaster.bean;
+
+/**
+ * Created by ScorpioMiku on 2018/9/3.
+ */
+
+public class DailyCard {
+ /***
+ * 每日卡片bean类
+ */
+ private String title;
+ private String description;
+ private int pictureId;
+
+ public DailyCard(String title, String description, int pictureId) {
+ this.title = title;
+ this.description = description;
+ this.pictureId = pictureId;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public int getPictureId() {
+ return pictureId;
+ }
+
+ public void setPictureId(int pictureId) {
+ this.pictureId = pictureId;
+ }
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/bean/User.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/bean/User.java
new file mode 100644
index 0000000..54c888c
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/bean/User.java
@@ -0,0 +1,14 @@
+package com.example.ninefourone.nutritionmaster.bean;
+
+/**
+ * Created by ScorpioMiku on 2018/8/30.
+ */
+
+public class User {
+ private float height;
+ private float weight;
+ private float BMI;
+ private String sex;
+ private int age;
+ private String job;
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/camera/CameraPreview.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/camera/CameraPreview.java
new file mode 100644
index 0000000..0a26aa8
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/camera/CameraPreview.java
@@ -0,0 +1,63 @@
+package com.example.ninefourone.nutritionmaster.camera;
+
+import android.content.Context;
+import android.hardware.Camera;
+import android.view.SurfaceView;
+import android.view.SurfaceHolder;
+
+
+import com.orhanobut.logger.Logger;
+
+import java.io.IOException;
+
+/**
+ * Created by ScorpioMiku on 2018/9/3.
+ */
+
+public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
+
+ private SurfaceHolder mHolder;
+ private Camera camera;
+
+ public CameraPreview(Context context, Camera camera) {
+ super(context);
+ this.camera = camera;
+ mHolder = getHolder();
+ mHolder.addCallback(this);
+// mHolder.setType();
+ }
+
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ try {
+ camera.setPreviewDisplay(holder);
+ camera.startPreview();
+ } catch (IOException e) {
+ Logger.e(e.getMessage());
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ if (mHolder.getSurface() == null) {
+ return;
+ }
+ try {
+ camera.stopPreview();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ camera.setPreviewDisplay(mHolder);
+ camera.startPreview();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+
+ }
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/camera/FoodMaterialCamera.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/camera/FoodMaterialCamera.java
new file mode 100644
index 0000000..2477de1
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/camera/FoodMaterialCamera.java
@@ -0,0 +1,197 @@
+package com.example.ninefourone.nutritionmaster.camera;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.Camera;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.view.Surface;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.example.ninefourone.nutritionmaster.R;
+import com.example.ninefourone.nutritionmaster.utils.MessageUtils;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+
+/**
+ * Created by ScorpioMiku on 2018/9/3.
+ */
+
+public class FoodMaterialCamera extends AppCompatActivity {
+ @BindView(R.id.camera_preview)
+ FrameLayout mCameraLayout;
+ @BindView(R.id.results_text_view)
+ TextView resultsTextView;
+ @BindView(R.id.more_take_photo_button_capture)
+ ImageView moreTakePhotoButtonCapture;
+ @BindView(R.id.more_takephoto_ok)
+ ImageView moreTakephotoOk;
+ @BindView(R.id.more_camera_cover_linearlayout)
+ FrameLayout moreCameraCoverLinearlayout;
+
+ private Camera mCamera;
+ private CameraPreview mPreview;
+ private int mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
+
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ //取消toolbar
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ //设置全屏
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ //注意:上面两个设置必须写在setContentView前面
+ setContentView(R.layout.cameras_layout);
+ ButterKnife.bind(this);
+
+ if (!checkCameraHardware(this)) {
+ MessageUtils.MakeToast("不支持相机");
+ } else {
+ openCamera();
+ }
+
+ setCameraDisplayOrientation(this, mCameraId, mCamera);
+ }
+
+ /**
+ * 检查当前设备是否有相机
+ *
+ * @param context
+ * @return
+ */
+ private boolean checkCameraHardware(Context context) {
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_CAMERA)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * 打开相机
+ */
+ private void openCamera() {
+ if (null == mCamera) {
+ mCamera = getCameraInstance();
+ mPreview = new CameraPreview(this, mCamera);
+// mPreview.setOnTouchListener(new View.OnTouchListener() {
+// @Override
+// public boolean onTouch(View v, MotionEvent event) {
+// mCamera.autoFocus(null);
+// return false;
+// }
+// });
+ mCameraLayout.addView(mPreview);
+ mCamera.startPreview();
+ }
+ }
+
+ /**
+ * 获取相机
+ *
+ * @return
+ */
+ private Camera getCameraInstance() {
+ Camera c = null;
+ try {
+ c = Camera.open();
+ Camera.Parameters mParameters = c.getParameters();
+ mParameters.setPictureSize(720, 1280);
+ c.setParameters(mParameters);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return c;
+ }
+
+ /**
+ * 对焦回调,对焦完成后进行拍照
+ */
+ private Camera.AutoFocusCallback mAutoFocusCallback = new Camera.AutoFocusCallback() {
+ @Override
+ public void onAutoFocus(boolean success, Camera camera) {
+ if (success) {
+ mCamera.takePicture(null, null, mPictureCallback);
+ }
+ }
+ };
+
+ /**
+ * 拍照回调
+ */
+ private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
+ @Override
+ public void onPictureTaken(final byte[] data, Camera camera) {
+ MessageUtils.MakeToast("拍照!");
+ mCamera.startPreview();
+ }
+ };
+
+
+ /**
+ * 两个按钮的事件
+ *
+ * @param view
+ */
+ @OnClick({R.id.more_take_photo_button_capture, R.id.more_takephoto_ok})
+ public void onViewClicked(View view) {
+ switch (view.getId()) {
+ case R.id.more_take_photo_button_capture:
+ mCamera.autoFocus(mAutoFocusCallback);
+ break;
+ case R.id.more_takephoto_ok:
+ break;
+ }
+ }
+
+ //将相机设置成竖屏
+ public static void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
+
+ int degrees = 0;
+
+ //可以获得摄像头信息
+ Camera.CameraInfo info = new Camera.CameraInfo();
+ Camera.getCameraInfo(cameraId, info);
+
+ //获取屏幕旋转方向
+ int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
+
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ degrees = 0;
+ break;
+ case Surface.ROTATION_90:
+ degrees = 90;
+ break;
+ case Surface.ROTATION_180:
+ degrees = 180;
+ break;
+ case Surface.ROTATION_270:
+ degrees = 270;
+ break;
+ }
+ int result;
+ if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+ result = (info.orientation + degrees) % 360;
+ result = (360 - result) % 360;
+ } else {
+ result = (info.orientation - degrees + 360) % 360;
+ }
+ camera.setDisplayOrientation(result);
+ }
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/cardconfig/CardConfig.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/cardconfig/CardConfig.java
new file mode 100644
index 0000000..9e3dc07
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/cardconfig/CardConfig.java
@@ -0,0 +1,25 @@
+package com.example.ninefourone.nutritionmaster.cardconfig;
+
+import android.content.Context;
+import android.util.TypedValue;
+
+/**
+ * 初始化一些配置信息、固定数据
+ */
+public class CardConfig {
+ //屏幕上最多同时显示几个Item
+ public static int MAX_SHOW_COUNT;
+
+ //每一级Scale相差0.05f,translationY相差15dp,translationZ相差0.5dp左右
+ public static float SCALE_GAP;
+ public static int TRANS_Y_GAP;
+ public static int TRANS_Z_GAP;
+
+ public static void initConfig(Context context) {
+ MAX_SHOW_COUNT = 4;
+ SCALE_GAP = 0.05f;
+ //这里是把dp转换成px
+ TRANS_Y_GAP = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15f, context.getResources().getDisplayMetrics());
+ TRANS_Z_GAP = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0.5f, context.getResources().getDisplayMetrics());
+ }
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/cardconfig/CardItemTouchCallBack.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/cardconfig/CardItemTouchCallBack.java
new file mode 100644
index 0000000..6fd06c0
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/cardconfig/CardItemTouchCallBack.java
@@ -0,0 +1,256 @@
+package com.example.ninefourone.nutritionmaster.cardconfig;
+
+import android.graphics.Canvas;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.util.Log;
+import android.view.View;
+
+import com.example.ninefourone.nutritionmaster.adapter.CardAdapter;
+import com.example.ninefourone.nutritionmaster.adapter.CardHolder;
+
+import java.util.List;
+
+/**
+ * Created by ScorpioMiku on 2018/9/2.
+ */
+
+public class CardItemTouchCallBack extends ItemTouchHelper.Callback {
+
+ private static final String TAG = "CardItemTouchCallBack";
+ private RecyclerView mRecyclerView;
+ private CardAdapter mAdapter;
+ private List mDatas;
+
+ public CardItemTouchCallBack(RecyclerView recyclerView, CardAdapter adapter, List datas) {
+ this.mRecyclerView = recyclerView;
+ this.mAdapter = adapter;
+ this.mDatas = datas;
+ }
+
+ /**
+ * 是否开启长按拖拽
+ * true,开启
+ * false,不开启长按退拽
+ *
+ * @return
+ */
+ @Override
+ public boolean isLongPressDragEnabled() {
+ return false;
+ }
+
+ /**
+ * 是否开启滑动
+ * true,开启
+ * false,不开启长按退拽
+ *
+ * @return
+ */
+ @Override
+ public boolean isItemViewSwipeEnabled() {
+ return true;
+ }
+
+ /**
+ * ItemTouchHelper支持设置事件方向,并且必须重写当前getMovementFlags来指定支持的方向
+ * dragFlags 表示拖拽的方向,有六个类型的值:LEFT、RIGHT、START、END、UP、DOWN
+ * swipeFlags 表示滑动的方向,有六个类型的值:LEFT、RIGHT、START、END、UP、DOWN
+ * 最后要通过makeMovementFlags(dragFlag,swipe)创建方向的Flag
+ */
+ @Override
+ public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ /**
+ * 由于我们不需要长按拖拽,所以直接传入0即可,传入0代表不监听
+ */
+ int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.UP | ItemTouchHelper.DOWN;
+ return makeMovementFlags(0, swipeFlags);
+ }
+
+ /**
+ * 长按item就可以拖动,然后拖动到其他item的时候触发onMove
+ * 这里我们不需要
+ *
+ * @param recyclerView
+ * @param viewHolder 拖动的viewholder
+ * @param target 目标位置的viewholder
+ * @return
+ */
+ @Override
+ public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
+ return false;
+ }
+
+ /**
+ * 把item滑走(飞出屏幕)的时候调用
+ *
+ * @param viewHolder 滑动的viewholder
+ * @param direction 滑动的方向
+ */
+ @Override
+ public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+ //这里来判断画出的方向,左边是4,右边是8,然后可以做一些数据操作
+ Log.d(TAG, "onSwiped: " + direction);
+ switch (direction) {
+ case 4:
+ Log.d(TAG, "onSwiped: 左边滑出");
+ mAdapter.swipe2left();
+ break;
+ case 8:
+ Log.d(TAG, "onSwiped: 右边滑出");
+ mAdapter.swipe2Right();
+ break;
+ }
+ //移除这条数据
+ Object remove = mDatas.remove(viewHolder.getLayoutPosition());
+
+ /** 这个位置可以用来加载数据,当滑到还剩4个或者多少个时可以在后面加载数据,添加到mDatas中*/
+ //这里就为了方便,直接循环了,把移除的元素再添加到末尾
+ mDatas.add(mDatas.size(), remove);
+
+ //刷新
+ mAdapter.notifyDataSetChanged();
+ //复位
+ viewHolder.itemView.setRotation(0);
+ if (viewHolder instanceof CardHolder) {
+ CardHolder holder = (CardHolder) viewHolder;
+ }
+ }
+
+ /**
+ * 只要拖动、滑动了item,就会触发这个方法,而且是动的过程中会一直触发
+ * 所以动画效果就是在这个方法中来实现的
+ *
+ * @param c
+ * @param recyclerView
+ * @param viewHolder
+ * @param dX
+ * @param dY
+ * @param actionState
+ * @param isCurrentlyActive
+ */
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
+ float dX, float dY, int actionState, boolean isCurrentlyActive) {
+ super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
+ double swipeValue = Math.sqrt(dX * dX + dY * dY); //滑动离中心的距离
+ double fraction = swipeValue / (mRecyclerView.getWidth() * 0.5f);
+ //边界修正 最大为1
+ if (fraction > 1) {
+ fraction = 1;
+ }
+
+ /**
+ * 调整每个子view的缩放、位移之类的
+ */
+ int childCount = recyclerView.getChildCount(); //拿到子view的数量
+ isUpOrDown(mRecyclerView.getChildAt(childCount - 1));
+ for (int i = 0; i < childCount; i++) {
+ /** 拿到子view 注意这里,先绘制的i=0,所以最下面一层view的i=0,最上面的i=3*/
+ View childView = recyclerView.getChildAt(i);
+ int level = childCount - i - 1; //转换一下,level代表层数,最上面是第0层
+ if (level > 0) {
+ //下面层,每一层的水平方向都要增大
+ childView.setScaleX((float) (1 - CardConfig.SCALE_GAP * level + fraction * CardConfig.SCALE_GAP));
+ if (level < CardConfig.MAX_SHOW_COUNT - 1) {
+ //1 2层
+ childView.setScaleY((float) (1 - CardConfig.SCALE_GAP * level + fraction * CardConfig.SCALE_GAP));
+ childView.setTranslationY((float) (CardConfig.TRANS_Y_GAP * level - fraction * CardConfig.TRANS_Y_GAP));
+ childView.setTranslationZ((float) (CardConfig.TRANS_Z_GAP * (CardConfig.MAX_SHOW_COUNT - 1 - level)
+ + fraction * CardConfig.TRANS_Z_GAP));
+ } else {
+ //最下面一层,3层,这层不用变,所以这里不用写
+ }
+ } else {
+ //第0层
+ //拿到水平方向的偏移比率
+ float xFraction = dX / (mRecyclerView.getWidth() * 0.5f);
+ //边界修正,有正有负,因为旋转有两个方向
+ if (xFraction > 1) {
+ xFraction = 1;
+ } else if (xFraction < -1) {
+ xFraction = -1;
+ }
+ //第一层左右滑动的时候稍微有点旋转
+ childView.setRotation(xFraction * 15); //这里最多旋转15度
+
+ if (viewHolder instanceof CardHolder) {
+ CardHolder holder = (CardHolder) viewHolder;
+ if (dX > 0) {
+ //右滑,显示爱心
+// holder.iv_love.setAlpha(xFraction);
+ } else if (dX < 0) {
+ //左滑,显示叉,注意这里xFraction为负数,所以要取反
+// holder.iv_del.setAlpha(-xFraction);
+ } else {
+// holder.iv_love.setAlpha(0f);
+// holder.iv_del.setAlpha(0f);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
+// Log.i(TAG, "getSwipeThreshold: ");
+// if (isUpOrDown(viewHolder.itemView)) { //如果是向上或者向下滑动
+// return Float.MAX_VALUE; //就返回阈值为很大
+// }
+ return super.getSwipeThreshold(viewHolder);
+ }
+
+ /**
+ * 获得逃脱(swipe)速度
+ *
+ * @param defaultValue
+ * @return
+ */
+ @Override
+ public float getSwipeEscapeVelocity(float defaultValue) {
+ Log.d(TAG, "getSwipeEscapeVelocity: " + defaultValue);
+ View topView = mRecyclerView.getChildAt(mRecyclerView.getChildCount() - 1);
+ if (isUpOrDown(topView)) { //如果是向上或者向下滑动
+ return Float.MAX_VALUE; //就返回阈值为很大
+ }
+ return super.getSwipeEscapeVelocity(defaultValue);
+ }
+
+
+ /**
+ * 获得swipe的速度阈值
+ *
+ * @param defaultValue
+ * @return
+ */
+ @Override
+ public float getSwipeVelocityThreshold(float defaultValue) {
+ Log.d(TAG, "getSwipeVelocityThreshold: " + defaultValue);
+ View topView = mRecyclerView.getChildAt(mRecyclerView.getChildCount() - 1);
+ if (isUpOrDown(topView)) { //如果是向上或者向下滑动
+ return Float.MAX_VALUE; //就返回阈值为很大
+ }
+ return super.getSwipeVelocityThreshold(defaultValue);
+ }
+
+ /**
+ * 判断是否是向上滑或者向下滑
+ */
+ private boolean isUpOrDown(View topView) {
+ float x = topView.getX();
+ float y = topView.getY();
+ int left = topView.getLeft();
+ int top = topView.getTop();
+ if (Math.pow(x - left, 2) > Math.pow(y - top, 2)) {
+ //水平方向大于垂直方向
+// Log.i(TAG, "isUpOrDown: 不是");
+ return false;
+ } else {
+ return true;
+// Log.i(TAG, "isUpOrDown: 是");
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/cardconfig/SwipeCardLayoutManager.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/cardconfig/SwipeCardLayoutManager.java
new file mode 100644
index 0000000..f55e40f
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/cardconfig/SwipeCardLayoutManager.java
@@ -0,0 +1,98 @@
+package com.example.ninefourone.nutritionmaster.cardconfig;
+
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Created by ScorpioMiku on 2018/9/2.
+ */
+
+public class SwipeCardLayoutManager extends RecyclerView.LayoutManager {
+ @Override
+ public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+ return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+
+ /**
+ * 在这里面给子view布局,也就是item
+ *
+ * @param recycler
+ * @param state
+ */
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+ //在布局之前,将所有的子View先Detach掉,放入到Scrap缓存中
+ detachAndScrapAttachedViews(recycler);
+
+ //拿到总item数量
+ int itemCount = getItemCount();
+ if (itemCount < 1) {//没有item当然就没必要布局了
+ return;
+ }
+ int bottomPosition; //用来记录最底层view的postion
+
+ if (itemCount < CardConfig.MAX_SHOW_COUNT) { //如果不足最大数量(4个)
+ //那么最底层就是最后一条数据对应的position
+ bottomPosition = itemCount - 1;
+ } else {
+ //否则最底层就是第MAX_SHOW_COUNT(4)条数据对应的position
+ bottomPosition = CardConfig.MAX_SHOW_COUNT - 1;
+ }
+
+ /**
+ * 这里开始布局且绘制子view
+ * 注意:这里要先从最底层开始绘制,因为后绘制的才能覆盖先绘制的,
+ * 滑动的时候是滑最上面一层的,也就是后绘制的
+ * position也是层数
+ */
+ for (int position = bottomPosition; position >= 0; position--) {
+ //根据position找recycler要itemview
+ View view = recycler.getViewForPosition(position);
+ //将子View添加至RecyclerView中
+ addView(view);
+ //测量子view并且把Margin也作为子控件的一部分
+ measureChildWithMargins(view, 0, 0);
+ //宽度空隙 getWidth()得到Recycler控件的宽度,getDecoratedMeasuredWidth(view)拿到子view的宽度
+ int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
+ //高度空隙
+ int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
+ //给子view布局,这里居中了
+ layoutDecoratedWithMargins(view, widthSpace / 2, 0,
+ widthSpace / 2 + getDecoratedMeasuredWidth(view),
+ getDecoratedMeasuredHeight(view) + 0);
+
+ /**
+ * 下面要调整每一层itemview的的大小及Y轴和Z轴的偏移
+ * 最上面一层(第0层)的Scale为1,translationY为0
+ * 依次往下,每层比上面一层:
+ * (1)Scale相差0.05f
+ * (2)translationY相差7dp
+ * (3)translationZ相差1dp
+ *
+ * 注意:最后一层,除了水平方向的大小其他都与上一层一样,所以要特殊判断
+ */
+ if (position > 0) { //大于0就是不是最上面那层
+ //依次往下,每层都要水平方向缩小
+ view.setScaleX(1 - CardConfig.SCALE_GAP * position);
+ if (position < CardConfig.MAX_SHOW_COUNT - 1) {
+ //如果,不是最后一层,就都要调整
+ view.setScaleY(1 - CardConfig.SCALE_GAP * position); //垂直方向缩小
+ view.setTranslationY(CardConfig.TRANS_Y_GAP * position); //向下平移
+ view.setTranslationZ(CardConfig.TRANS_Z_GAP * (CardConfig.MAX_SHOW_COUNT - 1 - position)); //Z轴方向的平移
+ } else {
+ //否则,就是最后一层,与上一层保持一致
+ view.setScaleY(1 - CardConfig.SCALE_GAP * (position - 1)); //垂直方向缩小
+ view.setTranslationY(CardConfig.TRANS_Y_GAP * (position - 1)); //向下平移
+ view.setTranslationZ(CardConfig.TRANS_Z_GAP * (CardConfig.MAX_SHOW_COUNT - 1 - (position - 1))); //Z轴方向的平移
+ }
+ } else {
+ //否则,是第0层(最上面那层),只需调整Z轴高度
+ view.setTranslationZ(CardConfig.TRANS_Z_GAP * (CardConfig.MAX_SHOW_COUNT - 1)); //Z轴方向的平移
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/MainActivity.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/MainActivity.java
index 8c08218..1d2d6ef 100644
--- a/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/MainActivity.java
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/MainActivity.java
@@ -1,31 +1,54 @@
package com.example.ninefourone.nutritionmaster.modules;
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.v7.widget.Toolbar;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
-
-import com.ToxicBakery.viewpager.transforms.AccordionTransformer;
-import com.ToxicBakery.viewpager.transforms.CubeInTransformer;
import com.ToxicBakery.viewpager.transforms.CubeOutTransformer;
-import com.ToxicBakery.viewpager.transforms.DepthPageTransformer;
-import com.ToxicBakery.viewpager.transforms.FlipHorizontalTransformer;
-import com.ToxicBakery.viewpager.transforms.FlipVerticalTransformer;
-import com.ToxicBakery.viewpager.transforms.RotateUpTransformer;
-import com.ToxicBakery.viewpager.transforms.StackTransformer;
-import com.ToxicBakery.viewpager.transforms.TabletTransformer;
-import com.ToxicBakery.viewpager.transforms.ZoomInTransformer;
+import com.cb.ratingbar.CBRatingBar;
import com.example.ninefourone.nutritionmaster.R;
import com.example.ninefourone.nutritionmaster.adapter.HomePagerAdapter;
import com.example.ninefourone.nutritionmaster.base.BaseActivity;
+import com.example.ninefourone.nutritionmaster.camera.FoodMaterialCamera;
import com.example.ninefourone.nutritionmaster.ui.NoScrollViewPager;
+import com.example.ninefourone.nutritionmaster.utils.MessageUtils;
+import com.example.ninefourone.nutritionmaster.utils.PermissionUtils;
import com.flyco.tablayout.SlidingTabLayout;
+import com.github.mikephil.charting.charts.RadarChart;
+import com.github.mikephil.charting.components.Description;
+import com.github.mikephil.charting.components.Legend;
+import com.github.mikephil.charting.components.XAxis;
+import com.github.mikephil.charting.components.YAxis;
+import com.github.mikephil.charting.data.RadarData;
+import com.github.mikephil.charting.data.RadarDataSet;
+import com.github.mikephil.charting.data.RadarEntry;
+import com.github.mikephil.charting.formatter.IndexAxisValueFormatter;
+import com.github.siyamed.shapeimageview.CircularImageView;
+import com.miguelcatalan.materialsearchview.MaterialSearchView;
import com.mxn.soul.flowingdrawer_core.ElasticDrawer;
import com.mxn.soul.flowingdrawer_core.FlowingDrawer;
+import com.nightonke.boommenu.BoomButtons.HamButton;
+import com.nightonke.boommenu.BoomButtons.OnBMClickListener;
+import com.nightonke.boommenu.BoomMenuButton;
+import com.orhanobut.logger.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
+
public class MainActivity extends BaseActivity {
@BindView(R.id.drawerlayout)
@@ -36,6 +59,28 @@ public class MainActivity extends BaseActivity {
NoScrollViewPager viewPager;
@BindView(R.id.sliding_tab_layout)
SlidingTabLayout slidingTabLayout;
+ @BindView(R.id.bar_cover)
+ FrameLayout barCover;
+ @BindView(R.id.cb_rating_bar)
+ CBRatingBar cbRatingBar;
+ @BindView(R.id.toolbar_user_avatar)
+ CircularImageView toolbarUserAvatar;
+ @BindView(R.id.drawer_user_avatar)
+ CircularImageView drawerUserAvatar;
+ // @BindView(R.id.spiderWeb_mainActivity)
+// SpiderWebScoreView spiderWebMainActivity;
+// @BindView(R.id.layout_mainActivity_circular)
+// CircularLayout layoutMainActivityCircular;
+ // @BindView(R.id.search_button)
+// ImageView searchButton;
+ @BindView(R.id.search_view)
+ MaterialSearchView searchView;
+ @BindView(R.id.tool_bar)
+ Toolbar toolBar;
+ @BindView(R.id.boom_menu_button)
+ BoomMenuButton boomMenuButton;
+ @BindView(R.id.spider_view)
+ RadarChart spiderView;
@Override
@@ -47,10 +92,13 @@ public class MainActivity extends BaseActivity {
public void initViews(Bundle savedInstanceState) {
mDrawer.setTouchMode(ElasticDrawer.TOUCH_MODE_BEZEL);
mDrawer.setOnDrawerStateChangeListener(new ElasticDrawer.OnDrawerStateChangeListener() {
+ @SuppressLint("ResourceAsColor")
@Override
public void onDrawerStateChange(int oldState, int newState) {
if (newState == ElasticDrawer.STATE_CLOSED) {
-// Logger.i("Drawer STATE_CLOSED");
+ barCover.setVisibility(View.INVISIBLE);
+ } else {
+ barCover.setVisibility(View.VISIBLE);
}
}
@@ -59,7 +107,10 @@ public class MainActivity extends BaseActivity {
// Logger.i("openRatio=" + openRatio + " ,offsetPixels=" + offsetPixels);
}
});
+ initSpiderView();
initViewPager();
+ initSearchView();
+ initBMB();
}
/**
@@ -75,7 +126,6 @@ public class MainActivity extends BaseActivity {
viewPager.setPageTransformer(true, new CubeOutTransformer());
slidingTabLayout.setViewPager(viewPager);
viewPager.setCurrentItem(1);
-
}
@Override
@@ -88,13 +138,34 @@ public class MainActivity extends BaseActivity {
}
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(Bundle savedInstanceState) {
+
super.onCreate(savedInstanceState);
// TODO: add setContentView(...) invocation
ButterKnife.bind(this);
+ Logger.d("oncreate");
+ setSupportActionBar(toolBar);
+ askPermission();
}
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ Logger.d("oncreateMenu");
+ getMenuInflater().inflate(R.menu.menu_main, menu);
+ MenuItem item = menu.findItem(R.id.id_action_search);
+ searchView.setMenuItem(item);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ Logger.d("prepareMenu");
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+
/**
* 点击事件
*/
@@ -102,4 +173,136 @@ public class MainActivity extends BaseActivity {
public void onViewClicked() {
mDrawer.openMenu();
}
+
+
+ /**
+ * 初始化蛛网图
+ */
+ private void initSpiderView() {
+ float[] scores = {9.1f, 5.5f, 7.7f, 8.9f, 4.6f};
+ String[] flags = {"糖分", "淡水", "蛋白质", "维生素", "矿物质"};
+
+ List radarEntries = new ArrayList<>();
+ for (int i = 0; i < flags.length; i++) {
+ RadarEntry radarEntry = new RadarEntry(scores[i], flags[i]);
+ radarEntries.add(radarEntry);
+ }
+
+ Description description = new Description();
+ description.setText("");
+ spiderView.setDescription(description);
+
+
+ spiderView.setWebLineWidth(1.5f);
+ // 内部线条宽度,外面的环状线条
+ spiderView.setWebLineWidthInner(1.5f);
+ // 所有线条WebLine透明度
+ spiderView.setWebAlpha(300);
+
+
+ Legend legend = spiderView.getLegend();
+ legend.setEnabled(false);
+
+ XAxis xAxis = spiderView.getXAxis();
+ // X坐标值字体样式
+ // xAxis.setTypeface(tf);
+ // X坐标值字体大小
+ xAxis.setTextSize(8f);
+ ArrayList xVals = new ArrayList();
+ for (String flag : flags) {
+ xVals.add(flag);
+ }
+ xAxis.setValueFormatter(new IndexAxisValueFormatter(xVals));
+
+
+ YAxis yAxis = spiderView.getYAxis();
+ // Y坐标值字体样式
+ // yAxis.setTypeface(tf);
+ // Y坐标值字体大小
+ yAxis.setTextSize(0f);
+ // Y坐标值是否从0开始
+ yAxis.setStartAtZero(true);
+ // 是否显示y值在图表上
+ yAxis.setDrawLabels(false);
+ yAxis.setAxisLineWidth(2f);
+ RadarDataSet set = new RadarDataSet(radarEntries, "体质情况");
+// set.setColor(R.color.bar_open);
+ set.setLineWidth(0.5f);
+ set.setDrawFilled(true);
+// set.setFillColor(R.color.spider_view_color);
+// set.resetColors();
+ RadarData data = new RadarData(set);
+ data.setDrawValues(false);
+ spiderView.setData(data);
+ spiderView.setTouchEnabled(false);
+ spiderView.invalidate();
+
+
+ }
+
+ /**
+ * 初始化SearchView
+ */
+ private void initSearchView() {
+ searchView.setOnQueryTextListener(new MaterialSearchView.OnQueryTextListener() {
+ @Override
+ public boolean onQueryTextSubmit(String query) {
+ MessageUtils.MakeToast(query);
+ return false;
+ }
+
+ @Override
+ public boolean onQueryTextChange(String newText) {
+// MessageUtils.MakeToast(newText);
+ return false;
+ }
+ });
+
+ searchView.setOnSearchViewListener(new MaterialSearchView.SearchViewListener() {
+ @Override
+ public void onSearchViewShown() {
+// MessageUtils.MakeToast("Shown");
+ }
+
+ @Override
+ public void onSearchViewClosed() {
+// MessageUtils.MakeToast("closed");
+ }
+ });
+
+ }
+
+ /**
+ * 初始化悬浮按钮
+ */
+ private void initBMB() {
+ HamButton.Builder builder = new HamButton.Builder()
+ .normalImageRes(R.drawable.food_material)
+ .normalTextRes(R.string.food_meterial_title)
+ .listener(new OnBMClickListener() {
+ @Override
+ public void onBoomButtonClick(int index) {
+ Intent cameraIntent = new Intent(MainActivity.this, FoodMaterialCamera.class);
+ startActivity(cameraIntent);
+ }
+ });
+ boomMenuButton.addBuilder(builder);
+ HamButton.Builder builder2 = new HamButton.Builder()
+ .normalImageRes(R.drawable.foods)
+ .normalTextRes(R.string.food_title);
+ boomMenuButton.addBuilder(builder2);
+ }
+
+ /**
+ * 请求权限
+ */
+ private void askPermission() {
+ PermissionUtils.requestCameraPermission(this);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+ MessageUtils.MakeToast("权限赋予成功");
+ }
}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/bodyinformation/BodyInformationFragment.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/bodyinformation/BodyInformationFragment.java
index c36c892..ceda657 100644
--- a/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/bodyinformation/BodyInformationFragment.java
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/bodyinformation/BodyInformationFragment.java
@@ -1,20 +1,34 @@
package com.example.ninefourone.nutritionmaster.modules.viewpagerfragments.bodyinformation;
-import android.graphics.Color;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.TextView;
-import com.akexorcist.roundcornerprogressbar.IconRoundCornerProgressBar;
-import com.akexorcist.roundcornerprogressbar.RoundCornerProgressBar;
import com.example.ninefourone.nutritionmaster.R;
import com.example.ninefourone.nutritionmaster.base.BaseFragment;
-import com.gelitenight.waveview.library.WaveView;
+import com.example.ninefourone.nutritionmaster.utils.ChartDrawer;
+import com.github.mikephil.charting.charts.LineChart;
+import com.github.mikephil.charting.data.Entry;
+import com.today.step.lib.ISportStepInterface;
+import com.today.step.lib.TodayStepManager;
+import com.today.step.lib.TodayStepService;
+
+import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
+import me.itangqi.waveloadingview.WaveLoadingView;
/**
* Created by ScorpioMiku on 2018/8/26.
@@ -22,13 +36,27 @@ import butterknife.Unbinder;
public class BodyInformationFragment extends BaseFragment {
- @BindView(R.id.progress_1)
- RoundCornerProgressBar progress1;
- @BindView(R.id.progress_2)
- IconRoundCornerProgressBar progress2;
+
Unbinder unbinder;
- @BindView(R.id.wave_view)
- WaveView waveView;
+ @BindView(R.id.step_text_view)
+ TextView stepTextView;
+ @BindView(R.id.waveLoadingView)
+ WaveLoadingView waveLoadingView;
+ @BindView(R.id.weight_line_chart)
+ LineChart weightLineChart;
+ @BindView(R.id.step_line_chart)
+ LineChart stepLineChart;
+
+ private int stepCount = 0;
+ private static final int REFRESH_STEP_WHAT = 0;
+
+ //循环取当前时刻的步数中间的间隔时间
+ private long TIME_INTERVAL_REFRESH = 500;
+
+ private Handler mDelayHandler = new Handler(new TodayStepCounterCall());
+
+ private ISportStepInterface iSportStepInterface;
+
@Override
public int getLayoutResId() {
@@ -37,31 +65,8 @@ public class BodyInformationFragment extends BaseFragment {
@Override
public void initView(Bundle state) {
- progress1.setProgressColor(Color.parseColor("#ed3b27"));
- progress1.setProgressBackgroundColor(Color.parseColor("#808080"));
- progress1.setMax(70);
- progress1.setProgress(15);
-
- int progressColor1 = progress1.getProgressColor();
- int backgroundColor1 = progress1.getProgressBackgroundColor();
- int max1 = (int) progress1.getMax();
- int progress_1 = (int) progress1.getProgress();
-
-
- progress2.setProgressColor(Color.parseColor("#56d2c2"));
- progress2.setProgressBackgroundColor(Color.parseColor("#757575"));
- progress2.setIconBackgroundColor(Color.parseColor("#38c0ae"));
- progress2.setMax(550);
- progress2.setProgress(147);
- progress2.setIconImageResource(R.drawable.test_avatar);
-
- int progressColor2 = progress2.getProgressColor();
- int backgroundColor2 = progress2.getProgressBackgroundColor();
- int headerColor2 = progress2.getColorIconBackground();
- int max2 = (int) progress2.getMax();
- int progress_2 = (int) progress2.getProgress();
-
- waveView.setShapeType(WaveView.ShapeType.CIRCLE);
+ initStepCounter();
+ initChart();
}
@@ -82,4 +87,91 @@ public class BodyInformationFragment extends BaseFragment {
super.onDestroyView();
unbinder.unbind();
}
+
+ /**
+ * 计步器初始化
+ */
+ private void initStepCounter() {
+ TodayStepManager.init(getActivity().getApplication());
+ //开启计步
+ Intent stepCounterStart = new Intent(getActivity(), TodayStepService.class);
+ getActivity().startService(stepCounterStart);
+ getActivity().bindService(stepCounterStart, new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ iSportStepInterface = ISportStepInterface.Stub.asInterface(service);
+ try {
+ stepCount = iSportStepInterface.getCurrentTimeSportStep();
+ updateStepCount();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ mDelayHandler.sendEmptyMessageDelayed(REFRESH_STEP_WHAT, TIME_INTERVAL_REFRESH);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+
+ }
+ }, Context.BIND_AUTO_CREATE);
+ }
+
+ /**
+ * 改变记步UI中的数字
+ */
+ private void updateStepCount() {
+ stepTextView.setText(stepCount + "");
+ }
+
+
+ /**
+ * 定时器,修改UI
+ */
+ class TodayStepCounterCall implements Handler.Callback {
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case REFRESH_STEP_WHAT: {
+ //每隔500毫秒获取一次计步数据刷新UI
+ if (null != iSportStepInterface) {
+ int step = 0;
+ try {
+ step = iSportStepInterface.getCurrentTimeSportStep();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ if (stepCount != step) {
+ stepCount = step;
+ updateStepCount();
+ }
+ }
+ mDelayHandler.sendEmptyMessageDelayed(REFRESH_STEP_WHAT, TIME_INTERVAL_REFRESH);
+ break;
+ }
+ }
+ return false;
+ }
+ }
+
+
+ /**
+ * 初始化表格
+ */
+ private void initChart() {
+ ArrayList weightPointValues = new ArrayList<>();
+ for (int i = 1; i < 15; i++) {
+ int y = (int) (Math.random() * 20);
+ weightPointValues.add(new Entry(i, y));
+ }
+ ChartDrawer.initSingleLineChart(weightLineChart, weightPointValues, "体重");
+
+ ArrayList stepPointValues = new ArrayList<>();
+ for (int i = 1; i < 15; i++) {
+ int y = (int) (Math.random() * 20);
+ stepPointValues.add(new Entry(i, y));
+ }
+ ChartDrawer.initSingleLineChart(stepLineChart, stepPointValues, "步数");
+ }
+
}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/customization/CustomizationFragment.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/customization/CustomizationFragment.java
new file mode 100644
index 0000000..7844d9a
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/customization/CustomizationFragment.java
@@ -0,0 +1,111 @@
+package com.example.ninefourone.nutritionmaster.modules.viewpagerfragments.customization;
+
+import android.os.Bundle;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.example.ninefourone.nutritionmaster.R;
+import com.example.ninefourone.nutritionmaster.adapter.CardAdapter;
+import com.example.ninefourone.nutritionmaster.adapter.CardHolder;
+import com.example.ninefourone.nutritionmaster.base.BaseFragment;
+import com.example.ninefourone.nutritionmaster.bean.DailyCard;
+import com.example.ninefourone.nutritionmaster.cardconfig.CardConfig;
+import com.example.ninefourone.nutritionmaster.cardconfig.CardItemTouchCallBack;
+import com.example.ninefourone.nutritionmaster.cardconfig.SwipeCardLayoutManager;
+import com.example.ninefourone.nutritionmaster.utils.ConstantUtils;
+
+import java.util.ArrayList;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.Unbinder;
+
+/**
+ * Created by ScorpioMiku on 2018/8/26.
+ */
+
+public class CustomizationFragment extends BaseFragment {
+
+ @BindView(R.id.card_recycler_view)
+ RecyclerView cardRecyclerView;
+ Unbinder unbinder;
+
+ private CardAdapter cardAdapter;
+ private CardHolder cardHolder;
+ private ArrayList mDataList = new ArrayList<>();
+
+ private int[] picList = new int[]{
+ R.drawable.monday,
+ R.drawable.tuesday,
+ R.drawable.wednesday,
+ R.drawable.thursday,
+ R.drawable.friday,
+ R.drawable.saturday,
+ R.drawable.sunday
+ };
+
+
+ @Override
+ public int getLayoutResId() {
+ return R.layout.customization;
+ }
+
+ @Override
+ public void initView(Bundle state) {
+ loadData();
+ initCardRecyclerView();
+ }
+
+
+ public static BaseFragment getInstance() {
+ return new CustomizationFragment();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ // TODO: inflate a fragment view
+ View rootView = super.onCreateView(inflater, container, savedInstanceState);
+ unbinder = ButterKnife.bind(this, rootView);
+ return rootView;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+
+ @Override
+ protected void loadData() {
+ super.loadData();
+ for (int i = 1; i <= 7; i++) {
+// mDataList.add("周" + ConstantUtils.arab2Chinese(i) + "美食普");
+ DailyCard dailyCard = new DailyCard(
+ "周" + ConstantUtils.arab2Chinese(i) + "美食普",
+ "这里放描述",
+ picList[i - 1]
+ );
+ mDataList.add(dailyCard);
+ }
+ }
+
+ /**
+ * 初始化card recyclerview
+ */
+ private void initCardRecyclerView() {
+ CardConfig.initConfig(getContext());
+ cardRecyclerView.setLayoutManager(new SwipeCardLayoutManager());
+ cardAdapter = new CardAdapter(getContext(), mDataList);
+ cardRecyclerView.setAdapter(cardAdapter);
+
+ CardItemTouchCallBack callBack = new CardItemTouchCallBack(cardRecyclerView, cardAdapter, mDataList);
+ //2.创建ItemTouchHelper并把callBack传进去
+ ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callBack);
+ //3.与RecyclerView关联起来
+ itemTouchHelper.attachToRecyclerView(cardRecyclerView);
+ }
+
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/page1/Page1.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/page1/Page1.java
deleted file mode 100644
index 24a795d..0000000
--- a/app/src/main/java/com/example/ninefourone/nutritionmaster/modules/viewpagerfragments/page1/Page1.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package com.example.ninefourone.nutritionmaster.modules.viewpagerfragments.page1;
-
-import android.os.Bundle;
-
-import com.example.ninefourone.nutritionmaster.R;
-import com.example.ninefourone.nutritionmaster.base.BaseFragment;
-
-/**
- * Created by ScorpioMiku on 2018/8/26.
- */
-
-public class Page1 extends BaseFragment {
- @Override
- public int getLayoutResId() {
- return R.layout.page_1;
- }
-
- @Override
- public void initView(Bundle state) {
-
- }
-
-
- public static BaseFragment getInstance() {
- return new Page1();
- }
-}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/step/StepStarter.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/step/StepStarter.java
new file mode 100644
index 0000000..895a9da
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/step/StepStarter.java
@@ -0,0 +1,28 @@
+package com.example.ninefourone.nutritionmaster.step;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import com.example.ninefourone.nutritionmaster.NutritionMaster;
+import com.example.ninefourone.nutritionmaster.modules.MainActivity;
+import com.orhanobut.logger.Logger;
+
+
+public class StepStarter extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // TODO: This method is called when the BroadcastReceiver is receiving
+ // an Intent broadcast.
+// throw new UnsupportedOperationException("Not yet implemented");
+ NutritionMaster nutritionMaster = (NutritionMaster) context.getApplicationContext();
+ if (!nutritionMaster.isForeground()) {
+ Intent mainIntent = new Intent(context, MainActivity.class);
+ mainIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(mainIntent);
+ }else {
+ Logger.d("已经在计步了");
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/CalculateUtils.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/CalculateUtils.java
new file mode 100644
index 0000000..65f90e8
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/CalculateUtils.java
@@ -0,0 +1,59 @@
+package com.example.ninefourone.nutritionmaster.utils;
+
+/**
+ * Created by ScorpioMiku on 2018/8/29.
+ */
+
+public class CalculateUtils {
+ /**
+ * 计算BMI值 BMI值計算公式: BMI = 體重(公斤) / 身高2(公尺2)
+ *
+ * @param height
+ * @param weight
+ * @return
+ */
+ public static float BMI(float height, float weight) {
+ if (height > 10) {
+ height = height / 100;
+ }
+ return weight / (height * height);
+ }
+
+ /**
+ * 通过身高获得健康的体重
+ *
+ * @param height
+ * @return
+ */
+ public static float[] standardH2W(float height) {
+ if (height > 10) {
+ height = height / 100;
+ }
+ float min;
+ float max;
+ min = (float) 18.5 * height * height;
+ max = (float) 14 * height * height;
+ float[] re = {min, max};
+ return re;
+ }
+
+ /**
+ * 根据BMI得到体质情况
+ *
+ * @param BMI
+ * @return
+ */
+ public static String bodyStatus(float BMI) {
+ if (BMI < 18.5) {
+ return "轻体重";
+ } else if (BMI < 24) {
+ return "健康体重";
+ } else if (BMI < 27) {
+ return "轻度肥胖";
+ } else if (BMI < 30) {
+ return "中度肥胖";
+ } else {
+ return "重度肥胖";
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/ChartDrawer.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/ChartDrawer.java
new file mode 100644
index 0000000..b8eab0e
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/ChartDrawer.java
@@ -0,0 +1,203 @@
+package com.example.ninefourone.nutritionmaster.utils;
+
+import android.content.Context;
+import android.graphics.Color;
+
+import com.example.ninefourone.nutritionmaster.R;
+import com.github.mikephil.charting.animation.Easing;
+import com.github.mikephil.charting.charts.LineChart;
+import com.github.mikephil.charting.components.AxisBase;
+import com.github.mikephil.charting.components.Description;
+import com.github.mikephil.charting.components.Legend;
+import com.github.mikephil.charting.components.XAxis;
+import com.github.mikephil.charting.components.YAxis;
+import com.github.mikephil.charting.data.Entry;
+import com.github.mikephil.charting.data.LineData;
+import com.github.mikephil.charting.data.LineDataSet;
+import com.github.mikephil.charting.formatter.IAxisValueFormatter;
+import com.github.mikephil.charting.formatter.IndexAxisValueFormatter;
+import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
+import com.orhanobut.logger.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by ScorpioMiku on 2018/8/30.
+ */
+
+public class ChartDrawer {
+
+ /**
+ * 创建一条折线
+ *
+ * @param index
+ * @param datas
+ * @param linename
+ * @return
+ */
+ public static void initSingleLineChart(LineChart mLineChart, ArrayList pointValues, String linename) {
+// if (index.length != datas.length) {
+// MessageUtils.MakeToast("index长度与datas长度不符");
+// Logger.d("长度不符");
+// return;
+// } else {
+// ArrayList xValues = new ArrayList<>();
+// for (int i = 0; i < datas.length; i++) {
+// xValues.add(index[i] + "");
+// }
+// ArrayList pointValues = new ArrayList<>();
+// for (int i = 0; i < datas.length; i++) {
+// pointValues.add(new Entry(datas[i], i));
+// }
+// LineDataSet dataSet = new LineDataSet(pointValues, linename);
+// dataSet.setLineWidth(1.75f);
+// dataSet.setColor(R.color.colorPrimary);
+//
+// ArrayList dataSetArrayList = new ArrayList<>();
+// dataSetArrayList.add(dataSet);
+//
+// LineData lineData = new LineData(dataSetArrayList);
+
+ //表格属性
+// lineChart.setDrawBorders(false);
+// lineChart.setDrawGridBackground(false); //表格颜色
+// lineChart.setGridBackgroundColor(Color.GRAY & 0x70FFFFFF); //表格的颜色,设置一个透明度
+// lineChart.setTouchEnabled(true); //可点击
+// lineChart.setDragEnabled(true); //可拖拽
+// lineChart.setScaleEnabled(true); //可缩放
+// lineChart.setPinchZoom(false);
+// lineChart.setBackgroundColor(Color.WHITE); //设置背景颜色
+//
+// lineChart.setData(lineData);
+//
+// Legend mLegend = lineChart.getLegend(); //设置标示,就是那个一组y的value的
+// mLegend.setForm(Legend.LegendForm.SQUARE); //样式
+// mLegend.setFormSize(6f); //字体
+// mLegend.setTextColor(Color.GRAY); //颜色
+// lineChart.setVisibleXRange(0, 4); //x轴可显示的坐标范围
+// XAxis xAxis = lineChart.getXAxis(); //x轴的标示
+// xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); //x轴位置
+// xAxis.setTextColor(Color.GRAY); //字体的颜色
+// xAxis.setTextSize(10f); //字体大小
+// xAxis.setGridColor(Color.GRAY);//网格线颜色
+// xAxis.setDrawGridLines(false); //不显示网格线
+// YAxis axisLeft = lineChart.getAxisLeft(); //y轴左边标示
+// YAxis axisRight = lineChart.getAxisRight(); //y轴右边标示
+// axisLeft.setTextColor(Color.GRAY); //字体颜色
+// axisLeft.setTextSize(10f); //字体大小
+// //axisLeft.setAxisMaxValue(800f); //最大值
+// axisLeft.setLabelCount(5, true); //显示格数
+// axisLeft.setGridColor(Color.GRAY); //网格线颜色
+//
+// axisRight.setDrawAxisLine(false);
+// axisRight.setDrawGridLines(false);
+// axisRight.setDrawLabels(false);
+//
+// //设置动画效果
+// lineChart.animateY(2000, Easing.EasingOption.Linear);
+// lineChart.animateX(2000, Easing.EasingOption.Linear);
+// lineChart.invalidate();
+ mLineChart.setNoDataText("没有数据喔~~");
+ //设置是否绘制chart边框的线
+ mLineChart.setDrawBorders(true);
+ //设置chart边框线颜色
+ mLineChart.setBorderColor(Color.GRAY);
+ //设置chart边框线宽度
+ mLineChart.setBorderWidth(1f);
+ //设置chart是否可以触摸
+ mLineChart.setTouchEnabled(true);
+ //设置是否可以拖拽
+ mLineChart.setDragEnabled(true);
+ //设置是否可以缩放 x和y,默认true
+ mLineChart.setScaleEnabled(false);
+ //设置是否可以通过双击屏幕放大图表。默认是true
+ mLineChart.setDoubleTapToZoomEnabled(false);
+ //设置chart动画
+ mLineChart.animateXY(1000, 1000);
+
+ //=========================设置图例=========================
+ // 像"□ xxx"就是图例
+ Legend legend = mLineChart.getLegend();
+ legend.setEnabled(false);
+
+
+ //=======================设置X轴显示效果==================
+ XAxis xAxis = mLineChart.getXAxis();
+ //是否启用X轴
+ xAxis.setEnabled(true);
+ //是否绘制X轴线
+ xAxis.setDrawAxisLine(true);
+ //设置X轴上每个竖线是否显示
+ xAxis.setDrawGridLines(true);
+ //设置是否绘制X轴上的对应值(标签)
+ xAxis.setDrawLabels(true);
+ //设置X轴显示位置
+ xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
+ //设置竖线为虚线样式
+ // xAxis.enableGridDashedLine(10f, 10f, 0f);
+ //设置x轴标签数
+ xAxis.setLabelCount(8,false);
+ xAxis.setTextSize(5);
+ //图表第一个和最后一个label数据不超出左边和右边的Y轴
+ // xAxis.setAvoidFirstLastClipping(true);
+ xAxis.setDrawGridLines(false);//设置x轴上每个点对应的线
+
+ //修改横轴
+ //准备好每个点对应的x轴数值
+ List list = new ArrayList<>();
+ for (int i = 0; i < pointValues.size(); i++) {
+ list.add(String.valueOf(i+1).concat("号"));
+ }
+ xAxis.setValueFormatter(new IndexAxisValueFormatter(list));
+
+
+ YAxis rightAxis = mLineChart.getAxisRight();
+ rightAxis.setDrawAxisLine(false);
+ rightAxis.setDrawGridLines(false);
+ rightAxis.setEnabled(false);
+ YAxis leftAxis = mLineChart.getAxisLeft();
+ leftAxis.setEnabled(false);
+ leftAxis.setDrawAxisLine(false);
+
+ //点构成的某条线
+ LineDataSet lineDataSet = new LineDataSet(pointValues, "体重");
+ //设置该线的颜色
+ lineDataSet.setColor(R.color.color_bar_background);
+ //设置每个点的颜色
+ lineDataSet.setCircleColor(0xff0171c9);
+ //设置该线的宽度
+ lineDataSet.setLineWidth(0f);
+
+ //设置每个坐标点的圆大小
+ //lineDataSet.setCircleRadius(1f);
+ //设置是否画圆
+ lineDataSet.setDrawCircles(false);
+ // 设置平滑曲线模式
+ // lineDataSet.setMode(LineDataSet.Mode.CUBIC_BEZIER);
+ //设置线一面部分是否填充颜色
+ lineDataSet.setDrawFilled(true);
+ //设置填充的颜色
+ lineDataSet.setFillColor(0x20A0FF);
+ //设置是否显示点的坐标值
+ lineDataSet.setDrawValues(false);
+
+
+ //隐藏x轴描述
+ Description description = new Description();
+ description.setEnabled(false);
+ mLineChart.setDescription(description);
+ mLineChart.setDrawBorders(false);
+ //线的集合(可单条或多条线)
+ List dataSets = new ArrayList<>();
+ dataSets.add(lineDataSet);
+ //把要画的所有线(线的集合)添加到LineData里
+ LineData lineData = new LineData(dataSets);
+ //把最终的数据setData
+ mLineChart.setData(lineData);
+ mLineChart.invalidate();
+
+ }
+
+
+}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/ConstantUtils.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/ConstantUtils.java
index 9b4ef5d..a982033 100644
--- a/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/ConstantUtils.java
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/ConstantUtils.java
@@ -1,8 +1,31 @@
package com.example.ninefourone.nutritionmaster.utils;
+import java.util.ArrayList;
+
/**
* Created by ScorpioMiku on 2018/8/26.
*/
public class ConstantUtils {
+ public static String arab2Chinese(int number) {
+ switch (number) {
+ case 1:
+ return "一";
+ case 2:
+ return "二";
+ case 3:
+ return "三";
+ case 4:
+ return "四";
+ case 5:
+ return "五";
+ case 6:
+ return "六";
+ case 7:
+ return "日";
+ default:
+ return "";
+ }
+ }
+
}
diff --git a/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/PermissionUtils.java b/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/PermissionUtils.java
new file mode 100644
index 0000000..45a0be0
--- /dev/null
+++ b/app/src/main/java/com/example/ninefourone/nutritionmaster/utils/PermissionUtils.java
@@ -0,0 +1,44 @@
+package com.example.ninefourone.nutritionmaster.utils;
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.support.v4.app.ActivityCompat;
+
+/**
+ * Created by ScorpioMiku on 2018/9/3.
+ */
+
+public class PermissionUtils {
+ public static final int REQUEST_CAMERA = 1056;
+
+ /**
+ * 动态获取相机权限
+ *
+ * @param activity
+ */
+ public static void requestCameraPermission(Activity activity) {
+ if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
+ != PackageManager.PERMISSION_GRANTED) {
+ /**
+ * 直接请求四个权限
+ */
+ ActivityCompat.requestPermissions(activity,
+ new String[]{
+ Manifest.permission.CAMERA,
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.READ_PHONE_STATE
+ }, REQUEST_CAMERA);
+// MessageUtils.MakeToast("权限赋予成功");
+ } else {
+ /**
+ * 否则
+ */
+ }
+
+ }
+}
diff --git a/app/src/main/res/drawable-v24/selector.xml b/app/src/main/res/drawable-v24/selector.xml
new file mode 100644
index 0000000..38a6b39
--- /dev/null
+++ b/app/src/main/res/drawable-v24/selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/body_bg.png b/app/src/main/res/drawable/body_bg.png
new file mode 100644
index 0000000..ded6ac3
Binary files /dev/null and b/app/src/main/res/drawable/body_bg.png differ
diff --git a/app/src/main/res/drawable/food_material.jpg b/app/src/main/res/drawable/food_material.jpg
new file mode 100644
index 0000000..af1bc94
Binary files /dev/null and b/app/src/main/res/drawable/food_material.jpg differ
diff --git a/app/src/main/res/drawable/food_test.jpg b/app/src/main/res/drawable/food_test.jpg
new file mode 100644
index 0000000..59d9a4c
Binary files /dev/null and b/app/src/main/res/drawable/food_test.jpg differ
diff --git a/app/src/main/res/drawable/foods.jpg b/app/src/main/res/drawable/foods.jpg
new file mode 100644
index 0000000..5e7e428
Binary files /dev/null and b/app/src/main/res/drawable/foods.jpg differ
diff --git a/app/src/main/res/drawable/friday.jpg b/app/src/main/res/drawable/friday.jpg
new file mode 100644
index 0000000..fe6abbb
Binary files /dev/null and b/app/src/main/res/drawable/friday.jpg differ
diff --git a/app/src/main/res/drawable/ic_bmi.xml b/app/src/main/res/drawable/ic_bmi.xml
new file mode 100644
index 0000000..470e941
--- /dev/null
+++ b/app/src/main/res/drawable/ic_bmi.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_exchange.xml b/app/src/main/res/drawable/ic_exchange.xml
new file mode 100644
index 0000000..2b6e6b5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_exchange.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_height.xml b/app/src/main/res/drawable/ic_height.xml
new file mode 100644
index 0000000..803f5c5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_height.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_infor_weight.xml b/app/src/main/res/drawable/ic_infor_weight.xml
new file mode 100644
index 0000000..71f19e4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_infor_weight.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_ok.xml b/app/src/main/res/drawable/ic_ok.xml
new file mode 100644
index 0000000..400fd38
--- /dev/null
+++ b/app/src/main/res/drawable/ic_ok.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_power.xml b/app/src/main/res/drawable/ic_power.xml
new file mode 100644
index 0000000..ab9923f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_power.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_record.xml b/app/src/main/res/drawable/ic_record.xml
new file mode 100644
index 0000000..d808cb1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_record.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_score.xml b/app/src/main/res/drawable/ic_score.xml
new file mode 100644
index 0000000..0b3d8a5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_score.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_search.xml b/app/src/main/res/drawable/ic_search.xml
new file mode 100644
index 0000000..6f3f8b5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_search.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_step.xml b/app/src/main/res/drawable/ic_step.xml
new file mode 100644
index 0000000..998b680
--- /dev/null
+++ b/app/src/main/res/drawable/ic_step.xml
@@ -0,0 +1,4 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_weight.xml b/app/src/main/res/drawable/ic_weight.xml
new file mode 100644
index 0000000..28da841
--- /dev/null
+++ b/app/src/main/res/drawable/ic_weight.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/icon_black.xml b/app/src/main/res/drawable/icon_black.xml
new file mode 100644
index 0000000..0154340
--- /dev/null
+++ b/app/src/main/res/drawable/icon_black.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/icon_colorful.png b/app/src/main/res/drawable/icon_colorful.png
new file mode 100644
index 0000000..8df889d
Binary files /dev/null and b/app/src/main/res/drawable/icon_colorful.png differ
diff --git a/app/src/main/res/drawable/monday.jpg b/app/src/main/res/drawable/monday.jpg
new file mode 100644
index 0000000..452d4dc
Binary files /dev/null and b/app/src/main/res/drawable/monday.jpg differ
diff --git a/app/src/main/res/drawable/saturday.jpg b/app/src/main/res/drawable/saturday.jpg
new file mode 100644
index 0000000..7757408
Binary files /dev/null and b/app/src/main/res/drawable/saturday.jpg differ
diff --git a/app/src/main/res/drawable/sunday.jpg b/app/src/main/res/drawable/sunday.jpg
new file mode 100644
index 0000000..bb7e1d8
Binary files /dev/null and b/app/src/main/res/drawable/sunday.jpg differ
diff --git a/app/src/main/res/drawable/thursday.jpg b/app/src/main/res/drawable/thursday.jpg
new file mode 100644
index 0000000..fa60e1e
Binary files /dev/null and b/app/src/main/res/drawable/thursday.jpg differ
diff --git a/app/src/main/res/drawable/tuesday.jpg b/app/src/main/res/drawable/tuesday.jpg
new file mode 100644
index 0000000..35b4668
Binary files /dev/null and b/app/src/main/res/drawable/tuesday.jpg differ
diff --git a/app/src/main/res/drawable/wednesday.jpg b/app/src/main/res/drawable/wednesday.jpg
new file mode 100644
index 0000000..374fd97
Binary files /dev/null and b/app/src/main/res/drawable/wednesday.jpg differ
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 40d848a..c3f12e9 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -11,74 +11,141 @@
app:edMenuSize="230dp"
app:edPosition="1">
-
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:layout_alignParentTop="true">
-
+ android:layout_height="wrap_content">
+
+
+
+
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+
+
+
+
+
-
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_drawer_home" />
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
-
+
+
+
+
+
+
-
-
+ android:orientation="horizontal">
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
-
+ android:gravity="center"
+ android:orientation="vertical">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/body_information_fragment.xml b/app/src/main/res/layout/body_information_fragment.xml
index c5cf7d4..5a8601f 100644
--- a/app/src/main/res/layout/body_information_fragment.xml
+++ b/app/src/main/res/layout/body_information_fragment.xml
@@ -1,39 +1,335 @@
-
+ android:overScrollMode="never"
+ android:scrollbars="none
+">
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
-
+
-
+
-
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/cameras_layout.xml b/app/src/main/res/layout/cameras_layout.xml
new file mode 100644
index 0000000..8fd2bc9
--- /dev/null
+++ b/app/src/main/res/layout/cameras_layout.xml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/card_item.xml b/app/src/main/res/layout/card_item.xml
new file mode 100644
index 0000000..f363533
--- /dev/null
+++ b/app/src/main/res/layout/card_item.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/customization.xml b/app/src/main/res/layout/customization.xml
new file mode 100644
index 0000000..8ce91da
--- /dev/null
+++ b/app/src/main/res/layout/customization.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/page_1.xml b/app/src/main/res/layout/page_1.xml
deleted file mode 100644
index a9ec1dd..0000000
--- a/app/src/main/res/layout/page_1.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/score.xml b/app/src/main/res/layout/score.xml
new file mode 100644
index 0000000..ca6abe5
--- /dev/null
+++ b/app/src/main/res/layout/score.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
new file mode 100644
index 0000000..c5bb617
--- /dev/null
+++ b/app/src/main/res/menu/menu_main.xml
@@ -0,0 +1,26 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-xxhdpi/camera_button.png b/app/src/main/res/mipmap-xxhdpi/camera_button.png
new file mode 100644
index 0000000..b667458
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/camera_button.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/camera_button_pressed.png b/app/src/main/res/mipmap-xxhdpi/camera_button_pressed.png
new file mode 100644
index 0000000..2b6e54e
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/camera_button_pressed.png differ
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 3741717..b2237a2 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -1,8 +1,8 @@
- - page1
- - page2
+ - 一周定制
+ - 今日信息
- page3
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index f877446..f3c137e 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,13 +1,24 @@
- #FF03A9F4
- #ff0171c9
+ #25d43c
+ #17a346
#FF00E5FF
#FF78909C
#FF03A9F4
#FF78909C
+ #17a346
+ #b3b3b3
+ #e6e5e5
+ #52ec2f
+ #9ac3f9
+
+ #ff0000
+
+
+
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index cc6254c..e9c8804 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -12,4 +12,13 @@
36dp
+ 120dp
+ 35dp
+ 90dp
+ 200dp
+
+
+ 20dp
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index df15394..80a90d1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,8 @@
NutritionMaster
+ 当前值
+ 标准值
+ M1080.3,453.7c-77.2,88.2 -214.6,234.4 -214.6,234.4s22,160.2 35.3,269.7c5.9,55.9 -37.5,80.1 -86,58.1 -92.6,-43.4 -233.7,-111 -265.3,-126.4 -32.3,14.7 -174.2,81.6 -267.5,124.9 -49.2,21.3 -92.6,-2.2 -87.5,-58.1 12.5,-109.5 35.3,-269 35.3,-269S91.1,541.9 13.2,453.7c-27.9,-32.3 -9.6,-77.9 44.8,-86 111.7,-19.8 284.4,-51.4 284.4,-51.4s94.8,-163.1 154.3,-263.1C529.8,-7.8 552.6,-0.4 556.3,1c10.3,2.9 26.5,15.4 47,52.2 58.8,99.9 152.1,263.1 152.1,263.1s170.5,31.6 280.7,51.4c53.6,8.1 71.3,54.4 44.1,86z
+ 食材识别
+ 菜品识别
diff --git a/build.gradle b/build.gradle
index a1cb46b..14a009b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -21,6 +21,7 @@ allprojects {
repositories {
google()
jcenter()
+ maven { url 'https://jitpack.io' }
}
}
diff --git a/settings.gradle b/settings.gradle
index e7b4def..7691e36 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app'
+include ':app', ':todaystepcounterlib'
diff --git a/todaystepcounterlib/.gitignore b/todaystepcounterlib/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/todaystepcounterlib/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/todaystepcounterlib/build.gradle b/todaystepcounterlib/build.gradle
new file mode 100644
index 0000000..af7f3ed
--- /dev/null
+++ b/todaystepcounterlib/build.gradle
@@ -0,0 +1,34 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 26
+ defaultConfig {
+ minSdkVersion 19
+ targetSdkVersion 26
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ debug{
+ buildConfigField "boolean", "TODAY_STEP_DEBUG", "true"
+ }
+ release {
+ buildConfigField "boolean", "TODAY_STEP_DEBUG", "true"
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(include: ['*.jar'], dir: 'libs')
+ compile 'com.android.support:appcompat-v7:26.1.0'
+ androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+ exclude group: 'com.android.support', module: 'support-annotations'
+ })
+ testCompile 'junit:junit:4.12'
+ testCompile 'org.robolectric:robolectric:3.0-rc3'
+ testCompile 'org.mockito:mockito-core:1.+'
+ compile files('libs/microlog4android-1.0.0.jar')
+}
diff --git a/todaystepcounterlib/libs/microlog4android-1.0.0.jar b/todaystepcounterlib/libs/microlog4android-1.0.0.jar
new file mode 100644
index 0000000..d6fbe99
Binary files /dev/null and b/todaystepcounterlib/libs/microlog4android-1.0.0.jar differ
diff --git a/todaystepcounterlib/proguard-rules.pro b/todaystepcounterlib/proguard-rules.pro
new file mode 100644
index 0000000..1eec44e
--- /dev/null
+++ b/todaystepcounterlib/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/jiahongfei/Documents/DeveloperSoftware/adt-bundle-mac-x86_64-20140702/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/todaystepcounterlib/src/main/AndroidManifest.xml b/todaystepcounterlib/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..fea9fbf
--- /dev/null
+++ b/todaystepcounterlib/src/main/AndroidManifest.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/todaystepcounterlib/src/main/aidl/com/today/step/lib/ISportStepInterface.aidl b/todaystepcounterlib/src/main/aidl/com/today/step/lib/ISportStepInterface.aidl
new file mode 100644
index 0000000..9913ffa
--- /dev/null
+++ b/todaystepcounterlib/src/main/aidl/com/today/step/lib/ISportStepInterface.aidl
@@ -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);
+}
diff --git a/todaystepcounterlib/src/main/assets/microlog.properties b/todaystepcounterlib/src/main/assets/microlog.properties
new file mode 100644
index 0000000..d6f16e3
--- /dev/null
+++ b/todaystepcounterlib/src/main/assets/microlog.properties
@@ -0,0 +1,4 @@
+# This is a simple Microlog configuration file
+microlog.level=DEBUG
+microlog.appender=LogCatAppender;FileAppender
+microlog.formatter=SimpleFormatter
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/BaseClickBroadcast.java b/todaystepcounterlib/src/main/java/com/today/step/lib/BaseClickBroadcast.java
new file mode 100644
index 0000000..01dc55b
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/BaseClickBroadcast.java
@@ -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 {
+
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/DateUtils.java b/todaystepcounterlib/src/main/java/com/today/step/lib/DateUtils.java
new file mode 100644
index 0000000..2644d5a
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/DateUtils.java
@@ -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;
+ }
+
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/ITodayStepDBHelper.java b/todaystepcounterlib/src/main/java/com/today/step/lib/ITodayStepDBHelper.java
new file mode 100644
index 0000000..61b4c71
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/ITodayStepDBHelper.java
@@ -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 getQueryAll();
+
+ List getStepListByDate(String dateString);
+
+ List getStepListByStartDateAndDays(String startDate, int days);
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/JobSchedulerService.java b/todaystepcounterlib/src/main/java/com/today/step/lib/JobSchedulerService.java
new file mode 100644
index 0000000..d76f95f
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/JobSchedulerService.java
@@ -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;
+ }
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/Logger.java b/todaystepcounterlib/src/main/java/com/today/step/lib/Logger.java
new file mode 100644
index 0000000..249caa6
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/Logger.java
@@ -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);
+ }
+ }
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/Microlog4Android.java b/todaystepcounterlib/src/main/java/com/today/step/lib/Microlog4Android.java
new file mode 100644
index 0000000..8f15721
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/Microlog4Android.java
@@ -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);
+ }
+ }
+
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/OnStepCounterListener.java b/todaystepcounterlib/src/main/java/com/today/step/lib/OnStepCounterListener.java
new file mode 100644
index 0000000..7cefca4
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/OnStepCounterListener.java
@@ -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();
+
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/PreferencesHelper.java b/todaystepcounterlib/src/main/java/com/today/step/lib/PreferencesHelper.java
new file mode 100644
index 0000000..62f4fa4
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/PreferencesHelper.java
@@ -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);
+ }
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/SportStepJsonUtils.java b/todaystepcounterlib/src/main/java/com/today/step/lib/SportStepJsonUtils.java
new file mode 100644
index 0000000..14ebb14
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/SportStepJsonUtils.java
@@ -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 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);
+ }
+
+
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/StepAlertManagerUtils.java b/todaystepcounterlib/src/main/java/com/today/step/lib/StepAlertManagerUtils.java
new file mode 100644
index 0000000..388f3b1
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/StepAlertManagerUtils.java
@@ -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);
+ }
+
+ }
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepAlertReceive.java b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepAlertReceive.java
new file mode 100644
index 0000000..0e2e2fd
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepAlertReceive.java
@@ -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");
+ }
+
+ }
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepBootCompleteReceiver.java b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepBootCompleteReceiver.java
new file mode 100644
index 0000000..14b9133
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepBootCompleteReceiver.java
@@ -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");
+
+ }
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepCounter.java b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepCounter.java
new file mode 100644
index 0000000..14856c5
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepCounter.java
@@ -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) {
+
+ }
+
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepDBHelper.java b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepDBHelper.java
new file mode 100644
index 0000000..a7f582c
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepDBHelper.java
@@ -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 getQueryAll() {
+ Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_ALL, new String[]{});
+ List todayStepDatas = getTodayStepDataList(cursor);
+ cursor.close();
+ return todayStepDatas;
+ }
+
+ /**
+ * 根据时间获取步数列表
+ *
+ * @param dateString 格式yyyy-MM-dd
+ * @return
+ */
+ @Override
+ public synchronized List getStepListByDate(String dateString) {
+ Cursor cursor = getReadableDatabase().rawQuery(SQL_QUERY_STEP_BY_DATE, new String[]{dateString});
+ List 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 getStepListByStartDateAndDays(String startDate, int days) {
+ List 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 getTodayStepDataList(Cursor cursor) {
+
+ List 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 todayStepDataList = getQueryAll();
+ Set 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);
+ }
+
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepData.java b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepData.java
new file mode 100644
index 0000000..6f7b986
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepData.java
@@ -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 CREATOR = new Creator() {
+ @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 +
+ '}';
+ }
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepDetector.java b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepDetector.java
new file mode 100644
index 0000000..0f123ed
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepDetector.java
@@ -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;
+ }
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepManager.java b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepManager.java
new file mode 100644
index 0000000..937d146
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepManager.java
@@ -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 失败");
+ }
+ }
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepService.java b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepService.java
new file mode 100644
index 0000000..8ff48f0
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepService.java
@@ -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 todayStepDataArrayList) {
+ return SportStepJsonUtils.getSportStepJsonArray(todayStepDataArrayList);
+ }
+
+ @Override
+ public String getTodaySportStepArray() throws RemoteException {
+ if (null != mTodayStepDBHelper) {
+ List 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 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 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);
+ }
+ }
+
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepShutdownReceiver.java b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepShutdownReceiver.java
new file mode 100644
index 0000000..c47df83
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/TodayStepShutdownReceiver.java
@@ -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);
+ }
+ }
+
+}
diff --git a/todaystepcounterlib/src/main/java/com/today/step/lib/WakeLockUtils.java b/todaystepcounterlib/src/main/java/com/today/step/lib/WakeLockUtils.java
new file mode 100644
index 0000000..2db3788
--- /dev/null
+++ b/todaystepcounterlib/src/main/java/com/today/step/lib/WakeLockUtils.java
@@ -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);
+ }
+
+}
diff --git a/todaystepcounterlib/src/main/res/mipmap-xxxhdpi/ic_notification_default.png b/todaystepcounterlib/src/main/res/mipmap-xxxhdpi/ic_notification_default.png
new file mode 100644
index 0000000..aee44e1
Binary files /dev/null and b/todaystepcounterlib/src/main/res/mipmap-xxxhdpi/ic_notification_default.png differ
diff --git a/todaystepcounterlib/src/main/res/values/strings.xml b/todaystepcounterlib/src/main/res/values/strings.xml
new file mode 100644
index 0000000..c7f2281
--- /dev/null
+++ b/todaystepcounterlib/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ TodayStepCounterLib
+ 当前步数:%1$s
+
diff --git a/todaystepcounterlib/src/test/java/com.today.step.lib/MyRobolectricTestRunner.java b/todaystepcounterlib/src/test/java/com.today.step.lib/MyRobolectricTestRunner.java
new file mode 100644
index 0000000..4ca5cd1
--- /dev/null
+++ b/todaystepcounterlib/src/test/java/com.today.step.lib/MyRobolectricTestRunner.java
@@ -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;
+ }
+ };
+ }
+
+}
diff --git a/todaystepcounterlib/src/test/java/com.today.step.lib/TodayStepDBHelperTest.java b/todaystepcounterlib/src/test/java/com.today.step.lib/TodayStepDBHelperTest.java
new file mode 100644
index 0000000..447b0da
--- /dev/null
+++ b/todaystepcounterlib/src/test/java/com.today.step.lib/TodayStepDBHelperTest.java
@@ -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 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 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;
+ }
+}