“Study”app介绍
这是本学期的一个大作业,简单记录一下,还有很多不足。
首先感谢博主 “请叫我大苏” ,正是在他的基础上我完成了这个不成熟的app
https://www.cnblogs.com/dasusu/p/5470635.html
实现极简番茄时钟:https://www.ctolib.com/topics-123941.html
一、开发说明
开发工具:AndroidStudio
sdk版本号
minSdkVersion 15
targetSdkVersion 29
二、 主要功能
1、强制学习功能
1.1 说明
开启start按钮后程序启动,当你点击非系统app和本app,就会触发闪退功能,同时弹出toast,奉上精辟的短句。
1.2 实现
Android 辅助功能(AccessibilityService) 为我们提供了一系列的事件回调,帮助我们指示一些用户界面的状态变化。 我们可以派生辅助功能类,进而对不同的 AccessibilityEvent 进行处理。 同样的,这个服务就可以用来判断当前的前台应用。判断完打开了什么app后,只要模拟“home”键效果,就能制造闪退功能。同时连接网上的”精辟短句“接口,跳出toast就完成。
注:需要要用户开启辅助功能
1.3 代码
派生 ACCESSIBILITY SERVICE,创建窗口状态探测服务
public class DetectService extends AccessibilityService {
private static String mForegroundPackageName;
private static DetectService mInstance = null;
private NotificationManager mNotificationManager;
private PendingIntent pendingIntent;
private Intent mIntent;
private NotificationCompat.Builder mBuilder;
private Context mContext;
private Notification notification;
private static final int NOTICATION_ID = 0x1;
public DetectService() {
}
public static DetectService getInstance() {
if (mInstance == null) {
synchronized (DetectService.class) {
if (mInstance == null) {
mInstance = new DetectService();
}
}
}
return mInstance;
}
/**
* 监听窗口焦点,并且获取焦点窗口的包名,并进行判断
*
*/
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
if (Features.showForeground) {
mForegroundPackageName = event.getPackageName().toString();
PackageManager pckMan = getPackageManager();
List<PackageInfo> packs = pckMan.getInstalledPackages(0);
int count = packs.size();
int installedNum = 0;
for (int i = 0; i < count; i++) {
//判断是否为系统app和自身
PackageInfo p = packs.get(i);
if (p.packageName.equals(mForegroundPackageName)) {
ApplicationInfo appInfo = p.applicationInfo;
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0) {
Log.d("study", "系统" + mForegroundPackageName);
} else if (p.packageName.equals("com.example.w.study")) {
Log.d("study", "我自己" + mForegroundPackageName);
} else {
Log.d("study", "外界" + mForegroundPackageName);
Intent intent = new Intent();
intent.setPackage(getPackageName());
intent.setAction("org.crazyit");
intent.putExtra("msg", "home");
sendBroadcast(intent);
Log.d("study", "发射");
}
}
}
}
}
}
@Override
public void onInterrupt() {
}
public String getForegroundPackage() {
return mForegroundPackageName;
}
/**
* 此方法用来判断当前应用的辅助功能服务是否开启
*
*/
public static boolean isAccessibilitySettingsOn(Context context) {
int accessibilityEnabled = 0;
try {
accessibilityEnabled = Settings.Secure.getInt(context.getContentResolver(),
android.provider.Settings.Secure.ACCESSIBILITY_ENABLED);
} catch (Settings.SettingNotFoundException e) {
Log.d("study", e.getMessage());
}
if (accessibilityEnabled == 1) {
String services = Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (services != null) {
return services.toLowerCase().contains(context.getPackageName().toLowerCase());
}
}
return false;
}
}
模拟“home"键效果
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onCreate() {
super.onCreate();
Log.d("study", "home");
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
}
}
判断应用是否在前台
public boolean getFromAccessibilityService(Context context, String packageName) {
if (DetectService.isAccessibilitySettingsOn(context) == true) {
Log.d("study", "开始" );
detectService = DetectService.getInstance();
foreground = detectService.getForegroundPackage();
Log.d("study", "**方法五** App处于" + foreground);
return foreground.equals(packageName);
} else {
//打开辅助功能,引导至辅助功能设置页面
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
Toast.makeText(context, com.example.w.study.R.string.accessbiliityNo, Toast.LENGTH_SHORT).show();
return false;
}
}
2、倒计时功能和学习记录
2.1说明
用户可以为自己学习时间立一个倒计时,app将记录时间
2.2 实现
自定义view,用数据库记录每次时间,存入时每次更新最近7天记录,每次调取时取最近七天数据,柱状图绘制是导入了网上一个包。
2.3 代码
自定义view
public class ClockView extends View {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint timePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int mColor = Color.parseColor("#D1D1D1");
private int centerX;
private int centerY;
private int radius;
private RectF mRectF = new RectF();
public static final float START_ANGLE = -90;
public static final int MAX_TIME = 60;
private float sweepVelocity = 0;
private String textTime = "00:00";
private DBHelper dbHelper;
//分钟
private int time;
//倒计时
private int countdownTime;
private float touchX;
private float touchY;
private float offsetX;
private float offsetY;
private boolean isStarted;
private Context context;
public ClockView(Context context) {
super(context);
dbHelper = DBHelper.getInstance(context);
}
public ClockView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
dbHelper = DBHelper.getInstance(context);
this.context=context;
}
public ClockView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//存入数据库
protected void saveToDBhelper()
{
String date;
for(int i=-7;i<=-1;i++)
{
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, i);
Date dat = calendar.getTime();
date=(dat.getYear()+1900)+"年"+(dat.getMonth()+1)+"月"+dat.getDate()+"日";
dbHelper.insertData(date,0);
}
date=(new Date().getYear()+1900)+"年"+(new Date().getMonth()+1)+"月"+new Date().getDate()+"日";
dbHelper.insertData(date,time);
}
public static float dpToPixel(float dp) {
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
return dp * metrics.density;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
centerX = width / 2;
centerY = height / 2;
radius = (int) dpToPixel(120);
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mRectF.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
//黑圆
canvas.save();
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(dpToPixel(5));
canvas.drawCircle(centerX, centerY, radius, mPaint);
canvas.restore();
//灰圆
canvas.save();
mPaint.setColor(mColor);
canvas.drawArc(mRectF, START_ANGLE, 360 * sweepVelocity, false, mPaint);
canvas.restore();
//时间
canvas.save();
timePaint.setColor(Color.BLACK);
timePaint.setStyle(Paint.Style.FILL);
timePaint.setTextSize(dpToPixel(40));
canvas.drawText(textTime, centerX - timePaint.measureText(textTime) / 2,
centerY - (timePaint.ascent() + timePaint.descent()) / 2, timePaint);
canvas.restore();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (isStarted) {
return true;
}
float x = event.getX();
float y = event.getY();
boolean isContained = isContained(x, y);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
if (isContained) {
touchX = x;
touchY = y;
}
break;
case MotionEvent.ACTION_MOVE:
if (isContained) {
offsetX = x - touchX;
offsetY = y - touchY;
time = (int) (offsetY / 2 / radius * MAX_TIME);
if (time <= 0) {
time = 0;
}
textTime = formatTime(time);
countdownTime = time * 60;
invalidate();
}
break;
}
return true;
}
private boolean isContained(float x, float y) {
if (Math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY)) > radius) {
return false;
} else {
return true;
}
}
private String formatTime(int time) {
StringBuilder sb = new StringBuilder();
if (time < 10) {
sb.append("0" + time + ":00");
} else {
sb.append(time + ":00");
}
return sb.toString();
}
private String formatCountdownTime(int countdownTime) {
StringBuilder sb = new StringBuilder();
int minute = countdownTime / 60;
int second = countdownTime - 60 * minute;
if (minute < 10) {
sb.append("0" + minute + ":");
} else {
sb.append(minute + ":");
}
if (second < 10) {
sb.append("0" + second);
} else {
sb.append(second);
}
return sb.toString();
}
//先画一个黑圆以及显示时间文本,传入一个时间值后,可以实现倒计时功能。
// 实现倒计时需要用到CountDownTimer,因此只要在该类的onTick中不断重绘就行了
public void start(){
if (countdownTime == 0 || isStarted) {
return;
}
isStarted = true;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.0f);
valueAnimator.setDuration(countdownTime * 1000);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
sweepVelocity = (float) animation.getAnimatedValue();
mColor = Color.parseColor("#D1D1D1");
invalidate();
}
});
valueAnimator.start();
new CountDownTimer(countdownTime * 1000 + 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
countdownTime = (countdownTime * 1000 - 1000) / 1000;
textTime = formatCountdownTime(countdownTime);
invalidate();
}
@Override
public void onFinish() {
mColor = Color.BLACK;
sweepVelocity = 0;
isStarted = false;
invalidate();
}
}.start();
saveToDBhelper();
dbHelper.close();
}
}
数据库
public class DBHelper extends SQLiteOpenHelper {
//表名
private static String TableName = "times";
//数据库名
private static String DBName = "test.db";
//数据库版本号
private static int DBVersion = 1;
private Context context;
//数据库实例
private SQLiteDatabase database;
//此类自己的实例
public static DBHelper dbHelper;
//创建数据库的语句
private String createDBSql =
"create table times ("
+ "tododate String primary key , "
+ "todotime int)";
public DBHelper(Context context){
super(context, DBName, null, DBVersion);
this.context = context;
}
//DBHepler单例模式,节省资源,防止访问冲突
public static synchronized DBHelper getInstance(Context context){
if(dbHelper == null){
dbHelper = new DBHelper(context);
}
return dbHelper;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(createDBSql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists times");
onCreate(db);
}
//插入数据,使用ContentValues方式传入
public void insertData(String date, int time){
ContentValues contentValues = new ContentValues();
database = getWritableDatabase();
if(findByDate(date)!=0) {
time += findByDate(date);
database.delete(TableName,"tododate=?",new String[]{date});
}
contentValues.put("tododate",date);
contentValues.put("todotime", time);
database.insert(TableName, null, contentValues);
}
public boolean delete(String da) {
database = getReadableDatabase();
database.delete(TableName, "tododate=?", new String[] { da });
return true;
}
int findByDate(String date)
{
database = getReadableDatabase();
String selectSql = "select * from times where tododate ='"+date +"'";
// Toast.makeText(context, selectSql, Toast.LENGTH_SHORT).show();
Cursor cursor = database.rawQuery(selectSql, null);
while (cursor.moveToNext()){
// Toast.makeText(context, "找到了", Toast.LENGTH_SHORT).show();
return cursor.getInt(cursor.getColumnIndex("todotime"));
}
// Toast.makeText(context, "没找到", Toast.LENGTH_SHORT).show();
return 0;
}
//查询最近七天数据
public List<Map<String, Integer>> queryAll(){
List<Map<String,Integer>> list = new ArrayList<Map<String,Integer>>();
//这里需要可读的数据库
database = getReadableDatabase();
Cursor cursor = database.query(TableName, null, null, null, null, null, null, null);
if (cursor.getCount() > 0) {
int j=1;
cursor.moveToLast();
Map<String, Integer> map = new HashMap<String, Integer>();
map.put(cursor.getString(cursor.getColumnIndex("tododate")), cursor.getInt(cursor.getColumnIndex("todotime")));
list.add(map);
while (cursor.moveToPrevious()&&j<7){
map = new HashMap<String, Integer>();
map.put(cursor.getString(cursor.getColumnIndex("tododate")), cursor.getInt(cursor.getColumnIndex("todotime")));
list.add(map);
j++;
}
}
return list;
}
}
3、设置计划并提醒功能
3.1 说明
用户可以自己设定时间计划和提醒时间
3.2 实现
调用DatePickerDialog实现时间选择器,通过监听其选择的时间进行闹钟设置
1.获取系统服务
-
创建PendingIntent
3、 设置闹钟,到时间就唤醒
4、闹钟触发是震动20秒在 AlarmReceiver中实现,并用toast提示事件
3.3 代码
获取系统服务:
public class ClockManager {
private static ClockManager instance = new ClockManager();
private ClockManager() {
}
public static ClockManager getInstance() {
return instance;
}
/**
* 获取系统闹钟服务
*/
private static AlarmManager getAlarmManager() {
return (AlarmManager) MemoApplication.getContext().getSystemService(Context.ALARM_SERVICE);
}
/**
* 取消闹钟
*/
public void cancelAlarm(PendingIntent pendingIntent) {
getAlarmManager().cancel(pendingIntent);
}
/**
* 添加闹钟
*/
public void addAlarm(PendingIntent pendingIntent, Date performTime) {
cancelAlarm(pendingIntent);
getAlarmManager().set(AlarmManager.RTC_WAKEUP, performTime.getTime(), pendingIntent);
}
}
数据库
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
private static String TableName = "clock";
//数据库名
private static String DBName = "clock.db";
//数据库版本号
private static int DBVersion = 1;
private Context context;
//数据库实例
private SQLiteDatabase database;
//此类自己的实例
public static MySQLiteOpenHelper mySQLiteOpenHelper ;
//创建数据库的语句
private String createDBSql =
"create table clock("
+ " id varchar(16) primary key ,"
+ "things varchar(80),"
+ " update_time varchar(16))";
public MySQLiteOpenHelper (Context context){
super(context, DBName, null, DBVersion);
this.context = context;
}
public static synchronized MySQLiteOpenHelper getInstance(Context context){
if(mySQLiteOpenHelper == null){
mySQLiteOpenHelper = new MySQLiteOpenHelper(context);
}
return mySQLiteOpenHelper;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(createDBSql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists clock");
onCreate(db);
}
@SuppressLint("SimpleDateFormat")
public String addClock(String dateTime,String thing) {
database = getWritableDatabase();
ContentValues values = new ContentValues();
String id = dateTime;
values.put("id", id);
values.put("things", thing);
values.put("update_time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
database .insert("clock", null, values);
return id;
}
public boolean deleteClock(String id) {
database = getReadableDatabase();
database.delete("clock", "id=?", new String[] { id});
return true;
}
public boolean updateClock(Integer id,String isRapeat,MySQLiteOpenHelper dbOpenHelper) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
ContentValues values = new ContentValues();
db.update("clock", values,"id=?", new String[] { id.toString() });
return true;
}
public List<MyClock> getClockList(){
database = getReadableDatabase();
Cursor cursor = database.query(TableName, null, null, null, null, null, null, null);
List<MyClock> clockList = new ArrayList<MyClock>();
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
clockList.add(new MyClock(cursor.getString(cursor.getColumnIndex("id")),
cursor.getString(cursor.getColumnIndex("things")),
cursor.getString(cursor.getColumnIndex("update_time"))));
}
}
return clockList;
}
}
显示已定的计划
public class ClockActivity extends Activity {
AlarmManager alarmManager = null;
Calendar calendar = Calendar.getInstance();
private MySQLiteOpenHelper mySQLiteOpenHelper;
private List<Map<String, Object>> listems = new ArrayList<Map<String, Object>>();
private String[]ids,thing;
private MyAdapter myAdapter;
private Button deleteButton;
private Button addButton;
private ListView listView;
private ClockManager mClockManager = ClockManager.getInstance();
private ImageView imageView;
private class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return Ids.length;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewSet viewSet = null;
if (convertView == null) {
viewSet = new ViewSet();
convertView = LayoutInflater.from(getApplication()).inflate(R.layout.my_clock_list, null);
viewSet.clockView = (TextView) convertView.findViewById(R.id.my_clock);
viewSet.thingsView = (TextView) convertView.findViewById(R.id.my_things);
viewSet.checkBox = (CheckBox) convertView.findViewById(R.id.listview_item_checkbox);
convertView.setTag(viewSet);
} else {
viewSet = (ViewSet) convertView.getTag();
}
viewSet.clockView.setText( Ids[position]);
viewSet.thingsView.setText(things[position]);
viewSet.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
checkedArray[position] = true;
checkedNum++;
if (checkedNum == 1) {
button.setEnabled(true);
}
} else {
checkedArray[position] = false;
checkedNum--;
if (checkedNum == 0) {
button.setEnabled(false);
}
}
}
});
return convertView;
}
private class ViewSet{
TextView clockView;
TextView thingsView;
CheckBox checkBox;
}
private String[] things;
private int checkedNum = 0;
private Button button;
private boolean[] checkedArray;
private String[] Ids;
private Context context;
public MyAdapter(Context context,String[] things,String[] Ids, Button button){
this.context=context;
this.button = button;
this.Ids = Ids;
this.things=things;
this.checkedArray = new boolean[ Ids.length];
for(int i=0;i< Ids.length;i++) {
this.checkedArray[i] = false;
}
}
public String[] getChecked(){
List<String> checkedList = new ArrayList<String>();
for(int i=0;i<checkedArray.length;i++){
if(checkedArray[i] == true){
checkedList.add(Ids[i]);
}
}
String[] checkedArray = new String[checkedList.size()];
return checkedList.toArray(checkedArray);
}
}
private void changeAdapter(List<Map<String, Object>>list){
ids = new String[list.size()];
thing=new String[list.size()];
for(int i=0;i<list.size();i++){
ids[i] = list.get(i).get("id").toString();
thing[i]= list.get(i).get("things").toString();
}
myAdapter = new MyAdapter(ClockActivity.this,thing,ids, deleteButton);
listView.setAdapter(myAdapter);
}
public List<Map<String, Object>> getClockList(){
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Map<String, Object> map = null;
List<MyClock> clocks = mySQLiteOpenHelper.getClockList();
for (MyClock myClock : clocks) {
map = new HashMap<String, Object>();
map.put("id",myClock.getId());
map.put("things", myClock.getThings()) ;
list.add(map);
}
return list;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.clock_layout);
mySQLiteOpenHelper = MySQLiteOpenHelper.getInstance(ClockActivity.this);
alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
deleteButton = (Button)findViewById(R.id.delete_button);
addButton=(Button)findViewById(R.id.setclock);
listView = (ListView)findViewById(R.id.clocklist);
imageView=findViewById(R.id.iv_back);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
if(getClockList().size()>0) {
changeAdapter(getClockList());
}
deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String[] result = myAdapter.getChecked();
for(int i=0; i<result.length; i++){
mySQLiteOpenHelper.deleteClock(result[i]);
Intent intent = new Intent(ClockActivity.this,ClockReceiver.class); //创建Intent对象
intent.setAction(result[i]);//作为取消时候的标识
PendingIntent pi = PendingIntent.getBroadcast(ClockActivity.this, 1,
intent, PendingIntent.FLAG_CANCEL_CURRENT); //创建PendingIntent
mClockManager.cancelAlarm(pi);
}
changeAdapter( getClockList());
}
});
addButton. setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(ClockActivity.this, AddActivity.class);
Bundle bundle = new Bundle();
intent.putExtras(bundle);
startActivityForResult(intent, 0);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == Activity.RESULT_OK) {
if(getClockList().size()>0) {
changeAdapter( getClockList());
}
}
}
}
添加计划
public class AddActivity extends Activity {
EditText tvRemindTime;
EditText ed_title;
private MySQLiteOpenHelper mySQLiteOpenHelper;
TextView textView;
private AlarmManager alarmManager=null;
private ClockManager mClockManager = ClockManager.getInstance();
public static final String DEFAULT_TIME_FORMAT = "yyyy-MM-dd HH:mm";
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_clock);
mySQLiteOpenHelper = MySQLiteOpenHelper.getInstance(AddActivity.this);
tvRemindTime = findViewById(R.id.tv_remind_time_picker);
ed_title=findViewById(R.id.ed_title);
textView=findViewById(R.id.tv_confirm);
imageView=findViewById(R.id.iv_back);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
tvRemindTime .setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Calendar calendar = Calendar.getInstance();
DatePickerDialog dialog = new DatePickerDialog(AddActivity.this, new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, final int year, final int month, final int dayOfMonth) {
TimePickerDialog timePickerDialog = new TimePickerDialog(AddActivity.this, new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
String time = year + "-" + StringUtil.getLocalMonth(month) + "-" + StringUtil.getMultiNumber(dayOfMonth) + " " + StringUtil.getMultiNumber(hourOfDay) + ":" + StringUtil.getMultiNumber(minute);
tvRemindTime.setText(time);
}
}, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), false);
timePickerDialog.show();
}
}, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
dialog.getDatePicker().setMinDate(calendar.getTimeInMillis());
dialog.show();
}
});
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Toast.makeText(AddActivity.this, "添加中", Toast.LENGTH_SHORT).show();
String time=tvRemindTime.getText().toString();
String thing=ed_title.getText().toString()+"";
// Toast.makeText(AddActivity.this, time, Toast.LENGTH_SHORT).show();
Intent intent = new Intent(AddActivity.this,ClockReceiver.class); //创建Intent对象
intent.setAction(time);//作为取消时候的标识
Bundle bundle = new Bundle();
bundle.putString("thing", thing);
intent.putExtras(bundle);
PendingIntent pi = PendingIntent.getBroadcast(AddActivity.this, 1,
intent, PendingIntent.FLAG_CANCEL_CURRENT); //创建PendingIntent
mClockManager.addAlarm(pi, str2Date(time));
mySQLiteOpenHelper.addClock(time,thing);
Intent intent2 = getIntent();
setResult(AppCompatActivity.RESULT_OK, intent2);
Toast.makeText(AddActivity.this, "添加成功", Toast.LENGTH_SHORT).show();
finish();
}
});
}
public static Date str2Date(String src) {
SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_TIME_FORMAT, Locale.CHINA);
try {
return sdf.parse(src);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
提醒部分
public class ClockReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
WakeLockUtil.wakeUpAndUnlock();
Bundle bundle = intent.getExtras();
String thing=bundle.getString("thing");
Toast toast = Toast.makeText(context, thing, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER,0,0);
toast.show();
VibrateUtil.vibrate(context, 20000);
}
}
4、更换背景
4.1 说明
更换主页面壁纸
4.2 实现
用SharedPreferences记录图片
4.3 代码
public class BackGround extends Activity implements View.OnClickListener {
private int drawableArray[] = { R.drawable.ic_img4, R.drawable.ic_img6, R.drawable.ic_img11,
R.drawable.ic_img8, R.drawable.ic_img2, R.drawable.ic_img7, R.drawable.ic_img10,
R.drawable.ic_img3, R.drawable.ic_img5 , R.drawable.ic_img12};
List<HashMap<String, Object>> list = new ArrayList<HashMap<String, Object>>();
private Button lastPhoto;
private Button nextPhoto;
private Button selectPhoto;
private ImageButton backButton;
private ImageView displayPhoto;
private ImageView imageView;
//显示当前图片的索引
private int photoIndex = 0;
//图片索引最大值(图片数-1)
private int maxIndex = 9;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_background);
//初始化
imageView=findViewById(R.id.iv_back);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
init();
}
/**
* 控件初始化
*/
private void init() {
lastPhoto = findViewById(R.id.lastPhoto);
lastPhoto.setOnClickListener( BackGround.this);
selectPhoto=findViewById(R.id.select);
selectPhoto.setOnClickListener(BackGround.this);
nextPhoto = findViewById(R.id.nextPhoto);
nextPhoto.setOnClickListener( BackGround.this);
displayPhoto = findViewById(R.id.displayPhoto);
// backButton=findViewById(R.id.back_button);
// backButton.setOnClickListener(BackGround.this);
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.lastPhoto:
//如果当前图片是第一张,则上一张图片为最后一张图片
if (photoIndex == 0) {
photoIndex = maxIndex;
} else {
//否则改为上一张图片索引
photoIndex = photoIndex - 1;
}
break;
case R.id.nextPhoto:
//如果当前图片是最后一张,则下一张图片为第一张图片
if (photoIndex == maxIndex) {
photoIndex = 0;
} else {
//否则改为下一张图片索引
photoIndex = photoIndex + 1;
}
break;
case R.id.select:
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
bundle.putInt("data",drawableArray[photoIndex]);
intent.putExtras(bundle);
setResult(AppCompatActivity.RESULT_OK, intent);
finish();
// case R.id.back_button:
default:
break;
}
//显示图片
displayPhoto.setImageResource(drawableArray[photoIndex]);
}
}
//打开Preferences,名称为data,如果存在则打开它,否则创建新的Preferences
SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
int background = pref.getInt("background",0);
Log.d("study", "background"+background);
linearLayout=findViewById(R.id.bg);
if(background==0)
linearLayout.setBackgroundResource(Features.backGrounds);
else {
linearLayout.setBackgroundResource(background);
Features.backGrounds = background;
}
三、难点
3.1 监控程序
方法:在git上找到一个项目可以监控前台程序,项目提出六种方法,考虑到Android 辅助功能(AccessibilityService) 是是一个稳定的方法,它并非利用 Android 一些设计上的漏洞,可以长期使用的可能很大 ,并且覆盖范围广,选择了这个方法。
3.2 实现关掉其他app的功能
方法:在网上没有相关方法,跟老师交流完知道不可行。后来用模拟“home"键效果直接返回桌面实现类似效果
3.3 关闭程序
方法:一开始发现关闭app后,继承AccessibilityService的DetectService 会自己运行,导致依然无法打开其他app。后来在DetectService里加了个判断当前app是否存活,MainActivity里onDestroy()方法设置为否
//设定全局变量
public class Features {
public static boolean showForeground = false;
public static int backGrounds = R.drawable.ic_img2;
}
//MainActivity里onCreate设置true,onDestroy()方法设置为false
protected void onCreate(Bundle savedInstanceState) {
Features.showForeground = true;
}
protected void onDestroy() {
Features.showForeground = false;
super.onDestroy();
}