如何检测WhatsApp/Telegram/Messenger外呼通话的接听及结束状态?是否可通过BroadcastReceiver实现?
Hey there! Let's break down your questions about detecting outbound call states for WhatsApp, Telegram, and Messenger, plus whether BroadcastReceiver can handle this.
Short answer: No, not directly with system-level broadcasts. The Android system's ACTION_PHONE_STATE_CHANGED broadcast only tracks native cellular calls, not VoIP calls from third-party apps like WhatsApp or Telegram. These apps handle their calls internally, so they don't trigger system-wide call state events that a standard BroadcastReceiver can catch.
That said, you can't rely on BroadcastReceiver alone for this task—you'll need a different approach, which we'll cover next.
Since none of these apps expose official APIs to track call states, your best bet is to use an AccessibilityService to monitor UI changes. These services can observe the on-screen elements of other apps, which lets you infer call states based on what's displayed.
Identifying an Answered Outbound Call
When an outbound call connects, each app's UI changes in predictable ways:
- WhatsApp: Switches from a "Calling..." screen to a live call interface showing call duration, mute/hold buttons, and the contact's name/photo.
- Telegram: Moves from the ringing screen to a call screen with active controls (like hangup, video toggle).
- Messenger: Similar to WhatsApp—ringing UI replaces with a live call interface with duration tracking.
In your AccessibilityService, you can listen for these UI transitions by checking for specific text (like "Connected" or call duration labels) or UI components (like active call control buttons) that appear when the call is answered.
Detecting Ended or Unanswered Calls
- Unanswered calls: The app will stay on the ringing screen until a timeout, then switch back to the chat/contact screen, often showing a "Missed call" or "Call not answered" notification/text.
- Ended calls: Whether you hang up or the other party does, the live call UI disappears, and you're taken back to the chat screen. Some apps show a "Call ended" toast or update the chat with a call record.
Your service can watch for these UI switches and the presence of these status messages to determine the call's outcome.
Here's a simplified code snippet to get you started. This service monitors the target apps and reacts to key UI cues:
public class CallMonitorService extends AccessibilityService { // Target app package names private static final String[] TARGET_APPS = { "com.whatsapp", "org.telegram.messenger", "com.facebook.orca" // Messenger }; @Override public void onAccessibilityEvent(AccessibilityEvent event) { String currentPackage = event.getPackageName().toString(); if (!Arrays.asList(TARGET_APPS).contains(currentPackage)) { return; // Ignore non-target apps } AccessibilityNodeInfo rootNode = getRootInActiveWindow(); if (rootNode == null) return; // Check for answered call cues (adjust text for your locale) List<AccessibilityNodeInfo> answeredCues = rootNode.findAccessibilityNodeInfosByText("Connected"); if (!answeredCues.isEmpty()) { logCallState(currentPackage, "ANSWERED"); } // Check for ended/missed call cues List<AccessibilityNodeInfo> endedCues = rootNode.findAccessibilityNodeInfosByText("Call ended"); List<AccessibilityNodeInfo> missedCues = rootNode.findAccessibilityNodeInfosByText("Missed call"); if (!endedCues.isEmpty()) { logCallState(currentPackage, "ENDED"); } else if (!missedCues.isEmpty()) { logCallState(currentPackage, "UNANSWERED"); } rootNode.recycle(); // Always recycle node info to avoid memory leaks } private void logCallState(String app, String state) { // Replace this with your custom logic (e.g., save to database, trigger an event) Log.d("CallMonitor", String.format("%s call %s", app, state)); } @Override public void onInterrupt() { // Handle service interruptions here } }
Don't forget to register the service in your AndroidManifest.xml with the required permissions:
<service android:name=".CallMonitorService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config" /> </service>
And create an accessibility_service_config.xml file in res/xml/ to define your service's capabilities:
<?xml version="1.0" encoding="utf-8"?> <accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeWindowStateChanged|typeViewTextChanged" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagDefault" android:canRetrieveWindowContent="true" android:description="@string/accessibility_service_description" />
- User Permission: Accessibility services require users to manually enable them in Settings > Accessibility. You'll need to guide users through this process.
- UI Compatibility: App UIs (and text labels) change with updates. You might need to adjust your cues (like using resource IDs instead of text, though those are also internal and can change) or support multiple locales.
- Privacy Compliance: Monitoring user call activity requires clear disclosure in your app's privacy policy—make sure you're following local regulations.
- No Official Support: This is a "hacky" workaround since there's no public API for this. If an app updates its UI, your monitoring logic might break until you adjust it.
内容的提问来源于stack exchange,提问作者Syed Muhammad Ahsan

