问题描述
我正在尝试使用 Android 的 ConnectionService 创建一个通话应用。我可以成功接听电话,但我正在尝试通过 TelecomManager.addNewIncomingCall 中的“extras”参数传递特定于应用程序的数据。但是,当我在 ConnectionService 类中实际创建 Connection 对象时,我找不到可以访问我设置和传入的 Bundle 的位置。
当我检查 onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount,ConnectionRequest request) 中的传入参数时,connectionManagerPhoneAccount.getExtras() 或 request.getExtras() 都不是我传递给 TelecomManager.addNewIncomingCall 的额外参数。
在将这个额外的对象传递给 TelecomManager.addNewIncomingCall 之后,有没有人有设置和检索它的经验?
我正在尝试将正在呼叫的电话号码传递给 Connection 对象,以便我可以从设备的联系人正确解析来电显示并显示它。
代码:
package com.twilio.voice.quickstart;
...
public class VoiceActivity extends AppCompatActivity {
@RequiresApi(api = Build.VERSION_CODES.M)
private void handleIncomingCall() {
Log.d(TAG,"handleIncomingCall() triggered");
Bundle extras = new Bundle();
Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL,activeCallInvite.getFrom(),null);
extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,uri);
extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,handle);
extras.putParcelable(Constants.INCOMING_CALL_INVITE,activeCallInvite);
telecomManager.addNewIncomingCall(handle,extras);
}
package com.twilio.voice.quickstart;
@RequiresApi(api = Build.VERSION_CODES.M)
public class VoiceConnectionService extends ConnectionService {
private static final String TAG = "VoiceConnectionService";
private static Connection connection;
public static Connection getConnection() {
return connection;
}
public static void deinitConnection() {
connection = null;
}
@Override
public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount,ConnectionRequest request) {
//Not sure how to get the extra information to rebuild the twilio call invitation back up..
Log.i(TAG,"Incoming Connection Request,came with extras: " + request.getExtras());
// CallInvite activeCallInvite = intent.getParcelableExtra(Constants.INCOMING_CALL_INVITE);
Connection incomingCallConnection = createConnection(request);
incomingCallConnection.setRinging();
return incomingCallConnection;
}
@Override
public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount,ConnectionRequest request) {
Connection outgoingCallConnection = createConnection(request);
outgoingCallConnection.setDialing();
return outgoingCallConnection;
}
private Connection createConnection(ConnectionRequest request) {
connection = new Connection() {
@Override
public void onStateChanged(int state) { //Is this where we can get the phone number & set the caller id?
Log.i(TAG,"Connection Request: " + request.toString());
if (state == Connection.STATE_DIALING) {
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
// sendCallRequestToActivity(ACTION_OUTGOING_CALL); //I think this is getting triggered as an extra thing....
}
});
}
}
@Override
public void onCallAudioStateChanged(CallAudioState state) {
Log.d(TAG,"onCallAudioStateChanged called,current state is " + state);
}
@Override
public void onPlayDtmfTone(char c) {
Log.d(TAG,"onPlayDtmfTone called with DTMF " + c);
Bundle extras = new Bundle();
extras.putString(DTMF,Character.toString(c));
connection.setExtras(extras);
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
sendCallRequestToActivity(ACTION_DTMF_SEND);
}
});
}
@Override
public void ondisconnect() {
super.ondisconnect();
connection.setdisconnected(new disconnectCause(disconnectCause.LOCAL));
connection.destroy();
connection = null;
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
sendCallRequestToActivity(ACTION_disCONNECT_CALL);
}
});
}
@Override
public void onSeparate() {
super.onSeparate();
}
@Override
public void onAbort() {
super.onAbort();
connection.setdisconnected(new disconnectCause(disconnectCause.CANCELED));
connection.destroy();
}
@Override
public void onAnswer() {
super.onAnswer();
Log.i(TAG,"Connection was answered!");
connection.setActive();
final Handler handler = new Handler();
handler.post(new Runnable() {
@Override
public void run() {
sendCallRequestToActivity(ACTION_ANSWER_CALL);
}
});
}
@Override
public void onReject() {
super.onReject();
connection.setdisconnected(new disconnectCause(disconnectCause.CANCELED));
connection.destroy();
}
@Override
public void onPostDialContinue(boolean proceed) {
super.onPostDialContinue(true);
}
};
//How to get the phone number,and resolve it to a contact/address?
//https://developer.android.com/reference/android/telecom/Connection
Log.i(TAG,"Creating the connection object for the incoming call,here are the extras: " + request.getExtras() + "; " + connection.getExtras());
connection.setConnectionCapabilities(Connection.CAPABILITY_MUTE);
if (request.getExtras().getString(CALLEE) == null) {
connection.setAddress(request.getAddress(),TelecomManager.PRESENTATION_ALLOWED);
} else {
connection.setAddress(Uri.parse(request.getExtras().getString(CALLEE)),TelecomManager.PRESENTATION_ALLOWED);
}
//both returning null
// Log.i(TAG,"CALLEE: " + request.getExtras().getString(CALLEE));
// Log.i(TAG,"CALLER: " + request.getExtras().getString(CALLER));
// connection.setDialing();
connection.setExtras(request.getExtras()); //This is where we want to connect..?
//How can we get the caller Id...?
connection.setCallerdisplayName("Example Contact.",TelecomManager.PRESENTATION_ALLOWED);
return connection;
}
/*
* Send call request to the VoiceConnectionServiceActivity
*/
private void sendCallRequestToActivity(String action) {
Log.i(TAG,"Transmitting broadcast from VoiceConnectionService to Voice Activity with action: " + action);
Intent intent = new Intent(action);
Bundle extras = new Bundle();
switch (action) {
case ACTION_OUTGOING_CALL:
Uri address = connection.getAddress();
extras.putString(OUTGOING_CALL_ADDRESS,address.toString());
intent.putExtras(extras);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
LocalbroadcastManager.getInstance(this).sendbroadcast(intent);
break;
case ACTION_disCONNECT_CALL:
extras.putInt("Reason",disconnectCause.LOCAL);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtras(extras);
LocalbroadcastManager.getInstance(this).sendbroadcast(intent);
break;
case ACTION_DTMF_SEND:
String d = connection.getExtras().getString(DTMF);
extras.putString(DTMF,connection.getExtras().getString(DTMF));
intent.putExtras(extras);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
LocalbroadcastManager.getInstance(this).sendbroadcast(intent);
break;
case ACTION_ANSWER_CALL:
// Uri address2 = connection.getAddress();
// extras.putString(OUTGOING_CALL_ADDRESS,address2.toString());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtras(extras);
LocalbroadcastManager.getInstance(this).sendbroadcast(intent);
break;
default:
break;
}
}
}
解决方法
我曾经遇到过同样的问题,花了很长时间才找到解决方案。
关键是将我自己的捆绑存储在密钥 EXTRA_INCOMING_CALL_EXTRAS
中,类似于在拨出呼叫情况下使用 EXTRA_OUTGOING_CALL_EXTRAS
的建议。
val myBundle = Bundle().apply {
putParcelable(TWILIO_CALL_INVITE,callInvite)
}
telecomManager.addNewIncomingCall(
phoneAccountHandle,Bundle().apply {
putBundle(EXTRA_INCOMING_CALL_EXTRAS,myBundle)
putParcelable(EXTRA_PHONE_ACCOUNT_HANDLE,phoneAccountHandle)
}
)