You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否通过Espresso Tests模拟来电接听及静音等UI操作?

Awesome question! 完全可以通过Espresso + UIAutomator的组合来实现你要的通话场景模拟——毕竟Espresso擅长APP内的UI操作,而系统级的通话界面得靠UIAutomator来搞定。下面给你拆解具体思路和可复用的代码示例:

核心思路

因为通话界面属于系统级组件(比如原生的InCallUI或者厂商定制的通话应用),Espresso无法直接操作跨APP的元素,所以我们需要:

  • 用Espresso处理自己APP内的逻辑(如果测试流程涉及的话)
  • 借助UIAutomator的UiDevice来定位并操作系统通话界面的控件
  • 通过adb shell命令触发来电事件,模拟用户接到电话的场景
具体实现步骤 & 代码示例

首先确保你的测试模块已经添加了UIAutomator依赖,在build.gradle(Module级别)里加入:

androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'

1. 模拟用户接收来电

我们可以通过执行adb shell命令来触发来电,在测试代码里用Instrumentation执行这个命令更方便:

private fun simulateIncomingCall(phoneNumber: String = "1234567890") {
    val instrumentation = InstrumentationRegistry.getInstrumentation()
    // 执行来电触发命令
    instrumentation.uiAutomation.executeShellCommand(
        "am start -a android.intent.action.CALL -d tel:$phoneNumber"
    )
    // 等待系统弹出通话界面,也可以用UIAutomator的wait方法替代固定sleep
    Thread.sleep(2000)
}

2. 模拟接听来电

用UIAutomator定位接听按钮,注意不同Android版本和厂商的控件ID可能不同,所以我们同时做ID匹配和文本匹配的兼容处理:

private fun answerIncomingCall() {
    val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
    
    // 优先通过控件ID定位(原生系统常用ID)
    val answerButton = uiDevice.findObject(
        UiSelector().resourceId("com.android.incallui:id/answer_button")
    )
    
    if (answerButton.waitForExists(5000) && answerButton.isEnabled) {
        answerButton.click()
    } else {
        // 兼容厂商定制系统,用文本匹配(支持中英文)
        val answerTextButton = uiDevice.findObject(
            UiSelector().textMatches("(?i)接听|answer")
        )
        if (answerTextButton.waitForExists(5000) && answerTextButton.isEnabled) {
            answerTextButton.click()
        }
    }
    // 等待通话建立完成
    Thread.sleep(1000)
}

3. 模拟点击静音按钮

同样的思路,定位静音控件并执行点击操作:

private fun toggleCallMute() {
    val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
    
    val muteButton = uiDevice.findObject(
        UiSelector().resourceId("com.android.incallui:id/mute_button")
    )
    
    if (muteButton.waitForExists(5000) && muteButton.isEnabled) {
        muteButton.click()
    } else {
        // 兼容定制系统的文本匹配
        val muteTextButton = uiDevice.findObject(
            UiSelector().textMatches("(?i)静音|mute")
        )
        if (muteTextButton.waitForExists(5000) && muteTextButton.isEnabled) {
            muteTextButton.click()
        }
    }
}
关键注意事项
  • 权限处理:测试需要CALL_PHONE权限,可以在测试开始前授予:
    Espresso.onView(ViewMatchers.isRoot())
        .perform(ViewActions.grantPermission(Manifest.permission.CALL_PHONE))
    
  • 兼容性适配:不同厂商的通话界面控件差异很大,建议用UiAutomatorViewer工具(Android SDK tools/bin目录下)查看目标设备的控件属性,调整定位规则
  • 等待优化:尽量用waitForExists()替代固定的Thread.sleep(),让测试更稳定
  • 流程整合:可以把这些方法组合成完整的测试用例,比如:
    @Test
    fun testFullCallScenario() {
        // 1. 启动目标APP
        ActivityScenario.launch(MainActivity::class.java)
        
        // 2. 授予通话权限
        Espresso.onView(ViewMatchers.isRoot())
            .perform(ViewActions.grantPermission(Manifest.permission.CALL_PHONE))
        
        // 3. 模拟来电
        simulateIncomingCall()
        
        // 4. 接听电话
        answerIncomingCall()
        
        // 5. 触发静音操作
        toggleCallMute()
        
        // 6. 可添加自定义验证逻辑,比如检查APP内的状态变化
    }
    

内容的提问来源于stack exchange,提问作者user2386226

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:39:33