Loading android/app/AndroidManifest.xml +9 −1 Original line number Diff line number Diff line Loading @@ -342,5 +342,13 @@ <action android:name="android.bluetooth.IBluetoothHeadsetClient" /> </intent-filter> </service> <service android:name=".hfpclient.connserv.HfpClientConnectionService" android:permission="android.permission.BIND_CONNECTION_SERVICE" android:enabled="@bool/profile_supported_hfpclient"> <intent-filter> <!-- Mechanism for Telecom stack to connect --> <action android:name="android.telecom.ConnectionService" /> </intent-filter> </service> </application> </manifest> android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +22 −3 Original line number Diff line number Diff line Loading @@ -51,13 +51,15 @@ import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.telecom.TelecomManager; import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.hfpclient.connserv.HfpClientConnectionService; import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -155,6 +157,7 @@ final class HeadsetClientStateMachine extends StateMachine { private boolean mAudioWbs; private final BluetoothAdapter mAdapter; private boolean mNativeAvailable; private TelecomManager mTelecomManager; // currently connected device private BluetoothDevice mCurrentDevice = null; Loading Loading @@ -318,6 +321,7 @@ final class HeadsetClientStateMachine extends StateMachine { } private void sendCallChangedIntent(BluetoothHeadsetClientCall c) { Log.d(TAG, "sendCallChangedIntent " + c); Intent intent = new Intent(BluetoothHeadsetClient.ACTION_CALL_CHANGED); intent.putExtra(BluetoothHeadsetClient.EXTRA_CALL, c); mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); Loading Loading @@ -1214,6 +1218,8 @@ final class HeadsetClientStateMachine extends StateMachine { mAudioRouteAllowed = context.getResources().getBoolean( R.bool.headset_client_initial_audio_route_allowed); mTelecomManager = (TelecomManager) context.getSystemService(context.TELECOM_SERVICE); mIndicatorNetworkState = HeadsetClientHalConstants.NETWORK_STATE_NOT_AVAILABLE; mIndicatorNetworkType = HeadsetClientHalConstants.SERVICE_TYPE_HOME; mIndicatorNetworkSignal = 0; Loading Loading @@ -2344,6 +2350,19 @@ final class HeadsetClientStateMachine extends StateMachine { HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH) { intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE_AND_DETACH, true); } // If we are connected to HFP AG, then register the phone account so that telecom can // make calls via HFP. mTelecomManager.registerPhoneAccount( HfpClientConnectionService.getAccount(mService, device)); mTelecomManager.enablePhoneAccount( HfpClientConnectionService.getAccount(mService, device).getAccountHandle(), true); mTelecomManager.setUserSelectedOutgoingPhoneAccount( HfpClientConnectionService.getHandle(mService)); mService.startService(new Intent(mService, HfpClientConnectionService.class)); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { mTelecomManager.unregisterPhoneAccount(HfpClientConnectionService.getHandle(mService)); mService.stopService(new Intent(mService, HfpClientConnectionService.class)); } mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); Loading android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConference.java 0 → 100644 +105 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.hfpclient.connserv; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothHeadsetClientCall; import android.os.Bundle; import android.telecom.Conference; import android.telecom.Connection; import android.telecom.DisconnectCause; import android.telecom.PhoneAccountHandle; import android.util.Log; import java.util.List; import java.util.ArrayList; public class HfpClientConference extends Conference { private static final String TAG = "HfpClientConference"; private BluetoothDevice mDevice; private BluetoothHeadsetClient mHeadsetProfile; public HfpClientConference(PhoneAccountHandle handle, BluetoothDevice device, BluetoothHeadsetClient client) { super(handle); mDevice = device; mHeadsetProfile = client; boolean manage = HfpClientConnectionService.hasHfpClientEcc(client, device); setConnectionCapabilities(Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD | (manage ? Connection.CAPABILITY_MANAGE_CONFERENCE : 0)); setActive(); } @Override public void onDisconnect() { Log.d(TAG, "onDisconnect"); mHeadsetProfile.terminateCall(mDevice, 0); setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); } @Override public void onMerge(Connection connection) { Log.d(TAG, "onMerge " + connection); addConnection(connection); } @Override public void onSeparate(Connection connection) { Log.d(TAG, "onSeparate " + connection); ((HfpClientConnection) connection).enterPrivateMode(); removeConnection(connection); } @Override public void onHold() { Log.d(TAG, "onHold"); mHeadsetProfile.holdCall(mDevice); } @Override public void onUnhold() { if (getPrimaryConnection().getConnectionService() .getAllConnections().size() > 1) { Log.w(TAG, "Ignoring unhold; call hold on the foreground call"); return; } Log.d(TAG, "onUnhold"); mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_HOLD); } @Override public void onPlayDtmfTone(char c) { Log.d(TAG, "onPlayDtmfTone " + c); if (mHeadsetProfile != null) { mHeadsetProfile.sendDTMF(mDevice, (byte) c); } } @Override public void onConnectionAdded(Connection connection) { Log.d(TAG, "onConnectionAdded " + connection); if (connection.getState() == Connection.STATE_HOLDING && getState() == Connection.STATE_ACTIVE) { connection.onAnswer(); } else if (connection.getState() == Connection.STATE_ACTIVE && getState() == Connection.STATE_HOLDING) { mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE); } } } android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnection.java 0 → 100644 +235 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.hfpclient.connserv; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothHeadsetClientCall; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.net.Uri; import android.telecom.Connection; import android.telecom.DisconnectCause; import android.telecom.TelecomManager; import android.util.Log; public class HfpClientConnection extends Connection { private static final String TAG = "HfpClientConnection"; private final Context mContext; private final BluetoothDevice mDevice; private BluetoothHeadsetClient mHeadsetProfile; private BluetoothHeadsetClientCall mCurrentCall; private boolean mClosed; private boolean mLocalDisconnect; private boolean mClientHasEcc; private boolean mAdded; public HfpClientConnection(Context context, BluetoothDevice device, BluetoothHeadsetClient client, BluetoothHeadsetClientCall call, Uri number) { mDevice = device; mContext = context; mHeadsetProfile = client; mCurrentCall = call; if (mHeadsetProfile != null) { mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice); } setAudioModeIsVoip(false); setAddress(number, TelecomManager.PRESENTATION_ALLOWED); setInitializing(); if (mHeadsetProfile != null) { finishInitializing(); } } public void onHfpConnected(BluetoothHeadsetClient client) { mHeadsetProfile = client; mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice); finishInitializing(); } public void onHfpDisconnected() { mHeadsetProfile = null; close(DisconnectCause.ERROR); } public void onAdded() { mAdded = true; } public BluetoothHeadsetClientCall getCall() { return mCurrentCall; } public boolean inConference() { return mAdded && mCurrentCall != null && mCurrentCall.isMultiParty() && getState() != Connection.STATE_DISCONNECTED; } public void enterPrivateMode() { mHeadsetProfile.enterPrivateMode(mDevice, mCurrentCall.getId()); setActive(); } public void handleCallChanged(BluetoothHeadsetClientCall call) { HfpClientConference conference = (HfpClientConference) getConference(); mCurrentCall = call; int state = call.getState(); Log.d(TAG, "Got call state change to " + state); switch (state) { case BluetoothHeadsetClientCall.CALL_STATE_ACTIVE: setActive(); if (conference != null) { conference.setActive(); } break; case BluetoothHeadsetClientCall.CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: case BluetoothHeadsetClientCall.CALL_STATE_HELD: setOnHold(); if (conference != null) { conference.setOnHold(); } break; case BluetoothHeadsetClientCall.CALL_STATE_DIALING: case BluetoothHeadsetClientCall.CALL_STATE_ALERTING: setDialing(); break; case BluetoothHeadsetClientCall.CALL_STATE_INCOMING: case BluetoothHeadsetClientCall.CALL_STATE_WAITING: setRinging(); break; case BluetoothHeadsetClientCall.CALL_STATE_TERMINATED: // TODO Use more specific causes close(mLocalDisconnect ? DisconnectCause.LOCAL : DisconnectCause.REMOTE); break; default: Log.wtf(TAG, "Unexpected phone state " + state); } setConnectionCapabilities(CAPABILITY_SUPPORT_HOLD | CAPABILITY_MUTE | CAPABILITY_SEPARATE_FROM_CONFERENCE | CAPABILITY_DISCONNECT_FROM_CONFERENCE | (getState() == STATE_ACTIVE || getState() == STATE_HOLDING ? CAPABILITY_HOLD : 0)); } private void finishInitializing() { if (mCurrentCall == null) { String number = getAddress().getSchemeSpecificPart(); Log.d(TAG, "Dialing " + number); setInitialized(); mHeadsetProfile.dial(mDevice, number); } else { handleCallChanged(mCurrentCall); } } private void close(int cause) { Log.d(TAG, "Closing " + mClosed); if (mClosed) { return; } setDisconnected(new DisconnectCause(cause)); mClosed = true; mCurrentCall = null; destroy(); } @Override public void onPlayDtmfTone(char c) { Log.d(TAG, "onPlayDtmfTone " + c + " " + mCurrentCall); if (!mClosed && mHeadsetProfile != null) { mHeadsetProfile.sendDTMF(mDevice, (byte) c); } } @Override public void onDisconnect() { Log.d(TAG, "onDisconnect " + mCurrentCall); if (!mClosed) { if (mHeadsetProfile != null && mCurrentCall != null) { mHeadsetProfile.terminateCall(mDevice, mClientHasEcc ? mCurrentCall.getId() : 0); mLocalDisconnect = true; } else { close(DisconnectCause.LOCAL); } } } @Override public void onAbort() { Log.d(TAG, "onAbort " + mCurrentCall); onDisconnect(); } @Override public void onHold() { Log.d(TAG, "onHold " + mCurrentCall); if (!mClosed && mHeadsetProfile != null) { mHeadsetProfile.holdCall(mDevice); } } @Override public void onUnhold() { if (getConnectionService().getAllConnections().size() > 1) { Log.w(TAG, "Ignoring unhold; call hold on the foreground call"); return; } Log.d(TAG, "onUnhold " + mCurrentCall); if (!mClosed && mHeadsetProfile != null) { mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_HOLD); } } @Override public void onAnswer() { Log.d(TAG, "onAnswer " + mCurrentCall); if (!mClosed) { mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE); } } @Override public void onReject() { Log.d(TAG, "onReject " + mCurrentCall); if (!mClosed) { mHeadsetProfile.rejectCall(mDevice); } } @Override public boolean equals(Object o) { if (!(o instanceof HfpClientConnection)) { return false; } Uri otherAddr = ((HfpClientConnection) o).getAddress(); return getAddress() == otherAddr || otherAddr != null && otherAddr.equals(getAddress()); } @Override public int hashCode() { return getAddress() == null ? 0 : getAddress().hashCode(); } @Override public String toString() { return "HfpClientConnection{" + getAddress() + "," + stateToString(getState()) + "," + mCurrentCall + "}"; } } android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnectionService.java 0 → 100644 +412 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
android/app/AndroidManifest.xml +9 −1 Original line number Diff line number Diff line Loading @@ -342,5 +342,13 @@ <action android:name="android.bluetooth.IBluetoothHeadsetClient" /> </intent-filter> </service> <service android:name=".hfpclient.connserv.HfpClientConnectionService" android:permission="android.permission.BIND_CONNECTION_SERVICE" android:enabled="@bool/profile_supported_hfpclient"> <intent-filter> <!-- Mechanism for Telecom stack to connect --> <action android:name="android.telecom.ConnectionService" /> </intent-filter> </service> </application> </manifest>
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +22 −3 Original line number Diff line number Diff line Loading @@ -51,13 +51,15 @@ import android.media.AudioManager; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; import android.telecom.TelecomManager; import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.bluetooth.Utils; import com.android.bluetooth.btservice.AdapterService; import com.android.bluetooth.btservice.ProfileService; import com.android.bluetooth.hfpclient.connserv.HfpClientConnectionService; import com.android.internal.util.IState; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -155,6 +157,7 @@ final class HeadsetClientStateMachine extends StateMachine { private boolean mAudioWbs; private final BluetoothAdapter mAdapter; private boolean mNativeAvailable; private TelecomManager mTelecomManager; // currently connected device private BluetoothDevice mCurrentDevice = null; Loading Loading @@ -318,6 +321,7 @@ final class HeadsetClientStateMachine extends StateMachine { } private void sendCallChangedIntent(BluetoothHeadsetClientCall c) { Log.d(TAG, "sendCallChangedIntent " + c); Intent intent = new Intent(BluetoothHeadsetClient.ACTION_CALL_CHANGED); intent.putExtra(BluetoothHeadsetClient.EXTRA_CALL, c); mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); Loading Loading @@ -1214,6 +1218,8 @@ final class HeadsetClientStateMachine extends StateMachine { mAudioRouteAllowed = context.getResources().getBoolean( R.bool.headset_client_initial_audio_route_allowed); mTelecomManager = (TelecomManager) context.getSystemService(context.TELECOM_SERVICE); mIndicatorNetworkState = HeadsetClientHalConstants.NETWORK_STATE_NOT_AVAILABLE; mIndicatorNetworkType = HeadsetClientHalConstants.SERVICE_TYPE_HOME; mIndicatorNetworkSignal = 0; Loading Loading @@ -2344,6 +2350,19 @@ final class HeadsetClientStateMachine extends StateMachine { HeadsetClientHalConstants.CHLD_FEAT_MERGE_DETACH) { intent.putExtra(BluetoothHeadsetClient.EXTRA_AG_FEATURE_MERGE_AND_DETACH, true); } // If we are connected to HFP AG, then register the phone account so that telecom can // make calls via HFP. mTelecomManager.registerPhoneAccount( HfpClientConnectionService.getAccount(mService, device)); mTelecomManager.enablePhoneAccount( HfpClientConnectionService.getAccount(mService, device).getAccountHandle(), true); mTelecomManager.setUserSelectedOutgoingPhoneAccount( HfpClientConnectionService.getHandle(mService)); mService.startService(new Intent(mService, HfpClientConnectionService.class)); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { mTelecomManager.unregisterPhoneAccount(HfpClientConnectionService.getHandle(mService)); mService.stopService(new Intent(mService, HfpClientConnectionService.class)); } mService.sendBroadcast(intent, ProfileService.BLUETOOTH_PERM); Loading
android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConference.java 0 → 100644 +105 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.hfpclient.connserv; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothHeadsetClientCall; import android.os.Bundle; import android.telecom.Conference; import android.telecom.Connection; import android.telecom.DisconnectCause; import android.telecom.PhoneAccountHandle; import android.util.Log; import java.util.List; import java.util.ArrayList; public class HfpClientConference extends Conference { private static final String TAG = "HfpClientConference"; private BluetoothDevice mDevice; private BluetoothHeadsetClient mHeadsetProfile; public HfpClientConference(PhoneAccountHandle handle, BluetoothDevice device, BluetoothHeadsetClient client) { super(handle); mDevice = device; mHeadsetProfile = client; boolean manage = HfpClientConnectionService.hasHfpClientEcc(client, device); setConnectionCapabilities(Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD | (manage ? Connection.CAPABILITY_MANAGE_CONFERENCE : 0)); setActive(); } @Override public void onDisconnect() { Log.d(TAG, "onDisconnect"); mHeadsetProfile.terminateCall(mDevice, 0); setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); } @Override public void onMerge(Connection connection) { Log.d(TAG, "onMerge " + connection); addConnection(connection); } @Override public void onSeparate(Connection connection) { Log.d(TAG, "onSeparate " + connection); ((HfpClientConnection) connection).enterPrivateMode(); removeConnection(connection); } @Override public void onHold() { Log.d(TAG, "onHold"); mHeadsetProfile.holdCall(mDevice); } @Override public void onUnhold() { if (getPrimaryConnection().getConnectionService() .getAllConnections().size() > 1) { Log.w(TAG, "Ignoring unhold; call hold on the foreground call"); return; } Log.d(TAG, "onUnhold"); mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_HOLD); } @Override public void onPlayDtmfTone(char c) { Log.d(TAG, "onPlayDtmfTone " + c); if (mHeadsetProfile != null) { mHeadsetProfile.sendDTMF(mDevice, (byte) c); } } @Override public void onConnectionAdded(Connection connection) { Log.d(TAG, "onConnectionAdded " + connection); if (connection.getState() == Connection.STATE_HOLDING && getState() == Connection.STATE_ACTIVE) { connection.onAnswer(); } else if (connection.getState() == Connection.STATE_ACTIVE && getState() == Connection.STATE_HOLDING) { mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE); } } }
android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnection.java 0 → 100644 +235 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.hfpclient.connserv; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothHeadsetClientCall; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.net.Uri; import android.telecom.Connection; import android.telecom.DisconnectCause; import android.telecom.TelecomManager; import android.util.Log; public class HfpClientConnection extends Connection { private static final String TAG = "HfpClientConnection"; private final Context mContext; private final BluetoothDevice mDevice; private BluetoothHeadsetClient mHeadsetProfile; private BluetoothHeadsetClientCall mCurrentCall; private boolean mClosed; private boolean mLocalDisconnect; private boolean mClientHasEcc; private boolean mAdded; public HfpClientConnection(Context context, BluetoothDevice device, BluetoothHeadsetClient client, BluetoothHeadsetClientCall call, Uri number) { mDevice = device; mContext = context; mHeadsetProfile = client; mCurrentCall = call; if (mHeadsetProfile != null) { mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice); } setAudioModeIsVoip(false); setAddress(number, TelecomManager.PRESENTATION_ALLOWED); setInitializing(); if (mHeadsetProfile != null) { finishInitializing(); } } public void onHfpConnected(BluetoothHeadsetClient client) { mHeadsetProfile = client; mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice); finishInitializing(); } public void onHfpDisconnected() { mHeadsetProfile = null; close(DisconnectCause.ERROR); } public void onAdded() { mAdded = true; } public BluetoothHeadsetClientCall getCall() { return mCurrentCall; } public boolean inConference() { return mAdded && mCurrentCall != null && mCurrentCall.isMultiParty() && getState() != Connection.STATE_DISCONNECTED; } public void enterPrivateMode() { mHeadsetProfile.enterPrivateMode(mDevice, mCurrentCall.getId()); setActive(); } public void handleCallChanged(BluetoothHeadsetClientCall call) { HfpClientConference conference = (HfpClientConference) getConference(); mCurrentCall = call; int state = call.getState(); Log.d(TAG, "Got call state change to " + state); switch (state) { case BluetoothHeadsetClientCall.CALL_STATE_ACTIVE: setActive(); if (conference != null) { conference.setActive(); } break; case BluetoothHeadsetClientCall.CALL_STATE_HELD_BY_RESPONSE_AND_HOLD: case BluetoothHeadsetClientCall.CALL_STATE_HELD: setOnHold(); if (conference != null) { conference.setOnHold(); } break; case BluetoothHeadsetClientCall.CALL_STATE_DIALING: case BluetoothHeadsetClientCall.CALL_STATE_ALERTING: setDialing(); break; case BluetoothHeadsetClientCall.CALL_STATE_INCOMING: case BluetoothHeadsetClientCall.CALL_STATE_WAITING: setRinging(); break; case BluetoothHeadsetClientCall.CALL_STATE_TERMINATED: // TODO Use more specific causes close(mLocalDisconnect ? DisconnectCause.LOCAL : DisconnectCause.REMOTE); break; default: Log.wtf(TAG, "Unexpected phone state " + state); } setConnectionCapabilities(CAPABILITY_SUPPORT_HOLD | CAPABILITY_MUTE | CAPABILITY_SEPARATE_FROM_CONFERENCE | CAPABILITY_DISCONNECT_FROM_CONFERENCE | (getState() == STATE_ACTIVE || getState() == STATE_HOLDING ? CAPABILITY_HOLD : 0)); } private void finishInitializing() { if (mCurrentCall == null) { String number = getAddress().getSchemeSpecificPart(); Log.d(TAG, "Dialing " + number); setInitialized(); mHeadsetProfile.dial(mDevice, number); } else { handleCallChanged(mCurrentCall); } } private void close(int cause) { Log.d(TAG, "Closing " + mClosed); if (mClosed) { return; } setDisconnected(new DisconnectCause(cause)); mClosed = true; mCurrentCall = null; destroy(); } @Override public void onPlayDtmfTone(char c) { Log.d(TAG, "onPlayDtmfTone " + c + " " + mCurrentCall); if (!mClosed && mHeadsetProfile != null) { mHeadsetProfile.sendDTMF(mDevice, (byte) c); } } @Override public void onDisconnect() { Log.d(TAG, "onDisconnect " + mCurrentCall); if (!mClosed) { if (mHeadsetProfile != null && mCurrentCall != null) { mHeadsetProfile.terminateCall(mDevice, mClientHasEcc ? mCurrentCall.getId() : 0); mLocalDisconnect = true; } else { close(DisconnectCause.LOCAL); } } } @Override public void onAbort() { Log.d(TAG, "onAbort " + mCurrentCall); onDisconnect(); } @Override public void onHold() { Log.d(TAG, "onHold " + mCurrentCall); if (!mClosed && mHeadsetProfile != null) { mHeadsetProfile.holdCall(mDevice); } } @Override public void onUnhold() { if (getConnectionService().getAllConnections().size() > 1) { Log.w(TAG, "Ignoring unhold; call hold on the foreground call"); return; } Log.d(TAG, "onUnhold " + mCurrentCall); if (!mClosed && mHeadsetProfile != null) { mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_HOLD); } } @Override public void onAnswer() { Log.d(TAG, "onAnswer " + mCurrentCall); if (!mClosed) { mHeadsetProfile.acceptCall(mDevice, BluetoothHeadsetClient.CALL_ACCEPT_NONE); } } @Override public void onReject() { Log.d(TAG, "onReject " + mCurrentCall); if (!mClosed) { mHeadsetProfile.rejectCall(mDevice); } } @Override public boolean equals(Object o) { if (!(o instanceof HfpClientConnection)) { return false; } Uri otherAddr = ((HfpClientConnection) o).getAddress(); return getAddress() == otherAddr || otherAddr != null && otherAddr.equals(getAddress()); } @Override public int hashCode() { return getAddress() == null ? 0 : getAddress().hashCode(); } @Override public String toString() { return "HfpClientConnection{" + getAddress() + "," + stateToString(getState()) + "," + mCurrentCall + "}"; } }
android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnectionService.java 0 → 100644 +412 −0 File added.Preview size limit exceeded, changes collapsed. Show changes