Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java +15 −55 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ import com.android.bluetooth.Utils; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * Provides Bluetooth Headset Client (HF Role) profile, as a service in the Loading Loading @@ -342,12 +342,12 @@ public class HeadsetClientService extends ProfileService { } @Override public boolean terminateCall(BluetoothDevice device, int index) { public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) { HeadsetClientService service = getService(); if (service == null) { return false; } return service.terminateCall(device, index); return service.terminateCall(device, call.getUUID()); } @Override Loading @@ -369,32 +369,14 @@ public class HeadsetClientService extends ProfileService { } @Override public boolean redial(BluetoothDevice device) { public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { HeadsetClientService service = getService(); if (service == null) { return false; } return service.redial(device); } @Override public boolean dial(BluetoothDevice device, String number) { HeadsetClientService service = getService(); if (service == null) { return false; return null; } return service.dial(device, number); } @Override public boolean dialMemory(BluetoothDevice device, int location) { HeadsetClientService service = getService(); if (service == null) { return false; } return service.dialMemory(device, location); } @Override public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { HeadsetClientService service = getService(); Loading Loading @@ -654,7 +636,7 @@ public class HeadsetClientService extends ProfileService { return true; } boolean terminateCall(BluetoothDevice device, int index) { boolean terminateCall(BluetoothDevice device, UUID uuid) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED && Loading @@ -663,7 +645,7 @@ public class HeadsetClientService extends ProfileService { } Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL); msg.arg1 = index; msg.obj = uuid; mStateMachine.sendMessage(msg); return true; } Loading @@ -682,44 +664,22 @@ public class HeadsetClientService extends ProfileService { return true; } boolean redial(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED && connectionState != BluetoothProfile.STATE_CONNECTING) { return false; } Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.REDIAL); mStateMachine.sendMessage(msg); return true; } boolean dial(BluetoothDevice device, String number) { BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED && connectionState != BluetoothProfile.STATE_CONNECTING) { return false; return null; } BluetoothHeadsetClientCall call = new BluetoothHeadsetClientCall( device, HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID, BluetoothHeadsetClientCall.CALL_STATE_DIALING, number, false /* multiparty */, true /* outgoing */); Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER); msg.obj = number; msg.obj = call; mStateMachine.sendMessage(msg); return true; } boolean dialMemory(BluetoothDevice device, int location) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED && connectionState != BluetoothProfile.STATE_CONNECTING) { return false; } Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_MEMORY); msg.arg1 = location; mStateMachine.sendMessage(msg); return true; return call; } public boolean sendDTMF(BluetoothDevice device, byte code) { Loading android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +409 −730 File changed.Preview size limit exceeded, changes collapsed. Show changes android/app/src/com/android/bluetooth/hfpclient/connserv/ConnectionKey.javadeleted 100644 → 0 +0 −108 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.BluetoothHeadsetClientCall; import android.net.Uri; import android.telecom.PhoneAccount; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; /* Matching a call to internal state requires understanding of the ph number and the state of the * remote itself. The best way to associate a call with remote is to use the Call IDs that are * passed by the HFP AG role. But consider the scenario when even before a call is notified to the * remote and it tries to get back to us -- we execute a full cycle of Call -> Hangup. In such case * we have no recourse but to use phone number as the key. This class implements the matching logic * for phone numbers & IDs. It identifies uniquely a {@link HfpClientConnection}. */ class ConnectionKey { /* Initialize with invalid values */ public static final int INVALID_ID = -1; private final int mId; private final String mPhoneNumber; ConnectionKey(int id, Uri phoneNumber) { if (id == INVALID_ID && phoneNumber == null) { throw new IllegalStateException("invalid id and phone number"); } mId = id; mPhoneNumber = normalizePhoneUri(phoneNumber); } private static String normalizePhoneUri(Uri phoneNumber) { // Sometimes the number can be rewritten with brackets and such, we normalize to take that // factor out. String schemeSpecificPart = phoneNumber.getSchemeSpecificPart(); if (!TextUtils.isEmpty(schemeSpecificPart)) { if (schemeSpecificPart.startsWith("+")) { schemeSpecificPart = schemeSpecificPart.substring(1); } schemeSpecificPart = PhoneNumberUtils.normalizeNumber(schemeSpecificPart); } return schemeSpecificPart; } public static ConnectionKey getKey(BluetoothHeadsetClientCall call) { if (call == null) { throw new IllegalStateException("call may not be null"); } // IDs in the call start with *1*. int id = call.getId() > 0 ? call.getId() : INVALID_ID; Uri phoneNumberUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, call.getNumber(), null); return new ConnectionKey(id, phoneNumberUri); } public int getId() { return mId; } public String getPhoneNumber() { return mPhoneNumber; } @Override public String toString() { return "Key " + getId() + " Phone number " + getPhoneNumber(); } @Override public boolean equals(Object o) { if (!(o instanceof ConnectionKey)) { return false; } ConnectionKey candidate = (ConnectionKey) o; /* Match based on IDs */ if (getId() != INVALID_ID && candidate.getId() != INVALID_ID) { return (getId() == candidate.getId()); } /* Otherwise match has to be based on phone numbers */ return (getPhoneNumber() != null && candidate.getPhoneNumber() != null && getPhoneNumber().equals(candidate.getPhoneNumber())); } @Override public int hashCode() { // Since we may do partial match based on either ID or phone numbers hence put all the items // in same bucket. return 0; } } android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConference.java +1 −1 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public class HfpClientConference extends Conference { @Override public void onDisconnect() { Log.d(TAG, "onDisconnect"); mHeadsetProfile.terminateCall(mDevice, 0); mHeadsetProfile.terminateCall(mDevice, null); setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); } Loading android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnection.java +35 −51 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.telecom.DisconnectCause; import android.telecom.TelecomManager; import android.util.Log; import java.util.UUID; public class HfpClientConnection extends Connection { private static final String TAG = "HfpClientConnection"; Loading @@ -34,34 +36,46 @@ public class HfpClientConnection extends Connection { private BluetoothHeadsetClient mHeadsetProfile; private BluetoothHeadsetClientCall mCurrentCall; private boolean mClosing; private boolean mClosed; private boolean mLocalDisconnect; private boolean mClientHasEcc; private boolean mAdded; public HfpClientConnection(Context context, BluetoothDevice device, BluetoothHeadsetClient client, BluetoothHeadsetClientCall call, Uri number) { public HfpClientConnection(Context context, BluetoothDevice device, BluetoothHeadsetClient client, BluetoothHeadsetClientCall call, Uri number) { mDevice = device; mContext = context; mHeadsetProfile = client; setInitializing(); if (call != null) { mCurrentCall = call; handleCallChanged(); } else if (mHeadsetProfile != null) { mCurrentCall = mHeadsetProfile.dial( mDevice, number.getSchemeSpecificPart()); setDialing(); } if (mHeadsetProfile != null) { mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice); } setAudioModeIsVoip(false); setAddress(number, TelecomManager.PRESENTATION_ALLOWED); setInitialized(); if (mHeadsetProfile != null) { finishInitializing(); setConnectionCapabilities(CAPABILITY_SUPPORT_HOLD | CAPABILITY_MUTE | CAPABILITY_SEPARATE_FROM_CONFERENCE | CAPABILITY_DISCONNECT_FROM_CONFERENCE | (getState() == STATE_ACTIVE || getState() == STATE_HOLDING ? CAPABILITY_HOLD : 0)); } public UUID getUUID() { return mCurrentCall.getUUID(); } public void onHfpConnected(BluetoothHeadsetClient client) { mHeadsetProfile = client; mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice); finishInitializing(); handleCallChanged(); } public void onHfpDisconnected() { Loading @@ -87,27 +101,14 @@ public class HfpClientConnection extends Connection { setActive(); } public void handleCallChanged(BluetoothHeadsetClientCall call) { HfpClientConference conference = (HfpClientConference) getConference(); public void updateCall(BluetoothHeadsetClientCall call) { mCurrentCall = call; int state = call.getState(); // If this call is already terminated (locally) but we are only hearing about the handle of // the call right now -- then close the call. boolean closing = false; synchronized (this) { closing = mClosing; } if (closing && state != BluetoothHeadsetClientCall.CALL_STATE_TERMINATED) { if (mHeadsetProfile != null) { mHeadsetProfile.terminateCall(mDevice, mClientHasEcc ? mCurrentCall.getId() : 0); mLocalDisconnect = true; } else { Log.e(TAG, "HFP disconnected but call update received, ignore."); } return; } public void handleCallChanged() { HfpClientConference conference = (HfpClientConference) getConference(); int state = mCurrentCall.getState(); Log.d(TAG, "Got call state change to " + state); switch (state) { case BluetoothHeadsetClientCall.CALL_STATE_ACTIVE: Loading Loading @@ -138,21 +139,6 @@ public class HfpClientConnection extends Connection { 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); mHeadsetProfile.dial(mDevice, number); setDialing(); // We will change state dependent on broadcasts from BluetoothHeadsetClientCall. } else { handleCallChanged(mCurrentCall); } } private void close(int cause) { Loading @@ -160,6 +146,7 @@ public class HfpClientConnection extends Connection { if (mClosed) { return; } setDisconnected(new DisconnectCause(cause)); mClosed = true; Loading @@ -179,17 +166,14 @@ public class HfpClientConnection extends Connection { @Override public synchronized void onDisconnect() { Log.d(TAG, "onDisconnect " + mCurrentCall); mClosing = true; if (!mClosed) { // In this state we can close the call without problems. if (mHeadsetProfile != null && mCurrentCall != null) { mHeadsetProfile.terminateCall(mDevice, mClientHasEcc ? mCurrentCall.getId() : 0); if (mHeadsetProfile != null) { mHeadsetProfile.terminateCall(mDevice, mCurrentCall); mLocalDisconnect = true; } else if (mCurrentCall == null) { Log.w(TAG, "Call disconnected but call handle not received."); } } } @Override public void onAbort() { Loading Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientService.java +15 −55 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ import com.android.bluetooth.Utils; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * Provides Bluetooth Headset Client (HF Role) profile, as a service in the Loading Loading @@ -342,12 +342,12 @@ public class HeadsetClientService extends ProfileService { } @Override public boolean terminateCall(BluetoothDevice device, int index) { public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) { HeadsetClientService service = getService(); if (service == null) { return false; } return service.terminateCall(device, index); return service.terminateCall(device, call.getUUID()); } @Override Loading @@ -369,32 +369,14 @@ public class HeadsetClientService extends ProfileService { } @Override public boolean redial(BluetoothDevice device) { public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { HeadsetClientService service = getService(); if (service == null) { return false; } return service.redial(device); } @Override public boolean dial(BluetoothDevice device, String number) { HeadsetClientService service = getService(); if (service == null) { return false; return null; } return service.dial(device, number); } @Override public boolean dialMemory(BluetoothDevice device, int location) { HeadsetClientService service = getService(); if (service == null) { return false; } return service.dialMemory(device, location); } @Override public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) { HeadsetClientService service = getService(); Loading Loading @@ -654,7 +636,7 @@ public class HeadsetClientService extends ProfileService { return true; } boolean terminateCall(BluetoothDevice device, int index) { boolean terminateCall(BluetoothDevice device, UUID uuid) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED && Loading @@ -663,7 +645,7 @@ public class HeadsetClientService extends ProfileService { } Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.TERMINATE_CALL); msg.arg1 = index; msg.obj = uuid; mStateMachine.sendMessage(msg); return true; } Loading @@ -682,44 +664,22 @@ public class HeadsetClientService extends ProfileService { return true; } boolean redial(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED && connectionState != BluetoothProfile.STATE_CONNECTING) { return false; } Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.REDIAL); mStateMachine.sendMessage(msg); return true; } boolean dial(BluetoothDevice device, String number) { BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED && connectionState != BluetoothProfile.STATE_CONNECTING) { return false; return null; } BluetoothHeadsetClientCall call = new BluetoothHeadsetClientCall( device, HeadsetClientStateMachine.HF_ORIGINATED_CALL_ID, BluetoothHeadsetClientCall.CALL_STATE_DIALING, number, false /* multiparty */, true /* outgoing */); Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_NUMBER); msg.obj = number; msg.obj = call; mStateMachine.sendMessage(msg); return true; } boolean dialMemory(BluetoothDevice device, int location) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); int connectionState = mStateMachine.getConnectionState(device); if (connectionState != BluetoothProfile.STATE_CONNECTED && connectionState != BluetoothProfile.STATE_CONNECTING) { return false; } Message msg = mStateMachine.obtainMessage(HeadsetClientStateMachine.DIAL_MEMORY); msg.arg1 = location; mStateMachine.sendMessage(msg); return true; return call; } public boolean sendDTMF(BluetoothDevice device, byte code) { Loading
android/app/src/com/android/bluetooth/hfpclient/HeadsetClientStateMachine.java +409 −730 File changed.Preview size limit exceeded, changes collapsed. Show changes
android/app/src/com/android/bluetooth/hfpclient/connserv/ConnectionKey.javadeleted 100644 → 0 +0 −108 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.BluetoothHeadsetClientCall; import android.net.Uri; import android.telecom.PhoneAccount; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; /* Matching a call to internal state requires understanding of the ph number and the state of the * remote itself. The best way to associate a call with remote is to use the Call IDs that are * passed by the HFP AG role. But consider the scenario when even before a call is notified to the * remote and it tries to get back to us -- we execute a full cycle of Call -> Hangup. In such case * we have no recourse but to use phone number as the key. This class implements the matching logic * for phone numbers & IDs. It identifies uniquely a {@link HfpClientConnection}. */ class ConnectionKey { /* Initialize with invalid values */ public static final int INVALID_ID = -1; private final int mId; private final String mPhoneNumber; ConnectionKey(int id, Uri phoneNumber) { if (id == INVALID_ID && phoneNumber == null) { throw new IllegalStateException("invalid id and phone number"); } mId = id; mPhoneNumber = normalizePhoneUri(phoneNumber); } private static String normalizePhoneUri(Uri phoneNumber) { // Sometimes the number can be rewritten with brackets and such, we normalize to take that // factor out. String schemeSpecificPart = phoneNumber.getSchemeSpecificPart(); if (!TextUtils.isEmpty(schemeSpecificPart)) { if (schemeSpecificPart.startsWith("+")) { schemeSpecificPart = schemeSpecificPart.substring(1); } schemeSpecificPart = PhoneNumberUtils.normalizeNumber(schemeSpecificPart); } return schemeSpecificPart; } public static ConnectionKey getKey(BluetoothHeadsetClientCall call) { if (call == null) { throw new IllegalStateException("call may not be null"); } // IDs in the call start with *1*. int id = call.getId() > 0 ? call.getId() : INVALID_ID; Uri phoneNumberUri = Uri.fromParts(PhoneAccount.SCHEME_TEL, call.getNumber(), null); return new ConnectionKey(id, phoneNumberUri); } public int getId() { return mId; } public String getPhoneNumber() { return mPhoneNumber; } @Override public String toString() { return "Key " + getId() + " Phone number " + getPhoneNumber(); } @Override public boolean equals(Object o) { if (!(o instanceof ConnectionKey)) { return false; } ConnectionKey candidate = (ConnectionKey) o; /* Match based on IDs */ if (getId() != INVALID_ID && candidate.getId() != INVALID_ID) { return (getId() == candidate.getId()); } /* Otherwise match has to be based on phone numbers */ return (getPhoneNumber() != null && candidate.getPhoneNumber() != null && getPhoneNumber().equals(candidate.getPhoneNumber())); } @Override public int hashCode() { // Since we may do partial match based on either ID or phone numbers hence put all the items // in same bucket. return 0; } }
android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConference.java +1 −1 Original line number Diff line number Diff line Loading @@ -49,7 +49,7 @@ public class HfpClientConference extends Conference { @Override public void onDisconnect() { Log.d(TAG, "onDisconnect"); mHeadsetProfile.terminateCall(mDevice, 0); mHeadsetProfile.terminateCall(mDevice, null); setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); } Loading
android/app/src/com/android/bluetooth/hfpclient/connserv/HfpClientConnection.java +35 −51 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ import android.telecom.DisconnectCause; import android.telecom.TelecomManager; import android.util.Log; import java.util.UUID; public class HfpClientConnection extends Connection { private static final String TAG = "HfpClientConnection"; Loading @@ -34,34 +36,46 @@ public class HfpClientConnection extends Connection { private BluetoothHeadsetClient mHeadsetProfile; private BluetoothHeadsetClientCall mCurrentCall; private boolean mClosing; private boolean mClosed; private boolean mLocalDisconnect; private boolean mClientHasEcc; private boolean mAdded; public HfpClientConnection(Context context, BluetoothDevice device, BluetoothHeadsetClient client, BluetoothHeadsetClientCall call, Uri number) { public HfpClientConnection(Context context, BluetoothDevice device, BluetoothHeadsetClient client, BluetoothHeadsetClientCall call, Uri number) { mDevice = device; mContext = context; mHeadsetProfile = client; setInitializing(); if (call != null) { mCurrentCall = call; handleCallChanged(); } else if (mHeadsetProfile != null) { mCurrentCall = mHeadsetProfile.dial( mDevice, number.getSchemeSpecificPart()); setDialing(); } if (mHeadsetProfile != null) { mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice); } setAudioModeIsVoip(false); setAddress(number, TelecomManager.PRESENTATION_ALLOWED); setInitialized(); if (mHeadsetProfile != null) { finishInitializing(); setConnectionCapabilities(CAPABILITY_SUPPORT_HOLD | CAPABILITY_MUTE | CAPABILITY_SEPARATE_FROM_CONFERENCE | CAPABILITY_DISCONNECT_FROM_CONFERENCE | (getState() == STATE_ACTIVE || getState() == STATE_HOLDING ? CAPABILITY_HOLD : 0)); } public UUID getUUID() { return mCurrentCall.getUUID(); } public void onHfpConnected(BluetoothHeadsetClient client) { mHeadsetProfile = client; mClientHasEcc = HfpClientConnectionService.hasHfpClientEcc(mHeadsetProfile, mDevice); finishInitializing(); handleCallChanged(); } public void onHfpDisconnected() { Loading @@ -87,27 +101,14 @@ public class HfpClientConnection extends Connection { setActive(); } public void handleCallChanged(BluetoothHeadsetClientCall call) { HfpClientConference conference = (HfpClientConference) getConference(); public void updateCall(BluetoothHeadsetClientCall call) { mCurrentCall = call; int state = call.getState(); // If this call is already terminated (locally) but we are only hearing about the handle of // the call right now -- then close the call. boolean closing = false; synchronized (this) { closing = mClosing; } if (closing && state != BluetoothHeadsetClientCall.CALL_STATE_TERMINATED) { if (mHeadsetProfile != null) { mHeadsetProfile.terminateCall(mDevice, mClientHasEcc ? mCurrentCall.getId() : 0); mLocalDisconnect = true; } else { Log.e(TAG, "HFP disconnected but call update received, ignore."); } return; } public void handleCallChanged() { HfpClientConference conference = (HfpClientConference) getConference(); int state = mCurrentCall.getState(); Log.d(TAG, "Got call state change to " + state); switch (state) { case BluetoothHeadsetClientCall.CALL_STATE_ACTIVE: Loading Loading @@ -138,21 +139,6 @@ public class HfpClientConnection extends Connection { 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); mHeadsetProfile.dial(mDevice, number); setDialing(); // We will change state dependent on broadcasts from BluetoothHeadsetClientCall. } else { handleCallChanged(mCurrentCall); } } private void close(int cause) { Loading @@ -160,6 +146,7 @@ public class HfpClientConnection extends Connection { if (mClosed) { return; } setDisconnected(new DisconnectCause(cause)); mClosed = true; Loading @@ -179,17 +166,14 @@ public class HfpClientConnection extends Connection { @Override public synchronized void onDisconnect() { Log.d(TAG, "onDisconnect " + mCurrentCall); mClosing = true; if (!mClosed) { // In this state we can close the call without problems. if (mHeadsetProfile != null && mCurrentCall != null) { mHeadsetProfile.terminateCall(mDevice, mClientHasEcc ? mCurrentCall.getId() : 0); if (mHeadsetProfile != null) { mHeadsetProfile.terminateCall(mDevice, mCurrentCall); mLocalDisconnect = true; } else if (mCurrentCall == null) { Log.w(TAG, "Call disconnected but call handle not received."); } } } @Override public void onAbort() { Loading