diff --git a/src/app/src/main/java/com/example/sleep/AfterSleep.java b/src/app/src/main/java/com/example/sleep/AfterSleep.java new file mode 100644 index 0000000..2b35d35 --- /dev/null +++ b/src/app/src/main/java/com/example/sleep/AfterSleep.java @@ -0,0 +1,272 @@ +package com.example.sleep; + +import android.app.Activity; +import android.content.ContentValues; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.KeyEvent; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.sleep.database.MyDataBaseHelper; +import com.github.mikephil.charting.charts.PieChart; +import com.example.sleep.database.GetRecord; +import com.example.sleep.database.RecordBean; +import com.example.sleep.drawChart.DrawPieChart; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; +import java.util.Random; + +import static com.example.sleep.database.GetRecord.getRecord; +import static java.lang.Math.pow; + +/** + * 结束记录的界面 + */ +// 这是一个Android活动,用于显示睡眠分析的结果。 +// 与这个活动关联的布局文件名为aftersleep。 + +public class AfterSleep extends Activity { + + // 这些变量存储对布局文件中的UI元素的引用。 + RelativeLayout background; // 屏幕的背景图像。 + TextView mTime; // 显示总睡眠时间的文字视图。 + TextView mStartTime; // 显示开始睡眠时间的文字视图。 + TextView mStopTime; // 显示停止睡眠时间的文字视图。 + PieChart mPieChart; // 饼状图用于显示深度、浅度和REM睡眠的时间比例。 + TextView mDeep; // 显示深度睡眠时间的文字视图。 + TextView mSwallow; // 显示浅度睡眠时间的文字视图。 + TextView mDream; // 显示REM睡眠时间的文字视图。 + DrawPieChart mDrawPieChart; // 用于绘制饼状图的对象。 + private RecordBean mRecord; // 记录睡眠数据的对象。 + private ImageView sleepReport;// 显示睡眠报告的图像视图。 + private long timeusedinsec; // 睡眠持续的时间(以秒为单位)。 + private String suggest; // 建议信息。 + private int timeOfSleep; // 睡眠时间(小时)。 + + @Override // 覆写父类的onCreate方法,在此方法中进行初始化工作。 + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); // 调用父类的方法,加载默认的布局文件。 + setContentView(R.layout.aftersleep); // 设置当前活动的布局文件为aftersleep。 + + // 初始化各个UI组件。 + background = findViewById(R.id.aftersleep_background); + findViewById(R.id.btn_AfterSleep).setOnClickListener(v -> { + finish(); // 当点击“完成”按钮时,结束当前活动。 + }); + sleepReport = findViewById(R.id.report); + mPieChart = findViewById(R.id.mPiechart); + mTime = findViewById(R.id.sleepTime); + mStartTime = findViewById(R.id.startTime); + mStopTime = findViewById(R.id.stopTime); + mDeep = findViewById(R.id.deep); + mSwallow = findViewById(R.id.swallow); + mDream = findViewById(R.id.dream); + + // 随机设置背景图片。 + int[] array = {R.drawable.bg_1, R.drawable.bg_4, R.drawable.bg_5}; + Random rnd = new Random(); + int index = rnd.nextInt(3); + Resources resources = getBaseContext().getResources(); + Drawable cur = resources.getDrawable(array[index]); + background.setBackground(cur); + + // 获取最新的睡眠记录。 + GetRecord mGetRecord = getRecord(); + mRecord = mGetRecord.getLatestRecord(); + + initView(); // 初始化各个UI组件的内容。 + saveData(); // 存储睡眠记录的数据。 + } + + private List StringSplitAndConvert(String timeString) { + // String timeString = "15:24"; + List timeList = new ArrayList<>(); + // 使用冒号 ":" 分割字符串 + String[] timeParts = timeString.split(":"); + + if (timeParts.length == 2) { + try { + // 将分割后的字符串转换为整数 + int hours = Integer.parseInt(timeParts[0]); + int minutes = Integer.parseInt(timeParts[1]); + timeList.add(hours); + timeList.add(minutes); + // 输出结果 + System.out.println("Hours: " + hours); + System.out.println("Minutes: " + minutes); + } catch (NumberFormatException e) { + System.err.println("无法将字符串转换为整数。"); + } + } else { + System.err.println("字符串格式不正确。"); + } + return timeList; + } + + + private void saveData() { + // 获取最新的记录 + GetRecord mGetRecord = getRecord(); + mRecord = mGetRecord.getLatestRecord(); + + // 计算播放次数的评分 + double grade_numberOfPlay = pow(1.01, -0); + + // 获取记录的开始时间和结束时间 + String startTime = mRecord.getStartTime(); + String endTime = mRecord.getEndTime(); + + // 计算触摸次数的评分 + double grade_numberOfTouch; + int numberOfTouch = 0; + if (numberOfTouch > 2000) { + grade_numberOfTouch = 0.89; + suggest += "最近是不是辗转难眠呢~睡眠质量不够高呢~"; + } else { + grade_numberOfTouch = 1; + } + + // 计算睡眠时长的评分 + double sleepHour = (double) (timeusedinsec / 60 / 60) % 60; + double grade_sumOfSleep; + int nowHour = StringSplitAndConvert(endTime).get(0); + int nowMinute = StringSplitAndConvert(endTime).get(1); + int alarmHour = MySharedPreferences.getHours(App.mContext); + int alarmMinute = MySharedPreferences.getMinutes(App.mContext); + int subOfAlarm; + double alarmTime = alarmHour + alarmMinute / 60, nowTime = nowHour + nowMinute / 60; + if (nowTime > alarmTime) { + subOfAlarm = (nowHour - alarmHour) * 60 + nowMinute - alarmMinute; + } else if (nowTime == alarmTime) { + subOfAlarm = Math.abs(nowMinute - alarmMinute); + } else { + subOfAlarm = (alarmHour - nowHour) * 60 + nowMinute - alarmMinute; + } + double x1 = subOfAlarm / 20; + double grade_subOfAlarm; + + if (x1 > 2) { + suggest += "最近睡眠不深,不知道怎么了?"; + grade_subOfAlarm = 0.8; + } else if (x1 > -1) { + suggest += "您的生物钟很规律哦~希望您继续保持呢~"; + grade_subOfAlarm = 0.99; + } else { + suggest += "最近有点赖床哦~"; + grade_subOfAlarm = 0.9; + } + + // 计算总睡眠评分 + if (sleepHour > 9.3) { + suggest += "睡的时间太长了噢~该早就醒了~"; + grade_sumOfSleep = 0.88; + } else if (sleepHour > 6) { + suggest += "睡觉时长很健康呐~"; + grade_sumOfSleep = 0.96; + } else { + suggest += "最近睡眠缺乏~"; + grade_sumOfSleep = 0.6; + } + + // 计算睡眠时间的评分 + double grade_timeOfSleep; + Calendar cl = Calendar.getInstance(); + java.util.TimeZone timeZone = java.util.TimeZone.getTimeZone("GMT+8"); + cl.setTimeZone(timeZone); + timeOfSleep = cl.get(Calendar.HOUR_OF_DAY); + if (timeOfSleep > 22 && timeOfSleep < 23) { + grade_timeOfSleep = 1; + } else if (timeOfSleep >= 23) { + grade_timeOfSleep = 0.95; + suggest += "另外,最近睡得有点迟啊~"; + } else if (timeOfSleep > 0 && timeOfSleep < 2) { + grade_timeOfSleep = 0.75; + suggest += "另外,最近睡得有点迟啊~"; + } else if (timeOfSleep > 11 && timeOfSleep < 15) { + grade_timeOfSleep = 1; + } else if (timeOfSleep > 2 && timeOfSleep < 6) { + grade_timeOfSleep = 0.65; + suggest += "最近在赶project吗?这样对身体不好的...\n"; + } else { + grade_timeOfSleep = 0.95; + } + + // 计算总评分 + double grade = 100 * grade_subOfAlarm * grade_sumOfSleep * grade_numberOfTouch * grade_timeOfSleep * pow(grade_numberOfPlay, 0.2); + grade = 10 * pow(grade, 0.5); + + // 获取当前日期 + Calendar calendar1 = Calendar.getInstance(); + java.util.TimeZone timeZone1 = java.util.TimeZone.getTimeZone("GTM+8"); + calendar1.setTimeZone(timeZone1); + int month = calendar1.get(Calendar.MONTH) + 1; + int day = calendar1.get(Calendar.DAY_OF_MONTH); + String x = month + "." + day; + + // 保存评分和建议到SharedPreferences + SharedPreferences sharedpref = App.mContext.getSharedPreferences("info", MODE_PRIVATE); + float z = sharedpref.getFloat("grade", 100); + long grade1 = Math.round(grade); + z = (float) (0.2 * z + 0.8 * grade1); + SharedPreferences.Editor editor = sharedpref.edit(); + editor.putFloat("grade", z); + editor.putString("suggestion", suggest); + editor.apply(); + + // 将评分和其他数据保存到数据库 + MyDataBaseHelper dbHelp = new MyDataBaseHelper(this); + final SQLiteDatabase sqLiteDatabase = dbHelp.getWritableDatabase(); + ContentValues cv = new ContentValues(); + cv.put("time", x); + cv.put("grade", z); + cv.put("sumOfSleep", sleepHour); + cv.put("timeOfSleep", timeOfSleep); + sqLiteDatabase.insert("grade_table", null, cv); + } + + + //设置文本 + protected void initView() { + if (mRecord != null) { + mStartTime.setText(String.format(getResources().getString(R.string.sleep_time), mRecord.getStartTime())); + mStopTime.setText(String.format(getResources().getString(R.string.get_up_time), mRecord.getEndTime())); + mTime.setText(String.format(Locale.getDefault(), "时长 %02d:%02d", + mRecord.getTotalTime() / 60, mRecord.getTotalTime() % 60)); + mDeep.setText(String.format(Locale.getDefault(), "深度睡眠 %02d:%02d", + mRecord.getDeepTime() / 60, mRecord.getDeepTime() % 60)); + mSwallow.setText(String.format(Locale.getDefault(), "浅层睡眠 %02d:%02d", + mRecord.getSwallowTime() / 60, mRecord.getSwallowTime() % 60)); + mDream.setText(String.format(Locale.getDefault(), "醒/梦 %02d:%02d", + mRecord.getAwakeTime() / 60, mRecord.getAwakeTime() % 60)); + mDrawPieChart = new DrawPieChart(mPieChart, mRecord, getResources()); + } else { + Toast.makeText(this, "数据错误", Toast.LENGTH_SHORT).show(); + } + } + + //返回键效果 + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + Intent i = new Intent().setClass(AfterSleep.this, MainScreen.class); + AfterSleep.this.startActivity(i); + AfterSleep.this.finish(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } +} diff --git a/src/app/src/main/java/com/example/sleep/AfterSleepReport.java b/src/app/src/main/java/com/example/sleep/AfterSleepReport.java new file mode 100644 index 0000000..d8931e8 --- /dev/null +++ b/src/app/src/main/java/com/example/sleep/AfterSleepReport.java @@ -0,0 +1,116 @@ +package com.example.sleep; + +import static com.example.sleep.database.GetRecord.getRecord; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.view.KeyEvent; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.sleep.database.GetRecord; +import com.example.sleep.database.RecordBean; +import com.example.sleep.drawChart.DrawPieChart; +import com.github.mikephil.charting.charts.PieChart; + +import java.util.Locale; +import java.util.Random; + +/** + * 结束记录的界面 + */ +public class AfterSleepReport extends Activity { + + //这些变量存储对布局文件中的UI元素的引用 + RelativeLayout background; //背景图片布局 + TextView mTime; //显示总的睡眠时间的文字视图 + TextView mStartTime; //显示开始睡眠时间的文字视图 + TextView mStopTime; //显示结束睡眠时间的文字视图 + PieChart mPieChart; //用于显示深度、浅度和REM睡眠时间的饼状图 + TextView mDeep; //显示深度睡眠时间的文字视图 + TextView mSwallow; //显示浅度睡眠时间的文字视图 + TextView mDream; //显示睡眠时间的文字视图 + DrawPieChart mDrawPieChart; //显示睡眠信息图 + + private RecordBean mRecord; + private ImageView sleepReport; + + + + @Override + public void onCreate(Bundle savedInstanceState) { + //调用父类的方法,设置默认的布局文件 + super.onCreate(savedInstanceState); + setContentView(R.layout.aftersleep); + + //初始化各个UI组件 + background = findViewById(R.id.aftersleep_background); + findViewById(R.id.btn_AfterSleep).setOnClickListener(v -> { + finish(); //当点击"完成"按钮时,结束当前活动 + }); + sleepReport = findViewById(R.id.report); + mPieChart = findViewById(R.id.mPiechart); + mTime = findViewById(R.id.sleepTime); + mStartTime = findViewById(R.id.startTime); + mStopTime = findViewById(R.id.stopTime); + mDeep = findViewById(R.id.deep); + mSwallow = findViewById(R.id.swallow); + mDream = findViewById(R.id.dream); + + //随机背景 + int[] array = {R.drawable.bg_1, R.drawable.bg_4, R.drawable.bg_5}; + Random rnd = new Random(); + int index = rnd.nextInt(3); + Resources resources = getBaseContext().getResources(); + Drawable cur = resources.getDrawable(array[index]); + background.setBackground(cur); + //long recordId = this.getIntent().getLongExtra("recordId", 0); + //获取最新的睡眠记录 + GetRecord mGetRecord = getRecord(); + mRecord = mGetRecord.getLatestRecord(); + initView(); + + } + + //设置文本 + protected void initView() { + if (mRecord != null) { + mStartTime.setText(String.format(getResources().getString(R.string.sleep_time), mRecord.getStartTime())); + mStopTime.setText(String.format(getResources().getString(R.string.get_up_time), mRecord.getEndTime())); + mTime.setText(String.format(Locale.getDefault(), "时长 %02d:%02d", + mRecord.getTotalTime() / 60, mRecord.getTotalTime() % 60)); + mDeep.setText(String.format(Locale.getDefault(), "深度睡眠 %02d:%02d", + mRecord.getDeepTime() / 60, mRecord.getDeepTime() % 60)); + mSwallow.setText(String.format(Locale.getDefault(), "浅层睡眠 %02d:%02d", + mRecord.getSwallowTime() / 60, mRecord.getSwallowTime() % 60)); + mDream.setText(String.format(Locale.getDefault(), "醒/梦 %02d:%02d", + mRecord.getAwakeTime() / 60, mRecord.getAwakeTime() % 60)); + mDrawPieChart = new DrawPieChart(mPieChart, mRecord, getResources()); + } else { + Toast.makeText(this, "数据错误", Toast.LENGTH_SHORT).show(); + } + } + + //返回键效果 + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + Intent i = new Intent().setClass(AfterSleepReport.this, MainScreen.class); + AfterSleepReport.this.startActivity(i); + AfterSleepReport.this.finish(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + +} diff --git a/src/app/src/main/java/com/example/sleep/AlarmReceiver.java b/src/app/src/main/java/com/example/sleep/AlarmReceiver.java new file mode 100644 index 0000000..7ac411b --- /dev/null +++ b/src/app/src/main/java/com/example/sleep/AlarmReceiver.java @@ -0,0 +1,38 @@ +package com.example.sleep; + +import android.Manifest; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.support.v4.content.ContextCompat; +import android.util.Log; + +public class AlarmReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + // 获取默认的闹钟铃声的URI + // Uri alarmTone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); + // Uri alarmTone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + Uri alarmTone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); + Log.e("闹铃:","received: " +alarmTone.toString()); + // 检查权限 + if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + // 使用Ringtone来播放声音 + Ringtone ringtone = RingtoneManager.getRingtone(App.mContext, alarmTone); + if (ringtone != null) { + Log.e("闹铃:","ringtone is playing"); + ringtone.play(); + } else { + Log.e("闹铃:","ringtone is null"); + } + } else { + // 如果没有权限,可以选择播放内置的声音或其他方式提醒用户 + Log.e("闹铃:","no premission"); + } + + } +} diff --git a/src/app/src/main/java/com/example/sleep/GoSleepBroadcastReceiver.java b/src/app/src/main/java/com/example/sleep/GoSleepBroadcastReceiver.java new file mode 100644 index 0000000..60d5419 --- /dev/null +++ b/src/app/src/main/java/com/example/sleep/GoSleepBroadcastReceiver.java @@ -0,0 +1,29 @@ +package com.example.sleep; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Build; + +import com.example.sleep.service.GoSleepService; + +public class GoSleepBroadcastReceiver extends BroadcastReceiver { + // 定义一个静态常量ACTION,用于接收系统开机广播 + static final String ACTION = "android.intent.action.BOOT_COMPLETED"; + + @Override + public void onReceive(Context context, Intent intent) { + // 当接收到系统广播时 + if (ACTION.equals(intent.getAction())) { + // 创建一个意图,启动GoSleepService服务 + Intent ifSleepIntent = new Intent(context, GoSleepService.class); + // 根据Android版本选择启动前台服务或普通服务 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(ifSleepIntent); + } else { + context.startService(ifSleepIntent); + } + } + } +} +//这段代码是一个广播接收器,用于接收系统开机广播,并在接收到广播时启动GoSleepService服务。根据Android版本的不同,选择启动前台服务或普通服务。 diff --git a/src/app/src/main/java/com/example/sleep/SleepFragment.java b/src/app/src/main/java/com/example/sleep/SleepFragment.java new file mode 100644 index 0000000..fcc9be0 --- /dev/null +++ b/src/app/src/main/java/com/example/sleep/SleepFragment.java @@ -0,0 +1,128 @@ +package com.example.sleep; + + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.app.TimePickerDialog; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TimePicker; +import android.widget.Toast; + +import java.util.Calendar; +import java.util.Random; + +public class SleepFragment extends Fragment { + private Button startSleep; + private FragmentActivity activity; + private Button alarmTime; + private Calendar calendar; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // 在这里设置 SleepFragment 的布局,例如从 XML 文件中加载 + View view = inflater.inflate(R.layout.fragment_sleep, container, false); + initView(view); + initListener(); + return view; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + // 在这里获取关联的Activity上下文 + activity = getActivity(); + } + + private void initListener() { + startSleep.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Toast.makeText(App.mContext, "开始记录!", Toast.LENGTH_SHORT).show(); + Intent i = new Intent(); + i.setClass(App.mContext, SleepMonitoringScreen.class); + activity.startActivity(i); + } + }); + } + public void initView(View view) { + ImageView mImageText; + mImageText = view.findViewById(R.id.imageText); + startSleep = view.findViewById(R.id.btn_start); + alarmTime = view.findViewById(R.id.timeBtn); + alarmTime.setText("我将会在" + " 00:00 " + "醒来"); + alarmTime.setOnClickListener(new Button.OnClickListener() { + @Override + public void onClick(View arg0) { + calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + new TimePickerDialog(getActivity(), new TimePickerDialog.OnTimeSetListener() { + @Override + public void onTimeSet(TimePicker arg0, int h, int m) { + MySharedPreferences.saveTime(App.mContext,h,m); + //更新按钮上的时间 + alarmTime.setText("我将会在 " + formatTime(h, m) + " " + "醒来"); + //设置日历的时间,主要是让日历的年月日和当前同步 + calendar.setTimeInMillis(System.currentTimeMillis()); + //设置日历的小时和分钟 + calendar.set(Calendar.HOUR_OF_DAY, h); + calendar.set(Calendar.MINUTE, m); + //将秒和毫秒设置为0 + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + } + }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), true).show(); + } + }); + //设置随机背景 + int[] array = {R.drawable.main_bg_1, R.drawable.main_bg_2, R.drawable.main_bg_3, + R.drawable.main_bg_4, R.drawable.main_bg_5, R.drawable.main_bg_6}; + Random rnd = new Random(); + int index = rnd.nextInt(6); + Resources resources = getActivity().getResources(); + Drawable cur = resources.getDrawable(array[index]); + mImageText.setBackground(cur); + } + + public String formatTime(int h, int m) { + StringBuffer buf = new StringBuffer(); + if (h < 10) { + buf.append("0" + h); + } else { + buf.append(h); + } + buf.append(" : "); + if (m < 10) { + buf.append("0" + m); + } else { + buf.append(m); + } + setAlarm(getActivity(),h,m); + return buf.toString(); + } + + public void setAlarm(Context context, int h, int m) { + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + Intent intent = new Intent(context, AlarmReceiver.class); + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); + + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + calendar.set(Calendar.HOUR_OF_DAY, h); + calendar.set(Calendar.MINUTE, m); + + alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent); + } + +} diff --git a/src/app/src/main/java/com/example/sleep/SleepMonitoringScreen.java b/src/app/src/main/java/com/example/sleep/SleepMonitoringScreen.java new file mode 100644 index 0000000..1e71bec --- /dev/null +++ b/src/app/src/main/java/com/example/sleep/SleepMonitoringScreen.java @@ -0,0 +1,293 @@ +package com.example.sleep; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.content.res.Resources; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.widget.Button; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import com.example.sleep.service.DaemonService; +import com.example.sleep.service.GoSleepService; +import com.example.sleep.service.GrayService; +import com.example.sleep.service.MediaService; +import com.example.sleep.service.PlayerMusicService; +import com.example.sleep.service.SensorService; +import com.shihoo.daemon.DaemonEnv; +import com.shihoo.daemon.WatchProcessPrefHelper; + +import java.util.Calendar; +import java.util.Locale; +import java.util.Random; +import java.util.Timer; +import java.util.TimerTask; + +import static android.content.ContentValues.TAG; + +/** + * 记录睡眠的界面 + */ +public class SleepMonitoringScreen extends Activity { + TextView clock; + TextView musicTitle; + RelativeLayout background; + + private Button playButton; + + private int runningTime; + + private Timer mRunTimer; + + private boolean playing; + //private JobSchedulerManager mJobManager; + private MediaService.MyBinder mMyBinder; + // 连接音乐服务 + private ServiceConnection mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mMyBinder = (MediaService.MyBinder) service; + mMyBinder.getMusicTitle(musicTitle); + Log.e(TAG, "Service与Activity已连接"); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + } + }; + + private BroadcastReceiver mScreenOReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + + if (action != null && action.equals("android.intent.action.SCREEN_ON")) { + stopRunTimer(); + startRunTimer(); + } + } + + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.sleep); + //mJobManager = JobSchedulerManager.getJobSchedulerInstance(this); + //mJobManager.startJobScheduler(); + stopGoSleepService(); + + initView(); + initMedia(); + initData(); + + IntentFilter mScreenOnFilter = new IntentFilter("android.intent.action.SCREEN_ON"); + this.registerReceiver(mScreenOReceiver, mScreenOnFilter); + } + + //开始记录数据 + public void initData() { + runningTime = 0; + startRunTimer(); + //startPlayMusicService(); + //stopGosleepService(); + startDaemonService(); + + WatchProcessPrefHelper.setIsStartSDaemon(this, true); + DaemonEnv.startServiceSafely(this, SensorService.class, false); + } + + public void initMedia() { + playing = false; + Intent MediaServiceIntent = new Intent(this, MediaService.class); + bindService(MediaServiceIntent, mServiceConnection, BIND_AUTO_CREATE); + } + + //界面初始化 + public void initView() { + Typeface typeface = Typeface.createFromAsset(getAssets(), "clock_font.ttf"); + clock = findViewById(R.id.mRunTime); + clock.setTypeface(typeface); + musicTitle = findViewById(R.id.musicName); + playButton = findViewById(R.id.play); + + //设置随机背景 + background = findViewById(R.id.sleep_background); + int[] array = {R.drawable.bg_2, R.drawable.bg_3, R.drawable.bg_6, R.drawable.bg_7}; + Random rnd = new Random(); + int index = rnd.nextInt(4); + Resources resources = getBaseContext().getResources(); + Drawable cur = resources.getDrawable(array[index]); + background.setBackground(cur); + } + + // 音乐播放按钮 + public void onClickMedia(View v) { + runningTime = 0; + switch (v.getId()) { + case R.id.play: + if (!playing) { + mMyBinder.playMusic(); + Log.e(TAG, "Play music."); + playButton.setBackground(getResources().getDrawable(R.drawable.ic_play_btn_pause)); + } else { + mMyBinder.pauseMusic(); + Log.e(TAG, "Pause music."); + playButton.setBackground(getResources().getDrawable(R.drawable.ic_play_btn_play)); + } + playing = !playing; + break; + case R.id.next: + mMyBinder.nextMusic(); + break; + case R.id.previous: + mMyBinder.previousMusic(); + break; + } + } + + // 停止记录按钮 + public void onRunningClick2(View v) { + Toast.makeText(this, "停止记录!", Toast.LENGTH_SHORT).show(); + WatchProcessPrefHelper.setIsStartSDaemon(this, false); + DaemonEnv.stopAllServices(this); + stopRunTimer(); + stopDaemonService(); + //stopPlayMusicService(); + //stopGrayService(); + Intent i = new Intent(); + i.setClass(SleepMonitoringScreen.this, AfterSleep.class); + SleepMonitoringScreen.this.startActivity(i); + SleepMonitoringScreen.this.finish(); + } + + //返回键效果 + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + Toast.makeText(SleepMonitoringScreen.this, "正在睡觉", Toast.LENGTH_SHORT).show(); + return true; + } + return super.onKeyDown(keyCode, event); + } + + //计时器 + public void startRunTimer() { + TimerTask mTask = new TimerTask() { + Calendar calendar = Calendar.getInstance(); + int hour = calendar.get(Calendar.HOUR_OF_DAY); + int minute = calendar.get(Calendar.MINUTE); + + @Override + public void run() { + if (playing) { + ++runningTime; + if (runningTime > 15) { + mMyBinder.closeMedia(); + } + } + ++minute; + if (minute == 60) { + minute = 0; + hour++; + } + if (hour == 24) { + minute = 0; + hour = 0; + } + // 更新UI,有bug,需要重写 + runOnUiThread(new Runnable() { + @Override + public void run() { + clock.setText(String.format(Locale.getDefault(), "%02d:%02d", hour, minute)); + } + }); + } + }; + Calendar calendar = Calendar.getInstance(); + clock.setText(String.format(Locale.getDefault(), "%02d:%02d", + calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE))); + mRunTimer = new Timer(); + mRunTimer.schedule(mTask, 60000 - calendar.get(Calendar.SECOND) * 1000 + - calendar.get(Calendar.MILLISECOND), 60000); + } + + //停止计时器 + private void stopRunTimer() { + if (mRunTimer != null) { + mRunTimer.cancel(); + mRunTimer = null; + } + } + + //下面各种的保活策略,部分在sdk=25时有效,于是暂时去掉了 + private void startPlayMusicService() { + Intent intent = new Intent(SleepMonitoringScreen.this, PlayerMusicService.class); + startService(intent); + } + + private void stopPlayMusicService() { + Intent intent = new Intent(SleepMonitoringScreen.this, PlayerMusicService.class); + stopService(intent); + } + + private void startGoSleepService() { + Intent intent = new Intent(SleepMonitoringScreen.this, GoSleepService.class); + startService(intent); + } + + private void stopGoSleepService() { + Intent intent = new Intent(SleepMonitoringScreen.this, GoSleepService.class); + stopService(intent); + } + + private void startDaemonService() { + Intent intent = new Intent(SleepMonitoringScreen.this, DaemonService.class); + startService(intent); + } + + private void stopDaemonService() { + Intent intent = new Intent(SleepMonitoringScreen.this, DaemonService.class); + stopService(intent); + } + + private void startGrayService() { + Intent intent = new Intent(SleepMonitoringScreen.this, GrayService.class); + startService(intent); + } + + private void stopGrayService() { + Intent intent = new Intent(SleepMonitoringScreen.this, GrayService.class); + stopService(intent); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + this.unregisterReceiver(mScreenOReceiver); + + if (mMyBinder != null && playing) { + mMyBinder.closeMedia(); + } + unbindService(mServiceConnection); + + WatchProcessPrefHelper.setIsStartSDaemon(this, false); + DaemonEnv.stopAllServices(this); + stopRunTimer(); +// stopPlayMusicService(); + stopDaemonService(); + //startGosleepService(); + //mJobManager.stopJobScheduler(); + } +} diff --git a/src/app/src/main/java/com/example/sleep/drawChart/DrawLineChart.java b/src/app/src/main/java/com/example/sleep/drawChart/DrawLineChart.java new file mode 100644 index 0000000..28449e8 --- /dev/null +++ b/src/app/src/main/java/com/example/sleep/drawChart/DrawLineChart.java @@ -0,0 +1,139 @@ +package com.example.sleep.drawChart; + +import android.content.res.Resources; +import android.graphics.Color; + +import com.github.mikephil.charting.charts.LineChart; +import com.github.mikephil.charting.components.AxisBase; +import com.github.mikephil.charting.components.Legend; +import com.github.mikephil.charting.components.LimitLine; +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.example.sleep.R; +import com.example.sleep.database.RecordBean; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class DrawLineChart { + private LineChart mLineChart; + private RecordBean mRecord; + private Resources mResources; + private ArrayList times; + private ArrayList sleepDetails; + private List entries = new ArrayList<>(); + + /** + * 绘制折线图 + * + * @param lineChart 折线图元素 + * @param mRecord 睡眠记录 + * @param mResources 绘图资源 + */ + public DrawLineChart(LineChart lineChart, RecordBean mRecord, Resources mResources) { + mLineChart = lineChart; + mLineChart.setDrawBorders(false); + mLineChart.setNoDataText("睡眠时间太短啦!没有足够数据!"); + mLineChart.setNoDataTextColor(Color.WHITE); + mLineChart.setDrawGridBackground(true); + mLineChart.setGridBackgroundColor(mResources.getColor(R.color.transparent_gray)); + mLineChart.setDragEnabled(true); + mLineChart.animateX(1000); + mLineChart.setScaleEnabled(true); + mLineChart.setPinchZoom(true); + mLineChart.getDescription().setEnabled(false); + //画折线图 + if (mRecord.getDrawChart()) { + this.mResources = mResources; + this.mRecord = mRecord; + readRecordDetails(); + drawChart(); + } else { + mLineChart.clear(); + } + } + + public void setRecord(RecordBean mRecord) { + this.mRecord = mRecord; + if (mRecord.getDrawChart()) { + readRecordDetails(); + drawChart(); + } else { + mLineChart.clear(); + } + } + + private void readRecordDetails() { + String[] arr = mRecord.getSleepDetail().split(" "); + String[] buf; + for (String e : arr) { + buf = e.split(","); + entries.add(new Entry(Integer.parseInt(buf[0]), Float.parseFloat(buf[1]))); + } + } + + private void drawChart() { + // 创建线性数据集并设置属性 + LineDataSet lineDataSet = new LineDataSet(entries, ""); + lineDataSet.setColor(mResources.getColor(R.color.Pie_Yellow)); + lineDataSet.setLineWidth(1.6f); + lineDataSet.setDrawCircles(false); + lineDataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER); + + // 设置线性图数据并绘制 + LineData data = new LineData(lineDataSet); + data.setDrawValues(false); + + // 设置X轴属性 + XAxis xAxis = mLineChart.getXAxis(); + xAxis.setPosition(XAxis.XAxisPosition.BOTTOM); + xAxis.setGranularity(1f); + xAxis.setLabelCount(8, false); + xAxis.setTextColor(Color.WHITE); + xAxis.setDrawGridLines(false); + xAxis.setLabelRotationAngle(0); + xAxis.setValueFormatter(new IAxisValueFormatter() { + @Override + public String getFormattedValue(float value, AxisBase axis) { + int IValue = (int) value; + return String.format(Locale.getDefault(), "%02d:%02d", IValue % 1440 / 60, IValue % 60); + } + }); + + // 设置左侧Y轴属性 + YAxis leftYAxis = mLineChart.getAxisLeft(); + leftYAxis.setEnabled(true); + leftYAxis.setDrawGridLines(false); + leftYAxis.setAxisMinimum(0); + leftYAxis.setValueFormatter(new IAxisValueFormatter() { + @Override + public String getFormattedValue(float value, AxisBase axis) { + return ""; + } + }); + + // 设置限制线并添加到左侧Y轴 + LimitLine limitLine = new LimitLine(0.37f, "深度睡眠"); + limitLine.setLineColor(mResources.getColor(R.color.Pie_Green)); + limitLine.setTextColor(mResources.getColor(R.color.Pie_Green)); + leftYAxis.addLimitLine(limitLine); + + LimitLine limitLine1 = new LimitLine(0.8f, "浅层睡眠"); + limitLine1.setLineColor(mResources.getColor(R.color.Pie_Blue)); + limitLine1.setTextColor(mResources.getColor(R.color.Pie_Blue)); + leftYAxis.addLimitLine(limitLine1); + + // 设置图例并绘制线性图 + Legend legend = mLineChart.getLegend(); + legend.setEnabled(false); + + mLineChart.setData(data); + mLineChart.invalidate(); + } +} + diff --git a/src/app/src/main/java/com/example/sleep/drawChart/DrawPieChart.java b/src/app/src/main/java/com/example/sleep/drawChart/DrawPieChart.java new file mode 100644 index 0000000..ef1822a --- /dev/null +++ b/src/app/src/main/java/com/example/sleep/drawChart/DrawPieChart.java @@ -0,0 +1,106 @@ +package com.example.sleep.drawChart; + +import android.content.res.Resources; +import android.graphics.Color; + +import com.github.mikephil.charting.animation.Easing; +import com.github.mikephil.charting.charts.PieChart; +import com.github.mikephil.charting.components.Legend; +import com.github.mikephil.charting.data.PieData; +import com.github.mikephil.charting.data.PieDataSet; +import com.github.mikephil.charting.data.PieEntry; +import com.github.mikephil.charting.formatter.PercentFormatter; +import com.example.sleep.R; +import com.example.sleep.database.RecordBean; + +import java.util.ArrayList; + +public class DrawPieChart { + + private PieChart mPieChart; + private RecordBean mRecord; + private Resources mResources; + // 构造函数,设置饼状图的一些属性 + /** + * 绘制饼状图 + * @param pieChart 饼状图的对象 + * @param mRecord 睡眠记录 + * @param mResources 资源实例 + */ + public DrawPieChart(PieChart pieChart, RecordBean mRecord, Resources mResources) { + mPieChart = pieChart; + mPieChart.setNoDataText("睡眠时间太短啦!没有足够数据!"); + mPieChart.setNoDataTextColor(Color.WHITE); + //画空心饼状图 + if (mRecord.getDrawChart()) { + this.mResources = mResources; + this.mRecord = mRecord; + drawChart(); + } else { + mPieChart.clear(); + } + } + // 设置睡眠记录 + public void setRecord(RecordBean mRecord) { + this.mRecord = mRecord; + if (mRecord.getDrawChart()) { + drawChart(); + } else { + mPieChart.clear(); + } + } + // 绘制饼状图 + private void drawChart() { + mPieChart.setCenterText("您的睡眠状态"); + mPieChart.setCenterTextColor(Color.WHITE); + mPieChart.setUsePercentValues(true); + mPieChart.getDescription().setEnabled(false); + mPieChart.setExtraOffsets(10, 10, 10, 5); + mPieChart.setDrawCenterText(true); + mPieChart.setDrawHoleEnabled(true); + mPieChart.setTransparentCircleColor(Color.WHITE); + mPieChart.setTransparentCircleAlpha(110); + mPieChart.setHoleRadius(58f); + mPieChart.setHoleColor(Color.TRANSPARENT); + mPieChart.setTransparentCircleRadius(61f); + mPieChart.setRotationAngle(0); + mPieChart.setRotationEnabled(true); + mPieChart.setHighlightPerTapEnabled(false); + // 创建包含睡眠状态数据的 PieEntry 对象列表 + ArrayList entries = new ArrayList<>(); + entries.add(new PieEntry(mRecord.getDeepTime(), "深度睡眠")); + entries.add(new PieEntry(mRecord.getSwallowTime(), "浅层睡眠")); + entries.add(new PieEntry(mRecord.getAwakeTime(), "醒/梦")); + // 设置饼状图数据集 + PieDataSet dataSet = new PieDataSet(entries, ""); + dataSet.setSliceSpace(3f); + dataSet.setSelectionShift(5f); + // 设置图例 + mPieChart.setEntryLabelColor(Color.WHITE); + mPieChart.setEntryLabelTextSize(12f); + Legend l = mPieChart.getLegend(); + l.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP); + l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT); + l.setOrientation(Legend.LegendOrientation.VERTICAL); + l.setDrawInside(false); + l.setXEntrySpace(7f); + l.setYEntrySpace(0f); + l.setYOffset(0f); + l.setTextColor(Color.WHITE); + // 设置颜色 + ArrayList colors = new ArrayList<>(); + colors.add(mResources.getColor(R.color.Pie_Green)); + colors.add(mResources.getColor(R.color.Pie_Blue)); + colors.add(mResources.getColor(R.color.Pie_Yellow)); + dataSet.setColors(colors); + // 设置饼状图数据并进行动画效果的设置 + PieData data = new PieData(dataSet); + data.setValueFormatter(new PercentFormatter()); + data.setValueTextSize(11f); + data.setValueTextColor(Color.WHITE); + mPieChart.setData(data); + mPieChart.highlightValues(null); + mPieChart.animateY(1400, Easing.EasingOption.EaseInOutQuad); + mPieChart.invalidate(); + } +} diff --git a/src/app/src/main/java/com/example/sleep/drawChart/SimpleLineChart.java b/src/app/src/main/java/com/example/sleep/drawChart/SimpleLineChart.java new file mode 100644 index 0000000..72d054f --- /dev/null +++ b/src/app/src/main/java/com/example/sleep/drawChart/SimpleLineChart.java @@ -0,0 +1,193 @@ +package com.example.sleep.drawChart; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.view.View; + +import java.util.HashMap; + + +public class SimpleLineChart extends View { + //View 的宽和高 + private int mWidth, mHeight; + private int yInterval; + //Y轴字体的大小 + private float mYAxisFontSize = 24; + + //线的颜色 + private int mLineColor = Color.parseColor("#00BCD4"); + + //线条的宽度 + private float mStrokeWidth = 8.0f; + + //点的集合 + private HashMap mPointMap; + + //点的半径 + private float mPointRadius = 10; + + //没有数据的时候的内容 + private String mNoDataMsg = "no data"; + + //X轴的文字 + private String[] mXAxis = {"aa"}; + + //Y轴的文字 + private String[] mYAxis = {"bb"}; + + public SimpleLineChart(Context context) { + this(context, null); + } + + public SimpleLineChart(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SimpleLineChart(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + if (widthMode == MeasureSpec.EXACTLY) { + mWidth = widthSize; + }else if(widthMode == MeasureSpec.AT_MOST){ + throw new IllegalArgumentException("width must be EXACTLY,you should set like android:width=\"200dp\""); + } + + if (heightMode == MeasureSpec.EXACTLY) { + mHeight = heightSize; + }else if(widthMeasureSpec == MeasureSpec.AT_MOST){ + + throw new IllegalArgumentException("height must be EXACTLY,you should set like android:height=\"200dp\""); + } + + setMeasuredDimension(mWidth, mHeight); + } + + @Override + protected void onDraw(Canvas canvas) { + + if(mXAxis.length==0||mYAxis.length==0){ + throw new IllegalArgumentException("X or Y items is null"); + } + //画坐标线的轴 + Paint axisPaint = new Paint(); + axisPaint.setTextSize(mYAxisFontSize); + axisPaint.setColor(Color.parseColor("#3F51B5")); + + if (mPointMap == null || mPointMap.size() == 0) { + int textLength = (int) axisPaint.measureText(mNoDataMsg); + canvas.drawText(mNoDataMsg, mWidth/2 - textLength/2, mHeight/2, axisPaint); + } else { + //画 Y 轴 + + + //存放每个Y轴的坐标 + double[] yPoints = new double[mYAxis.length]; + + + //计算Y轴 每个刻度的间距 + yInterval = (int) ((mHeight - mYAxisFontSize - 2) / (mYAxis.length)); + + //测量Y轴文字的高度 用来画第一个数 + Paint.FontMetrics fm = axisPaint.getFontMetrics(); + int yItemHeight = (int) Math.ceil(fm.descent - fm.ascent); + + for (int i = 0; i < mYAxis.length; i++) { + canvas.drawText(mYAxis[i], 0, mYAxisFontSize + i * yInterval, axisPaint); + yPoints[i] = (int) (mYAxisFontSize + i * yInterval); + + + } + + + //画 X 轴 + + //x轴的刻度集合 + int[] xPoints = new int[mXAxis.length]; + + //计算Y轴开始的原点坐标 + int xItemX = (int) axisPaint.measureText(mYAxis[1]); + + //X轴偏移量 + int xOffset = 50; + //计算x轴 刻度间距 + int xInterval = (int) ((mWidth - xOffset) / (mXAxis.length)); + //获取X轴刻度Y坐标 + int xItemY = (int) (mYAxisFontSize + mYAxis.length * yInterval); + + for (int i = 0; i < mXAxis.length; i++) { + canvas.drawText(mXAxis[i], i * xInterval + xItemX + xOffset, xItemY, axisPaint); + xPoints[i] = (int) (i * xInterval + xItemX + axisPaint.measureText(mXAxis[i]) / 2 + xOffset + 10); +// Log.e("wing", xPoints[i] + ""); + } + + + //画点 + Paint pointPaint = new Paint(); + + pointPaint.setColor(mLineColor); + + Paint linePaint = new Paint(); + + linePaint.setColor(mLineColor); + linePaint.setAntiAlias(true); + //设置线条宽度 + linePaint.setStrokeWidth(mStrokeWidth); + pointPaint.setStyle(Paint.Style.FILL); + + + for (int i = 0; i < mXAxis.length; i++) { + if (mPointMap.get(i) == null) { + throw new IllegalArgumentException("PointMap has incomplete data!"); + } + + //画点 + canvas.drawCircle(xPoints[i], (float)(yPoints[5]+(yPoints[0]-yPoints[5])*mPointMap.get(i)), mPointRadius, pointPaint); + if (i > 0) { + canvas.drawLine(xPoints[i - 1], (float)(yPoints[5]+(yPoints[0]-yPoints[5])*mPointMap.get(i - 1)), xPoints[i], (float)(yPoints[5]+(yPoints[0]-yPoints[5])*mPointMap.get(i)), linePaint); + } + } + + } + } + + /** + * 设置map数据 + * @param data + */ + public void setData(HashMap data){ + mPointMap = data; + invalidate(); + } + + /** + * 设置Y轴文字 + * @param yItem + */ + public void setYItem(String[] yItem){ + mYAxis = yItem; + } + + /** + * 设置X轴文字 + * @param xItem + */ + public void setXItem(String[] xItem){ + mXAxis = xItem; + } + + public void setLineColor(int color){ + mLineColor = color; + invalidate(); + } +} \ No newline at end of file