Browse Source

add

newdev_shunjiawei
wolfplus 1 year ago
parent
commit
5eb0de4a51
  1. 78
      lib/modules/settings/controllers/settings_controller.dart
  2. 324
      lib/modules/settings/views/permissions_view.dart
  3. 92
      lib/modules/settings/views/settings_view.dart
  4. 8
      lib/routes/app_pages.dart
  5. 1
      lib/routes/app_routes.dart
  6. 2
      local_plugins/ble_service/ios/Classes/BleServicePlugin.h
  7. 2
      local_plugins/ble_service/pubspec.yaml
  8. 2
      local_plugins/open_ai_service/android/src/main/AndroidManifest.xml
  9. 421
      local_plugins/open_ai_service/android/src/main/kotlin/com/yunqiinnovation/open_ai_service/SystemFunctionHandler.kt

78
lib/modules/settings/controllers/settings_controller.dart

@ -12,6 +12,9 @@ import '../../../data/models/user_Info.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:async';
import 'package:app_settings/app_settings.dart';
class SettingsController extends GetxController {
// 语言设置
@ -101,6 +104,81 @@ class SettingsController extends GetxController {
final appVersion = ''.obs;
final buildNumber = ''.obs;
// 权限相关
// 权限组,用于在UI中显示
final List<Map<String, dynamic>> permissionGroups = [
{
'name': '通讯权限',
'icon': Icons.phone_android,
'permissions': [
{'type': Permission.phone, 'name': '电话', 'description': '用于拨打电话功能'},
{'type': Permission.sms, 'name': '短信', 'description': '用于发送短信功能'},
{'type': Permission.contacts, 'name': '通讯录', 'description': '用于访问联系人'}
]
},
{
'name': '日程权限',
'icon': Icons.calendar_today,
'permissions': [
{'type': Permission.calendarWriteOnly, 'name': '日历写入', 'description': '用于创建日历事件和提醒'},
{'type': Permission.calendarFullAccess, 'name': '日历完全访问', 'description': '用于读取和修改日历事件'}
]
},
{
'name': '存储权限',
'icon': Icons.storage,
'permissions': [
{'type': Permission.storage, 'name': '存储', 'description': '用于保存录音和文件'},
{'type': Permission.photos, 'name': '照片', 'description': '用于选择和保存照片'}
]
},
{
'name': '位置权限',
'icon': Icons.location_on,
'permissions': [
{'type': Permission.location, 'name': '位置', 'description': '用于获取当前位置信息'},
{'type': Permission.locationAlways, 'name': '后台位置', 'description': '用于后台获取位置信息'}
]
},
{
'name': '媒体权限',
'icon': Icons.mic,
'permissions': [
{'type': Permission.microphone, 'name': '麦克风', 'description': '用于语音识别和录音'},
{'type': Permission.bluetooth, 'name': '蓝牙', 'description': '用于连接蓝牙设备'}
]
}
];
// 检查单个权限状态
Future<PermissionStatus> checkPermission(Permission permission) async {
return await permission.status;
}
// 请求单个权限
Future<PermissionStatus> requestPermission(Permission permission) async {
return await permission.request();
}
// 打开应用设置
void openSettings() {
openAppSettings();
}
// 检查所有权限状态并返回结果
Future<Map<Permission, PermissionStatus>> checkAllPermissions() async {
Map<Permission, PermissionStatus> statuses = {};
for (var group in permissionGroups) {
for (var perm in group['permissions']) {
Permission permission = perm['type'];
statuses[permission] = await permission.status;
}
}
return statuses;
}
@override
void onInit() {
super.onInit();

324
lib/modules/settings/views/permissions_view.dart

@ -0,0 +1,324 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import '../controllers/settings_controller.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'dart:ui';
class PermissionsView extends GetView<SettingsController> {
const PermissionsView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold(
backgroundColor: isDarkMode ? Colors.black : Colors.grey[50],
appBar: AppBar(
backgroundColor: isDarkMode ? Colors.black : Colors.white,
elevation: 0.5,
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 20.w,
color: isDarkMode ? Colors.white : Colors.black87,
),
onPressed: () => Get.back(),
),
title: Text(
'权限管理'.tr,
style: TextStyle(
fontSize: 17.sp,
fontWeight: FontWeight.w600,
color: isDarkMode ? Colors.white : Colors.black,
),
),
centerTitle: true,
),
body: FutureBuilder<Map<Permission, PermissionStatus>>(
future: controller.checkAllPermissions(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('获取权限状态失败: ${snapshot.error}'.tr));
}
final permissionStatuses = snapshot.data ?? {};
return ListView(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
children: [
// 通讯权限组
_buildPermissionSection('通讯权限', Icons.phone_android, [
Permission.phone,
Permission.sms
], permissionStatuses, isDarkMode),
SizedBox(height: 20.h),
// 日历权限组
_buildPermissionSection('日历权限', Icons.calendar_today, [
Permission.calendarFullAccess
], permissionStatuses, isDarkMode),
SizedBox(height: 20.h),
// 位置权限组
_buildPermissionSection('位置权限', Icons.location_on, [
Permission.location
], permissionStatuses, isDarkMode),
],
);
},
),
);
}
// 构建权限组区域
Widget _buildPermissionSection(String title, IconData icon, List<Permission> permissions,
Map<Permission, PermissionStatus> statuses, bool isDarkMode) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 组标题
Padding(
padding: EdgeInsets.only(left: 4.w, bottom: 8.h),
child: Text(
title.tr,
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.blue[400] : Colors.blue[600],
letterSpacing: 1,
),
),
),
// 权限项容器
Container(
decoration: BoxDecoration(
color: isDarkMode ? Colors.white.withOpacity(0.05) : Colors.white,
borderRadius: BorderRadius.circular(16.r),
boxShadow: [
BoxShadow(
color: isDarkMode
? Colors.black.withOpacity(0.2)
: Colors.black.withOpacity(0.05),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(16.r),
child: BackdropFilter(
filter: isDarkMode
? ImageFilter.blur(sigmaX: 5, sigmaY: 5)
: ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: Column(
children: _buildPermissionItems(permissions, statuses, isDarkMode),
),
),
),
),
],
);
}
// 构建权限项列表
List<Widget> _buildPermissionItems(List<Permission> permissions,
Map<Permission, PermissionStatus> statuses, bool isDarkMode) {
final List<Widget> items = [];
// 获取描述文本
String getDescription(Permission permission) {
switch (permission) {
case Permission.phone:
return '用于拨打电话功能';
case Permission.sms:
return '用于发送短信功能';
case Permission.calendarWriteOnly:
return '用于创建日历事件和提醒';
case Permission.calendarFullAccess:
return '用于读取和管理日历事件及提醒';
case Permission.location:
return '用于获取当前位置信息';
default:
return '应用功能需要';
}
}
// 获取名称
String getName(Permission permission) {
switch (permission) {
case Permission.phone:
return '电话';
case Permission.sms:
return '短信';
case Permission.calendarWriteOnly:
return '日历写入';
case Permission.calendarFullAccess:
return '日历完整访问';
case Permission.location:
return '位置信息';
default:
return permission.toString();
}
}
for (int i = 0; i < permissions.length; i++) {
final permission = permissions[i];
final status = statuses[permission] ?? PermissionStatus.denied;
items.add(
_buildPermissionItem(
name: getName(permission),
description: getDescription(permission),
status: status,
permission: permission,
isDarkMode: isDarkMode,
),
);
// 添加分隔线,最后一个不加
if (i < permissions.length - 1) {
items.add(Divider(
height: 1,
color: isDarkMode ? Colors.white.withOpacity(0.1) : Colors.grey[200],
));
}
}
return items;
}
// 构建单个权限项
Widget _buildPermissionItem({
required String name,
required String description,
required PermissionStatus status,
required Permission permission,
required bool isDarkMode,
}) {
return Padding(
padding: EdgeInsets.all(16.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name.tr,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
),
),
SizedBox(height: 4.h),
Text(
description.tr,
style: TextStyle(
fontSize: 12.sp,
color: isDarkMode ? Colors.white70 : Colors.grey[600],
),
),
SizedBox(height: 4.h),
_buildStatusText(status, isDarkMode),
],
),
),
Switch(
value: status.isGranted,
onChanged: (value) {
if (value) {
_handlePermissionAction(permission, status);
} else if (status.isGranted) {
controller.openSettings();
}
},
activeColor: Colors.blue[600],
),
],
),
);
}
// 状态文本
Widget _buildStatusText(PermissionStatus status, bool isDarkMode) {
String text;
Color color;
if (status.isGranted) {
text = '已授权'.tr;
color = Colors.green;
} else if (status.isDenied) {
text = '未授权'.tr;
color = Colors.red;
} else if (status.isPermanentlyDenied) {
text = '需要在系统设置中开启'.tr;
color = Colors.grey;
} else if (status.isLimited) {
text = '部分授权'.tr;
color = Colors.orange;
} else {
text = '未知状态'.tr;
color = Colors.grey;
}
return Text(
text,
style: TextStyle(
color: color,
fontSize: 12.sp,
fontWeight: FontWeight.w500,
),
);
}
// 处理权限请求
Future<void> _handlePermissionAction(Permission permission, PermissionStatus status) async {
if (status.isPermanentlyDenied) {
// 打开应用设置
controller.openSettings();
return;
}
if (!status.isGranted) {
// 请求权限
final result = await controller.requestPermission(permission);
if (result.isGranted) {
Get.snackbar('成功'.tr, '权限已授予'.tr, snackPosition: SnackPosition.BOTTOM);
} else if (result.isPermanentlyDenied) {
Get.dialog(
AlertDialog(
title: Text('需要权限'.tr),
content: Text('此权限需要在设置中手动开启'.tr),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text('取消'.tr),
),
TextButton(
onPressed: () {
Get.back();
controller.openSettings();
},
child: Text('去设置'.tr),
),
],
),
);
}
// 刷新界面
Get.forceAppUpdate();
}
}
}

92
lib/modules/settings/views/settings_view.dart

@ -355,7 +355,7 @@ class SettingsView extends GetView<SettingsController> {
Padding(
padding: EdgeInsets.only(left: 4.w, bottom: 8.h),
child: Text(
'systemSetting'.tr, // 系统设置
'systemSettings'.tr, // 系统设置
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w500,
@ -586,6 +586,22 @@ class SettingsView extends GetView<SettingsController> {
// ? Colors.white.withOpacity(0.1)
// : Colors.grey[200]),
// 添加权限管理设置项
_buildSettingItem(
icon: Icons.security,
iconColor: Colors.orange,
title: '权限管理'.tr,
isDarkMode: isDarkMode,
onTap: () {
Get.toNamed(Routes.permissions);
},
),
Divider(
height: 1,
color: isDarkMode
? Colors.white.withOpacity(0.1)
: Colors.grey[200]),
// 退出登录
// _buildSimpleNavigationSetting(
// title: 'logout'.tr, // 退出登录
@ -1518,4 +1534,78 @@ class SettingsView extends GetView<SettingsController> {
),
);
}
// 添加权限管理设置项
Widget _buildSettingItem({
required IconData icon,
required Color iconColor,
required String title,
required bool isDarkMode,
required VoidCallback onTap,
}) {
return InkWell(
onTap: onTap,
child: Padding(
padding: EdgeInsets.all(16.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
children: [
Container(
width: 32.w,
height: 32.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r),
),
child: Icon(
icon,
size: 16.w,
color: iconColor,
),
),
SizedBox(width: 12.w),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w500,
color: isDarkMode ? Colors.white : Colors.black87,
),
overflow: TextOverflow.ellipsis,
),
],
),
),
],
),
),
Container(
width: 32.w,
height: 32.w,
decoration: BoxDecoration(
color: isDarkMode
? Colors.white.withOpacity(0.05)
: Colors.grey[100],
borderRadius: BorderRadius.circular(16.r),
),
child: Icon(
Icons.chevron_right,
size: 16.w,
color: isDarkMode ? Colors.white70 : Colors.grey[500],
),
),
],
),
),
);
}
}

8
lib/routes/app_pages.dart

@ -28,6 +28,7 @@ import '../modules/pairing/views/pairing_view.dart';
import '../modules/pairing/bindings/pairing_binding.dart';
import './app_routes.dart';
import '../modules/settings/views/settings_view.dart';
import '../modules/settings/views/permissions_view.dart';
import '../modules/settings/bindings/settings_binding.dart';
import '../modules/opus_test/views/opus_test_view.dart';
import '../modules/opus_test/bindings/opus_test_binding.dart';
@ -181,5 +182,12 @@ abstract class AppPages {
transition: Transition.rightToLeft,
transitionDuration: Duration(milliseconds: 250),
),
GetPage(
name: Routes.permissions,
page: () => const PermissionsView(),
binding: SettingsBinding(),
transition: Transition.rightToLeft,
transitionDuration: Duration(milliseconds: 250),
),
];
}

1
lib/routes/app_routes.dart

@ -16,6 +16,7 @@ abstract class Routes {
static const OTA_UPGRADE = '/ota_upgrade'; // OTA升级
static const timbre = '/timbre'; // 音色设置
static const settings = '/settings'; // 系统设置
static const permissions = '/permissions'; // 权限管理
static const recording = '/recording'; // 录音功能
// 会议相关

2
local_plugins/ble_service/ios/Classes/BleServicePlugin.h

@ -1,4 +1,4 @@
#import <Flutter/Flutter.h>
@interface BleServicePlugin : NSObject<FlutterPlugin>
@end

2
local_plugins/ble_service/pubspec.yaml

@ -21,6 +21,6 @@ flutter:
platforms:
android:
package: com.yunqiinnovation.ble_service
pluginClass: BleServicePlugin
pluginClass: BleServicePlugin
ios:
pluginClass: BleServicePlugin

2
local_plugins/open_ai_service/android/src/main/AndroidManifest.xml

@ -4,6 +4,8 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<application>
<!-- 插件不需要额外的组件声明 -->

421
local_plugins/open_ai_service/android/src/main/kotlin/com/yunqiinnovation/open_ai_service/SystemFunctionHandler.kt

@ -11,6 +11,7 @@ import android.os.Bundle
import android.provider.ContactsContract
import android.provider.AlarmClock
import android.provider.CalendarContract
import android.provider.MediaStore
import android.provider.Settings
import android.telephony.SmsManager
import android.util.Log
@ -22,6 +23,13 @@ import android.os.Handler
import android.os.Looper
import kotlinx.coroutines.withContext
import kotlinx.coroutines.Dispatchers
import android.Manifest
import android.content.ContentValues
import android.content.ContentUris
import androidx.core.content.ContextCompat
import android.app.ActivityManager
import android.app.Application
import android.os.Process
/**
* 系统功能处理器 - 负责调用系统API执行各种功能以及注册系统功能
*/
@ -67,6 +75,9 @@ class SystemFunctionHandler(private val context: Context) {
registerMediaPreviousFunction(client)
registerMediaNextFunction(client)
// 注册打开录音机功能
registerOpenRecorderFunction(client)
Log.d(TAG, "所有系统功能注册完成")
} catch (e: Exception) {
Log.e(TAG, "注册系统功能失败: ${e.message}", e)
@ -409,6 +420,30 @@ class SystemFunctionHandler(private val context: Context) {
Log.d(TAG, "已注册媒体下一首功能")
}
/**
* 注册打开录音机功能
*/
private fun registerOpenRecorderFunction(client: MCPClient) {
client.registerLocalFunction(
"open_recorder",
"打开系统录音机并开始录音",
JSONObject("""
{
"type": "object",
"properties": {},
"required": []
}
"""),
object : FunctionHandler {
override suspend fun handle(arguments: Map<String, Any>): String {
val result = openRecorder()
return "{\"result\": \"${result.message}\"}"
}
}
)
Log.d(TAG, "已注册打开录音机功能")
}
/**
* 控制媒体播放
* @param action 操作类型:"play", "pause", "previous", "next"
@ -555,6 +590,93 @@ class SystemFunctionHandler(private val context: Context) {
)
}
/**
* 检查权限并根据应用状态采取不同行为
* @param permission 需要检查的权限
* @param permissionName 权限名称(用于显示给用户)
* @param functionName 功能名称(用于日志和提示)
* @return 是否拥有权限
*/
private fun checkPermissionAndGuide(permission: String, permissionName: String, functionName: String): Boolean {
if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "缺少${permissionName}权限,无法执行${functionName}")
// 检查应用是否在前台
if (isAppInForeground()) {
// 应用在前台,尝试直接弹出权限申请框
try {
// 首先尝试发送广播通知DeepSound应用弹出权限申请对话框
val intent = Intent("com.yunqiinnovation.deepsound.action.REQUEST_PERMISSION").apply {
setPackage(context.packageName)
putExtra("permission", permission)
putExtra("permissionName", permissionName)
putExtra("functionName", functionName)
addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
}
context.sendBroadcast(intent)
// 由于插件无法直接请求权限(需要Activity),上面的广播会让主应用来处理权限请求
// 这里设置一个短暂延迟,让用户有时间响应权限请求
Thread.sleep(500)
// 再次检查权限是否已授予(以防用户立即授予)
if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) {
return true
}
} catch (e: Exception) {
Log.e(TAG, "请求权限失败: ${e.message}", e)
}
// 如果权限仍未授予,引导用户到权限管理页面
try {
// 尝试跳转到应用内的权限管理页面
val intent = Intent("com.yunqiinnovation.deepsound.action.PERMISSIONS_SETTINGS").apply {
setPackage(context.packageName)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
if (intent.resolveActivity(context.packageManager) != null) {
context.startActivity(intent)
} else {
// 如果应用内权限页面不可用,则跳转到系统应用设置页面
val settingsIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", context.packageName, null)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(settingsIntent)
}
} catch (e: Exception) {
Log.e(TAG, "打开权限设置页面失败: ${e.message}", e)
}
}
// 应用在后台或权限请求失败,只返回文字提示
return false
}
return true
}
/**
* 检查应用是否在前台运行
* @return 应用是否在前台
*/
private fun isAppInForeground(): Boolean {
try {
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val appProcesses = activityManager.runningAppProcesses ?: return false
val packageName = context.packageName
for (appProcess in appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
&& appProcess.processName == packageName) {
return true
}
}
} catch (e: Exception) {
Log.e(TAG, "检查应用状态失败: ${e.message}", e)
}
return false
}
/**
* 发送短信
* @param contact 联系人(名称或电话号码)
@ -565,6 +687,14 @@ class SystemFunctionHandler(private val context: Context) {
Log.d(TAG, "发送短信给 $contact: $message")
try {
// 检查发送短信权限
if (!checkPermissionAndGuide(Manifest.permission.SEND_SMS, "发送短信", "发送短信")) {
return Result(
success = false,
message = "需要短信权限才能发送短信,请在权限管理中开启短信权限"
)
}
val phoneNumber = getPhoneNumberForContact(contact)
if (phoneNumber.isEmpty()) {
return Result(
@ -599,6 +729,14 @@ class SystemFunctionHandler(private val context: Context) {
Log.d(TAG, "拨打电话给 $contact")
try {
// 检查拨打电话权限
if (!checkPermissionAndGuide(Manifest.permission.CALL_PHONE, "拨打电话", "拨打电话")) {
return Result(
success = false,
message = "需要电话权限才能拨打电话,请在权限管理中开启电话权限"
)
}
val phoneNumber = getPhoneNumberForContact(contact)
if (phoneNumber.isEmpty()) {
return Result(
@ -688,6 +826,11 @@ class SystemFunctionHandler(private val context: Context) {
return contact.replace(Regex("[^+\\d]"), "")
}
// 检查读取联系人权限
if (!checkPermissionAndGuide(Manifest.permission.READ_CONTACTS, "读取联系人", "访问联系人")) {
return ""
}
// 从联系人数据库查询
try {
val contentResolver = context.contentResolver
@ -751,55 +894,62 @@ class SystemFunctionHandler(private val context: Context) {
)
}
// 使用系统日历应用创建提醒
val intent = 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, time)
putExtra(CalendarContract.EXTRA_EVENT_END_TIME, time + 3600000) // 默认1小时
putExtra(CalendarContract.Events.HAS_ALARM, 1)
putExtra(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
// 检查日历权限
if (!checkPermissionAndGuide(Manifest.permission.WRITE_CALENDAR, "日历写入", "设置提醒")) {
return Result(
success = false,
message = "需要日历权限才能创建提醒,请在权限管理中开启日历权限"
)
}
// 直接使用ContentProvider写入日历
val endTime = time + 3600000 // 默认1小时后结束
// 获取默认日历ID
val calendarId = getDefaultCalendarId()
if (calendarId == -1L) {
Log.w(TAG, "未找到默认日历")
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)
}
// 检查是否有处理该Intent的应用
val calendarActivity = intent.resolveActivity(context.packageManager)
if (calendarActivity != null) {
context.startActivity(intent)
val eventUri = context.contentResolver.insert(CalendarContract.Events.CONTENT_URI, eventValues)
if (eventUri == null) {
Log.e(TAG, "插入日历事件失败")
return tryCreateAlarm(title, content, timeStr)
}
// 获取事件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(
success = true,
message = "已创建提醒: $title, 时间: $timeStr"
message = "已成功创建提醒: $title, 时间: $timeStr"
)
} else {
// 备选方案:如果没有日历应用,尝试创建闹钟
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, false)
alarmIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
if (alarmIntent.resolveActivity(context.packageManager) != null) {
context.startActivity(alarmIntent)
return Result(
success = true,
message = "已创建闹钟提醒: $title, 时间: $timeStr"
)
}
} catch (e: Exception) {
Log.e(TAG, "创建闹钟失败: ${e.message}", e)
}
// 仍然创建了事件,但没有提醒
return Result(
success = false,
message = "未找到可用的日历或闹钟应用"
success = true,
message = "已创建日历事件,但未设置提醒: $title"
)
}
} catch (e: Exception) {
@ -811,6 +961,69 @@ class SystemFunctionHandler(private val context: Context) {
}
}
/**
* 获取默认日历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(TAG, "获取默认日历ID失败: ${e.message}", e)
}
return calendarId
}
/**
* 尝试创建闹钟提醒(备选方案)
*/
private fun tryCreateAlarm(title: String, content: String, timeStr: String): Result {
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(
success = true,
message = "已创建闹钟提醒: $title, 时间: $timeStr"
)
}
} catch (e: Exception) {
Log.e(TAG, "创建闹钟失败: ${e.message}", e)
}
return Result(
success = false,
message = "未找到可用的日历或闹钟应用"
)
}
/**
* 获取当前时间
* @param format 时间格式(可选)
@ -892,22 +1105,10 @@ class SystemFunctionHandler(private val context: Context) {
val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
// 检查位置权限
val fineLocationPermission = android.Manifest.permission.ACCESS_FINE_LOCATION
val coarseLocationPermission = android.Manifest.permission.ACCESS_COARSE_LOCATION
val hasFineLocationPermission = context.checkPermission(
fineLocationPermission, android.os.Process.myPid(), android.os.Process.myUid()
) == PackageManager.PERMISSION_GRANTED
val hasCoarseLocationPermission = context.checkPermission(
coarseLocationPermission, android.os.Process.myPid(), android.os.Process.myUid()
) == PackageManager.PERMISSION_GRANTED
if (!hasFineLocationPermission && !hasCoarseLocationPermission) {
Log.d(TAG, "没有位置权限")
if (!checkPermissionAndGuide(Manifest.permission.ACCESS_FINE_LOCATION, "位置信息", "获取位置")) {
return@withContext Result(
success = false,
message = "需要位置权限才能获取当前位置"
message = "需要位置权限才能获取当前位置,请在权限管理中开启位置权限"
)
}
@ -916,6 +1117,15 @@ class SystemFunctionHandler(private val context: Context) {
!locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
Log.d(TAG, "位置服务未启用")
// 引导用户打开位置服务
try {
val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intent)
} catch (e: Exception) {
Log.e(TAG, "打开位置设置失败: ${e.message}", e)
}
return@withContext Result(
success = false,
message = "位置服务未启用,请打开GPS或网络定位"
@ -962,6 +1172,105 @@ class SystemFunctionHandler(private val context: Context) {
}
}
/**
* 打开系统录音机并尝试自动开始录音
* @return 操作结果
*/
fun openRecorder(): Result {
Log.d(TAG, "打开系统录音机并尝试自动开始录音")
try {
// 创建用于启动录音机应用的Intent
val recordIntent = Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION)
recordIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
// 添加额外参数尝试自动开始录音(不是所有应用都支持)
recordIntent.putExtra("android.intent.extra.quickCapture", true)
// 检查是否有应用能处理此Intent
if (recordIntent.resolveActivity(context.packageManager) != null) {
context.startActivity(recordIntent)
return Result(
success = true,
message = "已打开录音机,尝试自动开始录音"
)
} else {
// 尝试使用备用方法,针对不同厂商应用添加特定参数
val commonRecorderIntents = mapOf(
"com.android.soundrecorder" to Intent().setClassName("com.android.soundrecorder", "com.android.soundrecorder.SoundRecorder").setAction("android.intent.action.RECORD_SOUND"),
"com.sec.android.app.voicenote" to Intent().setClassName("com.sec.android.app.voicenote", "com.sec.android.app.voicenote.Main").putExtra("launch_mode", "record"),
"com.miui.soundrecorder" to Intent().setClassName("com.miui.soundrecorder", "com.miui.soundrecorder.SoundRecorderActivity").putExtra("startOnBoot", true),
"com.huawei.recorder" to Intent().setClassName("com.huawei.recorder", "com.huawei.recorder.activity.MainActivity").putExtra("autoRecord", true),
"com.google.android.apps.recorder" to Intent().setClassName("com.google.android.apps.recorder", "com.google.android.apps.recorder.ui.RecorderActivity").putExtra("start_recording", true)
)
for ((packageName, intent) in commonRecorderIntents) {
try {
if (isPackageInstalled(packageName, context.packageManager)) {
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intent)
return Result(
success = true,
message = "已打开录音应用并尝试自动开始录音"
)
}
} catch (e: Exception) {
Log.e(TAG, "尝试打开录音应用 $packageName 失败: ${e.message}")
// 继续尝试下一个应用
}
}
// 如果特定Intent都失败,回退到原来的方法
val commonRecorderPackages = listOf(
"com.android.soundrecorder",
"com.sec.android.app.voicenote",
"com.miui.soundrecorder",
"com.huawei.recorder",
"com.google.android.apps.recorder"
)
for (packageName in commonRecorderPackages) {
try {
val packageIntent = context.packageManager.getLaunchIntentForPackage(packageName)
if (packageIntent != null) {
packageIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
// 尝试添加通用的自动开始录音参数
packageIntent.putExtra("android.intent.extra.quickCapture", true)
context.startActivity(packageIntent)
return Result(
success = true,
message = "已打开录音应用,请手动开始录音"
)
}
} catch (e: Exception) {
Log.e(TAG, "尝试打开录音应用 $packageName 失败: ${e.message}")
}
}
return Result(
success = false,
message = "未找到录音应用"
)
}
} catch (e: Exception) {
Log.e(TAG, "打开录音机失败: ${e.message}", e)
return Result(
success = false,
message = "打开录音机失败: ${e.message}"
)
}
}
// 检查应用是否已安装
private fun isPackageInstalled(packageName: String, packageManager: PackageManager): Boolean {
return try {
packageManager.getPackageInfo(packageName, 0)
true
} catch (e: Exception) {
false
}
}
/**
* 操作结果数据类
*/

Loading…
Cancel
Save