cloudroam
2025-04-15 85d11d6cd12abdd1e1f5f7516a7fb53a4826633f
app/src/main/java/com/example/firstapp/MainActivity.kt
@@ -5,141 +5,96 @@
import android.provider.Telephony
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.firstapp.databinding.ActivityMainBinding
import com.example.firstapp.receiver.SmsReceiver
import android.Manifest
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import android.os.Build
import androidx.annotation.RequiresApi
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.entity.Rule
import com.example.firstapp.ui.home.HomeViewModel
import com.example.firstapp.database.service.RetrofitClient
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.time.format.DateTimeFormatter
import java.util.Calendar
import java.util.Date
import java.util.Locale
import java.util.concurrent.TimeUnit
class MainActivity : AppCompatActivity() {
    // 安全防护关键词数组
    private var securityKeywordsList = emptyList<String>()
    private lateinit var binding: ActivityMainBinding
    private var smsReceiver:SmsReceiver? = null
    private var smsReceiver: SmsReceiver? = null
    private lateinit var adapter: MyAdapter
    private lateinit var homeViewModel: HomeViewModel
    private val multiplePermissionRequest =
        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
            when {
                permissions.getOrDefault(
                    Manifest.permission.RECEIVE_SMS,
                    false
                ) && permissions.getOrDefault(Manifest.permission.READ_SMS, false) -> {
                    // 两个权限都获得授权
                    registerSmsReceiver()
                }
    private val multiplePermissionRequest = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        when {
            permissions.getOrDefault(Manifest.permission.RECEIVE_SMS, false) &&
                    permissions.getOrDefault(Manifest.permission.READ_SMS, false) -> {
                // 两个权限都获得授权
                registerSmsReceiver()
                syncRecentSms()
            }
            else -> {
                // 有权限被拒绝
                Toast.makeText(this, "需要短信读取和接收权限才能正常使用功能", Toast.LENGTH_SHORT).show()
                else -> {
                    // 有权限被拒绝
                    Toast.makeText(
                        this, "需要短信读取和接收权限才能正常使用功能", Toast.LENGTH_SHORT
                    ).show()
                }
            }
        }
    }
    private val syncLock = Object()
    @RequiresApi(Build.VERSION_CODES.O)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        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)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        // 只保留底部导航的设置
        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) {
        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(arrayOf(
                Manifest.permission.RECEIVE_SMS,
                Manifest.permission.READ_SMS
            ))
            multiplePermissionRequest.launch(
                arrayOf(
                    Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_SMS
                )
            )
        } else {
            // 权限已经授予,继续执行相关操作
            registerSmsReceiver()
            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)
    }
    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment_activity_main)
        return navController.navigateUp() || super.onSupportNavigateUp()
    }
    private fun registerSmsReceiver() {
//        应用启动时执行 registerSmsReceiver()
//        创建 SmsReceiver 实例
@@ -157,47 +112,54 @@
        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() {
        // 清除登录信息
        getSharedPreferences("user_info", Context.MODE_PRIVATE)
            .edit()
            .clear()
            .apply()
        getSharedPreferences("user_info", Context.MODE_PRIVATE).edit().clear().apply()
        // 跳转回登录页
        startActivity(Intent(this, LoginActivity::class.java))
        finish()
    }
    // 初始化禁用词
    @RequiresApi(Build.VERSION_CODES.O)
    private fun initializeSecurityKeywords() {
        CoroutineScope(Dispatchers.IO).launch {
            try {
                val response = RetrofitClient.apiService.getSecurityList()
                if (response.code == 200) {
                    securityKeywordsList = response.data.map { it.keyword }
                    android.util.Log.d(
                        "MainActivity", "securityKeywordsList: $securityKeywordsList"
                    )
                    // 确保在主线程中调用 syncRecentSms
                    runOnUiThread {
                        syncRecentSms()
                    }
                } else {
                    android.util.Log.e(
                        "MainActivity", "Failed to get security list: ${response.code}"
                    )
                }
            } catch (e: Exception) {
                android.util.Log.e("MainActivity", "Error fetching security list", e)
            }
        }
    }
    @RequiresApi(Build.VERSION_CODES.O)
    private fun syncRecentSms() {
        try {
            val calendar = Calendar.getInstance()
            calendar.add(Calendar.DAY_OF_YEAR, -3) // 获取3天前的时间
            calendar.add(Calendar.DAY_OF_YEAR, -3)
            val threeDaysAgo = calendar.timeInMillis
            val cursor = contentResolver.query(
//                Uri.parse("content://sms/sent"), //发送短信
                Uri.parse("content://sms/inbox"),
                arrayOf("address", "body", "date"),
                "date >= ?",
@@ -207,44 +169,153 @@
            cursor?.use {
                while (cursor.moveToNext()) {
                    //手机号
                    val address = cursor.getString(cursor.getColumnIndexOrThrow("address"))
                    //短信内容
                    val messageBody = cursor.getString(cursor.getColumnIndexOrThrow("body"))
                    //短信时间
                    val datetime = cursor.getLong(cursor.getColumnIndexOrThrow("date"))
                    // 这里我要写个数组,并创建个对象存放一些内容,如这个对象的属性有匹配内容,正则表达式,并循环遍历
                    val ruleList = mutableListOf(
                        Rule("快递","京东","\\d{6}"),
                        Rule("快递","菜鸟","\\d{1,2}-\\d{1,2}-\\d{4}")
                    )
                    for (rule in ruleList) {
                        val code = rule.extractCodeFromMessage(messageBody.toString())
                        if (code!==null) {
                    // 转换为 Date 对象
                    val date = Date(datetime)
                    val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
                    val dateString = sdf.format(date)
                            // 转换为 Date 对象
                            val date = Date(datetime)
                            // 如果需要格式化显示
                            val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
                            val dateString = sdf.format(date)
                            val existingCode = Core.code.queryByTypeAndCodeAndDate(rule.content, code, dateString)
                            if (existingCode == null) {
                                android.util.Log.d("SmsReceiver", "Received SMS code: ${code}")
                                val msg = Msg(0, "1111", "111111", messageBody.toString(), 1, "111", 1, 1)
                                val msgId = Core.msg.insert(msg)
                                val code = Code(0, rule.type, 1, rule.content, 1, 1, msgId, code, dateString, "中通",0,"","")
                                Core.code.insert(code)
                                android.util.Log.d("SMS_DEBUG", "历史短信已保存到数据库")
                            }else{
                                android.util.Log.d("SmsReceiver", "Received SMS code: 已存在相同记录,不保存")
                    // 保存原始短信
                    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 {
                            val response = RetrofitModelClient.modelService.processSms(mapOf("content" to messageBody))
                            synchronized(syncLock) {
                                if (response.status == "success") {
                                    when (response.data.category) {
                                        "快递" -> {
                                            val pickupCode = response.data.details.pickupCode ?: ""
                                            if (pickupCode.isNotEmpty()) {
                                                val existingCode = Core.code.queryByTypeAndCodeAndDate(
                                                    response.data.category,
                                                    pickupCode,
                                                    dateString
                                                )
                                                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 = pickupCode,
                                                        pickup = 0,
                                                        pickupTime = "",
                                                        overTime = "",
                                                        address = response.data.details.address ?: "",
                                                        remarks = response.data.details.time ?: "",
                                                    )
//                                                    if(code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) {
                                                    if(code.oneLevel.isNotEmpty()  && code.code.isNotEmpty()) {
                                                        Core.code.insert(code)
                                                        android.util.Log.d("MainActivity", "历史快递短信已保存: $pickupCode")
                                                    }
                                                } else {
                                                    android.util.Log.d("MainActivity", "发现重复快递短信,跳过保存: $pickupCode")
                                                }
                                            }
                                        }
                                        "还款" -> {
                                            val amount = response.data.details.amount ?: ""
                                            if (amount.isNotEmpty()) {
                                                val existingCode = Core.code.queryByTypeAndCodeAndDate(
                                                    response.data.category,
                                                    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 = 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.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) {
                                                        Core.code.insert(code)
                                                        android.util.Log.d("MainActivity", "历史还款短信已保存: $amount")
                                                    }
                                                } else {
                                                    android.util.Log.d("MainActivity", "发现重复还款短信,跳过保存: $amount")
                                                }
                                            }
                                        }
                                        "收入" -> {
                                            val amount = response.data.details.amount ?: ""
                                            if (amount.isNotEmpty()) {
                                                val existingCode = Core.code.queryByTypeAndCodeAndDate(
                                                    response.data.category,
                                                    amount,
                                                    dateString
                                                )
                                                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 = amount,
                                                        pickup = 0, // 0-未取件,1-已取件
                                                        pickupTime = "", // 取件时间为空
                                                        overTime = response.data.details.datetime
                                                            ?: "",  // 超时时间为空,暂时没有这块处理逻辑
                                                        address = response.data.details.address ?: "",
                                                        remarks = "余额" + response.data.details.balance ?: "",
                                                    )
                                                    if(code.oneLevel.isNotEmpty() && code.secondLevel.isNotEmpty() && code.code.isNotEmpty()) {
                                                        Core.code.insert(code)
                                                        android.util.Log.d("MainActivity", "历史还款短信已保存: $amount")
                                                    }
                                                } else {
                                                    android.util.Log.d("MainActivity", "发现重复还款短信,跳过保存: $amount")
                                                }
                                            }
                                        }
                                    }
                                    // 发送广播通知数据已更新
                                    val updateIntent = Intent("com.example.firstapp.DATA_UPDATED")
                                    sendBroadcast(updateIntent)
                                }
                            }
                        }else{
                            android.util.Log.d("SmsReceiver", "Received SMS code: 没有匹配到历史短信内容")
                        } catch (e: Exception) {
                            android.util.Log.e("MainActivity", "处理历史短信出错: ${e.message}", e)
                        }
                    }
                    // 发送广播通知数据已更新
                    val updateIntent = Intent("com.example.firstapp.DATA_UPDATED")
                    sendBroadcast(updateIntent)
                }
            }
        } catch (e: Exception) {