feat: 联系人增加头像选择

This commit is contained in:
2026-05-30 04:07:18 +08:00
parent 87903b7216
commit 1c89943459
52 changed files with 1892 additions and 226 deletions

View File

@@ -0,0 +1,72 @@
package com.ttstd.dialer.alarmclock;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.provider.Settings;
import cn.jpush.android.service.AlarmReceiver;
public class AlarmManagerHelper {
public static final int ALARM_REQUEST_CODE = 1001;
/**
* 设置一个精准闹钟(兼容 Android 5.0 到 Android 16
*
* @param context 上下文
* @param triggerAtMillis 触发的时间戳(毫秒)
*/
public static void setExactAlarm(Context context, long triggerAtMillis) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (alarmManager == null) return;
// 检查 Android 12+ 的精准闹钟权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (!alarmManager.canScheduleExactAlarms()) {
// 如果没有权限,跳转到系统设置页让用户授权
Intent intent = new Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
return;
}
}
Intent intent = new Intent(context, AlarmReceiver.class);
// 使用 FLAG_IMMUTABLE 或 FLAG_MUTABLE 增强 Android 12+ 安全性
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ?
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE :
PendingIntent.FLAG_UPDATE_CURRENT;
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, ALARM_REQUEST_CODE, intent, flags);
// 核心兼容性定时逻辑
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android 6.0+ 支持低功耗休眠模式Doze Mode下的精准唤醒
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// Android 4.4 - 5.1 精准唤醒
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
} else {
// Android 4.4 以下
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
}
}
/**
* 取消闹钟
*/
public static void cancelAlarm(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (alarmManager != null) {
Intent intent = new Intent(context, AlarmReceiver.class);
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ?
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE :
PendingIntent.FLAG_UPDATE_CURRENT;
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, ALARM_REQUEST_CODE, intent, flags);
alarmManager.cancel(pendingIntent);
}
}
}

View File

@@ -0,0 +1,34 @@
package com.ttstd.dialer.alarmclock;
import java.util.ArrayList;
import java.util.Calendar;
public class AlarmRepeatConfig {
public static final int REPEAT_ONCE = 0; // 只响一次
public static final int REPEAT_EVERYDAY = 1; // 每天
public static final int REPEAT_WEEKDAYS = 2; // 周一至周五
public static final int REPEAT_CUSTOM = 3; // 自定义星期几(比如只选周六日)
private int repeatType;
private ArrayList<Integer> customDays; // 存储 Calendar.MONDAY (2) 到 Calendar.SATURDAY (7)
public AlarmRepeatConfig(int repeatType) {
this.repeatType = repeatType;
this.customDays = new ArrayList<>();
if (repeatType == REPEAT_WEEKDAYS) {
customDays.add(Calendar.MONDAY);
customDays.add(Calendar.TUESDAY);
customDays.add(Calendar.WEDNESDAY);
customDays.add(Calendar.THURSDAY);
customDays.add(Calendar.FRIDAY);
}
}
public int getRepeatType() {
return repeatType;
}
public ArrayList<Integer> getCustomDays() {
return customDays;
}
}

View File

@@ -0,0 +1,69 @@
package com.ttstd.dialer.alarmclock;
import java.util.ArrayList;
import java.util.Calendar;
public class AlarmTimeCalculator {
/**
* 根据重复配置,计算下一次闹钟应该响铃的绝对时间(毫秒)
*
* @param hour 闹钟设定的小时
* @param minute 闹钟设定的分钟
* @param config 重复配置
* @return 下一次响铃的时间戳
*/
public static long calculateNextAlarmTime(int hour, int minute, AlarmRepeatConfig config) {
Calendar now = Calendar.getInstance();
Calendar target = Calendar.getInstance();
target.set(Calendar.HOUR_OF_DAY, hour);
target.set(Calendar.MINUTE, minute);
target.set(Calendar.SECOND, 0);
target.set(Calendar.MILLISECOND, 0);
// 情况 1只响一次
if (config.getRepeatType() == AlarmRepeatConfig.REPEAT_ONCE) {
// 如果设定的时间在今天已经过去了,就定在明天
if (target.getTimeInMillis() <= now.getTimeInMillis()) {
target.add(Calendar.DAY_OF_MONTH, 1);
}
return target.getTimeInMillis();
}
// 情况 2每天
if (config.getRepeatType() == AlarmRepeatConfig.REPEAT_EVERYDAY) {
if (target.getTimeInMillis() <= now.getTimeInMillis()) {
target.add(Calendar.DAY_OF_MONTH, 1);
}
return target.getTimeInMillis();
}
// 情况 3 & 4周一至周五 或 自定义星期
if (config.getRepeatType() == AlarmRepeatConfig.REPEAT_WEEKDAYS ||
config.getRepeatType() == AlarmRepeatConfig.REPEAT_CUSTOM) {
ArrayList<Integer> targetDays = config.getCustomDays();
// 从今天开始往后最多循环7天找到最近的符合星期要求的日子
for (int i = 0; i < 7; i++) {
int currentDayOfWeek = target.get(Calendar.DAY_OF_WEEK);
// 如果 target 的日子在今天或今天之后,且其星期在用户选中的列表中
if (targetDays.contains(currentDayOfWeek)) {
// 如果刚好是今天,但时间已经过去了,则不能算今天,继续往后找
if (i == 0 && target.getTimeInMillis() <= now.getTimeInMillis()) {
target.add(Calendar.DAY_OF_MONTH, 1);
continue;
}
// 找到了最近的匹配日期
return target.getTimeInMillis();
}
// 否则,日期加一天,继续匹配
target.add(Calendar.DAY_OF_MONTH, 1);
}
}
return target.getTimeInMillis();
}
}