Revert "UpdateAbility: Implement BluetoothInCallService and its ..."
Revert "Bluetooth updateability: Move BluetoothPhoneService out ..."
Revert "Updateability: Remove IBluetoothHeadsetPhone aidl"
Revert submission 1311861-BluetoothInCallService
Reason for revert: Bug: 176883407
Reverted Changes:
Ie3a5ceda5:UpdateAbility: Implement BluetoothInCallService an...
I2e3bc64eb:Updateability: Remove IBluetoothHeadsetPhone aidl
If26bab4ad:Bluetooth updateability: Move BluetoothPhoneServic...
Revert changes for droid food for now.
Change-Id: I8c823f44667ac6a238f7faa0ad12ece94d45803d
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 749e65e..158504b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -26,7 +26,6 @@
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"/>
<uses-permission android:name="android.permission.BLUETOOTH_MAP"/>
- <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
<uses-permission android:name="android.permission.DUMP"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
@@ -425,17 +424,5 @@
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator"/>
</service>
- <service
- android:name=".hfp.BluetoothInCallService"
- android:permission="android.permission.BIND_INCALL_SERVICE"
- android:process="@string/process"
- android:enabled="@bool/profile_supported_hfp_incallservice"
- android:exported="true">
- <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
- android:value="true" />
- <intent-filter>
- <action android:name="android.telecom.InCallService"/>
- </intent-filter>
- </service>
</application>
</manifest>
diff --git a/res/values/config.xml b/res/values/config.xml
index 484253d..9a1c5b1 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -17,7 +17,6 @@
<bool name="profile_supported_a2dp_sink">false</bool>
<bool name="profile_supported_hs_hfp">true</bool>
<bool name="profile_supported_hfpclient">false</bool>
- <bool name="profile_supported_hfp_incallservice">true</bool>
<bool name="profile_supported_hid_host">true</bool>
<bool name="profile_supported_opp">true</bool>
<bool name="profile_supported_pan">true</bool>
diff --git a/src/com/android/bluetooth/btservice/AdapterState.java b/src/com/android/bluetooth/btservice/AdapterState.java
index 570239b..8596627 100644
--- a/src/com/android/bluetooth/btservice/AdapterState.java
+++ b/src/com/android/bluetooth/btservice/AdapterState.java
@@ -17,13 +17,9 @@
package com.android.bluetooth.btservice;
import android.bluetooth.BluetoothAdapter;
-import android.content.ComponentName;
-import android.content.pm.PackageManager;
import android.os.Message;
import android.util.Log;
-import com.android.bluetooth.R;
-import com.android.bluetooth.hfp.BluetoothInCallService;
import com.android.bluetooth.statemachine.State;
import com.android.bluetooth.statemachine.StateMachine;
@@ -79,10 +75,6 @@
static final int BREDR_START_TIMEOUT_DELAY = 4000;
static final int BREDR_STOP_TIMEOUT_DELAY = 4000;
- static final ComponentName BLUETOOTH_INCALLSERVICE_COMPONENT
- = new ComponentName(R.class.getPackage().getName(),
- BluetoothInCallService.class.getCanonicalName());
-
private AdapterService mAdapterService;
private TurningOnState mTurningOnState = new TurningOnState();
private TurningBleOnState mTurningBleOnState = new TurningBleOnState();
@@ -231,24 +223,6 @@
}
@Override
- public void enter() {
- super.enter();
- mAdapterService.getPackageManager().setComponentEnabledSetting(
- BLUETOOTH_INCALLSERVICE_COMPONENT,
- PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
- PackageManager.DONT_KILL_APP);
- }
-
- @Override
- public void exit() {
- mAdapterService.getPackageManager().setComponentEnabledSetting(
- BLUETOOTH_INCALLSERVICE_COMPONENT,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- super.exit();
- }
-
- @Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case USER_TURN_OFF:
diff --git a/src/com/android/bluetooth/hfp/BluetoothCall.java b/src/com/android/bluetooth/hfp/BluetoothCall.java
deleted file mode 100644
index edd696e..0000000
--- a/src/com/android/bluetooth/hfp/BluetoothCall.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2020 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.hfp;
-
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.telecom.Call;
-import android.telecom.GatewayInfo;
-import android.telecom.InCallService;
-import android.telecom.PhoneAccountHandle;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A proxy class of android.telecom.Call that
- * 1) facilitates testing of the BluetoothInCallService class; We can't mock the final class
- * Call directly;
- * 2) Some helper functions, to let Call have same methods as com.android.server.telecom.Call
- *
- * This is necessary due to the "final" attribute of the Call class. In order to
- * test the correct functioning of the BluetoothInCallService class, the final class must be put
- * into a container that can be mocked correctly.
- */
-@VisibleForTesting
-public class BluetoothCall {
-
- private Call mCall;
-
- public Call getCall() {
- return mCall;
- }
-
- public void setCall(Call call) {
- mCall = call;
- }
-
- public BluetoothCall(Call call) {
- mCall = call;
- }
-
- public String getRemainingPostDialSequence() {
- return mCall.getRemainingPostDialSequence();
- }
-
- public void answer(int videoState) {
- mCall.answer(videoState);
- }
-
- public void deflect(Uri address) {
- mCall.deflect(address);
- }
-
- public void reject(boolean rejectWithMessage, String textMessage) {
- mCall.reject(rejectWithMessage, textMessage);
- }
-
- public void disconnect() {
- mCall.disconnect();
- }
-
- public void hold() {
- mCall.hold();
- }
-
- public void unhold() {
- mCall.unhold();
- }
-
- public void enterBackgroundAudioProcessing() {
- mCall.enterBackgroundAudioProcessing();
- }
-
- public void exitBackgroundAudioProcessing(boolean shouldRing) {
- mCall.exitBackgroundAudioProcessing(shouldRing);
- }
-
- public void playDtmfTone(char digit) {
- mCall.playDtmfTone(digit);
- }
-
- public void stopDtmfTone() {
- mCall.stopDtmfTone();
- }
-
- public void postDialContinue(boolean proceed) {
- mCall.postDialContinue(proceed);
- }
-
- public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
- mCall.phoneAccountSelected(accountHandle, setDefault);
- }
-
- public void conference(BluetoothCall callToConferenceWith) {
- if (callToConferenceWith != null) {
- mCall.conference(callToConferenceWith.getCall());
- }
- }
-
- public void splitFromConference() {
- mCall.splitFromConference();
- }
-
- public void mergeConference() {
- mCall.mergeConference();
- }
-
- public void swapConference() {
- mCall.swapConference();
- }
-
- public void pullExternalCall() {
- mCall.pullExternalCall();
- }
-
- public void sendCallEvent(String event, Bundle extras) {
- mCall.sendCallEvent(event, extras);
- }
-
- public void sendRttRequest() {
- mCall.sendRttRequest();
- }
-
- public void respondToRttRequest(int id, boolean accept) {
- mCall.respondToRttRequest(id, accept);
- }
-
- public void handoverTo(PhoneAccountHandle toHandle, int videoState, Bundle extras) {
- mCall.handoverTo(toHandle, videoState, extras);
- }
-
- public void stopRtt() {
- mCall.stopRtt();
- }
-
- public void putExtras(Bundle extras) {
- mCall.putExtras(extras);
- }
-
- public void putExtra(String key, boolean value) {
- mCall.putExtra(key, value);
- }
-
- public void putExtra(String key, int value) {
- mCall.putExtra(key, value);
- }
-
- public void putExtra(String key, String value) {
- mCall.putExtra(key, value);
- }
-
- public void removeExtras(List<String> keys) {
- mCall.removeExtras(keys);
- }
-
- public void removeExtras(String... keys) {
- mCall.removeExtras(keys);
- }
-
- public String getParentId() {
- Call parent = mCall.getParent();
- if (parent != null) {
- return parent.getDetails().getTelecomCallId();
- }
- return null;
- }
-
- public List<String> getChildrenIds() {
- return getIds(mCall.getChildren());
- }
-
- public List<String> getConferenceableCalls() {
- return getIds(mCall.getConferenceableCalls());
- }
-
- public int getState() {
- return mCall.getState();
- }
-
- public List<String> getCannedTextResponses() {
- return mCall.getCannedTextResponses();
- }
-
- public InCallService.VideoCall getVideoCall() {
- return mCall.getVideoCall();
- }
-
- public Call.Details getDetails() {
- return mCall.getDetails();
- }
-
- public Call.RttCall getRttCall() {
- return mCall.getRttCall();
- }
-
- public boolean isRttActive() {
- return mCall.isRttActive();
- }
-
- public void registerCallback(Call.Callback callback) {
- mCall.registerCallback(callback);
- }
-
- public void registerCallback(Call.Callback callback, Handler handler) {
- mCall.registerCallback(callback, handler);
- }
-
- public void unregisterCallback(Call.Callback callback) {
- mCall.unregisterCallback(callback);
- }
-
- public String toString() {
- String string = mCall.toString();
- return string == null ? "" : string;
- }
-
- public void addListener(Call.Listener listener) {
- mCall.addListener(listener);
- }
-
- public void removeListener(Call.Listener listener) {
- mCall.removeListener(listener);
- }
-
- public String getGenericConferenceActiveChildCallId() {
- return mCall.getGenericConferenceActiveChildCall().getDetails().getTelecomCallId();
- }
-
- public String getContactDisplayName() {
- return mCall.getDetails().getContactDisplayName();
- }
-
- public PhoneAccountHandle getAccountHandle() {
- return mCall.getDetails().getAccountHandle();
- }
-
- public int getVideoState() {
- return mCall.getDetails().getVideoState();
- }
-
- public String getCallerDisplayName() {
- return mCall.getDetails().getCallerDisplayName();
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == null) {
- return getCall() == null;
- }
- return o instanceof BluetoothCall && getCall() == ((BluetoothCall) o).getCall();
- }
-
- // helper functions
- public boolean isSilentRingingRequested() {
- return getDetails().getExtras().getBoolean(Call.EXTRA_SILENT_RINGING_REQUESTED);
- }
-
- public boolean isConference() {
- return getDetails().hasProperty(Call.Details.PROPERTY_CONFERENCE);
- }
-
- public boolean can(int capability) {
- return getDetails().can(capability);
- }
-
- public Uri getHandle() {
- return getDetails().getHandle();
- }
-
- public GatewayInfo getGatewayInfo() {
- return getDetails().getGatewayInfo();
- }
-
- public boolean isIncoming() {
- return getDetails().getCallDirection() == Call.Details.DIRECTION_INCOMING;
- }
-
- public boolean isExternalCall() {
- return getDetails().hasProperty(Call.Details.PROPERTY_IS_EXTERNAL_CALL);
- }
-
- public String getTelecomCallId() {
- return getDetails().getTelecomCallId();
- }
-
- public boolean wasConferencePreviouslyMerged() {
- return can(Call.Details.CAPABILITY_SWAP_CONFERENCE) &&
- !can(Call.Details.CAPABILITY_MERGE_CONFERENCE);
- }
-
- public static List<String> getIds(List<Call> calls) {
- List<String> result = new ArrayList<>();
- for (Call call : calls) {
- if (call != null) {
- result.add(call.getDetails().getTelecomCallId());
- }
- }
- return result;
- }
-}
diff --git a/src/com/android/bluetooth/hfp/BluetoothHeadsetProxy.java b/src/com/android/bluetooth/hfp/BluetoothHeadsetProxy.java
deleted file mode 100644
index 824955d..0000000
--- a/src/com/android/bluetooth/hfp/BluetoothHeadsetProxy.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2020 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.hfp;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-
-import java.util.List;
-
-/**
- * A proxy class that facilitates testing of the BluetoothInCallService class.
- *
- * This is necessary due to the "final" attribute of the BluetoothHeadset class. In order to
- * test the correct functioning of the BluetoothInCallService class, the final class must be put
- * into a container that can be mocked correctly.
- */
-public class BluetoothHeadsetProxy {
-
- private BluetoothHeadset mBluetoothHeadset;
-
- public BluetoothHeadsetProxy(BluetoothHeadset headset) {
- mBluetoothHeadset = headset;
- }
-
- public void clccResponse(int index, int direction, int status, int mode, boolean mpty,
- String number, int type) {
-
- mBluetoothHeadset.clccResponse(index, direction, status, mode, mpty, number, type);
- }
-
- public void phoneStateChanged(int numActive, int numHeld, int callState, String number,
- int type, String name) {
-
- mBluetoothHeadset.phoneStateChanged(numActive, numHeld, callState, number, type,
- name);
- }
-
- public List<BluetoothDevice> getConnectedDevices() {
- return mBluetoothHeadset.getConnectedDevices();
- }
-
- public int getConnectionState(BluetoothDevice device) {
- return mBluetoothHeadset.getConnectionState(device);
- }
-
- public int getAudioState(BluetoothDevice device) {
- return mBluetoothHeadset.getAudioState(device);
- }
-
- public boolean connectAudio() {
- return mBluetoothHeadset.connectAudio();
- }
-
- public boolean setActiveDevice(BluetoothDevice device) {
- return mBluetoothHeadset.setActiveDevice(device);
- }
-
- public BluetoothDevice getActiveDevice() {
- return mBluetoothHeadset.getActiveDevice();
- }
-
- public boolean isAudioOn() {
- return mBluetoothHeadset.isAudioOn();
- }
-
- public boolean disconnectAudio() {
- return mBluetoothHeadset.disconnectAudio();
- }
-
- public boolean isInbandRingingEnabled() {
- return mBluetoothHeadset.isInbandRingingEnabled();
- }
-}
diff --git a/src/com/android/bluetooth/hfp/BluetoothInCallService.java b/src/com/android/bluetooth/hfp/BluetoothInCallService.java
deleted file mode 100644
index 0561794..0000000
--- a/src/com/android/bluetooth/hfp/BluetoothInCallService.java
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- * Copyright (C) 2020 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.hfp;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothProfile;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.IBinder;
-import android.telecom.Call;
-import android.telecom.CallAudioState;
-import android.telecom.Connection;
-import android.telecom.InCallService;
-import android.telecom.PhoneAccount;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import android.telecom.VideoProfile;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Used to receive updates about calls from the Telecom component. This service is bound to Telecom
- * while there exist calls which potentially require UI. This includes ringing (incoming), dialing
- * (outgoing), and active calls. When the last BluetoothCall is disconnected, Telecom will unbind
- * to the service triggering InCallActivity (via CallList) to finish soon after.
- */
-public class BluetoothInCallService extends InCallService {
-
- private static final String TAG = "BluetoothInCallService";
-
- // match up with bthf_call_state_t of bt_hf.h
- private static final int CALL_STATE_ACTIVE = 0;
- private static final int CALL_STATE_HELD = 1;
- private static final int CALL_STATE_DIALING = 2;
- private static final int CALL_STATE_ALERTING = 3;
- private static final int CALL_STATE_INCOMING = 4;
- private static final int CALL_STATE_WAITING = 5;
- private static final int CALL_STATE_IDLE = 6;
- private static final int CALL_STATE_DISCONNECTED = 7;
-
- // match up with bthf_call_state_t of bt_hf.h
- // Terminate all held or set UDUB("busy") to a waiting call
- private static final int CHLD_TYPE_RELEASEHELD = 0;
- // Terminate all active calls and accepts a waiting/held call
- private static final int CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD = 1;
- // Hold all active calls and accepts a waiting/held call
- private static final int CHLD_TYPE_HOLDACTIVE_ACCEPTHELD = 2;
- // Add all held calls to a conference
- private static final int CHLD_TYPE_ADDHELDTOCONF = 3;
-
- // Indicates that no BluetoothCall is ringing
- private static final int DEFAULT_RINGING_ADDRESS_TYPE = 128;
-
- private int mNumActiveCalls = 0;
- private int mNumHeldCalls = 0;
- private int mNumChildrenOfActiveCall = 0;
- private int mBluetoothCallState = CALL_STATE_IDLE;
- private String mRingingAddress = "";
- private int mRingingAddressType = DEFAULT_RINGING_ADDRESS_TYPE;
- private BluetoothCall mOldHeldCall = null;
- private boolean mHeadsetUpdatedRecently = false;
- private boolean mIsDisconnectedTonePlaying = false;
-
- private static final Object LOCK = new Object();
- private BluetoothHeadsetProxy mBluetoothHeadset;
-
- @VisibleForTesting
- public TelephonyManager mTelephonyManager;
-
- @VisibleForTesting
- public TelecomManager mTelecomManager;
-
- @VisibleForTesting
- public final HashMap<String, CallStateCallback> mCallbacks = new HashMap<>();
-
- @VisibleForTesting
- public final HashMap<String, BluetoothCall> mBluetoothCallHashMap = new HashMap<>();
-
- // A map from Calls to indexes used to identify calls for CLCC (C* List Current Calls).
- private final Map<BluetoothCall, Integer> mClccIndexMap = new HashMap<>();
-
- private static BluetoothInCallService sInstance;
-
- public CallInfo mCallInfo = new CallInfo();
-
- /**
- * Listens to connections and disconnections of bluetooth headsets. We need to save the current
- * bluetooth headset so that we know where to send BluetoothCall updates.
- */
- @VisibleForTesting
- public BluetoothProfile.ServiceListener mProfileListener =
- new BluetoothProfile.ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- synchronized (LOCK) {
- setBluetoothHeadset(new BluetoothHeadsetProxy((BluetoothHeadset) proxy));
- updateHeadsetWithCallState(true /* force */);
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- synchronized (LOCK) {
- setBluetoothHeadset(null);
- }
- }
- };
-
- /**
- * Receives events for global state changes of the bluetooth adapter.
- */
- // TODO: The code is moved from Telecom stack. Since we're running in the BT process itself,
- // we may be able to simplify this in a future patch.
- @VisibleForTesting
- public final BroadcastReceiver mBluetoothAdapterReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (LOCK) {
- int state = intent
- .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
- Log.d(TAG, "Bluetooth Adapter state: " + state);
- if (state == BluetoothAdapter.STATE_ON) {
- queryPhoneState();
- }
- }
- }
- };
-
- @VisibleForTesting
- public class CallStateCallback extends Call.Callback {
- public int mLastState;
-
- public CallStateCallback(int initialState) {
- mLastState = initialState;
- }
-
- public int getLastState() {
- return mLastState;
- }
-
- public void onStateChanged(BluetoothCall call, int state) {
- if (mCallInfo.isNullCall(call)) {
- return;
- }
- if (call.isExternalCall()) {
- return;
- }
-
- // If a BluetoothCall is being put on hold because of a new connecting call, ignore the
- // CONNECTING since the BT state update needs to send out the numHeld = 1 + dialing
- // state atomically.
- // When the BluetoothCall later transitions to DIALING/DISCONNECTED we will then
- // send out the aggregated update.
- if (getLastState() == Call.STATE_ACTIVE && state == Call.STATE_HOLDING) {
- for (BluetoothCall otherCall : mCallInfo.getBluetoothCalls()) {
- if (otherCall.getState() == Call.STATE_CONNECTING) {
- mLastState = state;
- return;
- }
- }
- }
-
- // To have an active BluetoothCall and another dialing at the same time is an invalid BT
- // state. We can assume that the active BluetoothCall will be automatically held
- // which will send another update at which point we will be in the right state.
- BluetoothCall activeCall = mCallInfo.getActiveCall();
- if (!mCallInfo.isNullCall(activeCall)
- && getLastState() == Call.STATE_CONNECTING
- && (state == Call.STATE_DIALING || state == Call.STATE_PULLING_CALL)) {
- mLastState = state;
- return;
- }
- mLastState = state;
- updateHeadsetWithCallState(false /* force */);
- }
-
- @Override
- public void onStateChanged(Call call, int state) {
- super.onStateChanged(call, state);
- onStateChanged(getBluetoothCallById(call.getDetails().getTelecomCallId()), state);
- }
-
- public void onDetailsChanged(BluetoothCall call, Call.Details details) {
- if (mCallInfo.isNullCall(call)) {
- return;
- }
- if (call.isExternalCall()) {
- onCallRemoved(call);
- } else {
- onCallAdded(call);
- }
- }
-
- @Override
- public void onDetailsChanged(Call call, Call.Details details) {
- super.onDetailsChanged(call, details);
- onDetailsChanged(getBluetoothCallById(call.getDetails().getTelecomCallId()), details);
- }
-
- public void onParentChanged(BluetoothCall call, BluetoothCall parent) {
- if (call.isExternalCall()) {
- return;
- }
- if (call.getParentId() != null) {
- // If this BluetoothCall is newly conferenced, ignore the callback.
- // We only care about the one sent for the parent conference call.
- Log.d(TAG,
- "Ignoring onIsConferenceChanged from child BluetoothCall with new parent");
- return;
- }
- updateHeadsetWithCallState(false /* force */);
- }
-
- @Override
- public void onParentChanged(Call call, Call parent) {
- super.onParentChanged(call, parent);
- onParentChanged(
- getBluetoothCallById(call.getDetails().getTelecomCallId()),
- getBluetoothCallById(parent.getDetails().getTelecomCallId()));
- }
-
- public void onChildrenChanged(BluetoothCall call, List<BluetoothCall> children) {
- if (call.isExternalCall()) {
- return;
- }
- if (call.getChildrenIds().size() == 1) {
- // If this is a parent BluetoothCall with only one child,
- // ignore the callback as well since the minimum number of child calls to
- // start a conference BluetoothCall is 2. We expect this to be called again
- // when the parent BluetoothCall has another child BluetoothCall added.
- Log.d(TAG,
- "Ignoring onIsConferenceChanged from parent with only one child call");
- return;
- }
- updateHeadsetWithCallState(false /* force */);
- }
-
- @Override
- public void onChildrenChanged(Call call, List<Call> children) {
- super.onChildrenChanged(call, children);
- onChildrenChanged(
- getBluetoothCallById(call.getDetails().getTelecomCallId()),
- getBluetoothCallsByIds(BluetoothCall.getIds(children)));
- }
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- Log.i(TAG, "onBind. Intent: " + intent);
- BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
- Log.i(TAG, "Bluetooth is off");
- ComponentName componentName
- = new ComponentName(getPackageName(), this.getClass().getName());
- getPackageManager().setComponentEnabledSetting(
- componentName,
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
- return null;
- }
- IBinder binder = super.onBind(intent);
- IntentFilter intentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
- registerReceiver(mBluetoothAdapterReceiver, intentFilter);
- mTelephonyManager = getSystemService(TelephonyManager.class);
- mTelecomManager = getSystemService(TelecomManager.class);
- return binder;
- }
-
- @Override
- public boolean onUnbind(Intent intent) {
- Log.i(TAG, "onUnbind. Intent: " + intent);
- unregisterReceiver(mBluetoothAdapterReceiver);
- return super.onUnbind(intent);
- }
-
- public BluetoothInCallService() {
- Log.i(TAG, "onCreate");
- BluetoothAdapter.getDefaultAdapter()
- .getProfileProxy(this, mProfileListener, BluetoothProfile.HEADSET);
- sInstance = this;
- }
-
- public static BluetoothInCallService getInstance() {
- return sInstance;
- }
-
- protected void enforceModifyPermission() {
- enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
- }
-
- public boolean answerCall() {
- synchronized (LOCK) {
- enforceModifyPermission();
- Log.i(TAG, "BT - answering call");
- BluetoothCall call = mCallInfo.getRingingOrSimulatedRingingCall();
- if (mCallInfo.isNullCall(call)) {
- return false;
- }
- call.answer(VideoProfile.STATE_AUDIO_ONLY);
- return true;
- }
- }
-
- public boolean hangupCall() {
- synchronized (LOCK) {
- enforceModifyPermission();
- Log.i(TAG, "BT - hanging up call");
- BluetoothCall call = mCallInfo.getForegroundCall();
- if (mCallInfo.isNullCall(call)) {
- return false;
- }
- call.disconnect();
- return true;
- }
- }
-
- public boolean sendDtmf(int dtmf) {
- synchronized (LOCK) {
- enforceModifyPermission();
- Log.i(TAG, "BT - sendDtmf " + dtmf);
- BluetoothCall call = mCallInfo.getForegroundCall();
- if (mCallInfo.isNullCall(call)) {
- return false;
- }
- // TODO: Consider making this a queue instead of starting/stopping
- // in quick succession.
- call.playDtmfTone((char) dtmf);
- call.stopDtmfTone();
- return true;
- }
- }
-
- public String getNetworkOperator() {
- synchronized (LOCK) {
- enforceModifyPermission();
- Log.i(TAG, "getNetworkOperator");
- PhoneAccount account = mCallInfo.getBestPhoneAccount();
- if (account != null && account.getLabel() != null) {
- return account.getLabel().toString();
- }
- // Finally, just get the network name from telephony.
- return mTelephonyManager.getNetworkOperatorName();
- }
- }
-
- public String getSubscriberNumber() {
- synchronized (LOCK) {
- enforceModifyPermission();
- Log.i(TAG, "getSubscriberNumber");
- String address = null;
- PhoneAccount account = mCallInfo.getBestPhoneAccount();
- if (account != null) {
- Uri addressUri = account.getAddress();
- if (addressUri != null) {
- address = addressUri.getSchemeSpecificPart();
- }
- }
- if (TextUtils.isEmpty(address)) {
- address = mTelephonyManager.getLine1Number();
- if (address == null) address = "";
- }
- return address;
- }
- }
-
- public boolean listCurrentCalls() {
- synchronized (LOCK) {
- enforceModifyPermission();
- // only log if it is after we recently updated the headset state or else it can
- // clog the android log since this can be queried every second.
- boolean logQuery = mHeadsetUpdatedRecently;
- mHeadsetUpdatedRecently = false;
-
- if (logQuery) {
- Log.i(TAG, "listcurrentCalls");
- }
-
- sendListOfCalls(logQuery);
- return true;
- }
- }
-
- public boolean queryPhoneState() {
- synchronized (LOCK) {
- enforceModifyPermission();
- Log.i(TAG, "queryPhoneState");
- updateHeadsetWithCallState(true);
- return true;
- }
- }
-
- public boolean processChld(int chld) {
- synchronized (LOCK) {
- enforceModifyPermission();
- long token = Binder.clearCallingIdentity();
- Log.i(TAG, "processChld " + chld);
- return _processChld(chld);
- }
- }
-
- public void onCallAdded(BluetoothCall call) {
- if (call.isExternalCall()) {
- return;
- }
- if (!mBluetoothCallHashMap.containsKey(call.getTelecomCallId())) {
- Log.d(TAG, "onCallAdded");
- CallStateCallback callback = new CallStateCallback(call.getState());
- mCallbacks.put(call.getTelecomCallId(), callback);
- call.registerCallback(callback);
-
- mBluetoothCallHashMap.put(call.getTelecomCallId(), call);
- updateHeadsetWithCallState(false /* force */);
- }
- }
-
- @Override
- public void onCallAdded(Call call) {
- super.onCallAdded(call);
- onCallAdded(new BluetoothCall(call));
- }
-
- public void onCallRemoved(BluetoothCall call) {
- if (call.isExternalCall()) {
- return;
- }
- Log.d(TAG, "onCallRemoved");
- CallStateCallback callback = getCallback(call);
- if (callback != null) {
- call.unregisterCallback(callback);
- }
-
- if (mBluetoothCallHashMap.containsKey(call.getTelecomCallId())) {
- mBluetoothCallHashMap.remove(call.getTelecomCallId());
- }
-
- mClccIndexMap.remove(call);
- updateHeadsetWithCallState(false /* force */);
- }
-
- @Override
- public void onCallRemoved(Call call) {
- super.onCallRemoved(call);
- onCallRemoved(getBluetoothCallById(call.getDetails().getTelecomCallId()));
- }
-
- @Override
- public void onCallAudioStateChanged(CallAudioState audioState) {
- super.onCallAudioStateChanged(audioState);
- Log.d(TAG, "onCallAudioStateChanged, audioState == " + audioState);
- }
-
-
- @Override
- public void onCreate() {
- Log.d(TAG, "onCreate");
- super.onCreate();
- }
-
- @Override
- public void onDestroy() {
- Log.d(TAG, "onDestroy");
- super.onDestroy();
- }
-
- private void sendListOfCalls(boolean shouldLog) {
- Collection<BluetoothCall> calls = mCallInfo.getBluetoothCalls();
- 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).
- if (!call.isConference()
- || (call.isConference()
- && call.can(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN))) {
- sendClccForCall(call, shouldLog);
- }
- }
- sendClccEndMarker();
- }
-
- private void sendClccEndMarker() {
- // End marker is recognized with an index value of 0. All other parameters are ignored.
- if (mBluetoothHeadset != null) {
- mBluetoothHeadset.clccResponse(0 /* index */, 0, 0, 0, false, null, 0);
- }
- }
-
- /**
- * Sends a single clcc (C* List Current Calls) event for the specified call.
- */
- private void sendClccForCall(BluetoothCall call, boolean shouldLog) {
- boolean isForeground = mCallInfo.getForegroundCall() == call;
- int state = getBtCallState(call, isForeground);
- boolean isPartOfConference = false;
- boolean isConferenceWithNoChildren = call.isConference()
- && call.can(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
-
- if (state == CALL_STATE_IDLE) {
- return;
- }
-
- BluetoothCall conferenceCall = getBluetoothCallById(call.getParentId());
- if (!mCallInfo.isNullCall(conferenceCall)) {
- isPartOfConference = true;
-
- // Run some alternative states for Conference-level merge/swap support.
- // Basically, if BluetoothCall supports swapping or merging at the conference-level,
- // then we need to expose the calls as having distinct states
- // (ACTIVE vs CAPABILITY_HOLD) or
- // the functionality won't show up on the bluetooth device.
-
- // Before doing any special logic, ensure that we are dealing with an
- // ACTIVE BluetoothCall and that the conference itself has a notion of
- // the current "active" child call.
- BluetoothCall activeChild = getBluetoothCallById(
- conferenceCall.getGenericConferenceActiveChildCallId());
- if (state == CALL_STATE_ACTIVE && !mCallInfo.isNullCall(activeChild)) {
- // Reevaluate state if we can MERGE or if we can SWAP without previously having
- // MERGED.
- boolean shouldReevaluateState =
- conferenceCall.can(Connection.CAPABILITY_MERGE_CONFERENCE)
- || (conferenceCall.can(Connection.CAPABILITY_SWAP_CONFERENCE)
- && !conferenceCall.wasConferencePreviouslyMerged());
-
- if (shouldReevaluateState) {
- isPartOfConference = false;
- if (call == activeChild) {
- state = CALL_STATE_ACTIVE;
- } else {
- // At this point we know there is an "active" child and we know that it is
- // not this call, so set it to HELD instead.
- state = CALL_STATE_HELD;
- }
- }
- }
- if (conferenceCall.getState() == Call.STATE_HOLDING
- && conferenceCall.can(Connection.CAPABILITY_MANAGE_CONFERENCE)) {
- // If the parent IMS CEP conference BluetoothCall is on hold, we should mark
- // this BluetoothCall as being on hold regardless of what the other
- // children are doing.
- state = CALL_STATE_HELD;
- }
- } else if (isConferenceWithNoChildren) {
- // Handle the special case of an IMS conference BluetoothCall without conference
- // event package support.
- // The BluetoothCall will be marked as a conference, but the conference will not have
- // child calls where conference event packages are not used by the carrier.
- isPartOfConference = true;
- }
-
- int index = getIndexForCall(call);
- int direction = call.isIncoming() ? 1 : 0;
- final Uri addressUri;
- if (call.getGatewayInfo() != null) {
- addressUri = call.getGatewayInfo().getOriginalAddress();
- } else {
- addressUri = call.getHandle();
- }
-
- String address = addressUri == null ? null : addressUri.getSchemeSpecificPart();
- if (address != null) {
- address = PhoneNumberUtils.stripSeparators(address);
- }
-
- int addressType = address == null ? -1 : PhoneNumberUtils.toaFromString(address);
-
- if (shouldLog) {
- Log.i(TAG, "sending clcc for BluetoothCall "
- + index + ", "
- + direction + ", "
- + state + ", "
- + isPartOfConference + ", "
- + addressType);
- }
-
- if (mBluetoothHeadset != null) {
- mBluetoothHeadset.clccResponse(
- index, direction, state, 0, isPartOfConference, address, addressType);
- }
- }
-
- /**
- * 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).
- */
- private int getIndexForCall(BluetoothCall call) {
- if (mClccIndexMap.containsKey(call)) {
- return mClccIndexMap.get(call);
- }
-
- int i = 1; // Indexes for bluetooth clcc are 1-based.
- while (mClccIndexMap.containsValue(i)) {
- i++;
- }
-
- // NOTE: Indexes are removed in {@link #onCallRemoved}.
- mClccIndexMap.put(call, i);
- return i;
- }
-
- private boolean _processChld(int chld) {
- BluetoothCall activeCall = mCallInfo.getActiveCall();
- BluetoothCall ringingCall = mCallInfo.getRingingOrSimulatedRingingCall();
- if (ringingCall == null) {
- Log.i(TAG, "asdf ringingCall null");
- } else {
- Log.i(TAG, "asdf ringingCall not null " + ringingCall.hashCode());
- }
-
- BluetoothCall heldCall = mCallInfo.getHeldCall();
-
- Log.i(TAG, "Active: " + activeCall
- + " Ringing: " + ringingCall
- + " Held: " + heldCall);
- Log.i(TAG, "asdf chld " + chld);
-
- if (chld == CHLD_TYPE_RELEASEHELD) {
- Log.i(TAG, "asdf CHLD_TYPE_RELEASEHELD");
- if (!mCallInfo.isNullCall(ringingCall)) {
- Log.i(TAG, "asdf reject " + ringingCall.hashCode());
- ringingCall.reject(false, null);
- return true;
- } else if (!mCallInfo.isNullCall(heldCall)) {
- heldCall.disconnect();
- return true;
- }
- } else if (chld == CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD) {
- if (mCallInfo.isNullCall(activeCall)
- && mCallInfo.isNullCall(ringingCall)
- && mCallInfo.isNullCall(heldCall)) {
- return false;
- }
- if (!mCallInfo.isNullCall(activeCall)) {
- activeCall.disconnect();
- if (!mCallInfo.isNullCall(ringingCall)) {
- ringingCall.answer(VideoProfile.STATE_AUDIO_ONLY);
- }
- return true;
- }
- if (!mCallInfo.isNullCall(ringingCall)) {
- ringingCall.answer(ringingCall.getVideoState());
- } else if (!mCallInfo.isNullCall(heldCall)) {
- heldCall.unhold();
- }
- return true;
- } else if (chld == CHLD_TYPE_HOLDACTIVE_ACCEPTHELD) {
- if (!mCallInfo.isNullCall(activeCall)
- && activeCall.can(Connection.CAPABILITY_SWAP_CONFERENCE)) {
- activeCall.swapConference();
- Log.i(TAG, "CDMA calls in conference swapped, updating headset");
- updateHeadsetWithCallState(true /* force */);
- return true;
- } else if (!mCallInfo.isNullCall(ringingCall)) {
- ringingCall.answer(VideoProfile.STATE_AUDIO_ONLY);
- return true;
- } else if (!mCallInfo.isNullCall(heldCall)) {
- // CallsManager will hold any active calls when unhold() is called on a
- // currently-held call.
- heldCall.unhold();
- return true;
- } else if (!mCallInfo.isNullCall(activeCall)
- && activeCall.can(Connection.CAPABILITY_HOLD)) {
- activeCall.hold();
- return true;
- }
- } else if (chld == CHLD_TYPE_ADDHELDTOCONF) {
- if (!mCallInfo.isNullCall(activeCall)) {
- if (activeCall.can(Connection.CAPABILITY_MERGE_CONFERENCE)) {
- activeCall.mergeConference();
- return true;
- } else {
- List<BluetoothCall> conferenceable = getBluetoothCallsByIds(
- activeCall.getConferenceableCalls());
- if (!conferenceable.isEmpty()) {
- activeCall.conference(conferenceable.get(0));
- return true;
- }
- }
- }
- }
- return false;
- }
-
- /**
- * Sends an update of the current BluetoothCall state to the current Headset.
- *
- * @param force {@code true} if the headset state should be sent regardless if no changes to
- * the state have occurred, {@code false} if the state should only be sent if the state
- * has changed.
- */
- private void updateHeadsetWithCallState(boolean force) {
- BluetoothCall activeCall = mCallInfo.getActiveCall();
- BluetoothCall ringingCall = mCallInfo.getRingingOrSimulatedRingingCall();
- BluetoothCall heldCall = mCallInfo.getHeldCall();
-
- int bluetoothCallState = getBluetoothCallStateForUpdate();
-
- String ringingAddress = null;
- int ringingAddressType = DEFAULT_RINGING_ADDRESS_TYPE;
- String ringingName = null;
- if (!mCallInfo.isNullCall(ringingCall) && ringingCall.getHandle() != null
- && !ringingCall.isSilentRingingRequested()) {
- ringingAddress = ringingCall.getHandle().getSchemeSpecificPart();
- if (ringingAddress != null) {
- ringingAddressType = PhoneNumberUtils.toaFromString(ringingAddress);
- }
- ringingName = ringingCall.getCallerDisplayName();
- if (TextUtils.isEmpty(ringingName)) {
- ringingName = ringingCall.getContactDisplayName();
- }
- }
- if (ringingAddress == null) {
- ringingAddress = "";
- }
-
- int numActiveCalls = mCallInfo.isNullCall(activeCall) ? 0 : 1;
- int numHeldCalls = mCallInfo.getNumHeldCalls();
- int numChildrenOfActiveCall =
- mCallInfo.isNullCall(activeCall) ? 0 : activeCall.getChildrenIds().size();
-
- // Intermediate state for GSM calls which are in the process of being swapped.
- // TODO: Should we be hardcoding this value to 2 or should we check if all top level calls
- // are held?
- boolean callsPendingSwitch = (numHeldCalls == 2);
-
- // For conference calls which support swapping the active BluetoothCall within the
- // conference (namely CDMA calls) we need to expose that as a held BluetoothCall
- // in order for the BT device to show "swap" and "merge" functionality.
- boolean ignoreHeldCallChange = false;
- if (!mCallInfo.isNullCall(activeCall) && activeCall.isConference()
- && !activeCall.can(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
- if (activeCall.can(Connection.CAPABILITY_SWAP_CONFERENCE)) {
- // Indicate that BT device should show SWAP command by indicating that there is a
- // BluetoothCall on hold, but only if the conference wasn't previously merged.
- numHeldCalls = activeCall.wasConferencePreviouslyMerged() ? 0 : 1;
- } else if (activeCall.can(Connection.CAPABILITY_MERGE_CONFERENCE)) {
- numHeldCalls = 1; // Merge is available, so expose via numHeldCalls.
- }
-
- for (String id : activeCall.getChildrenIds()) {
- // Held BluetoothCall has changed due to it being combined into a CDMA conference.
- // Keep track of this and ignore any future update since it doesn't really count
- // as a BluetoothCall change.
- if (mOldHeldCall != null && mOldHeldCall.getTelecomCallId() == id) {
- ignoreHeldCallChange = true;
- break;
- }
- }
- }
-
- if (mBluetoothHeadset != null
- && (force
- || (!callsPendingSwitch
- && (numActiveCalls != mNumActiveCalls
- || numChildrenOfActiveCall != mNumChildrenOfActiveCall
- || numHeldCalls != mNumHeldCalls
- || bluetoothCallState != mBluetoothCallState
- || !TextUtils.equals(ringingAddress, mRingingAddress)
- || ringingAddressType != mRingingAddressType
- || (heldCall != mOldHeldCall && !ignoreHeldCallChange))))) {
-
- // If the BluetoothCall is transitioning into the alerting state, send DIALING first.
- // Some devices expect to see a DIALING state prior to seeing an ALERTING state
- // so we need to send it first.
- boolean sendDialingFirst = mBluetoothCallState != bluetoothCallState
- && bluetoothCallState == CALL_STATE_ALERTING;
-
- mOldHeldCall = heldCall;
- mNumActiveCalls = numActiveCalls;
- mNumChildrenOfActiveCall = numChildrenOfActiveCall;
- mNumHeldCalls = numHeldCalls;
- mBluetoothCallState = bluetoothCallState;
- mRingingAddress = ringingAddress;
- mRingingAddressType = ringingAddressType;
-
- if (sendDialingFirst) {
- // Log in full to make logs easier to debug.
- Log.i(TAG, "updateHeadsetWithCallState "
- + "numActive " + mNumActiveCalls + ", "
- + "numHeld " + mNumHeldCalls + ", "
- + "callState " + CALL_STATE_DIALING + ", "
- + "ringing type " + mRingingAddressType);
- mBluetoothHeadset.phoneStateChanged(
- mNumActiveCalls,
- mNumHeldCalls,
- CALL_STATE_DIALING,
- mRingingAddress,
- mRingingAddressType,
- ringingName);
- }
-
- Log.i(TAG, "updateHeadsetWithCallState "
- + "numActive " + mNumActiveCalls + ", "
- + "numHeld " + mNumHeldCalls + ", "
- + "callState " + mBluetoothCallState + ", "
- + "ringing type " + mRingingAddressType);
-
- mBluetoothHeadset.phoneStateChanged(
- mNumActiveCalls,
- mNumHeldCalls,
- mBluetoothCallState,
- mRingingAddress,
- mRingingAddressType,
- ringingName);
-
- mHeadsetUpdatedRecently = true;
- }
- }
-
- private int getBluetoothCallStateForUpdate() {
- BluetoothCall ringingCall = mCallInfo.getRingingOrSimulatedRingingCall();
- BluetoothCall dialingCall = mCallInfo.getOutgoingCall();
- boolean hasOnlyDisconnectedCalls = mCallInfo.hasOnlyDisconnectedCalls();
-
- //
- // !! WARNING !!
- // You will note that CALL_STATE_WAITING, CALL_STATE_HELD, and CALL_STATE_ACTIVE are not
- // used in this version of the BluetoothCall state mappings. This is on purpose.
- // phone_state_change() in btif_hf.c is not written to handle these states. Only with the
- // listCalls*() method are WAITING and ACTIVE used.
- // Using the unsupported states here caused problems with inconsistent state in some
- // bluetooth devices (like not getting out of ringing state after answering a call).
- //
- int bluetoothCallState = CALL_STATE_IDLE;
- if (!mCallInfo.isNullCall(ringingCall) && !ringingCall.isSilentRingingRequested()) {
- bluetoothCallState = CALL_STATE_INCOMING;
- } else if (!mCallInfo.isNullCall(dialingCall)) {
- bluetoothCallState = CALL_STATE_ALERTING;
- } else if (hasOnlyDisconnectedCalls || mIsDisconnectedTonePlaying) {
- // Keep the DISCONNECTED state until the disconnect tone's playback is done
- bluetoothCallState = CALL_STATE_DISCONNECTED;
- }
- return bluetoothCallState;
- }
-
- private int getBtCallState(BluetoothCall call, boolean isForeground) {
- switch (call.getState()) {
- case Call.STATE_NEW:
- case Call.STATE_DISCONNECTED:
- case Call.STATE_AUDIO_PROCESSING:
- return CALL_STATE_IDLE;
-
- case Call.STATE_ACTIVE:
- return CALL_STATE_ACTIVE;
-
- case Call.STATE_CONNECTING:
- case Call.STATE_SELECT_PHONE_ACCOUNT:
- case Call.STATE_DIALING:
- case Call.STATE_PULLING_CALL:
- // Yes, this is correctly returning ALERTING.
- // "Dialing" for BT means that we have sent information to the service provider
- // to place the BluetoothCall but there is no confirmation that the BluetoothCall
- // is going through. When there finally is confirmation, the ringback is
- // played which is referred to as an "alert" tone, thus, ALERTING.
- // TODO: We should consider using the ALERTING terms in Telecom because that
- // seems to be more industry-standard.
- return CALL_STATE_ALERTING;
-
- case Call.STATE_HOLDING:
- return CALL_STATE_HELD;
-
- case Call.STATE_RINGING:
- case Call.STATE_SIMULATED_RINGING:
- if (call.isSilentRingingRequested()) {
- return CALL_STATE_IDLE;
- } else if (isForeground) {
- return CALL_STATE_INCOMING;
- } else {
- return CALL_STATE_WAITING;
- }
- }
- return CALL_STATE_IDLE;
- }
-
- @VisibleForTesting
- public CallStateCallback getCallback(BluetoothCall call) {
- return mCallbacks.get(call.getTelecomCallId());
- }
-
- @VisibleForTesting
- public void setBluetoothHeadset(BluetoothHeadsetProxy bluetoothHeadset) {
- mBluetoothHeadset = bluetoothHeadset;
- }
-
- @VisibleForTesting
- public BluetoothCall getBluetoothCallById(String id) {
- if (mBluetoothCallHashMap.containsKey(id)) {
- return mBluetoothCallHashMap.get(id);
- }
- return null;
- }
-
- @VisibleForTesting
- public List<BluetoothCall> getBluetoothCallsByIds(List<String> ids) {
- List<BluetoothCall> calls = new ArrayList<>();
- for (String id : ids) {
- BluetoothCall call = getBluetoothCallById(id);
- if (!mCallInfo.isNullCall(call)) {
- calls.add(call);
- }
- }
- return calls;
- }
-
- // extract call information functions out into this part, so we can mock it in testing
- @VisibleForTesting
- public class CallInfo {
-
- public BluetoothCall getForegroundCall() {
- LinkedHashSet<Integer> states = new LinkedHashSet<Integer>();
- BluetoothCall foregroundCall;
-
- states.add(Call.STATE_CONNECTING);
- foregroundCall = getCallByStates(states);
- if (!mCallInfo.isNullCall(foregroundCall)) {
- return foregroundCall;
- }
-
- states.clear();
- states.add(Call.STATE_ACTIVE);
- states.add(Call.STATE_DIALING);
- states.add(Call.STATE_PULLING_CALL);
- foregroundCall = getCallByStates(states);
- if (!mCallInfo.isNullCall(foregroundCall)) {
- return foregroundCall;
- }
-
- states.clear();
- states.add(Call.STATE_RINGING);
- foregroundCall = getCallByStates(states);
- if (!mCallInfo.isNullCall(foregroundCall)) {
- return foregroundCall;
- }
-
- return null;
- }
-
- public BluetoothCall getCallByStates(LinkedHashSet<Integer> states) {
- List<BluetoothCall> calls = getBluetoothCalls();
- for (BluetoothCall call : calls) {
- if (states.contains(call.getState())) {
- return call;
- }
- }
- return null;
- }
-
- public BluetoothCall getCallByState(int state) {
- List<BluetoothCall> calls = getBluetoothCalls();
- for (BluetoothCall call : calls) {
- if (state == call.getState()) {
- return call;
- }
- }
- return null;
- }
-
- public int getNumHeldCalls() {
- int number = 0;
- List<BluetoothCall> calls = getBluetoothCalls();
- for (BluetoothCall call : calls) {
- if (call.getState() == Call.STATE_HOLDING) {
- number++;
- }
- }
- return number;
- }
-
- public boolean hasOnlyDisconnectedCalls() {
- List<BluetoothCall> calls = getBluetoothCalls();
- if (calls.size() == 0) {
- return false;
- }
- for (BluetoothCall call : calls) {
- if (call.getState() != Call.STATE_DISCONNECTED) {
- return false;
- }
- }
- return true;
- }
-
- public List<BluetoothCall> getBluetoothCalls() {
- return getBluetoothCallsByIds(BluetoothCall.getIds(getCalls()));
- }
-
- public BluetoothCall getOutgoingCall() {
- LinkedHashSet<Integer> states = new LinkedHashSet<Integer>();
- states.add(Call.STATE_CONNECTING);
- states.add(Call.STATE_DIALING);
- states.add(Call.STATE_PULLING_CALL);
- return getCallByStates(states);
- }
-
- public BluetoothCall getRingingOrSimulatedRingingCall() {
- LinkedHashSet<Integer> states = new LinkedHashSet<Integer>();
- states.add(Call.STATE_RINGING);
- states.add(Call.STATE_SIMULATED_RINGING);
- return getCallByStates(states);
- }
-
- public BluetoothCall getActiveCall() {
- return getCallByState(Call.STATE_ACTIVE);
- }
-
- public BluetoothCall getHeldCall() {
- return getCallByState(Call.STATE_HOLDING);
- }
-
- /**
- * Returns the best phone account to use for the given state of all calls.
- * First, tries to return the phone account for the foreground call, second the default
- * phone account for PhoneAccount.SCHEME_TEL.
- */
- public PhoneAccount getBestPhoneAccount() {
- BluetoothCall call = getForegroundCall();
-
- PhoneAccount account = null;
- if (!mCallInfo.isNullCall(call)) {
- PhoneAccountHandle handle = call.getAccountHandle();
- if (handle != null) {
- // First try to get the network name of the foreground call.
- account = mTelecomManager.getPhoneAccount(handle);
- }
- }
-
- if (account == null) {
- // Second, Try to get the label for the default Phone Account.
- List<PhoneAccountHandle> handles =
- mTelecomManager.getPhoneAccountsSupportingScheme(PhoneAccount.SCHEME_TEL);
- while (handles.iterator().hasNext()) {
- account = mTelecomManager.getPhoneAccount(handles.iterator().next());
- if (account != null) {
- return account;
- }
- }
- }
- return null;
- }
-
- public boolean isNullCall(BluetoothCall call) {
- return call == null || call.getCall() == null;
- }
- };
-};
diff --git a/src/com/android/bluetooth/hfp/HeadsetService.java b/src/com/android/bluetooth/hfp/HeadsetService.java
index 7c08f15..6031a93 100644
--- a/src/com/android/bluetooth/hfp/HeadsetService.java
+++ b/src/com/android/bluetooth/hfp/HeadsetService.java
@@ -153,6 +153,7 @@
mStateMachinesThread.start();
// Step 3: Initialize system interface
mSystemInterface = HeadsetObjectsFactory.getInstance().makeSystemInterface(this);
+ mSystemInterface.init();
// Step 4: Initialize native interface
mMaxHeadsetConnections = mAdapterService.getMaxConnectedAudioDevices();
mNativeInterface = HeadsetObjectsFactory.getInstance().getNativeInterface();
diff --git a/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java b/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java
index a618019..52ca1bc 100644
--- a/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java
+++ b/src/com/android/bluetooth/hfp/HeadsetSystemInterface.java
@@ -20,15 +20,19 @@
import android.annotation.Nullable;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.IBluetoothHeadsetPhone;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.media.AudioManager;
+import android.os.IBinder;
import android.os.PowerManager;
+import android.os.RemoteException;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -48,6 +52,28 @@
private final AudioManager mAudioManager;
private final HeadsetPhoneState mHeadsetPhoneState;
private PowerManager.WakeLock mVoiceRecognitionWakeLock;
+ private volatile IBluetoothHeadsetPhone mPhoneProxy;
+ private final ServiceConnection mPhoneProxyConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) {
+ Log.d(TAG, "Proxy object connected");
+ }
+ synchronized (HeadsetSystemInterface.this) {
+ mPhoneProxy = IBluetoothHeadsetPhone.Stub.asInterface(service);
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) {
+ Log.d(TAG, "Proxy object disconnected");
+ }
+ synchronized (HeadsetSystemInterface.this) {
+ mPhoneProxy = null;
+ }
+ }
+ };
HeadsetSystemInterface(HeadsetService headsetService) {
if (headsetService == null) {
@@ -60,11 +86,21 @@
mVoiceRecognitionWakeLock =
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG + ":VoiceRecognition");
mVoiceRecognitionWakeLock.setReferenceCounted(false);
- mHeadsetPhoneState = new com.android.bluetooth.hfp.HeadsetPhoneState(mHeadsetService);
+ mHeadsetPhoneState = new HeadsetPhoneState(mHeadsetService);
}
- private BluetoothInCallService getBluetoothInCallServiceInstance() {
- return BluetoothInCallService.getInstance();
+ /**
+ * Initialize this system interface
+ */
+ public synchronized void init() {
+ // Bind to Telecom phone proxy service
+ Intent intent = new Intent(IBluetoothHeadsetPhone.class.getName());
+ intent.setComponent(resolveSystemService(mHeadsetService.getPackageManager(), 0, intent));
+ if (intent.getComponent() == null || !mHeadsetService.bindService(intent,
+ mPhoneProxyConnection, 0)) {
+ // Crash the stack if cannot bind to Telecom
+ Log.wtf(TAG, "Could not bind to IBluetoothHeadsetPhone Service, intent=" + intent);
+ }
}
/**
@@ -104,6 +140,14 @@
* Stop this system interface
*/
public synchronized void stop() {
+ if (mPhoneProxy != null) {
+ if (DBG) {
+ Log.d(TAG, "Unbinding phone proxy");
+ }
+ mPhoneProxy = null;
+ // Synchronization should make sure unbind can be successful
+ mHeadsetService.unbindService(mPhoneProxyConnection);
+ }
mHeadsetPhoneState.cleanup();
}
@@ -149,10 +193,14 @@
Log.w(TAG, "answerCall device is null");
return;
}
- BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
- if (bluetoothInCallService != null) {
- mHeadsetService.setActiveDevice(device);
- bluetoothInCallService.answerCall();
+
+ if (mPhoneProxy != null) {
+ try {
+ mHeadsetService.setActiveDevice(device);
+ mPhoneProxy.answerCall();
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
} else {
Log.e(TAG, "Handsfree phone proxy null for answering call");
}
@@ -174,9 +222,12 @@
if (mHeadsetService.isVirtualCallStarted()) {
mHeadsetService.stopScoUsingVirtualVoiceCall();
} else {
- BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
- if (bluetoothInCallService != null) {
- bluetoothInCallService.hangupCall();
+ if (mPhoneProxy != null) {
+ try {
+ mPhoneProxy.hangupCall();
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
} else {
Log.e(TAG, "Handsfree phone proxy null for hanging up call");
}
@@ -195,9 +246,12 @@
Log.w(TAG, "sendDtmf device is null");
return false;
}
- BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
- if (bluetoothInCallService != null) {
- return bluetoothInCallService.sendDtmf(dtmf);
+ if (mPhoneProxy != null) {
+ try {
+ return mPhoneProxy.sendDtmf(dtmf);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
} else {
Log.e(TAG, "Handsfree phone proxy null for sending DTMF");
}
@@ -211,9 +265,12 @@
*/
@VisibleForTesting
public boolean processChld(int chld) {
- BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
- if (bluetoothInCallService != null) {
- return bluetoothInCallService.processChld(chld);
+ if (mPhoneProxy != null) {
+ try {
+ return mPhoneProxy.processChld(chld);
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
} else {
Log.e(TAG, "Handsfree phone proxy null for sending DTMF");
}
@@ -227,13 +284,19 @@
*/
@VisibleForTesting
public String getNetworkOperator() {
- BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
- if (bluetoothInCallService == null) {
- Log.e(TAG, "getNetworkOperator() failed: mBluetoothInCallService is null");
+ final IBluetoothHeadsetPhone phoneProxy = mPhoneProxy;
+ if (phoneProxy == null) {
+ Log.e(TAG, "getNetworkOperator() failed: mPhoneProxy is null");
return null;
}
- // Should never return null
- return bluetoothInCallService.getNetworkOperator();
+ try {
+ // Should never return null
+ return mPhoneProxy.getNetworkOperator();
+ } catch (RemoteException exception) {
+ Log.e(TAG, "getNetworkOperator() failed: " + exception.getMessage());
+ exception.printStackTrace();
+ return null;
+ }
}
/**
@@ -243,12 +306,18 @@
*/
@VisibleForTesting
public String getSubscriberNumber() {
- BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
- if (bluetoothInCallService == null) {
- Log.e(TAG, "getSubscriberNumber() failed: mBluetoothInCallService is null");
+ final IBluetoothHeadsetPhone phoneProxy = mPhoneProxy;
+ if (phoneProxy == null) {
+ Log.e(TAG, "getSubscriberNumber() failed: mPhoneProxy is null");
return null;
}
- return bluetoothInCallService.getSubscriberNumber();
+ try {
+ return mPhoneProxy.getSubscriberNumber();
+ } catch (RemoteException exception) {
+ Log.e(TAG, "getSubscriberNumber() failed: " + exception.getMessage());
+ exception.printStackTrace();
+ return null;
+ }
}
@@ -260,12 +329,18 @@
*/
@VisibleForTesting
public boolean listCurrentCalls() {
- BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
- if (bluetoothInCallService == null) {
- Log.e(TAG, "listCurrentCalls() failed: mBluetoothInCallService is null");
+ final IBluetoothHeadsetPhone phoneProxy = mPhoneProxy;
+ if (phoneProxy == null) {
+ Log.e(TAG, "listCurrentCalls() failed: mPhoneProxy is null");
return false;
}
- return bluetoothInCallService.listCurrentCalls();
+ try {
+ return mPhoneProxy.listCurrentCalls();
+ } catch (RemoteException exception) {
+ Log.e(TAG, "listCurrentCalls() failed: " + exception.getMessage());
+ exception.printStackTrace();
+ return false;
+ }
}
/**
@@ -274,9 +349,13 @@
*/
@VisibleForTesting
public void queryPhoneState() {
- BluetoothInCallService bluetoothInCallService = getBluetoothInCallServiceInstance();
- if (bluetoothInCallService != null) {
- bluetoothInCallService.queryPhoneState();
+ final IBluetoothHeadsetPhone phoneProxy = mPhoneProxy;
+ if (phoneProxy != null) {
+ try {
+ mPhoneProxy.queryPhoneState();
+ } catch (RemoteException e) {
+ Log.e(TAG, Log.getStackTraceString(new Throwable()));
+ }
} else {
Log.e(TAG, "Handsfree phone proxy null for query phone state");
}
diff --git a/tests/unit/src/com/android/bluetooth/hfp/BluetoothInCallServiceTest.java b/tests/unit/src/com/android/bluetooth/hfp/BluetoothInCallServiceTest.java
deleted file mode 100644
index 8f9f544..0000000
--- a/tests/unit/src/com/android/bluetooth/hfp/BluetoothInCallServiceTest.java
+++ /dev/null
@@ -1,1186 +0,0 @@
-/*
- * Copyright (C) 2020 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.hfp;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.*;
-
-import android.bluetooth.BluetoothAdapter;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.IBinder;
-import android.telecom.Call;
-import android.telecom.Connection;
-import android.telecom.GatewayInfo;
-import android.telecom.PhoneAccount;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.rule.ServiceTestRule;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Tests for {@link BluetoothInCallService}
- */
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class BluetoothInCallServiceTest {
-
- private static final int TEST_DTMF_TONE = 0;
- private static final String TEST_ACCOUNT_ADDRESS = "//foo.com/";
- private static final int TEST_ACCOUNT_INDEX = 0;
-
- private static final int CALL_STATE_ACTIVE = 0;
- private static final int CALL_STATE_HELD = 1;
- private static final int CALL_STATE_DIALING = 2;
- private static final int CALL_STATE_ALERTING = 3;
- private static final int CALL_STATE_INCOMING = 4;
- private static final int CALL_STATE_WAITING = 5;
- private static final int CALL_STATE_IDLE = 6;
- private static final int CALL_STATE_DISCONNECTED = 7;
- // Terminate all held or set UDUB("busy") to a waiting call
- private static final int CHLD_TYPE_RELEASEHELD = 0;
- // Terminate all active calls and accepts a waiting/held call
- private static final int CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD = 1;
- // Hold all active calls and accepts a waiting/held call
- private static final int CHLD_TYPE_HOLDACTIVE_ACCEPTHELD = 2;
- // Add all held calls to a conference
- private static final int CHLD_TYPE_ADDHELDTOCONF = 3;
-
- private TestableBluetoothInCallService mBluetoothInCallService;
- @Rule public final ServiceTestRule mServiceRule
- = ServiceTestRule.withTimeout(1, TimeUnit.SECONDS);
-
- @Mock private BluetoothHeadsetProxy mMockBluetoothHeadset;
- @Mock private BluetoothInCallService.CallInfo mMockCallInfo;
- @Mock private TelephonyManager mMockTelephonyManager;
-
- public class TestableBluetoothInCallService extends BluetoothInCallService {
- @Override
- public IBinder onBind(Intent intent) {
- IBinder binder = super.onBind(intent);
- IntentFilter intentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
- registerReceiver(mBluetoothAdapterReceiver, intentFilter);
- mTelephonyManager = getSystemService(TelephonyManager.class);
- mTelecomManager = getSystemService(TelecomManager.class);
- return binder;
- }
- @Override
- protected void enforceModifyPermission() {}
- }
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- // Create the service Intent.
- Intent serviceIntent =
- new Intent(ApplicationProvider.getApplicationContext(),
- TestableBluetoothInCallService.class);
- // Bind the service
- mServiceRule.bindService(serviceIntent);
-
- // Ensure initialization does not actually try to access any of the CallsManager fields.
- // This also works to return null if it is not overwritten later in the test.
- doReturn(null).when(mMockCallInfo).getActiveCall();
- doReturn(null).when(mMockCallInfo)
- .getRingingOrSimulatedRingingCall();
- doReturn(null).when(mMockCallInfo).getHeldCall();
- doReturn(null).when(mMockCallInfo).getOutgoingCall();
- doReturn(0).when(mMockCallInfo).getNumHeldCalls();
- doReturn(false).when(mMockCallInfo).hasOnlyDisconnectedCalls();
- doReturn(true).when(mMockCallInfo).isNullCall(null);
- doReturn(false).when(mMockCallInfo).isNullCall(notNull());
-
- mBluetoothInCallService = new TestableBluetoothInCallService();
- mBluetoothInCallService.setBluetoothHeadset(mMockBluetoothHeadset);
- mBluetoothInCallService.mCallInfo = mMockCallInfo;
- }
-
- @After
- public void tearDown() throws Exception {
- mServiceRule.unbindService();
- mBluetoothInCallService = null;
- }
-
- @Test
- public void testHeadsetAnswerCall() throws Exception {
- BluetoothCall mockCall = createRingingCall();
-
- boolean callAnswered = mBluetoothInCallService.answerCall();
- verify(mockCall).answer(any(int.class));
-
- Assert.assertTrue(callAnswered);
- }
-
- @Test
- public void testHeadsetAnswerCallNull() throws Exception {
- when(mMockCallInfo.getRingingOrSimulatedRingingCall()).thenReturn(null);
-
- boolean callAnswered = mBluetoothInCallService.answerCall();
- Assert.assertFalse(callAnswered);
- }
-
- @Test
- public void testHeadsetHangupCall() throws Exception {
- BluetoothCall mockCall = createForegroundCall();
-
- boolean callHungup = mBluetoothInCallService.hangupCall();
-
- verify(mockCall).disconnect();
- Assert.assertTrue(callHungup);
- }
-
- @Test
- public void testHeadsetHangupCallNull() throws Exception {
- when(mMockCallInfo.getForegroundCall()).thenReturn(null);
-
- boolean callHungup = mBluetoothInCallService.hangupCall();
- Assert.assertFalse(callHungup);
- }
-
- @Test
- public void testHeadsetSendDTMF() throws Exception {
- BluetoothCall mockCall = createForegroundCall();
-
- boolean sentDtmf = mBluetoothInCallService.sendDtmf(TEST_DTMF_TONE);
-
- verify(mockCall).playDtmfTone(eq((char) TEST_DTMF_TONE));
- verify(mockCall).stopDtmfTone();
- Assert.assertTrue(sentDtmf);
- }
-
- @Test
- public void testHeadsetSendDTMFNull() throws Exception {
- when(mMockCallInfo.getForegroundCall()).thenReturn(null);
-
- boolean sentDtmf = mBluetoothInCallService.sendDtmf(TEST_DTMF_TONE);
- Assert.assertFalse(sentDtmf);
- }
-
- @Test
- public void testGetNetworkOperator() throws Exception {
- PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX);
- when(mMockCallInfo.getBestPhoneAccount()).thenReturn(fakePhoneAccount);
-
- String networkOperator = mBluetoothInCallService.getNetworkOperator();
- Assert.assertEquals(networkOperator, "label0");
- }
-
- @Test
- public void testGetNetworkOperatorNoPhoneAccount() throws Exception {
- when(mMockCallInfo.getForegroundCall()).thenReturn(null);
- when(mMockTelephonyManager.getNetworkOperatorName()).thenReturn("label1");
- mBluetoothInCallService.mTelephonyManager = mMockTelephonyManager;
-
- String networkOperator = mBluetoothInCallService.getNetworkOperator();
- Assert.assertEquals(networkOperator, "label1");
- }
-
- @Test
- public void testGetSubscriberNumber() throws Exception {
- PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX);
- when(mMockCallInfo.getBestPhoneAccount()).thenReturn(fakePhoneAccount);
-
- String subscriberNumber = mBluetoothInCallService.getSubscriberNumber();
- Assert.assertEquals(subscriberNumber, TEST_ACCOUNT_ADDRESS + TEST_ACCOUNT_INDEX);
- }
-
- @Test
- public void testGetSubscriberNumberFallbackToTelephony() throws Exception {
- String fakeNumber = "8675309";
- when(mMockCallInfo.getBestPhoneAccount()).thenReturn(null);
- when(mMockTelephonyManager.getLine1Number())
- .thenReturn(fakeNumber);
- mBluetoothInCallService.mTelephonyManager = mMockTelephonyManager;
-
- String subscriberNumber = mBluetoothInCallService.getSubscriberNumber();
- Assert.assertEquals(subscriberNumber, fakeNumber);
- }
-
- @Test
- public void testListCurrentCallsOneCall() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- BluetoothCall activeCall = createActiveCall();
- when(activeCall.getState()).thenReturn(Call.STATE_ACTIVE);
- calls.add(activeCall);
- mBluetoothInCallService.onCallAdded(activeCall);
- when(activeCall.isConference()).thenReturn(false);
- when(activeCall.getHandle()).thenReturn(Uri.parse("tel:555-000"));
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
-
- verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(0), eq(0), eq(false),
- eq("555000"), eq(PhoneNumberUtils.TOA_Unknown));
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- }
-
- @Test
- public void testListCurrentCallsSilentRinging() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- BluetoothCall silentRingingCall = createActiveCall();
- when(silentRingingCall.getState()).thenReturn(Call.STATE_RINGING);
- when(silentRingingCall.isSilentRingingRequested()).thenReturn(true);
- calls.add(silentRingingCall);
- mBluetoothInCallService.onCallAdded(silentRingingCall);
-
- when(silentRingingCall.isConference()).thenReturn(false);
- when(silentRingingCall.getHandle()).thenReturn(Uri.parse("tel:555-000"));
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- when(mMockCallInfo.getRingingOrSimulatedRingingCall()).thenReturn(silentRingingCall);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
-
- verify(mMockBluetoothHeadset, never()).clccResponse(eq(1), eq(0), eq(0), eq(0), eq(false),
- eq("555000"), eq(PhoneNumberUtils.TOA_Unknown));
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- }
-
- @Test
- public void testConferenceInProgressCDMA() throws Exception {
- // If two calls are being conferenced and updateHeadsetWithCallState runs while this is
- // still occurring, it will look like there is an active and held BluetoothCall still while
- // we are transitioning into a conference.
- // BluetoothCall has been put into a CDMA "conference" with one BluetoothCall on hold.
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- BluetoothCall parentCall = createActiveCall();
- final BluetoothCall confCall1 = getMockCall();
- final BluetoothCall confCall2 = createHeldCall();
- calls.add(parentCall);
- calls.add(confCall1);
- calls.add(confCall2);
- mBluetoothInCallService.onCallAdded(parentCall);
- mBluetoothInCallService.onCallAdded(confCall1);
- mBluetoothInCallService.onCallAdded(confCall2);
-
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- when(confCall1.getState()).thenReturn(Call.STATE_ACTIVE);
- when(confCall2.getState()).thenReturn(Call.STATE_ACTIVE);
- when(confCall1.isIncoming()).thenReturn(false);
- when(confCall2.isIncoming()).thenReturn(true);
- when(confCall1.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0000")));
- when(confCall2.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0001")));
- addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
- addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
- removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
- String confCall1Id = confCall1.getTelecomCallId();
- when(parentCall.getGenericConferenceActiveChildCallId())
- .thenReturn(confCall1Id);
- when(parentCall.isConference()).thenReturn(true);
- List<String> childrenIds = new LinkedList<String>(){{
- add(confCall1.getTelecomCallId());
- add(confCall2.getTelecomCallId());
- }};
- when(parentCall.getChildrenIds()).thenReturn(childrenIds);
- //Add links from child calls to parent
- String parentId = parentCall.getTelecomCallId();
- when(confCall1.getParentId()).thenReturn(parentId);
- when(confCall2.getParentId()).thenReturn(parentId);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.queryPhoneState();
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE),
- eq(""), eq(128), nullable(String.class));
-
- when(parentCall.wasConferencePreviouslyMerged()).thenReturn(true);
- List<BluetoothCall> children =
- mBluetoothInCallService.getBluetoothCallsByIds(parentCall.getChildrenIds());
- mBluetoothInCallService.getCallback(parentCall)
- .onChildrenChanged(parentCall, children);
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE),
- eq(""), eq(128), nullable(String.class));
-
- when(mMockCallInfo.getHeldCall()).thenReturn(null);
- // Spurious BluetoothCall to onIsConferencedChanged.
- mBluetoothInCallService.getCallback(parentCall)
- .onChildrenChanged(parentCall, children);
- // Make sure the BluetoothCall has only occurred collectively 2 times (not on the third)
- verify(mMockBluetoothHeadset, times(2)).phoneStateChanged(any(int.class),
- any(int.class), any(int.class), nullable(String.class), any(int.class),
- nullable(String.class));
- }
-
- @Test
- public void testListCurrentCallsCdmaHold() throws Exception {
- // BluetoothCall has been put into a CDMA "conference" with one BluetoothCall on hold.
- List<BluetoothCall> calls = new ArrayList<BluetoothCall>();
- BluetoothCall parentCall = createActiveCall();
- final BluetoothCall foregroundCall = getMockCall();
- final BluetoothCall heldCall = createHeldCall();
- calls.add(parentCall);
- calls.add(foregroundCall);
- calls.add(heldCall);
- mBluetoothInCallService.onCallAdded(parentCall);
- mBluetoothInCallService.onCallAdded(foregroundCall);
- mBluetoothInCallService.onCallAdded(heldCall);
-
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- when(foregroundCall.getState()).thenReturn(Call.STATE_ACTIVE);
- when(heldCall.getState()).thenReturn(Call.STATE_ACTIVE);
- when(foregroundCall.isIncoming()).thenReturn(false);
- when(heldCall.isIncoming()).thenReturn(true);
- when(foregroundCall.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0000")));
- when(heldCall.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0001")));
- addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
- addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
- removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
-
- String foregroundCallId = foregroundCall.getTelecomCallId();
- when(parentCall.getGenericConferenceActiveChildCallId()).thenReturn(foregroundCallId);
- when(parentCall.isConference()).thenReturn(true);
- List<String> childrenIds = new LinkedList<String>(){{
- add(foregroundCall.getTelecomCallId());
- add(heldCall.getTelecomCallId());
- }};
- when(parentCall.getChildrenIds()).thenReturn(childrenIds);
- //Add links from child calls to parent
- String parentId = parentCall.getTelecomCallId();
- when(foregroundCall.getParentId()).thenReturn(parentId);
- when(heldCall.getParentId()).thenReturn(parentId);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
-
- verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_ACTIVE), eq(0),
- eq(false), eq("5550000"), eq(PhoneNumberUtils.TOA_Unknown));
- verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(1), eq(CALL_STATE_HELD), eq(0),
- eq(false), eq("5550001"), eq(PhoneNumberUtils.TOA_Unknown));
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- }
-
- @Test
- public void testListCurrentCallsCdmaConference() throws Exception {
- // BluetoothCall is in a true CDMA conference
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- BluetoothCall parentCall = createActiveCall();
- final BluetoothCall confCall1 = getMockCall();
- final BluetoothCall confCall2 = createHeldCall();
- calls.add(parentCall);
- calls.add(confCall1);
- calls.add(confCall2);
- mBluetoothInCallService.onCallAdded(parentCall);
- mBluetoothInCallService.onCallAdded(confCall1);
- mBluetoothInCallService.onCallAdded(confCall2);
-
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- when(confCall1.getState()).thenReturn(Call.STATE_ACTIVE);
- when(confCall2.getState()).thenReturn(Call.STATE_ACTIVE);
- when(confCall1.isIncoming()).thenReturn(false);
- when(confCall2.isIncoming()).thenReturn(true);
- when(confCall1.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0000")));
- when(confCall2.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0001")));
- removeCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
- removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
- when(parentCall.wasConferencePreviouslyMerged()).thenReturn(true);
- //when(parentCall.getConferenceLevelActiveCall()).thenReturn(confCall1);
- when(parentCall.isConference()).thenReturn(true);
- List<String> childrenIds = new LinkedList<String>(){{
- add(confCall1.getTelecomCallId());
- add(confCall2.getTelecomCallId());
- }};
- when(parentCall.getChildrenIds()).thenReturn(childrenIds);
- //Add links from child calls to parent
- String parentId = parentCall.getTelecomCallId();
- when(confCall1.getParentId()).thenReturn(parentId);
- when(confCall2.getParentId()).thenReturn(parentId);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
-
- verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_ACTIVE), eq(0),
- eq(true), eq("5550000"), eq(PhoneNumberUtils.TOA_Unknown));
- verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(1), eq(CALL_STATE_ACTIVE), eq(0),
- eq(true), eq("5550001"), eq(PhoneNumberUtils.TOA_Unknown));
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- }
-
- @Test
- public void testWaitingCallClccResponse() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- // This test does not define a value for getForegroundCall(), so this ringing
- // BluetoothCall will be treated as if it is a waiting BluetoothCall
- // when listCurrentCalls() is invoked.
- BluetoothCall waitingCall = createRingingCall();
- calls.add(waitingCall);
- mBluetoothInCallService.onCallAdded(waitingCall);
-
- when(waitingCall.isIncoming()).thenReturn(true);
- when(waitingCall.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0000")));
- when(waitingCall.getState()).thenReturn(Call.STATE_RINGING);
- when(waitingCall.isConference()).thenReturn(false);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
- verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_WAITING, 0, false,
- "5550000", PhoneNumberUtils.TOA_Unknown);
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- verify(mMockBluetoothHeadset, times(2)).clccResponse(anyInt(),
- anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt());
- }
-
- @Test
- public void testNewCallClccResponse() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- BluetoothCall newCall = createForegroundCall();
- calls.add(newCall);
- mBluetoothInCallService.onCallAdded(newCall);
-
- when(newCall.getState()).thenReturn(Call.STATE_NEW);
- when(newCall.isConference()).thenReturn(false);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- verify(mMockBluetoothHeadset, times(1)).clccResponse(anyInt(),
- anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt());
- }
-
- @Test
- public void testRingingCallClccResponse() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- BluetoothCall ringingCall = createForegroundCall();
- calls.add(ringingCall);
- mBluetoothInCallService.onCallAdded(ringingCall);
-
- when(ringingCall.getState()).thenReturn(Call.STATE_RINGING);
- when(ringingCall.isIncoming()).thenReturn(true);
- when(ringingCall.isConference()).thenReturn(false);
- when(ringingCall.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0000")));
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
- verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_INCOMING, 0, false,
- "5550000", PhoneNumberUtils.TOA_Unknown);
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- verify(mMockBluetoothHeadset, times(2)).clccResponse(anyInt(),
- anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt());
- }
-
- @Test
- public void testCallClccCache() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- BluetoothCall ringingCall = createForegroundCall();
- calls.add(ringingCall);
- mBluetoothInCallService.onCallAdded(ringingCall);
-
- when(ringingCall.getState()).thenReturn(Call.STATE_RINGING);
- when(ringingCall.isIncoming()).thenReturn(true);
- when(ringingCall.isConference()).thenReturn(false);
- when(ringingCall.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:5550000")));
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
- verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_INCOMING, 0, false,
- "5550000", PhoneNumberUtils.TOA_Unknown);
-
- // Test Caching of old BluetoothCall indices in clcc
- when(ringingCall.getState()).thenReturn(Call.STATE_ACTIVE);
- BluetoothCall newHoldingCall = createHeldCall();
- calls.add(0, newHoldingCall);
- mBluetoothInCallService.onCallAdded(newHoldingCall);
-
- when(newHoldingCall.getState()).thenReturn(Call.STATE_HOLDING);
- when(newHoldingCall.isIncoming()).thenReturn(true);
- when(newHoldingCall.isConference()).thenReturn(false);
- when(newHoldingCall.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0001")));
-
- mBluetoothInCallService.listCurrentCalls();
- verify(mMockBluetoothHeadset).clccResponse(1, 1, CALL_STATE_ACTIVE, 0, false,
- "5550000", PhoneNumberUtils.TOA_Unknown);
- verify(mMockBluetoothHeadset).clccResponse(2, 1, CALL_STATE_HELD, 0, false,
- "5550001", PhoneNumberUtils.TOA_Unknown);
- verify(mMockBluetoothHeadset, times(2)).clccResponse(0, 0, 0, 0, false, null, 0);
- }
-
- @Test
- public void testAlertingCallClccResponse() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- BluetoothCall dialingCall = createForegroundCall();
- calls.add(dialingCall);
- mBluetoothInCallService.onCallAdded(dialingCall);
-
- when(dialingCall.getState()).thenReturn(Call.STATE_DIALING);
- when(dialingCall.isIncoming()).thenReturn(false);
- when(dialingCall.isConference()).thenReturn(false);
- when(dialingCall.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0000")));
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
- verify(mMockBluetoothHeadset).clccResponse(1, 0, CALL_STATE_ALERTING, 0, false,
- "5550000", PhoneNumberUtils.TOA_Unknown);
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- verify(mMockBluetoothHeadset, times(2)).clccResponse(anyInt(),
- anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt());
- }
-
- @Test
- public void testHoldingCallClccResponse() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
- BluetoothCall dialingCall = createForegroundCall();
- calls.add(dialingCall);
- mBluetoothInCallService.onCallAdded(dialingCall);
-
- when(dialingCall.getState()).thenReturn(Call.STATE_DIALING);
- when(dialingCall.isIncoming()).thenReturn(false);
- when(dialingCall.isConference()).thenReturn(false);
- when(dialingCall.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0000")));
- BluetoothCall holdingCall = createHeldCall();
- calls.add(holdingCall);
- mBluetoothInCallService.onCallAdded(holdingCall);
-
- when(holdingCall.getState()).thenReturn(Call.STATE_HOLDING);
- when(holdingCall.isIncoming()).thenReturn(true);
- when(holdingCall.isConference()).thenReturn(false);
- when(holdingCall.getGatewayInfo()).thenReturn(
- new GatewayInfo(null, null, Uri.parse("tel:555-0001")));
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
- verify(mMockBluetoothHeadset).clccResponse(1, 0, CALL_STATE_ALERTING, 0, false,
- "5550000", PhoneNumberUtils.TOA_Unknown);
- verify(mMockBluetoothHeadset).clccResponse(2, 1, CALL_STATE_HELD, 0, false,
- "5550001", PhoneNumberUtils.TOA_Unknown);
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- verify(mMockBluetoothHeadset, times(3)).clccResponse(anyInt(),
- anyInt(), anyInt(), anyInt(), anyBoolean(), nullable(String.class), anyInt());
- }
-
- @Test
- public void testListCurrentCallsImsConference() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- BluetoothCall parentCall = createActiveCall();
- calls.add(parentCall);
- mBluetoothInCallService.onCallAdded(parentCall);
-
- addCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
- when(parentCall.isConference()).thenReturn(true);
- when(parentCall.getState()).thenReturn(Call.STATE_ACTIVE);
- when(parentCall.isIncoming()).thenReturn(true);
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
-
- verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(1), eq(CALL_STATE_ACTIVE), eq(0),
- eq(true), (String) isNull(), eq(-1));
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- }
-
- @Test
- public void testListCurrentCallsHeldImsCepConference() throws Exception {
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- BluetoothCall parentCall = createHeldCall();
- BluetoothCall childCall1 = createActiveCall();
- BluetoothCall childCall2 = createActiveCall();
- calls.add(parentCall);
- calls.add(childCall1);
- calls.add(childCall2);
- mBluetoothInCallService.onCallAdded(parentCall);
- mBluetoothInCallService.onCallAdded(childCall1);
- mBluetoothInCallService.onCallAdded(childCall2);
-
- addCallCapability(parentCall, Connection.CAPABILITY_MANAGE_CONFERENCE);
- String parentId = parentCall.getTelecomCallId();
- when(childCall1.getParentId()).thenReturn(parentId);
- when(childCall2.getParentId()).thenReturn(parentId);
-
- when(parentCall.isConference()).thenReturn(true);
- when(parentCall.getState()).thenReturn(Call.STATE_HOLDING);
- when(childCall1.getState()).thenReturn(Call.STATE_ACTIVE);
- when(childCall2.getState()).thenReturn(Call.STATE_ACTIVE);
-
- when(parentCall.isIncoming()).thenReturn(true);
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.listCurrentCalls();
-
- verify(mMockBluetoothHeadset).clccResponse(eq(1), eq(0), eq(CALL_STATE_HELD), eq(0),
- eq(true), (String) isNull(), eq(-1));
- verify(mMockBluetoothHeadset).clccResponse(eq(2), eq(0), eq(CALL_STATE_HELD), eq(0),
- eq(true), (String) isNull(), eq(-1));
- verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
- }
-
- @Test
- public void testQueryPhoneState() throws Exception {
- BluetoothCall ringingCall = createRingingCall();
- when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:5550000"));
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.queryPhoneState();
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
- eq("5550000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class));
- }
-
- @Test
- public void testCDMAConferenceQueryState() throws Exception {
- BluetoothCall parentConfCall = createActiveCall();
- final BluetoothCall confCall1 = getMockCall();
- final BluetoothCall confCall2 = getMockCall();
- mBluetoothInCallService.onCallAdded(confCall1);
- mBluetoothInCallService.onCallAdded(confCall2);
- when(parentConfCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
- addCallCapability(parentConfCall, Connection.CAPABILITY_SWAP_CONFERENCE);
- removeCallCapability(parentConfCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
- when(parentConfCall.wasConferencePreviouslyMerged()).thenReturn(true);
- when(parentConfCall.isConference()).thenReturn(true);
- List<String> childrenIds = new LinkedList<String>(){{
- add(confCall1.getTelecomCallId());
- add(confCall2.getTelecomCallId());
- }};
- when(parentConfCall.getChildrenIds()).thenReturn(childrenIds);
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.queryPhoneState();
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE),
- eq(""), eq(128), nullable(String.class));
- }
-
- @Test
- public void testProcessChldTypeReleaseHeldRinging() throws Exception {
- BluetoothCall ringingCall = createRingingCall();
- Log.i("BluetoothInCallService", "asdf start " + Integer.toString(ringingCall.hashCode()));
-
- boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_RELEASEHELD);
-
- verify(ringingCall).reject(eq(false), nullable(String.class));
- Assert.assertTrue(didProcess);
- }
-
- @Test
- public void testProcessChldTypeReleaseHeldHold() throws Exception {
- BluetoothCall onHoldCall = createHeldCall();
- boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_RELEASEHELD);
-
- verify(onHoldCall).disconnect();
- Assert.assertTrue(didProcess);
- }
-
- @Test
- public void testProcessChldReleaseActiveRinging() throws Exception {
- BluetoothCall activeCall = createActiveCall();
- BluetoothCall ringingCall = createRingingCall();
-
- boolean didProcess = mBluetoothInCallService.processChld(
- CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD);
-
- verify(activeCall).disconnect();
- verify(ringingCall).answer(any(int.class));
- Assert.assertTrue(didProcess);
- }
-
- @Test
- public void testProcessChldReleaseActiveHold() throws Exception {
- BluetoothCall activeCall = createActiveCall();
- BluetoothCall heldCall = createHeldCall();
-
- boolean didProcess = mBluetoothInCallService.processChld(
- CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD);
-
- verify(activeCall).disconnect();
- // BluetoothCall unhold will occur as part of CallsManager auto-unholding
- // the background BluetoothCall on its own.
- Assert.assertTrue(didProcess);
- }
-
- @Test
- public void testProcessChldHoldActiveRinging() throws Exception {
- BluetoothCall ringingCall = createRingingCall();
-
- boolean didProcess = mBluetoothInCallService.processChld(
- CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
-
- verify(ringingCall).answer(any(int.class));
- Assert.assertTrue(didProcess);
- }
-
- @Test
- public void testProcessChldHoldActiveUnhold() throws Exception {
- BluetoothCall heldCall = createHeldCall();
-
- boolean didProcess = mBluetoothInCallService.processChld(
- CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
-
- verify(heldCall).unhold();
- Assert.assertTrue(didProcess);
- }
-
- @Test
- public void testProcessChldHoldActiveHold() throws Exception {
- BluetoothCall activeCall = createActiveCall();
- addCallCapability(activeCall, Connection.CAPABILITY_HOLD);
-
- boolean didProcess = mBluetoothInCallService.processChld(
- CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
-
- verify(activeCall).hold();
- Assert.assertTrue(didProcess);
- }
-
- @Test
- public void testProcessChldAddHeldToConfHolding() throws Exception {
- BluetoothCall activeCall = createActiveCall();
- addCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE);
-
- boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_ADDHELDTOCONF);
-
- verify(activeCall).mergeConference();
- Assert.assertTrue(didProcess);
- }
-
- @Test
- public void testProcessChldAddHeldToConf() throws Exception {
- BluetoothCall activeCall = createActiveCall();
- removeCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE);
- BluetoothCall conferenceableCall = getMockCall();
- ArrayList<String> conferenceableCalls = new ArrayList<>();
- conferenceableCalls.add(conferenceableCall.getTelecomCallId());
- mBluetoothInCallService.onCallAdded(conferenceableCall);
-
- when(activeCall.getConferenceableCalls()).thenReturn(conferenceableCalls);
-
- boolean didProcess = mBluetoothInCallService.processChld(CHLD_TYPE_ADDHELDTOCONF);
-
- verify(activeCall).conference(conferenceableCall);
- Assert.assertTrue(didProcess);
- }
-
- @Test
- public void testProcessChldHoldActiveSwapConference() throws Exception {
- // Create an active CDMA BluetoothCall with a BluetoothCall on hold
- // and simulate a swapConference().
- BluetoothCall parentCall = createActiveCall();
- final BluetoothCall foregroundCall = getMockCall();
- final BluetoothCall heldCall = createHeldCall();
- addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
- removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
- when(parentCall.isConference()).thenReturn(true);
- when(parentCall.wasConferencePreviouslyMerged()).thenReturn(false);
- List<String> childrenIds = new LinkedList<String>(){{
- add(foregroundCall.getTelecomCallId());
- add(heldCall.getTelecomCallId());
- }};
- when(parentCall.getChildrenIds()).thenReturn(childrenIds);
-
- clearInvocations(mMockBluetoothHeadset);
- boolean didProcess = mBluetoothInCallService.processChld(
- CHLD_TYPE_HOLDACTIVE_ACCEPTHELD);
-
- verify(parentCall).swapConference();
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE), eq(""),
- eq(128), nullable(String.class));
- Assert.assertTrue(didProcess);
- }
-
- // Testing the CallsManager Listener Functionality on Bluetooth
- @Test
- public void testOnCallAddedRinging() throws Exception {
- BluetoothCall ringingCall = createRingingCall();
- when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555000"));
-
- mBluetoothInCallService.onCallAdded(ringingCall);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
- eq("555000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class));
- }
-
- @Test
- public void testSilentRingingCallState() throws Exception {
- BluetoothCall ringingCall = createRingingCall();
- when(ringingCall.isSilentRingingRequested()).thenReturn(true);
- when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555000"));
-
- mBluetoothInCallService.onCallAdded(ringingCall);
-
- verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
- anyString(), anyInt(), nullable(String.class));
- }
-
- @Test
- public void testOnCallAddedCdmaActiveHold() throws Exception {
- // BluetoothCall has been put into a CDMA "conference" with one BluetoothCall on hold.
- BluetoothCall parentCall = createActiveCall();
- final BluetoothCall foregroundCall = getMockCall();
- final BluetoothCall heldCall = createHeldCall();
- addCallCapability(parentCall, Connection.CAPABILITY_MERGE_CONFERENCE);
- removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
- when(parentCall.isConference()).thenReturn(true);
- List<String> childrenIds = new LinkedList<String>(){{
- add(foregroundCall.getTelecomCallId());
- add(heldCall.getTelecomCallId());
- }};
- when(parentCall.getChildrenIds()).thenReturn(childrenIds);
-
- mBluetoothInCallService.onCallAdded(parentCall);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE),
- eq(""), eq(128), nullable(String.class));
- }
-
- @Test
- public void testOnCallRemoved() throws Exception {
- BluetoothCall activeCall = createActiveCall();
- mBluetoothInCallService.onCallAdded(activeCall);
- doReturn(null).when(mMockCallInfo).getActiveCall();
- mBluetoothInCallService.onCallRemoved(activeCall);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_IDLE),
- eq(""), eq(128), nullable(String.class));
- }
-
- @Test
- public void testOnCallStateChangedConnectingCall() throws Exception {
- BluetoothCall activeCall = getMockCall();
- BluetoothCall connectingCall = getMockCall();
- when(connectingCall.getState()).thenReturn(Call.STATE_CONNECTING);
- ArrayList<BluetoothCall> calls = new ArrayList<>();
- calls.add(connectingCall);
- calls.add(activeCall);
- mBluetoothInCallService.onCallAdded(connectingCall);
- mBluetoothInCallService.onCallAdded(activeCall);
- when(mMockCallInfo.getBluetoothCalls()).thenReturn(calls);
-
- mBluetoothInCallService.getCallback(activeCall)
- .onStateChanged(activeCall, Call.STATE_HOLDING);
-
- verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
- anyString(), anyInt(), nullable(String.class));
- }
-
- @Test
- public void testOnCallAddedAudioProcessing() throws Exception {
- BluetoothCall call = getMockCall();
- when(call.getState()).thenReturn(Call.STATE_AUDIO_PROCESSING);
- mBluetoothInCallService.onCallAdded(call);
-
- verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
- anyString(), anyInt(), nullable(String.class));
- }
-
- @Test
- public void testOnCallStateChangedRingingToAudioProcessing() throws Exception {
- BluetoothCall ringingCall = createRingingCall();
- when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555000"));
-
- mBluetoothInCallService.onCallAdded(ringingCall);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
- eq("555000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class));
-
- when(ringingCall.getState()).thenReturn(Call.STATE_AUDIO_PROCESSING);
- when(mMockCallInfo.getRingingOrSimulatedRingingCall()).thenReturn(null);
-
- mBluetoothInCallService.getCallback(ringingCall)
- .onStateChanged(ringingCall, Call.STATE_AUDIO_PROCESSING);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_IDLE),
- eq(""), eq(128), nullable(String.class));
- }
-
- @Test
- public void testOnCallStateChangedAudioProcessingToSimulatedRinging() throws Exception {
- BluetoothCall ringingCall = createRingingCall();
- when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
- mBluetoothInCallService.onCallAdded(ringingCall);
- mBluetoothInCallService.getCallback(ringingCall)
- .onStateChanged(ringingCall, Call.STATE_SIMULATED_RINGING);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
- eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class));
- }
-
- @Test
- public void testOnCallStateChangedAudioProcessingToActive() throws Exception {
- BluetoothCall activeCall = createActiveCall();
- when(activeCall.getState()).thenReturn(Call.STATE_ACTIVE);
- mBluetoothInCallService.onCallAdded(activeCall);
- mBluetoothInCallService.getCallback(activeCall)
- .onStateChanged(activeCall, Call.STATE_ACTIVE);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE),
- eq(""), eq(128), nullable(String.class));
- }
-
- @Test
- public void testOnCallStateChangedDialing() throws Exception {
- BluetoothCall activeCall = createActiveCall();
-
- // make "mLastState" STATE_CONNECTING
- BluetoothInCallService.CallStateCallback callback =
- mBluetoothInCallService.new CallStateCallback(Call.STATE_CONNECTING);
- mBluetoothInCallService.mCallbacks.put(
- activeCall.getTelecomCallId(), callback);
-
- mBluetoothInCallService.mCallbacks.get(activeCall.getTelecomCallId())
- .onStateChanged(activeCall, Call.STATE_DIALING);
-
- verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
- anyString(), anyInt(), nullable(String.class));
- }
-
- @Test
- public void testOnCallStateChangedAlerting() throws Exception {
- BluetoothCall outgoingCall = createOutgoingCall();
- mBluetoothInCallService.onCallAdded(outgoingCall);
- mBluetoothInCallService.getCallback(outgoingCall)
- .onStateChanged(outgoingCall, Call.STATE_DIALING);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_DIALING),
- eq(""), eq(128), nullable(String.class));
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_ALERTING),
- eq(""), eq(128), nullable(String.class));
- }
-
- @Test
- public void testOnCallStateChangedDisconnected() throws Exception {
- BluetoothCall disconnectedCall = createDisconnectedCall();
- doReturn(true).when(mMockCallInfo).hasOnlyDisconnectedCalls();
- mBluetoothInCallService.onCallAdded(disconnectedCall);
- mBluetoothInCallService.getCallback(disconnectedCall)
- .onStateChanged(disconnectedCall, Call.STATE_DISCONNECTED);
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_DISCONNECTED),
- eq(""), eq(128), nullable(String.class));
- }
-
- @Test
- public void testOnCallStateChanged() throws Exception {
- BluetoothCall ringingCall = createRingingCall();
- when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
- mBluetoothInCallService.onCallAdded(ringingCall);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
- eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class));
-
- //Switch to active
- doReturn(null).when(mMockCallInfo).getRingingOrSimulatedRingingCall();
- when(mMockCallInfo.getActiveCall()).thenReturn(ringingCall);
-
- mBluetoothInCallService.getCallback(ringingCall)
- .onStateChanged(ringingCall, Call.STATE_ACTIVE);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(0), eq(CALL_STATE_IDLE),
- eq(""), eq(128), nullable(String.class));
- }
-
- @Test
- public void testOnCallStateChangedGSMSwap() throws Exception {
- BluetoothCall heldCall = createHeldCall();
- when(heldCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
- mBluetoothInCallService.onCallAdded(heldCall);
- doReturn(2).when(mMockCallInfo).getNumHeldCalls();
-
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.getCallback(heldCall)
- .onStateChanged(heldCall, Call.STATE_HOLDING);
-
- verify(mMockBluetoothHeadset, never()).phoneStateChanged(eq(0), eq(2), eq(CALL_STATE_HELD),
- eq("5550000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class));
- }
-
- @Test
- public void testOnParentOnChildrenChanged() throws Exception {
- // Start with two calls that are being merged into a CDMA conference call. The
- // onIsConferencedChanged method will be called multiple times during the call. Make sure
- // that the bluetooth phone state is updated properly.
- BluetoothCall parentCall = createActiveCall();
- BluetoothCall activeCall = getMockCall();
- BluetoothCall heldCall = createHeldCall();
- mBluetoothInCallService.onCallAdded(parentCall);
- mBluetoothInCallService.onCallAdded(activeCall);
- mBluetoothInCallService.onCallAdded(heldCall);
- String parentId = parentCall.getTelecomCallId();
- when(activeCall.getParentId()).thenReturn(parentId);
- when(heldCall.getParentId()).thenReturn(parentId);
-
- ArrayList<String> calls = new ArrayList<>();
- calls.add(activeCall.getTelecomCallId());
-
- when(parentCall.getChildrenIds()).thenReturn(calls);
- when(parentCall.isConference()).thenReturn(true);
-
- removeCallCapability(parentCall, Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
- addCallCapability(parentCall, Connection.CAPABILITY_SWAP_CONFERENCE);
- when(parentCall.wasConferencePreviouslyMerged()).thenReturn(false);
-
- clearInvocations(mMockBluetoothHeadset);
- // Be sure that onIsConferencedChanged rejects spurious changes during set up of
- // CDMA "conference"
- mBluetoothInCallService.getCallback(activeCall)
- .onParentChanged(activeCall, parentCall);
- verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
- anyString(), anyInt(), nullable(String.class));
-
- mBluetoothInCallService.getCallback(heldCall)
- .onParentChanged(heldCall, parentCall);
- verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
- anyString(), anyInt(), nullable(String.class));
-
- mBluetoothInCallService.getCallback(parentCall)
- .onChildrenChanged(
- parentCall,
- mBluetoothInCallService.getBluetoothCallsByIds(calls));
- verify(mMockBluetoothHeadset, never()).phoneStateChanged(anyInt(), anyInt(), anyInt(),
- anyString(), anyInt(), nullable(String.class));
-
- calls.add(heldCall.getTelecomCallId());
- mBluetoothInCallService.onCallAdded(heldCall);
- mBluetoothInCallService.getCallback(parentCall)
- .onChildrenChanged(
- parentCall,
- mBluetoothInCallService.getBluetoothCallsByIds(calls));
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(1), eq(1), eq(CALL_STATE_IDLE),
- eq(""), eq(128), nullable(String.class));
- }
-
- @Test
- public void testBluetoothAdapterReceiver() throws Exception {
- BluetoothCall ringingCall = createRingingCall();
- when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:5550000"));
-
- Intent intent = new Intent();
- intent.putExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_ON);
- clearInvocations(mMockBluetoothHeadset);
- mBluetoothInCallService.mBluetoothAdapterReceiver
- .onReceive(mBluetoothInCallService, intent);
-
- verify(mMockBluetoothHeadset).phoneStateChanged(eq(0), eq(0), eq(CALL_STATE_INCOMING),
- eq("5550000"), eq(PhoneNumberUtils.TOA_Unknown), nullable(String.class));
- }
-
- private void addCallCapability(BluetoothCall call, int capability) {
- when(call.can(capability)).thenReturn(true);
- }
-
- private void removeCallCapability(BluetoothCall call, int capability) {
- when(call.can(capability)).thenReturn(false);
- }
-
- private BluetoothCall createActiveCall() {
- BluetoothCall call = getMockCall();
- when(mMockCallInfo.getActiveCall()).thenReturn(call);
- return call;
- }
-
- private BluetoothCall createRingingCall() {
- BluetoothCall call = getMockCall();
- Log.i("BluetoothInCallService", "asdf creaete " + Integer.toString(call.hashCode()));
- when(mMockCallInfo.getRingingOrSimulatedRingingCall()).thenReturn(call);
- return call;
- }
-
- private BluetoothCall createHeldCall() {
- BluetoothCall call = getMockCall();
- when(mMockCallInfo.getHeldCall()).thenReturn(call);
- return call;
- }
-
- private BluetoothCall createOutgoingCall() {
- BluetoothCall call = getMockCall();
- when(mMockCallInfo.getOutgoingCall()).thenReturn(call);
- return call;
- }
-
- private BluetoothCall createDisconnectedCall() {
- BluetoothCall call = getMockCall();
- when(mMockCallInfo.getCallByState(Call.STATE_DISCONNECTED)).thenReturn(call);
- return call;
- }
-
- private BluetoothCall createForegroundCall() {
- BluetoothCall call = getMockCall();
- when(mMockCallInfo.getForegroundCall()).thenReturn(call);
- return call;
- }
-
- private static ComponentName makeQuickConnectionServiceComponentName() {
- return new ComponentName("com.android.server.telecom.tests",
- "com.android.server.telecom.tests.MockConnectionService");
- }
-
- private static PhoneAccountHandle makeQuickAccountHandle(String id) {
- return new PhoneAccountHandle(makeQuickConnectionServiceComponentName(), id,
- Binder.getCallingUserHandle());
- }
-
- private PhoneAccount.Builder makeQuickAccountBuilder(String id, int idx) {
- return new PhoneAccount.Builder(makeQuickAccountHandle(id), "label" + idx);
- }
-
- private PhoneAccount makeQuickAccount(String id, int idx) {
- return makeQuickAccountBuilder(id, idx)
- .setAddress(Uri.parse(TEST_ACCOUNT_ADDRESS + idx))
- .setSubscriptionAddress(Uri.parse("tel:555-000" + idx))
- .setCapabilities(idx)
- .setShortDescription("desc" + idx)
- .setIsEnabled(true)
- .build();
- }
-
- private BluetoothCall getMockCall() {
- BluetoothCall call = mock(com.android.bluetooth.hfp.BluetoothCall.class);
- String uuid = UUID.randomUUID().toString();
- when(call.getTelecomCallId()).thenReturn(uuid);
- return call;
- }
-}
diff --git a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
index dbbf389..2dd5356 100644
--- a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
+++ b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceAndStateMachineTest.java
@@ -185,6 +185,7 @@
doAnswer(invocation -> mBondedDevices.toArray(new BluetoothDevice[]{})).when(
mAdapterService).getBondedDevices();
// Mock system interface
+ doNothing().when(mSystemInterface).init();
doNothing().when(mSystemInterface).stop();
when(mSystemInterface.getHeadsetPhoneState()).thenReturn(mPhoneState);
when(mSystemInterface.getAudioManager()).thenReturn(mAudioManager);
diff --git a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
index b3deb3a..cf3458c 100644
--- a/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
+++ b/tests/unit/src/com/android/bluetooth/hfp/HeadsetServiceTest.java
@@ -116,6 +116,7 @@
return keys.toArray(new BluetoothDevice[keys.size()]);
}).when(mAdapterService).getBondedDevices();
// Mock system interface
+ doNothing().when(mSystemInterface).init();
doNothing().when(mSystemInterface).stop();
when(mSystemInterface.getHeadsetPhoneState()).thenReturn(mPhoneState);
when(mSystemInterface.getAudioManager()).thenReturn(mAudioManager);