Loading android/app/src/com/android/bluetooth/telephony/BluetoothCall.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.bluetooth.telephony; import android.bluetooth.BluetoothLeCallControl; import android.net.Uri; import android.os.Bundle; import android.os.Handler; Loading Loading @@ -48,6 +47,9 @@ public class BluetoothCall { private Call mCall; private UUID mCallId; // An index used to identify calls for CLCC (C* List Current Calls). int mClccIndex = -1; public Call getCall() { return mCall; } Loading android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java +128 −89 Original line number Diff line number Diff line Loading @@ -59,11 +59,12 @@ import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Queue; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; Loading Loading @@ -139,14 +140,9 @@ public class BluetoothInCallService extends InCallService { private final HashMap<Integer, BluetoothCall> mBluetoothConferenceCallInference = new HashMap<>(); private final Map<String, Integer> mClccInferenceIndexMap = new HashMap<>(); // A queue record the removal order of bluetooth calls private final Queue<Integer> mBluetoothCallQueue = new ArrayDeque<>(); // A map from Calls to indexes used to identify calls for CLCC (C* List Current Calls). private final Map<String, Integer> mClccIndexMap = new HashMap<>(); private static BluetoothInCallService sInstance = null; public CallInfo mCallInfo = new CallInfo(); Loading Loading @@ -652,11 +648,6 @@ public class BluetoothInCallService extends InCallService { Log.d(TAG, "add inference call with reason: " + cause.getReason()); mBluetoothCallQueue.add(call.getId()); mBluetoothConferenceCallInference.put(call.getId(), call); Integer indexValue = mClccIndexMap.get(getClccMapKey(call)); mClccInferenceIndexMap.put(getClccMapKey(call), indexValue); if (indexValue == null) { Log.w(TAG, "CLCC index value is null"); } // queue size limited to 2 because merge operation only happens on 2 calls // we are only interested in last 2 calls merged if (mBluetoothCallQueue.size() > 2) { Loading @@ -669,12 +660,10 @@ public class BluetoothInCallService extends InCallService { if (call.isConference()) { Log.d(TAG, "conference call ends, clear inference"); mBluetoothConferenceCallInference.clear(); mClccInferenceIndexMap.clear(); mBluetoothCallQueue.clear(); } } mClccIndexMap.remove(getClccMapKey(call)); updateHeadsetWithCallState(false /* force */); if (mBluetoothLeCallControl != null) { Loading Loading @@ -748,9 +737,7 @@ public class BluetoothInCallService extends InCallService { sInstance = null; mCallbacks.clear(); mBluetoothCallHashMap.clear(); mClccIndexMap.clear(); mBluetoothConferenceCallInference.clear(); mClccInferenceIndexMap.clear(); mBluetoothCallQueue.clear(); mMaxNumberOfCalls = 0; } Loading @@ -766,10 +753,13 @@ public class BluetoothInCallService extends InCallService { boolean isInferenceEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH, CLCC_INFERENCE, false); Log.d(TAG, "is conference call inference enabled: " + isInferenceEnabled); // either do conference call CLCC index inference or normal conference call BluetoothCall conferenceCallChildrenNotReady = null; for (BluetoothCall call : calls) { if (isInferenceEnabled && call.isConference() // find the conference call parent among calls if (isInferenceEnabled && call.isConference() && !mBluetoothConferenceCallInference.isEmpty()) { SortedMap<Integer, Object[]> clccResponseMap = new TreeMap<>(); Log.d( TAG, "conference call inferred size: " Loading @@ -777,25 +767,55 @@ public class BluetoothInCallService extends InCallService { + " current size: " + mBluetoothCallHashMap.size()); // Do conference call inference until at least 2 children arrive // If carrier does send children info, then inference will end when info arrives. // If carrier does not send children info, then inference won't impact actual value. // If carrier sends children info, then inference will end when info arrives. // If carrier doesn't send children info, then inference won't impact actual value. if (call.getChildrenIds().size() >= 2) { mBluetoothConferenceCallInference.clear(); break; } conferenceCallChildrenNotReady = call; } } if (conferenceCallChildrenNotReady != null) { SortedMap<Integer, Object[]> clccResponseMap = new TreeMap<>(); for (BluetoothCall inferredCall : mBluetoothConferenceCallInference.values()) { String clccMapKey = getClccMapKey(inferredCall); if (!mClccInferenceIndexMap.containsKey(clccMapKey)) { Log.w(TAG, "Inference Index Map does not have: " + clccMapKey); if (inferredCall.isCallNull() || inferredCall.getHandle() == null) { Log.w(TAG, "inferredCall does not have handle"); continue; } if (mClccInferenceIndexMap.get(clccMapKey) == null) { Log.w(TAG, "inferred index is null"); // save the index so later on when real children arrive, index is the same int index = inferredCall.mClccIndex; if (index == -1) { Log.w(TAG, "inferred index is not valid"); continue; } int index = mClccInferenceIndexMap.get(clccMapKey); // save the index so later on when real children arrive, index is the same mClccIndexMap.put(clccMapKey, index); // associate existing bluetoothCall with inferredCall based on call handle for (BluetoothCall bluetoothCall : mBluetoothCallHashMap.values()) { if (bluetoothCall.getHandle() == null) { Log.w(TAG, "call id: " + bluetoothCall.getId() + " handle is null"); continue; } if (mTelephonyManager == null) { Log.w(TAG, "mTelephonyManager is null"); continue; } boolean isSame = PhoneNumberUtils.areSamePhoneNumber( bluetoothCall.getHandle().toString(), inferredCall.getHandle().toString(), mTelephonyManager.getNetworkCountryIso()); if (isSame) { Log.d( TAG, "found conference call children that has same call handle, " + "call id: " + bluetoothCall.getId()); bluetoothCall.mClccIndex = inferredCall.mClccIndex; break; } } int direction = inferredCall.isIncoming() ? 1 : 0; int state = CALL_STATE_ACTIVE; boolean isPartOfConference = true; Loading @@ -809,15 +829,14 @@ public class BluetoothInCallService extends InCallService { if (address != null) { address = PhoneNumberUtils.stripSeparators(address); } int addressType = address == null ? -1 : PhoneNumberUtils.toaFromString(address); int addressType = address == null ? -1 : PhoneNumberUtils.toaFromString(address); clccResponseMap.put( index, new Object[] { index, direction, state, 0, isPartOfConference, address, addressType }); } // ensure response is sorted by index // sort CLCC response based on index for (Object[] response : clccResponseMap.values()) { if (response.length < 7) { Log.e(TAG, "clccResponseMap entry too short"); Loading Loading @@ -845,15 +864,18 @@ public class BluetoothInCallService extends InCallService { sendClccEndMarker(); return; } } for (BluetoothCall call : calls) { // We don't send the parent conference BluetoothCall to the bluetooth device. // We do, however want to send conferences that have no children to the bluetooth // device (e.g. IMS Conference). boolean isConferenceWithNoChildren = isConferenceWithNoChildren(call); Log.i(TAG, "sendListOfCalls isConferenceWithNoChildren " + isConferenceWithNoChildren + ", call.getChildrenIds() size " + call.getChildrenIds().size()); Log.i( TAG, "sendListOfCalls isConferenceWithNoChildren " + isConferenceWithNoChildren + ", call.getChildrenIds() size " + call.getChildrenIds().size()); if (!call.isConference() || isConferenceWithNoChildren) { sendClccForCall(call, shouldLog); } Loading Loading @@ -985,31 +1007,48 @@ public class BluetoothInCallService extends InCallService { return key; } int getNextAvailableClccIndex(int index) { // find the next available smallest index SortedSet<Integer> availableIndex = new TreeSet<>(); for (int i = index; i <= mMaxNumberOfCalls + 1; i++) { availableIndex.add(i); } for (BluetoothCall bluetoothCall : mBluetoothCallHashMap.values()) { int callCLCCIndex = bluetoothCall.mClccIndex; if (availableIndex.contains(callCLCCIndex)) { availableIndex.remove(callCLCCIndex); } } Log.d(TAG, "availableIndex first: " + availableIndex.first()); return availableIndex.first(); } /** * Returns the caches index for the specified call. If no such index exists, then an index is * given (smallest number starting from 1 that isn't already taken). * given (the smallest number starting from 1 that isn't already taken). */ private int getIndexForCall(BluetoothCall call) { String key = getClccMapKey(call); if (mClccIndexMap.containsKey(key)) { return mClccIndexMap.get(key); if (mCallInfo.isNullCall(call)) { Log.w(TAG, "empty or null call"); return -1; } if (call.mClccIndex >= 1) { return call.mClccIndex; } int index = 1; // Indexes for bluetooth clcc are 1-based. if (call.isConference()) { index = mMaxNumberOfCalls + 1; // The conference call should have a higher index Log.i(TAG, "getIndexForCall for conference call starting from " + mMaxNumberOfCalls); } while (mClccIndexMap.containsValue(index)) { index++; Log.i(TAG, "getIndexForCall for conference call starting from " + mMaxNumberOfCalls); } // NOTE: Indexes are removed in {@link #onCallRemoved}. mClccIndexMap.put(key, index); return index; call.mClccIndex = getNextAvailableClccIndex(index); Log.d(TAG, "call " + call.getId() + " CLCC index is " + call.mClccIndex); return call.mClccIndex; } private boolean _processChld(int chld) { BluetoothCall activeCall = mCallInfo.getActiveCall(); BluetoothCall ringingCall = mCallInfo.getRingingOrSimulatedRingingCall(); Loading android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java +50 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ import java.util.concurrent.TimeUnit; @MediumTest @RunWith(AndroidJUnit4.class) public class BluetoothInCallServiceTest { private static final String TAG = "BluetoothInCallServiceTest"; private static final int TEST_DTMF_TONE = 0; private static final String TEST_ACCOUNT_ADDRESS = "//foo.com/"; Loading Loading @@ -553,6 +554,53 @@ public class BluetoothInCallServiceTest { anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt()); } @Test public void testListCurrentCallsCallHandleChanged() throws Exception { mBluetoothInCallService.mTelephonyManager = mMockTelephonyManager; when(mMockTelephonyManager.getNetworkCountryIso()).thenReturn(""); ArrayList<BluetoothCall> calls = new ArrayList<>(); when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); BluetoothCall activeCall = createForegroundCall(UUID.randomUUID()); calls.add(activeCall); mBluetoothInCallService.onCallAdded(activeCall); when(activeCall.getState()).thenReturn(Call.STATE_ACTIVE); when(activeCall.isIncoming()).thenReturn(true); when(activeCall.isConference()).thenReturn(false); when(activeCall.getHandle()).thenReturn(Uri.parse("tel:2135550000")); Log.w(TAG, "call handle" + Uri.parse("tel:2135550000")); when(activeCall.getGatewayInfo()) .thenReturn(new GatewayInfo(null, null, Uri.parse("tel:2135550000"))); clearInvocations(mMockBluetoothHeadset); mBluetoothInCallService.listCurrentCalls(); verify(mMockBluetoothHeadset) .clccResponse( 1, 1, CALL_STATE_ACTIVE, 0, false, "2135550000", PhoneNumberUtils.TOA_Unknown); // call handle changed when(activeCall.getHandle()).thenReturn(Uri.parse("tel:213-555-0000")); clearInvocations(mMockBluetoothHeadset); Log.w(TAG, "call handle" + Uri.parse("tel:213-555-0000")); mBluetoothInCallService.listCurrentCalls(); verify(mMockBluetoothHeadset) .clccResponse( 1, 1, CALL_STATE_ACTIVE, 0, false, "2135550000", PhoneNumberUtils.TOA_Unknown); } @Test public void testRingingCallClccResponse() throws Exception { ArrayList<BluetoothCall> calls = new ArrayList<>(); Loading Loading @@ -771,6 +819,8 @@ public class BluetoothInCallServiceTest { @Test public void testListCurrentCallsConferenceEmptyChildrenInference() throws Exception { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BLUETOOTH, CLCC_INFERENCE, "true", false); mBluetoothInCallService.mTelephonyManager = mMockTelephonyManager; when(mMockTelephonyManager.getNetworkCountryIso()).thenReturn(""); ArrayList<BluetoothCall> calls = new ArrayList<>(); when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); Loading Loading
android/app/src/com/android/bluetooth/telephony/BluetoothCall.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.bluetooth.telephony; import android.bluetooth.BluetoothLeCallControl; import android.net.Uri; import android.os.Bundle; import android.os.Handler; Loading Loading @@ -48,6 +47,9 @@ public class BluetoothCall { private Call mCall; private UUID mCallId; // An index used to identify calls for CLCC (C* List Current Calls). int mClccIndex = -1; public Call getCall() { return mCall; } Loading
android/app/src/com/android/bluetooth/telephony/BluetoothInCallService.java +128 −89 Original line number Diff line number Diff line Loading @@ -59,11 +59,12 @@ import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Queue; import java.util.SortedMap; import java.util.SortedSet; import java.util.TreeMap; import java.util.TreeSet; import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; Loading Loading @@ -139,14 +140,9 @@ public class BluetoothInCallService extends InCallService { private final HashMap<Integer, BluetoothCall> mBluetoothConferenceCallInference = new HashMap<>(); private final Map<String, Integer> mClccInferenceIndexMap = new HashMap<>(); // A queue record the removal order of bluetooth calls private final Queue<Integer> mBluetoothCallQueue = new ArrayDeque<>(); // A map from Calls to indexes used to identify calls for CLCC (C* List Current Calls). private final Map<String, Integer> mClccIndexMap = new HashMap<>(); private static BluetoothInCallService sInstance = null; public CallInfo mCallInfo = new CallInfo(); Loading Loading @@ -652,11 +648,6 @@ public class BluetoothInCallService extends InCallService { Log.d(TAG, "add inference call with reason: " + cause.getReason()); mBluetoothCallQueue.add(call.getId()); mBluetoothConferenceCallInference.put(call.getId(), call); Integer indexValue = mClccIndexMap.get(getClccMapKey(call)); mClccInferenceIndexMap.put(getClccMapKey(call), indexValue); if (indexValue == null) { Log.w(TAG, "CLCC index value is null"); } // queue size limited to 2 because merge operation only happens on 2 calls // we are only interested in last 2 calls merged if (mBluetoothCallQueue.size() > 2) { Loading @@ -669,12 +660,10 @@ public class BluetoothInCallService extends InCallService { if (call.isConference()) { Log.d(TAG, "conference call ends, clear inference"); mBluetoothConferenceCallInference.clear(); mClccInferenceIndexMap.clear(); mBluetoothCallQueue.clear(); } } mClccIndexMap.remove(getClccMapKey(call)); updateHeadsetWithCallState(false /* force */); if (mBluetoothLeCallControl != null) { Loading Loading @@ -748,9 +737,7 @@ public class BluetoothInCallService extends InCallService { sInstance = null; mCallbacks.clear(); mBluetoothCallHashMap.clear(); mClccIndexMap.clear(); mBluetoothConferenceCallInference.clear(); mClccInferenceIndexMap.clear(); mBluetoothCallQueue.clear(); mMaxNumberOfCalls = 0; } Loading @@ -766,10 +753,13 @@ public class BluetoothInCallService extends InCallService { boolean isInferenceEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH, CLCC_INFERENCE, false); Log.d(TAG, "is conference call inference enabled: " + isInferenceEnabled); // either do conference call CLCC index inference or normal conference call BluetoothCall conferenceCallChildrenNotReady = null; for (BluetoothCall call : calls) { if (isInferenceEnabled && call.isConference() // find the conference call parent among calls if (isInferenceEnabled && call.isConference() && !mBluetoothConferenceCallInference.isEmpty()) { SortedMap<Integer, Object[]> clccResponseMap = new TreeMap<>(); Log.d( TAG, "conference call inferred size: " Loading @@ -777,25 +767,55 @@ public class BluetoothInCallService extends InCallService { + " current size: " + mBluetoothCallHashMap.size()); // Do conference call inference until at least 2 children arrive // If carrier does send children info, then inference will end when info arrives. // If carrier does not send children info, then inference won't impact actual value. // If carrier sends children info, then inference will end when info arrives. // If carrier doesn't send children info, then inference won't impact actual value. if (call.getChildrenIds().size() >= 2) { mBluetoothConferenceCallInference.clear(); break; } conferenceCallChildrenNotReady = call; } } if (conferenceCallChildrenNotReady != null) { SortedMap<Integer, Object[]> clccResponseMap = new TreeMap<>(); for (BluetoothCall inferredCall : mBluetoothConferenceCallInference.values()) { String clccMapKey = getClccMapKey(inferredCall); if (!mClccInferenceIndexMap.containsKey(clccMapKey)) { Log.w(TAG, "Inference Index Map does not have: " + clccMapKey); if (inferredCall.isCallNull() || inferredCall.getHandle() == null) { Log.w(TAG, "inferredCall does not have handle"); continue; } if (mClccInferenceIndexMap.get(clccMapKey) == null) { Log.w(TAG, "inferred index is null"); // save the index so later on when real children arrive, index is the same int index = inferredCall.mClccIndex; if (index == -1) { Log.w(TAG, "inferred index is not valid"); continue; } int index = mClccInferenceIndexMap.get(clccMapKey); // save the index so later on when real children arrive, index is the same mClccIndexMap.put(clccMapKey, index); // associate existing bluetoothCall with inferredCall based on call handle for (BluetoothCall bluetoothCall : mBluetoothCallHashMap.values()) { if (bluetoothCall.getHandle() == null) { Log.w(TAG, "call id: " + bluetoothCall.getId() + " handle is null"); continue; } if (mTelephonyManager == null) { Log.w(TAG, "mTelephonyManager is null"); continue; } boolean isSame = PhoneNumberUtils.areSamePhoneNumber( bluetoothCall.getHandle().toString(), inferredCall.getHandle().toString(), mTelephonyManager.getNetworkCountryIso()); if (isSame) { Log.d( TAG, "found conference call children that has same call handle, " + "call id: " + bluetoothCall.getId()); bluetoothCall.mClccIndex = inferredCall.mClccIndex; break; } } int direction = inferredCall.isIncoming() ? 1 : 0; int state = CALL_STATE_ACTIVE; boolean isPartOfConference = true; Loading @@ -809,15 +829,14 @@ public class BluetoothInCallService extends InCallService { if (address != null) { address = PhoneNumberUtils.stripSeparators(address); } int addressType = address == null ? -1 : PhoneNumberUtils.toaFromString(address); int addressType = address == null ? -1 : PhoneNumberUtils.toaFromString(address); clccResponseMap.put( index, new Object[] { index, direction, state, 0, isPartOfConference, address, addressType }); } // ensure response is sorted by index // sort CLCC response based on index for (Object[] response : clccResponseMap.values()) { if (response.length < 7) { Log.e(TAG, "clccResponseMap entry too short"); Loading Loading @@ -845,15 +864,18 @@ public class BluetoothInCallService extends InCallService { sendClccEndMarker(); return; } } for (BluetoothCall call : calls) { // We don't send the parent conference BluetoothCall to the bluetooth device. // We do, however want to send conferences that have no children to the bluetooth // device (e.g. IMS Conference). boolean isConferenceWithNoChildren = isConferenceWithNoChildren(call); Log.i(TAG, "sendListOfCalls isConferenceWithNoChildren " + isConferenceWithNoChildren + ", call.getChildrenIds() size " + call.getChildrenIds().size()); Log.i( TAG, "sendListOfCalls isConferenceWithNoChildren " + isConferenceWithNoChildren + ", call.getChildrenIds() size " + call.getChildrenIds().size()); if (!call.isConference() || isConferenceWithNoChildren) { sendClccForCall(call, shouldLog); } Loading Loading @@ -985,31 +1007,48 @@ public class BluetoothInCallService extends InCallService { return key; } int getNextAvailableClccIndex(int index) { // find the next available smallest index SortedSet<Integer> availableIndex = new TreeSet<>(); for (int i = index; i <= mMaxNumberOfCalls + 1; i++) { availableIndex.add(i); } for (BluetoothCall bluetoothCall : mBluetoothCallHashMap.values()) { int callCLCCIndex = bluetoothCall.mClccIndex; if (availableIndex.contains(callCLCCIndex)) { availableIndex.remove(callCLCCIndex); } } Log.d(TAG, "availableIndex first: " + availableIndex.first()); return availableIndex.first(); } /** * Returns the caches index for the specified call. If no such index exists, then an index is * given (smallest number starting from 1 that isn't already taken). * given (the smallest number starting from 1 that isn't already taken). */ private int getIndexForCall(BluetoothCall call) { String key = getClccMapKey(call); if (mClccIndexMap.containsKey(key)) { return mClccIndexMap.get(key); if (mCallInfo.isNullCall(call)) { Log.w(TAG, "empty or null call"); return -1; } if (call.mClccIndex >= 1) { return call.mClccIndex; } int index = 1; // Indexes for bluetooth clcc are 1-based. if (call.isConference()) { index = mMaxNumberOfCalls + 1; // The conference call should have a higher index Log.i(TAG, "getIndexForCall for conference call starting from " + mMaxNumberOfCalls); } while (mClccIndexMap.containsValue(index)) { index++; Log.i(TAG, "getIndexForCall for conference call starting from " + mMaxNumberOfCalls); } // NOTE: Indexes are removed in {@link #onCallRemoved}. mClccIndexMap.put(key, index); return index; call.mClccIndex = getNextAvailableClccIndex(index); Log.d(TAG, "call " + call.getId() + " CLCC index is " + call.mClccIndex); return call.mClccIndex; } private boolean _processChld(int chld) { BluetoothCall activeCall = mCallInfo.getActiveCall(); BluetoothCall ringingCall = mCallInfo.getRingingOrSimulatedRingingCall(); Loading
android/app/tests/unit/src/com/android/bluetooth/telephony/BluetoothInCallServiceTest.java +50 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ import java.util.concurrent.TimeUnit; @MediumTest @RunWith(AndroidJUnit4.class) public class BluetoothInCallServiceTest { private static final String TAG = "BluetoothInCallServiceTest"; private static final int TEST_DTMF_TONE = 0; private static final String TEST_ACCOUNT_ADDRESS = "//foo.com/"; Loading Loading @@ -553,6 +554,53 @@ public class BluetoothInCallServiceTest { anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt()); } @Test public void testListCurrentCallsCallHandleChanged() throws Exception { mBluetoothInCallService.mTelephonyManager = mMockTelephonyManager; when(mMockTelephonyManager.getNetworkCountryIso()).thenReturn(""); ArrayList<BluetoothCall> calls = new ArrayList<>(); when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); BluetoothCall activeCall = createForegroundCall(UUID.randomUUID()); calls.add(activeCall); mBluetoothInCallService.onCallAdded(activeCall); when(activeCall.getState()).thenReturn(Call.STATE_ACTIVE); when(activeCall.isIncoming()).thenReturn(true); when(activeCall.isConference()).thenReturn(false); when(activeCall.getHandle()).thenReturn(Uri.parse("tel:2135550000")); Log.w(TAG, "call handle" + Uri.parse("tel:2135550000")); when(activeCall.getGatewayInfo()) .thenReturn(new GatewayInfo(null, null, Uri.parse("tel:2135550000"))); clearInvocations(mMockBluetoothHeadset); mBluetoothInCallService.listCurrentCalls(); verify(mMockBluetoothHeadset) .clccResponse( 1, 1, CALL_STATE_ACTIVE, 0, false, "2135550000", PhoneNumberUtils.TOA_Unknown); // call handle changed when(activeCall.getHandle()).thenReturn(Uri.parse("tel:213-555-0000")); clearInvocations(mMockBluetoothHeadset); Log.w(TAG, "call handle" + Uri.parse("tel:213-555-0000")); mBluetoothInCallService.listCurrentCalls(); verify(mMockBluetoothHeadset) .clccResponse( 1, 1, CALL_STATE_ACTIVE, 0, false, "2135550000", PhoneNumberUtils.TOA_Unknown); } @Test public void testRingingCallClccResponse() throws Exception { ArrayList<BluetoothCall> calls = new ArrayList<>(); Loading Loading @@ -771,6 +819,8 @@ public class BluetoothInCallServiceTest { @Test public void testListCurrentCallsConferenceEmptyChildrenInference() throws Exception { DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BLUETOOTH, CLCC_INFERENCE, "true", false); mBluetoothInCallService.mTelephonyManager = mMockTelephonyManager; when(mMockTelephonyManager.getNetworkCountryIso()).thenReturn(""); ArrayList<BluetoothCall> calls = new ArrayList<>(); when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls); Loading