Android自定义原生拨号器ConnectionService实现:外呼无法接通求助
自定义拨号器呼叫无法接通问题排查
正在基于ConnectionService、Connection实现自定义原生拨号器,注册PhoneAccount用于外呼,目前已能通过自定义PhoneAccount发起呼叫,但呼叫始终无法接通至目标号码,请求协助排查。
PhoneAccount注册代码
@RequiresApi(api = Build.VERSION_CODES.M) private void registerConnectionService() { try { TelecomManager manager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); String connectionServiceId = getConnectionServiceId(); ComponentName componentName = new ComponentName(getApplicationContext(), MyService.class); PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(componentName, "Dialer"); phoneAccount = manager.getPhoneAccount(phoneAccountHandle); // Log.i("phoneAccountTekV",phoneAccount.getAddress()+" "+phoneAccount.getCapabilities()+" "+phoneAccount.getLabel()); if (phoneAccount == null) { // no phone account from us registered yet PhoneAccount.Builder builder = PhoneAccount.builder(phoneAccountHandle, "Dialer"); Uri uri = Uri.parse("tel:123456789"); //builder.setSubscriptionAddress(uri); //builder.setAddress(uri); builder.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER); phoneAccount = builder.build(); manager.registerPhoneAccount(phoneAccount); Log.i("phoneAccount", "" + phoneAccount.isEnabled()); Intent intent = new Intent(); intent.setComponent(new ComponentName("com.android.server.telecom", "com.android.server.telecom.settings.EnableAccountPreferenceActivity")); startActivity(intent); } Log.i("is phoneAccountEnabled", "" + phoneAccount.isEnabled()); } catch (SecurityException se) { Log.e("registerPhoneAccount", "SecurityException: Ensure all necessary permissions are granted", se); } catch (IllegalArgumentException iae) { Log.e("registerPhoneAccount", "IllegalArgumentException: Ensure the PhoneAccount is properly configured", iae); } catch (RuntimeException re) { Log.e("registerPhoneAccount", "RuntimeException: An unexpected error occurred", re); } catch (Exception re) { Log.e("registerPhoneAccount", "Exception: An unexpected error occurred", re); } }
ConnectionService实现代码
@RequiresApi(api = Build.VERSION_CODES.Q) @RequiresPermission(value = "android.permission.READ_PHONE_STATE") @Override public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest originalRequest) { Uri handle = originalRequest.getAddress(); MyConnection connection = new MyConnection(false, originalRequest,this); connection.setAddress(handle, TelecomManager.PRESENTATION_ALLOWED); //connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED); // connection.setDialing(); connection.setInitializing(); connection.setConnectionCapabilities(Connection.CAPABILITY_HOLD | Connection.CAPABILITY_MUTE | Connection.CAPABILITY_SUPPORT_HOLD); connection.setVideoState(originalRequest.getVideoState()); addCall(connection); TelecomManager manager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); boolean isOut = manager.isOutgoingCallPermitted(connectionManagerPhoneAccount); Log.i("phoneAccountTekV",connectionManagerPhoneAccount.getUserHandle().toString()); //setAddress(connection,handle); Log.i("isOutgoingCallPermitted"," isOutgoingCallPermitted-"+isOut); PhoneAccountHandle ph = manager.getUserSelectedOutgoingPhoneAccount(); List<PhoneAccountHandle> selfHandles =manager.getSelfManagedPhoneAccounts(); List<PhoneAccountHandle> handles =manager.getCallCapablePhoneAccounts(); connection.startOutgoing(); return connection; }
LogCat日志
12:27:49.085 1563-1563/? W/Telecom: **Call: maybeOnInCallServiceTrackingChanged() request on a call without a connection service.: ICSBC.oSC(cgag)@C/U** 2024-06-24 12:27:49.085 1563-1563/? W/Telecom: **Call: maybeOnInCallServiceTrackingChanged() request on a call without a connection service.: ICSBC.oSC(cgaa)@C/Y** 2024-06-24 12:27:49.091 1563-6781/? W/WindowManager: Prepare app transition: mNextAppTransitionRequests=[TRANSIT_OPEN, TRANSIT_OPEN], mNextAppTransitionFlags=, displayId: 0 Callers=com.android.server.wm.DisplayContent.prepareAppTransition:6493 com.android.server.wm.TaskFragment.resumeTopActivity:1573 com.android.server.wm.TaskFragment.resumeTopActivity:1307 com.android.server.wm.Task.resumeTopActivityInnerLocked:6451 com.android.server.wm.Task.resumeTopActivityUncheckedLocked:6352 2024-06-24 12:27:49.091 1563-6781/? W/ActivityTaskManager: Tried to set launchTime (0) < mLastActivityLaunchTime (1105139) 2024-06-24 12:27:49.096 1563-1563/? W/Telecom: **Call: maybeOnInCallServiceTrackingChanged() request on a call without a connection service.: TSI.pC->CM.fOCP->CM.sOCPA->CM.dSMCP->CM.dSPA->CM.sRCQ->CM.pASP(ctd)@C/M** 2024-06-24 12:27:49.096 1563-1563/? W/Telecom: **Call: maybeOnInCallServiceTrackingChanged() request on a call without a connection service.: TSI.pC->CM.fOCP->CM.sOCPA->CM.dSMCP->CM.dSPA->CM.sRCQ->CM.pASP(ctd)@C/M** 2024-06-24 12:27:49.097 1563-6781/? W/WindowManager: Execute app transition: mNextAppTransitionRequests=[TRANSIT_OPEN, TRANSIT_OPEN], mNextAppTransitionFlags=, displayId: 0 Callers=com.android.server.wm.RootWindowContainer.executeAppTransitionForAllDisplay:2580 com.android.server.wm.ActivityTaskSupervisor.reportResumedActivityLocked:2287 com.android.server.wm.ActivityRecord.completeResumeLocked:6987 com.android.server.wm.Task.minimalResumeActivityLocked:6156 com.android.server.wm.ActivityTaskSupervisor.realStartActivityLocked:1137 2024-06-24 12:27:49.098 1563-1563/? W/Telecom: **Call: maybeOnInCallServiceTrackingChanged() request on a call without a connection service.: TSI.pC->CM.fOCP->CM.sOCPA->CM.dSMCP->CM.dSPA->CM.sRCQ->CM.pASP(ctd)@C/M** 2024-06-24 12:27:49.099 1224-1461/? W/SecAudioParamPolicy: g_volume_situation_key: did not support legacy situation volumes 2024-06-24 12:27:49.099 32494-32494/? E/m.samsung.crane: Not starting debugger since process cannot load the jdwp agent. 2024-06-24 12:27:49.102 9896-9925/? E/BluetoothAdapterService: getActiveDevices: HearingAidService is null 2024-06-24 12:27:49.107 1563-1563/? W/Telecom: Logging: Log.endSession was called with no session active. 2024-06-24 12:27:49.110 9896-9925/? E/BluetoothAdapterService: getActiveDevices: HearingAidService is null **W/ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast:1252 com.android.server.notification.sec.DisplayToast.sendIntentForToastDumpLog:156 com.android.server.notification.sec.DisplayToast.outFile:106 com.android.server.notification.sec.DisplayToast.out:62 com.android.server.notification.NotificationManagerService$12.enqueueToastForDex:3989** 2024-06-24 12:27:49.507 5214-5307/? W/Parcel: Expecting binder but got null! 2024-06-24 12:27:49.513 677-677/? W/keymaster_tee: [WRN]begin req PARAMS: A32 B32 P1 2024-06-24 12:27:49.521 677-677/? W/keymaster_tee: [WRN]begin req PARAMS: A32 B32 P1 2024-06-24 12:27:49.529 1121-1121/? E/Sensors: inject_scontext_data: New ssp_data_injection_fd(44) 2024-06-24 12:27:49.530 1563-1718/? W/BroadcastQueue: Background execution not allowed: receiving Intent { act=com.samsung.rcs.contentsharing.action.NUMBER_TOKEN flg=0x10 (has extras) } to com.samsung.crane/.app.PhoneNumberReceiver 2024-06-24 12:27:49.536 1563-1718/? W/BroadcastQueue: Permission Denial: receiving Intent { act=android.intent.action.PHONE_STATE flg=0x1000010 (has extras) } to ProcessRecord{b77a6ce 6726:com.samsung.android.app.cocktailbarservice/u0a52} (pid=6726, uid=10052) requires android.permission.READ_PHONE_STATE due to sender android (uid 1000) 2024-06-24 12:27:49.537 1563-1718/? W/BroadcastQueue: Permission Denial: receiving Intent { act=android.intent.action.PHONE_STATE flg=0x1000010 (has extras) } to ProcessRecord{b77a6ce 6726:com.samsung.android.app.cocktailbarservice/u0a52} (pid=6726, uid=10052) requires android.permission.READ_PHONE_STATE due to sender android (uid 1000) 2024-06-24 12:27:49.537 9896-18745/? E/BluetoothAdapterService: getActiveDevices: HearingAidService is null
排查关键点
- 核心日志警告分析:
Call: maybeOnInCallServiceTrackingChanged() request on a call without a connection service说明Telecom系统未识别到呼叫关联的有效ConnectionService,需检查Connection状态流转和服务配置。 - PhoneAccount配置修正:
- 注册时添加
PhoneAccount.CAPABILITY_SELF_MANAGED权限,确保系统将通话控制权交给自定义服务:builder.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SELF_MANAGED) - 取消注释
builder.setSubscriptionAddress(uri)或builder.setAddress(uri),为PhoneAccount设置有效地址标识,部分系统依赖该字段验证账户合法性。
- 注册时添加
- Connection状态与属性修正:
- 取消注释
connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED),明确标记为自管理通话。 - 补充状态流转逻辑:创建Connection后调用
connection.setDialing()标记拨号中,待实际通话接通后调用connection.setConnected(),系统需要明确状态更新才能正确处理通话。
- 取消注释
- Manifest与权限检查:
- 确保ConnectionService在Manifest中正确注册并绑定权限:
<service android:name=".MyService" android:permission="android.permission.BIND_CONNECTION_SERVICE"> <intent-filter> <action android:name="android.telecom.ConnectionService" /> </intent-filter> </service> - 确认已授予
READ_PHONE_STATE、CALL_PHONE等必要动态权限(Android 6.0+)。
- 确保ConnectionService在Manifest中正确注册并绑定权限:
- 补充通话发起逻辑:
onCreateOutgoingConnection仅创建了Connection对象,需在MyConnection内部实现实际的呼叫建立逻辑(如SIP、VoIP调用),并在逻辑完成后更新Connection状态。
内容的提问来源于stack exchange,提问作者rb743
相关产品推荐
相关产品推荐

