|
|
|
@ -1,12 +1,17 @@ |
|
|
|
package com.yunqiinnovation.chat_api |
|
|
|
|
|
|
|
import android.Manifest |
|
|
|
import android.content.ContentUris |
|
|
|
import android.content.ContentValues |
|
|
|
import android.content.Context |
|
|
|
import android.content.Intent |
|
|
|
import android.content.pm.PackageManager |
|
|
|
import android.location.LocationManager |
|
|
|
import android.net.Uri |
|
|
|
import android.os.Build |
|
|
|
import android.provider.AlarmClock |
|
|
|
import android.provider.CalendarContract |
|
|
|
import android.provider.ContactsContract |
|
|
|
import android.telephony.SmsManager |
|
|
|
import android.util.Log |
|
|
|
import androidx.core.content.ContextCompat |
|
|
|
@ -295,28 +300,108 @@ private class SendTextMessageHandler(private val context: Context?) : FunctionHa |
|
|
|
* 拨打电话处理器 |
|
|
|
*/ |
|
|
|
private class MakePhoneCallHandler(private val context: Context?) : FunctionHandler { |
|
|
|
|
|
|
|
/** |
|
|
|
* 根据联系人名称获取电话号码 |
|
|
|
* @param contact 联系人名称或电话号码 |
|
|
|
* @return 电话号码 |
|
|
|
*/ |
|
|
|
private fun getPhoneNumberForContact(contact: String): String { |
|
|
|
// 如果输入的是电话号码(简单判断,包含数字和特殊符号) |
|
|
|
if (contact.matches(Regex("^[+\\d\\s\\-()]*\$")) && contact.any { it.isDigit() }) { |
|
|
|
// 移除非数字字符 |
|
|
|
return contact.replace(Regex("[^+\\d]"), "") |
|
|
|
} |
|
|
|
|
|
|
|
// 检查读取联系人权限 |
|
|
|
if (!checkPermissionAndGuide(context!!, Manifest.permission.READ_CONTACTS, "读取联系人", "访问联系人")) { |
|
|
|
return "" |
|
|
|
} |
|
|
|
|
|
|
|
// 从联系人数据库查询 |
|
|
|
try { |
|
|
|
val contentResolver = context.contentResolver |
|
|
|
val uri = Uri.withAppendedPath( |
|
|
|
ContactsContract.Contacts.CONTENT_FILTER_URI, |
|
|
|
Uri.encode(contact) |
|
|
|
) |
|
|
|
|
|
|
|
val projection = arrayOf( |
|
|
|
ContactsContract.Contacts._ID, |
|
|
|
ContactsContract.Contacts.DISPLAY_NAME, |
|
|
|
ContactsContract.Contacts.HAS_PHONE_NUMBER |
|
|
|
) |
|
|
|
|
|
|
|
contentResolver.query(uri, projection, null, null, null)?.use { cursor -> |
|
|
|
if (cursor.moveToFirst()) { |
|
|
|
val hasPhoneNumber = cursor.getInt(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.HAS_PHONE_NUMBER)) |
|
|
|
|
|
|
|
if (hasPhoneNumber > 0) { |
|
|
|
val contactId = cursor.getString(cursor.getColumnIndexOrThrow( |
|
|
|
ContactsContract.Contacts._ID)) |
|
|
|
val phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI |
|
|
|
val phoneProjection = arrayOf(ContactsContract.CommonDataKinds.Phone.NUMBER) |
|
|
|
val phoneSelection = "${ContactsContract.CommonDataKinds.Phone.CONTACT_ID} = ?" |
|
|
|
val phoneSelectionArgs = arrayOf(contactId) |
|
|
|
|
|
|
|
contentResolver?.query(phoneUri, phoneProjection, phoneSelection, phoneSelectionArgs, null)?.use { phoneCursor -> |
|
|
|
if (phoneCursor.moveToFirst()) { |
|
|
|
return phoneCursor.getString(phoneCursor.getColumnIndexOrThrow( |
|
|
|
ContactsContract.CommonDataKinds.Phone.NUMBER)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e("ChatApi", "查询联系人信息失败: ${e.message}", e) |
|
|
|
} |
|
|
|
|
|
|
|
return "" |
|
|
|
} |
|
|
|
|
|
|
|
override suspend fun handle(arguments: Map<String, Any>): String { |
|
|
|
val contact = arguments["contact"] as? String |
|
|
|
|
|
|
|
if (contact == null) { |
|
|
|
return "{\"result\": \"缺少联系人参数\"}" |
|
|
|
} |
|
|
|
|
|
|
|
return try { |
|
|
|
val callIntent = Intent(Intent.ACTION_DIAL).apply { |
|
|
|
data = Uri.parse("tel:$contact") |
|
|
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK |
|
|
|
// 检查拨打电话权限 |
|
|
|
if (!checkPermissionAndGuide(context!!,Manifest.permission.CALL_PHONE, "拨打电话", "拨打电话")) { |
|
|
|
"{\"result\": \"需要电话权限才能拨打电话,请在权限管理中开启电话权限\"}" |
|
|
|
} |
|
|
|
|
|
|
|
if (context?.packageManager?.queryIntentActivities(callIntent, 0)?.isNotEmpty() == true) { |
|
|
|
context.startActivity(callIntent) |
|
|
|
"{\"result\": \"已发起电话呼叫\"}" |
|
|
|
} else { |
|
|
|
"{\"result\": \"无法拨打电话\"}" |
|
|
|
val phoneNumber = getPhoneNumberForContact(contact) |
|
|
|
if (phoneNumber.isEmpty()) { |
|
|
|
"{\"result\": \"未找到联系人信息: $contact\"}" |
|
|
|
} |
|
|
|
|
|
|
|
// 创建拨号意图 |
|
|
|
val intent = Intent(Intent.ACTION_CALL) |
|
|
|
intent.data = Uri.parse("tel:$phoneNumber") |
|
|
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK |
|
|
|
context?.startActivity(intent) |
|
|
|
"{\"result\": \"正在拨打${contact}的电话\"}" |
|
|
|
} catch (e: Exception) { |
|
|
|
"{\"result\": \"拨打电话失败:${e.message}\"}" |
|
|
|
Log.e("ChatApi", "拨打电话失败: ${e.message}", e) |
|
|
|
"{\"result\": \"权限不足或者为查询到联系人\"}" |
|
|
|
} |
|
|
|
// return try { |
|
|
|
// val callIntent = Intent(Intent.ACTION_DIAL).apply { |
|
|
|
// data = Uri.parse("tel:$contact") |
|
|
|
// flags = Intent.FLAG_ACTIVITY_NEW_TASK |
|
|
|
// } |
|
|
|
// |
|
|
|
// if (context?.packageManager?.queryIntentActivities(callIntent, 0)?.isNotEmpty() == true) { |
|
|
|
// context.startActivity(callIntent) |
|
|
|
// "{\"result\": \"已发起电话呼叫\"}" |
|
|
|
// } else { |
|
|
|
// "{\"result\": \"无法拨打电话\"}" |
|
|
|
// } |
|
|
|
// } catch (e: Exception) { |
|
|
|
// "{\"result\": \"拨打电话失败:${e.message}\"}" |
|
|
|
// } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -324,44 +409,178 @@ private class MakePhoneCallHandler(private val context: Context?) : FunctionHand |
|
|
|
* 设置提醒处理器 |
|
|
|
*/ |
|
|
|
private class SetReminderHandler(private val context: Context?) : FunctionHandler { |
|
|
|
override suspend fun handle(arguments: Map<String, Any>): String { |
|
|
|
val title = arguments["title"] as? String |
|
|
|
val content = arguments["content"] as? String ?: "" |
|
|
|
val timeString = arguments["time"] as? String |
|
|
|
|
|
|
|
if (title == null || timeString == null) { |
|
|
|
return "{\"result\": \"缺少必要参数\"}" |
|
|
|
/** |
|
|
|
* 获取默认日历ID |
|
|
|
*/ |
|
|
|
private fun getDefaultCalendarId(): Long { |
|
|
|
val projection = arrayOf(CalendarContract.Calendars._ID) |
|
|
|
var calendarId = -1L |
|
|
|
|
|
|
|
try { |
|
|
|
val uri = CalendarContract.Calendars.CONTENT_URI |
|
|
|
val selection = "(${CalendarContract.Calendars.VISIBLE} = 1) AND (${CalendarContract.Calendars.IS_PRIMARY} = 1)" |
|
|
|
context?.contentResolver?.query(uri, projection, selection, null, null)?.use { cursor -> |
|
|
|
if (cursor.moveToFirst()) { |
|
|
|
calendarId = cursor.getLong(0) |
|
|
|
} else { |
|
|
|
// 如果没有找到主日历,尝试找任何可见的日历 |
|
|
|
context.contentResolver.query(uri, projection, "${CalendarContract.Calendars.VISIBLE} = 1", null, null)?.use { c -> |
|
|
|
if (c.moveToFirst()) { |
|
|
|
calendarId = c.getLong(0) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e("CahtApi", "获取默认日历ID失败: ${e.message}", e) |
|
|
|
} |
|
|
|
|
|
|
|
return try { |
|
|
|
// 解析时间 |
|
|
|
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()) |
|
|
|
val date = formatter.parse(timeString) |
|
|
|
return calendarId |
|
|
|
} |
|
|
|
|
|
|
|
if (date == null) { |
|
|
|
return "{\"result\": \"时间格式错误\"}" |
|
|
|
/** |
|
|
|
* 尝试创建闹钟提醒(备选方案) |
|
|
|
*/ |
|
|
|
private fun tryCreateAlarm(title: String, content: String, timeStr: String): String { |
|
|
|
try { |
|
|
|
// 解析小时和分钟 |
|
|
|
val timeParts = timeStr.split(" ")[1].split(":") |
|
|
|
val hour = timeParts[0].toInt() |
|
|
|
val minute = timeParts[1].toInt() |
|
|
|
|
|
|
|
val alarmIntent = Intent(AlarmClock.ACTION_SET_ALARM) |
|
|
|
alarmIntent.putExtra(AlarmClock.EXTRA_MESSAGE, "$title: $content") |
|
|
|
alarmIntent.putExtra(AlarmClock.EXTRA_HOUR, hour) |
|
|
|
alarmIntent.putExtra(AlarmClock.EXTRA_MINUTES, minute) |
|
|
|
alarmIntent.putExtra(AlarmClock.EXTRA_SKIP_UI, true) // 尝试跳过UI |
|
|
|
alarmIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK |
|
|
|
|
|
|
|
if (alarmIntent.resolveActivity(context!!.packageManager) != null) { |
|
|
|
context.startActivity(alarmIntent) |
|
|
|
return "{\"result\": \"已创建闹钟提醒: $title, 时间: $timeStr\"}" |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e("CahtApi", "创建闹钟失败: ${e.message}", e) |
|
|
|
} |
|
|
|
return "{\"result\": \"未找到可用的日历或闹钟应用\"}" |
|
|
|
} |
|
|
|
|
|
|
|
// 创建日历事件 |
|
|
|
val calendarIntent = Intent(Intent.ACTION_INSERT).apply { |
|
|
|
data = CalendarContract.Events.CONTENT_URI |
|
|
|
putExtra(CalendarContract.Events.TITLE, title) |
|
|
|
putExtra(CalendarContract.Events.DESCRIPTION, content) |
|
|
|
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, date.time) |
|
|
|
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, date.time + 60 * 60 * 1000) // 默认1小时 |
|
|
|
putExtra(CalendarContract.Events.HAS_ALARM, 1) |
|
|
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK |
|
|
|
/** |
|
|
|
* 设置提醒 |
|
|
|
* @param title 提醒标题 |
|
|
|
* @param content 提醒内容(可选) |
|
|
|
* @param timeStr 提醒时间,格式为"yyyy-MM-dd HH:mm" |
|
|
|
* @return 操作结果 |
|
|
|
*/ |
|
|
|
fun setReminder(title: String, content: String, timeStr: String): String { |
|
|
|
Log.d("CahtApi", "设置提醒: $title, 时间: $timeStr") |
|
|
|
|
|
|
|
try { |
|
|
|
// 解析时间字符串 |
|
|
|
val time:Long = try { |
|
|
|
val dateFormat = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm", java.util.Locale.getDefault()) |
|
|
|
dateFormat.parse(timeStr)?.time ?: System.currentTimeMillis() |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e("CahtApi", "解析时间失败: $timeStr, ${e.message}") |
|
|
|
return "{\"result\": \"提醒时间格式无效,请使用'yyyy-MM-dd HH:mm'格式\"}" |
|
|
|
} |
|
|
|
|
|
|
|
// 检查日历权限 |
|
|
|
if (!checkPermissionAndGuide(context!!,Manifest.permission.WRITE_CALENDAR, "日历写入", "设置提醒")) { |
|
|
|
return "{\"result\": \"需要日历权限才能创建提醒,请在权限管理中开启日历权限\"}" |
|
|
|
} |
|
|
|
|
|
|
|
// 直接使用ContentProvider写入日历 |
|
|
|
val endTime = time + 3600000 // 默认1小时后结束 |
|
|
|
|
|
|
|
// 获取默认日历ID |
|
|
|
val calendarId = getDefaultCalendarId() |
|
|
|
if (calendarId == -1L) { |
|
|
|
Log.w("CahtApi", "未找到默认日历") |
|
|
|
return tryCreateAlarm(title, content, timeStr) |
|
|
|
} |
|
|
|
|
|
|
|
// 创建事件 |
|
|
|
val eventValues = ContentValues().apply { |
|
|
|
put(CalendarContract.Events.CALENDAR_ID, calendarId) |
|
|
|
put(CalendarContract.Events.TITLE, title) |
|
|
|
put(CalendarContract.Events.DESCRIPTION, content) |
|
|
|
put(CalendarContract.Events.DTSTART, time) |
|
|
|
put(CalendarContract.Events.DTEND, endTime) |
|
|
|
put(CalendarContract.Events.HAS_ALARM, 1) |
|
|
|
put(CalendarContract.Events.EVENT_TIMEZONE, java.util.TimeZone.getDefault().id) |
|
|
|
} |
|
|
|
|
|
|
|
val eventUri = context.contentResolver.insert(CalendarContract.Events.CONTENT_URI, eventValues) |
|
|
|
if (eventUri == null) { |
|
|
|
Log.e("CahtApi", "插入日历事件失败") |
|
|
|
return tryCreateAlarm(title, content, timeStr) |
|
|
|
} |
|
|
|
|
|
|
|
if (context?.packageManager?.queryIntentActivities(calendarIntent, 0)?.isNotEmpty() == true) { |
|
|
|
context.startActivity(calendarIntent) |
|
|
|
"{\"result\": \"提醒设置成功\"}" |
|
|
|
// 获取事件ID |
|
|
|
val eventId = ContentUris.parseId(eventUri) |
|
|
|
|
|
|
|
// 添加提醒(15分钟前提醒) |
|
|
|
val reminderValues = ContentValues().apply { |
|
|
|
put(CalendarContract.Reminders.EVENT_ID, eventId) |
|
|
|
put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT) |
|
|
|
put(CalendarContract.Reminders.MINUTES, 15) // 提前15分钟提醒 |
|
|
|
} |
|
|
|
|
|
|
|
val reminderUri = context.contentResolver.insert(CalendarContract.Reminders.CONTENT_URI, reminderValues) |
|
|
|
if (reminderUri != null) { |
|
|
|
return "{\"result\": \"已成功创建提醒: $title, 时间: $timeStr\"}" |
|
|
|
} else { |
|
|
|
"{\"result\": \"无法打开日历应用\"}" |
|
|
|
// 仍然创建了事件,但没有提醒 |
|
|
|
return "{\"result\": \"已创建日历事件,但未设置提醒: $title\"}" |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
"{\"result\": \"设置提醒失败:${e.message}\"}" |
|
|
|
Log.e("CahtApi", "设置提醒失败: ${e.message}", e) |
|
|
|
return "{\"result\": \"设置提醒失败: ${e.message}\"}" |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override suspend fun handle(arguments: Map<String, Any>): String { |
|
|
|
val title = arguments["title"] as? String |
|
|
|
val content = arguments["content"] as? String ?: "" |
|
|
|
val timeString = arguments["time"] as? String |
|
|
|
|
|
|
|
if (title == null || timeString == null) { |
|
|
|
return "{\"result\": \"缺少必要参数\"}" |
|
|
|
} |
|
|
|
return setReminder(title,content,timeString) |
|
|
|
// return try { |
|
|
|
// // 解析时间 |
|
|
|
// val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()) |
|
|
|
// val date = formatter.parse(timeString) |
|
|
|
// |
|
|
|
// if (date == null) { |
|
|
|
// return "{\"result\": \"时间格式错误\"}" |
|
|
|
// } |
|
|
|
// |
|
|
|
// // 创建日历事件 |
|
|
|
// val calendarIntent = Intent(Intent.ACTION_INSERT).apply { |
|
|
|
// data = CalendarContract.Events.CONTENT_URI |
|
|
|
// putExtra(CalendarContract.Events.TITLE, title) |
|
|
|
// putExtra(CalendarContract.Events.DESCRIPTION, content) |
|
|
|
// putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, date.time) |
|
|
|
// putExtra(CalendarContract.EXTRA_EVENT_END_TIME, date.time + 60 * 60 * 1000) // 默认1小时 |
|
|
|
// putExtra(CalendarContract.Events.HAS_ALARM, 1) |
|
|
|
// flags = Intent.FLAG_ACTIVITY_NEW_TASK |
|
|
|
// } |
|
|
|
// |
|
|
|
// if (context?.packageManager?.queryIntentActivities(calendarIntent, 0)?.isNotEmpty() == true) { |
|
|
|
// context.startActivity(calendarIntent) |
|
|
|
// "{\"result\": \"提醒设置成功\"}" |
|
|
|
// } else { |
|
|
|
// "{\"result\": \"无法打开日历应用\"}" |
|
|
|
// } |
|
|
|
// } catch (e: Exception) { |
|
|
|
// "{\"result\": \"设置提醒失败:${e.message}\"}" |
|
|
|
// } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|