From e96eba36176c5bd4d9ee622e71d946dd74403edf Mon Sep 17 00:00:00 2001 From: cloudroam <cloudroam> Date: 星期一, 21 四月 2025 17:02:00 +0800 Subject: [PATCH] fix : 优化 --- app/src/main/java/com/example/firstapp/MainActivity.kt | 415 +++++++++++++++++++++++++++++++---------------------------- 1 files changed, 218 insertions(+), 197 deletions(-) diff --git a/app/src/main/java/com/example/firstapp/MainActivity.kt b/app/src/main/java/com/example/firstapp/MainActivity.kt index 8b689c9..a099d9a 100644 --- a/app/src/main/java/com/example/firstapp/MainActivity.kt +++ b/app/src/main/java/com/example/firstapp/MainActivity.kt @@ -14,31 +14,26 @@ import android.Manifest import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri import android.os.Build import androidx.annotation.RequiresApi -import androidx.work.ExistingPeriodicWorkPolicy -import androidx.work.PeriodicWorkRequestBuilder -import androidx.work.WorkManager import com.example.firstapp.activity.LoginActivity -import com.example.firstapp.adapter.MyAdapter import com.example.firstapp.core.Core import com.example.firstapp.database.entity.Code import com.example.firstapp.database.entity.Msg import com.example.firstapp.database.service.RetrofitClient -import com.example.firstapp.ui.home.HomeViewModel +import com.example.firstapp.database.service.RetrofitModelClient import com.example.firstapp.utils.Log -import com.example.firstapp.workers.KeywordUpdateWorker import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.text.SimpleDateFormat -import java.time.LocalDateTime import java.util.Calendar import java.util.Date import java.util.Locale -import java.util.concurrent.TimeUnit -import java.time.ZoneId +import android.app.AlertDialog +import com.example.firstapp.utils.CodeUtils class MainActivity : AppCompatActivity() { // 安全防护关键词数组 @@ -48,29 +43,41 @@ private var smsReceiver: SmsReceiver? = null - private lateinit var adapter: MyAdapter - private lateinit var homeViewModel: HomeViewModel - - private val multiplePermissionRequest = + // 短信权限请求 + private val smsPermissionRequest = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> when { permissions.getOrDefault( - Manifest.permission.RECEIVE_SMS, - false + Manifest.permission.RECEIVE_SMS, false ) && permissions.getOrDefault(Manifest.permission.READ_SMS, false) -> { // 两个权限都获得授权 + Toast.makeText(this, "短信权限已授予", Toast.LENGTH_SHORT).show() registerSmsReceiver() -// syncRecentSms() -// initializeSecurityKeywords() + // 在Android O及以上版本同步最近短信 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + syncRecentSms() + } } else -> { // 有权限被拒绝 - Toast.makeText( - this, "需要短信读取和接收权限才能正常使用功能", Toast.LENGTH_SHORT - ).show() + showSmsPermissionExplanationDialog() } } + } + + // 通知权限请求 + private val notificationPermissionRequest = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> + if (isGranted) { + // 权限已授予 + Toast.makeText(this, "通知权限已授予,您将能收到重要提醒", Toast.LENGTH_SHORT).show() + } else { + // 权限被拒绝 + Toast.makeText(this, "通知权限被拒绝,应用将无法发送提醒通知", Toast.LENGTH_SHORT).show() + } + // 无论通知权限是否授予,都继续请求短信权限 + requestSmsPermissions() } private val syncLock = Object() @@ -82,104 +89,138 @@ binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setupViews() -// binding.btnLogout.setOnClickListener { -// logout() -// } - // 在此位置初始化 homeViewModel -// homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java) -// -// val navView: BottomNavigationView = binding.navView val navView = binding.navView val navController = findNavController(R.id.nav_host_fragment_activity_main) // 只保留底部导航的设置 navView.setupWithNavController(navController) - // 检查权限 - if (ContextCompat.checkSelfPermission( - this, Manifest.permission.RECEIVE_SMS - ) != android.content.pm.PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission( - this, Manifest.permission.READ_SMS - ) != android.content.pm.PackageManager.PERMISSION_GRANTED - ) { - // 同时请求两个权限 - multiplePermissionRequest.launch( + // 重置提醒计划并检查是否有错过的提醒 + resetReminders() + + // 开始权限请求流程 + startPermissionsFlow() + } + + override fun onResume() { + super.onResume() + + // 每次恢复活动时检查短信权限 + checkAndHandleSmsPermissions(showDialog = false) + } + + // 权限请求主流程 + private fun startPermissionsFlow() { + // 先请求通知权限,再请求短信权限 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // Android 13+ 需要通知权限 + if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS + ) != PackageManager.PERMISSION_GRANTED + ) { + notificationPermissionRequest.launch(Manifest.permission.POST_NOTIFICATIONS) + } else { + // 已有通知权限,直接请求短信权限 + requestSmsPermissions() + } + } else { + // 低版本Android无需请求通知权限,直接请求短信权限 + requestSmsPermissions() + } + } + + // 请求短信权限 + private fun requestSmsPermissions() { + if (!hasSmsPermissions()) { + // 没有短信权限,请求权限 + smsPermissionRequest.launch( arrayOf( Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_SMS ) ) } else { - // 权限已经授予,继续执行相关操作 + // 已有短信权限,直接初始化短信处理 registerSmsReceiver() - syncRecentSms() + // 在Android O及以上版本同步最近短信 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + syncRecentSms() + } } -// val recyclerView = findViewById<RecyclerView>(R.id.recyclerView) -// recyclerView.layoutManager = LinearLayoutManager(this) -// -// // 初始化适配器 -// adapter = MyAdapter() -// recyclerView.adapter = adapter -// -// // 观察 LiveData 数据 -// homeViewModel.codeList.observe(this) { codeList -> -// // 如果 codeList 为 null,避免闪退 -// if (codeList != null) { -// adapter.submitList(codeList) -// // 滚动到顶部 -// recyclerView.scrollToPosition(0) -// } else { -// // 如果数据为空,可以显示空列表或其他处理 -// Toast.makeText(this, "No data available", Toast.LENGTH_SHORT).show() -// } -// } - -// // 注册广播接收器来监听数据更新 -// val filter = IntentFilter("com.example.firstapp.DATA_UPDATED") -// registerReceiver(object : BroadcastReceiver() { -// override fun onReceive(context: Context, intent: Intent) { -// // 数据已更新,刷新 LiveData -// homeViewModel.loadData() -// } -// }, filter) - + } + + // 检查并处理短信权限(可选是否显示对话框) + private fun checkAndHandleSmsPermissions(showDialog: Boolean = true) { + if (!hasSmsPermissions()) { + if (showDialog) { + showSmsPermissionExplanationDialog() + } + } else { + // 已有短信权限,确保接收器已注册 + if (smsReceiver == null) { + registerSmsReceiver() + } + } + } + + // 检查是否有短信权限 + private fun hasSmsPermissions(): Boolean { + return ContextCompat.checkSelfPermission( + this, Manifest.permission.RECEIVE_SMS + ) == PackageManager.PERMISSION_GRANTED && + ContextCompat.checkSelfPermission( + this, Manifest.permission.READ_SMS + ) == PackageManager.PERMISSION_GRANTED + } + + // 显示短信权限解释对话框 + private fun showSmsPermissionExplanationDialog() { + AlertDialog.Builder(this) + .setTitle("需要短信权限") + .setMessage("应用需要短信权限来自动处理和分类您的短信信息,包括快递、付款等内容。没有此权限,应用核心功能将无法正常工作。") + .setPositiveButton("授予权限") { _, _ -> + requestSmsPermissions() + } + .setNegativeButton("暂时不要") { dialog, _ -> + dialog.dismiss() + Toast.makeText(this, "您可以稍后在设置中开启短信权限", Toast.LENGTH_LONG).show() + } + .setCancelable(false) + .show() + } + + // 提供给外部调用的请求通知权限方法 + fun requestNotificationPermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // 判断是否已经有通知权限 + if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS + ) != PackageManager.PERMISSION_GRANTED + ) { + notificationPermissionRequest.launch(Manifest.permission.POST_NOTIFICATIONS) + } else { + Toast.makeText(this, "已经拥有通知权限", Toast.LENGTH_SHORT).show() + } + } else { + // Android 13以下的版本不需要请求权限 + Toast.makeText(this, "当前系统版本无需单独请求通知权限", Toast.LENGTH_SHORT).show() + } } private fun registerSmsReceiver() { -// 应用启动时执行 registerSmsReceiver() -// 创建 SmsReceiver 实例 -// 注册广播接收器,开始监听短信 -// 等待新短信到达 -// 新短信到达时,系统发送广播 -// SmsReceiver 的 onReceive 方法被调用 -// 处理短信内容 -// 发送数据更新广播 -// MainActivity 接收到更新广播 -// 更新 UI - Log.d("SMS_DEBUG", "MainActivity收到数据更新广播") + // 确保不重复注册 + if (smsReceiver != null) return + + Log.d("SMS_DEBUG", "MainActivity注册短信接收器") smsReceiver = SmsReceiver() val filter = IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION) registerReceiver(smsReceiver, filter) } - private fun setupKeywordUpdate() { - val updateRequest = PeriodicWorkRequestBuilder<KeywordUpdateWorker>( - 1, TimeUnit.HOURS, // 每小时更新一次 - 15, TimeUnit.MINUTES // 灵活时间窗口 - ).build() - - WorkManager.getInstance(this).enqueueUniquePeriodicWork( - "keyword_update", ExistingPeriodicWorkPolicy.REPLACE, updateRequest - ) - } - private fun setupViews() { // 获取并显示当前登录的手机号 - val phone = - getSharedPreferences("user_info", Context.MODE_PRIVATE).getString("phone", "") ?: "" - -// binding.apply { -// tvPhone.text = "当前登录手机号:$phone" -// } + getSharedPreferences("user_info", Context.MODE_PRIVATE).getString("phone", "") ?: "" } private fun logout() { @@ -236,7 +277,7 @@ while (cursor.moveToNext()) { val messageBody = cursor.getString(cursor.getColumnIndexOrThrow("body")) val datetime = cursor.getLong(cursor.getColumnIndexOrThrow("date")) - + // 转换为 Date 对象 val date = Date(datetime) val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) @@ -246,122 +287,81 @@ val msg = Msg(0, "1111", "111111", messageBody, 1, "111", 1, 1) val msgId = Core.msg.insert(msg) - // 禁用关键词拦截 - if (securityKeywordsList.any { it in messageBody }) { - android.util.Log.d("MainActivity", "历史短信含有禁用关键词,跳过处理") - continue - } - // 使用协程处理API调用和数据库操作 CoroutineScope(Dispatchers.IO).launch { try { - // API调用移到synchronized块外 - val response = RetrofitClient.apiService.processSms(mapOf("content" to messageBody)) - - // 数据库操作放在synchronized块内 + val response = + RetrofitModelClient.modelService.processSms(mapOf("content" to messageBody)) + synchronized(syncLock) { if (response.status == "success") { when (response.data.category) { "快递" -> { - val existingCode = Core.code.queryByTypeAndCodeAndDate( - response.data.category, - response.data.details.pickupCode ?: "", - dateString + val code = CodeUtils.createExpressCode( + msgId = msgId, + createTime = dateString, + post = response.data.details.post, + company = response.data.details.company, + pickupCode = response.data.details.pickupCode, + address = response.data.details.address, + time = response.data.details.time ) - - if (existingCode == null) { - val code = Code( - id = 0, - category = response.data.category, - categoryId = 1, - typeId = 1, - ruleId = 1, - msgId = msgId, - createTime = dateString, - oneLevel = response.data.details.post ?: "", - secondLevel = response.data.details.company ?: "", - code = response.data.details.pickupCode ?: "", - pickup = 0, - pickupTime = "", - overTime = "", - address = response.data.details.address ?: "", - remarks = response.data.details.time ?: "", - ) - if(code.oneLevel!="" && code.secondLevel!="" && code.code!="") { - Core.code.insert(code) - } - android.util.Log.d("MainActivity", "历史快递短信已保存: ${response.data.details.pickupCode}") - } else { - android.util.Log.d("MainActivity", "发现重复快递短信,跳过保存: ${response.data.details.pickupCode}") - } + CodeUtils.saveCode(code) } - "还款" -> { - val existingCode = Core.code.queryByTypeAndCodeAndDate( - response.data.category, - response.data.details.amount ?: "", - dateString - ) - if (existingCode == null) { - val code = Code( - id = 0, - category = response.data.category, - categoryId = 2, - typeId = 1, - ruleId = 2, - msgId = msgId, - createTime = dateString, - oneLevel = response.data.details.type ?: "", - secondLevel = response.data.details.bank ?: "", - code = response.data.details.amount ?: "", - pickup = 0, - pickupTime = "", - overTime = response.data.details.date ?: "", - address = response.data.details.address ?: "", - remarks = "最小还款金额${response.data.details.min_amount}还款卡号${response.data.details.number}" - ) - if(code.oneLevel!="" && code.secondLevel!="" && code.code!="") { - Core.code.insert(code) - } - android.util.Log.d("MainActivity", "历史还款短信已保存: ${response.data.details.amount}") - } else { - android.util.Log.d("MainActivity", "发现重复还款短信,跳过保存: ${response.data.details.amount}") - } + "还款" -> { + val code = CodeUtils.createRepaymentCode( + msgId = msgId, + createTime = dateString, + type = response.data.details.type, + bank = response.data.details.bank, + amount = response.data.details.amount, + date = response.data.details.date, + address = response.data.details.address, + minAmount = response.data.details.min_amount, + number = response.data.details.number + ) + CodeUtils.saveCode(code) } "收入" -> { - val existingCode = Core.code.queryByTypeAndCodeAndDate( - response.data.category, - response.data.details.amount ?: "", - dateString + val code = CodeUtils.createIncomeCode( + msgId = msgId, + createTime = dateString, + bank = response.data.details.bank, + amount = response.data.details.amount, + datetime = response.data.details.datetime, + address = response.data.details.address, + balance = response.data.details.balance ) + CodeUtils.saveCode(code) + } - if (existingCode == null) { - val code = Code( - id = 0, - category = response.data.category, - categoryId = 3, // 3-收入类型 - typeId = 1, //暂时没有根据type分类 - ruleId = 2, //1-还款类型 - msgId = msgId, - createTime = dateString, - oneLevel = response.data.details.bank ?: "", - secondLevel = response.data.details.bank ?: "", - code = response.data.details.amount ?: "", - pickup = 0, // 0-未取件,1-已取件 - pickupTime = "", // 取件时间为空 - overTime = response.data.details.datetime - ?: "", // 超时时间为空,暂时没有这块处理逻辑 - address = response.data.details.address ?: "", - remarks = "余额" + response.data.details.balance ?: "", - ) - if(code.oneLevel!="" && code.secondLevel!="" && code.code!="") { - Core.code.insert(code) - } - android.util.Log.d("MainActivity", "历史还款短信已保存: ${response.data.details.amount}") - } else { - android.util.Log.d("MainActivity", "发现重复还款短信,跳过保存: ${response.data.details.amount}") - } + "航班" -> { + val code = CodeUtils.createFlightCode( + msgId = msgId, + createTime = dateString, + company = response.data.details.company, + start = response.data.details.start, + end = response.data.details.end, + seat = response.data.details.seat, + time = response.data.details.time, + address = response.data.details.address + ) + CodeUtils.saveCode(code) + } + + "火车票" -> { + val code = CodeUtils.createTrainTicketCode( + msgId = msgId, + createTime = dateString, + company = response.data.details.company, + seat = response.data.details.seat, + time = response.data.details.time, + address = response.data.details.address, + trips = response.data.details.trips + ) + CodeUtils.saveCode(code) } } @@ -381,4 +381,25 @@ Toast.makeText(this, "同步短信失败:${e.message}", Toast.LENGTH_SHORT).show() } } + + // 重置提醒计划 + private fun resetReminders() { + try { + // 取消所有现有的提醒任务 + androidx.work.WorkManager.getInstance(this).cancelAllWorkByTag("reminder_worker") + + // 清除旧的提醒偏好设置 + getSharedPreferences("reminder_prefs", Context.MODE_PRIVATE).edit().clear().apply() + + // 重新设置提醒任务 + (application as App).setupReminderWorker() + + // 检查是否有错过的提醒 + com.example.firstapp.service.ReminderWorker.checkMissedReminders(this) + + android.util.Log.d("MainActivity", "已重置提醒计划") + } catch (e: Exception) { + android.util.Log.e("MainActivity", "重置提醒计划失败: ${e.message}") + } + } } \ No newline at end of file -- Gitblit v1.9.3