Capture metrics on InCallService failures and inform user of failures
Test: Manual test on telecom testapps, atest TelecomUnitTest Bug: 147883088 Change-Id: Id0e11558c16d770156fd01e470969c99e956be45
This commit is contained in:
parent
73ae8d8599
commit
6306f47df7
|
@ -177,6 +177,13 @@ message InCallServiceInfo {
|
|||
|
||||
// The type of the in-call service
|
||||
optional InCallServiceType in_call_service_type = 2;
|
||||
|
||||
// The number of milliseconds that the in call service remained bound between binding and
|
||||
// disconnection.
|
||||
optional int64 bound_duration_millis = 3;
|
||||
|
||||
// True if the in call service has ever crashed during a call.
|
||||
optional bool is_null_binding = 4;
|
||||
}
|
||||
|
||||
// Information about each call.
|
||||
|
|
|
@ -68,6 +68,15 @@
|
|||
background. This app may be accessing and playing audio over the call.
|
||||
</string>
|
||||
|
||||
<!-- Crashed in call service notification label, used when the in call service has cranshed and
|
||||
the system fall back to use system dialer. [CHAR LIMIT=NONE] -->
|
||||
<string name="notification_crashedInCallService_title">Crashed phone app</string>
|
||||
<!-- Body of the notification presented when an in call service crashed. [CHAR LIMIT=NONE] -->
|
||||
<string name="notification_crashedInCallService_body">
|
||||
Your Phone app <xliff:g id="in_call_service_app_name">%s</xliff:g> has crashed.
|
||||
You call was continued using the Phone app that came with your device.
|
||||
</string>
|
||||
|
||||
<!-- Content description of the call muted notification icon for
|
||||
accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
|
||||
<string name="accessibility_call_muted">Call muted.</string>
|
||||
|
@ -300,6 +309,8 @@
|
|||
<string name="notification_channel_background_calls">Background calls</string>
|
||||
<!-- Notification channel name for a channel containing disconnected call notifications. -->
|
||||
<string name="notification_channel_disconnected_calls">Disconnected calls</string>
|
||||
<!-- Notification channel name for a channel containing crashed phone apps service notifications. -->
|
||||
<string name="notification_channel_in_call_service_crash">Crashed phone apps</string>
|
||||
|
||||
<!-- Alert dialog content used to inform the user that placing a new outgoing call will end the
|
||||
ongoing call in the app "other_app". -->
|
||||
|
|
|
@ -201,7 +201,8 @@ public class Analytics {
|
|||
public void addVideoEvent(int eventId, int videoState) {
|
||||
}
|
||||
|
||||
public void addInCallService(String serviceName, int type) {
|
||||
public void addInCallService(String serviceName, int type, long boundDuration,
|
||||
boolean isNullBinding) {
|
||||
}
|
||||
|
||||
public void addCallProperties(int properties) {
|
||||
|
@ -370,10 +371,13 @@ public class Analytics {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addInCallService(String serviceName, int type) {
|
||||
public void addInCallService(String serviceName, int type, long boundDuration,
|
||||
boolean isNullBinding) {
|
||||
inCallServiceInfos.add(new TelecomLogClass.InCallServiceInfo()
|
||||
.setInCallServiceName(serviceName)
|
||||
.setInCallServiceType(type));
|
||||
.setInCallServiceType(type)
|
||||
.setBoundDurationMillis(boundDuration)
|
||||
.setIsNullBinding(isNullBinding));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -533,6 +537,10 @@ public class Analytics {
|
|||
s.append(service.getInCallServiceName());
|
||||
s.append(" type: ");
|
||||
s.append(service.getInCallServiceType());
|
||||
s.append(" is crashed: ");
|
||||
s.append(service.getIsNullBinding());
|
||||
s.append(" service last time in ms: ");
|
||||
s.append(service.getBoundDurationMillis());
|
||||
s.append("\n");
|
||||
}
|
||||
s.append("]");
|
||||
|
|
|
@ -18,6 +18,8 @@ package com.android.server.telecom;
|
|||
|
||||
import android.Manifest;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -47,6 +49,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||
import com.android.internal.telecom.IInCallService;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.telecom.SystemStateHelper.SystemStateListener;
|
||||
import com.android.server.telecom.ui.NotificationChannelManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -65,6 +68,8 @@ import java.util.stream.Collectors;
|
|||
* a binding to the {@link IInCallService} (implemented by the in-call app).
|
||||
*/
|
||||
public class InCallController extends CallsManagerListenerBase {
|
||||
public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3;
|
||||
public static final String NOTIFICATION_TAG = InCallController.class.getSimpleName();
|
||||
|
||||
public class InCallServiceConnection {
|
||||
/**
|
||||
|
@ -83,7 +88,7 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
public static final int CONNECTION_NOT_SUPPORTED = 3;
|
||||
|
||||
public class Listener {
|
||||
public void onDisconnect(InCallServiceConnection conn) {}
|
||||
public void onDisconnect(InCallServiceConnection conn, Call call) {}
|
||||
}
|
||||
|
||||
protected Listener mListener;
|
||||
|
@ -97,6 +102,7 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
}
|
||||
public InCallServiceInfo getInfo() { return null; }
|
||||
public void dump(IndentingPrintWriter pw) {}
|
||||
public Call mCall;
|
||||
}
|
||||
|
||||
private class InCallServiceInfo {
|
||||
|
@ -104,6 +110,8 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
private boolean mIsExternalCallsSupported;
|
||||
private boolean mIsSelfManagedCallsSupported;
|
||||
private final int mType;
|
||||
private long mBindingStartTime;
|
||||
private long mDisconnectTime;
|
||||
|
||||
public InCallServiceInfo(ComponentName componentName,
|
||||
boolean isExternalCallsSupported,
|
||||
|
@ -131,6 +139,22 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
return mType;
|
||||
}
|
||||
|
||||
public long getBindingStartTime() {
|
||||
return mBindingStartTime;
|
||||
}
|
||||
|
||||
public long getDisconnectTime() {
|
||||
return mDisconnectTime;
|
||||
}
|
||||
|
||||
public void setBindingStartTime(long bindingStartTime) {
|
||||
mBindingStartTime = bindingStartTime;
|
||||
}
|
||||
|
||||
public void setDisconnectTime(long disconnectTime) {
|
||||
mDisconnectTime = disconnectTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
|
@ -198,14 +222,47 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNullBinding(ComponentName name) {
|
||||
Log.startSession("ICSBC.oNB");
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
Log.d(this, "onNullBinding: %s", name);
|
||||
mIsNullBinding = true;
|
||||
mIsBound = false;
|
||||
onDisconnected();
|
||||
} finally {
|
||||
Log.endSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindingDied(ComponentName name) {
|
||||
Log.startSession("ICSBC.oBD");
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
Log.d(this, "onBindingDied: %s", name);
|
||||
mIsBound = false;
|
||||
onDisconnected();
|
||||
} finally {
|
||||
Log.endSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final InCallServiceInfo mInCallServiceInfo;
|
||||
private boolean mIsConnected = false;
|
||||
private boolean mIsBound = false;
|
||||
private boolean mIsNullBinding = false;
|
||||
private NotificationManager mNotificationManager;
|
||||
|
||||
public InCallServiceBindingConnection(InCallServiceInfo info) {
|
||||
mInCallServiceInfo = info;
|
||||
mNotificationManager =
|
||||
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -234,6 +291,7 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
|
||||
Log.i(this, "Attempting to bind to InCall %s, with %s", mInCallServiceInfo, intent);
|
||||
mIsConnected = true;
|
||||
mInCallServiceInfo.setBindingStartTime(mClockProxy.elapsedRealtime());
|
||||
if (!mContext.bindServiceAsUser(intent, mServiceConnection,
|
||||
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
|
||||
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
|
||||
|
@ -242,11 +300,10 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
mIsConnected = false;
|
||||
}
|
||||
|
||||
if (call != null && mIsConnected) {
|
||||
call.getAnalytics().addInCallService(
|
||||
mInCallServiceInfo.getComponentName().flattenToShortString(),
|
||||
mInCallServiceInfo.getType());
|
||||
if (mIsConnected && call != null) {
|
||||
mCall = call;
|
||||
}
|
||||
Log.i(this, "mCall: %s, mIsConnected: %s", mCall, mIsConnected);
|
||||
|
||||
return mIsConnected ? CONNECTION_SUCCEEDED : CONNECTION_FAILED;
|
||||
}
|
||||
|
@ -259,10 +316,36 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
@Override
|
||||
public void disconnect() {
|
||||
if (mIsConnected) {
|
||||
Log.i(InCallController.this, "ICSBC#disconnect: unbinding; %s",
|
||||
mInCallServiceInfo);
|
||||
mInCallServiceInfo.setDisconnectTime(mClockProxy.elapsedRealtime());
|
||||
Log.i(InCallController.this, "ICSBC#disconnect: unbinding after %s ms;"
|
||||
+ "%s. isCrashed: %s", mInCallServiceInfo.mDisconnectTime
|
||||
- mInCallServiceInfo.mBindingStartTime,
|
||||
mInCallServiceInfo, mIsNullBinding);
|
||||
String packageName = mInCallServiceInfo.getComponentName().getPackageName();
|
||||
mContext.unbindService(mServiceConnection);
|
||||
mIsConnected = false;
|
||||
if (mIsNullBinding) {
|
||||
Notification.Builder builder = new Notification.Builder(mContext,
|
||||
NotificationChannelManager.CHANNEL_ID_IN_CALL_SERVICE_CRASH);
|
||||
builder.setSmallIcon(R.drawable.ic_phone)
|
||||
.setColor(mContext.getResources().getColor(R.color.theme_color))
|
||||
.setContentTitle(
|
||||
mContext.getText(
|
||||
R.string.notification_crashedInCallService_title))
|
||||
.setStyle(new Notification.BigTextStyle()
|
||||
.bigText(mContext.getString(
|
||||
R.string.notification_crashedInCallService_body,
|
||||
packageName)));
|
||||
mNotificationManager.notify(NOTIFICATION_TAG, IN_CALL_SERVICE_NOTIFICATION_ID,
|
||||
builder.build());
|
||||
}
|
||||
if (mCall != null) {
|
||||
mCall.getAnalytics().addInCallService(
|
||||
mInCallServiceInfo.getComponentName().flattenToShortString(),
|
||||
mInCallServiceInfo.getType(),
|
||||
mInCallServiceInfo.getDisconnectTime()
|
||||
- mInCallServiceInfo.getBindingStartTime(), mIsNullBinding);
|
||||
}
|
||||
} else {
|
||||
Log.i(InCallController.this, "ICSBC#disconnect: already disconnected; %s",
|
||||
mInCallServiceInfo);
|
||||
|
@ -302,7 +385,7 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
InCallController.this.onDisconnected(mInCallServiceInfo);
|
||||
disconnect(); // Unbind explicitly if we get disconnected.
|
||||
if (mListener != null) {
|
||||
mListener.onDisconnect(InCallServiceBindingConnection.this);
|
||||
mListener.onDisconnect(InCallServiceBindingConnection.this, mCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -319,7 +402,7 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
|
||||
private Listener mSubListener = new Listener() {
|
||||
@Override
|
||||
public void onDisconnect(InCallServiceConnection subConnection) {
|
||||
public void onDisconnect(InCallServiceConnection subConnection, Call call) {
|
||||
if (subConnection == mSubConnection) {
|
||||
if (mIsConnected && mIsProxying) {
|
||||
// At this point we know that we need to be connected to the InCallService
|
||||
|
@ -327,7 +410,7 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
// just died so we need to stop proxying and connect to the system in-call
|
||||
// service instead.
|
||||
mIsProxying = false;
|
||||
connect(null);
|
||||
connect(call);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -799,6 +882,7 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
private final Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
private CarSwappingInCallServiceConnection mInCallServiceConnection;
|
||||
private NonUIInCallServiceConnectionCollection mNonUIInCallServiceConnections;
|
||||
private final ClockProxy mClockProxy;
|
||||
|
||||
// Future that's in a completed state unless we're in the middle of binding to a service.
|
||||
// The future will complete with true if binding succeeds, false if it timed out.
|
||||
|
@ -809,7 +893,8 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
public InCallController(Context context, TelecomSystem.SyncRoot lock, CallsManager callsManager,
|
||||
SystemStateHelper systemStateHelper,
|
||||
DefaultDialerCache defaultDialerCache, Timeouts.Adapter timeoutsAdapter,
|
||||
EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker) {
|
||||
EmergencyCallHelper emergencyCallHelper, CarModeTracker carModeTracker,
|
||||
ClockProxy clockProxy) {
|
||||
mContext = context;
|
||||
mLock = lock;
|
||||
mCallsManager = callsManager;
|
||||
|
@ -819,6 +904,7 @@ public class InCallController extends CallsManagerListenerBase {
|
|||
mEmergencyCallHelper = emergencyCallHelper;
|
||||
mCarModeTracker = carModeTracker;
|
||||
mSystemStateHelper.addListener(mSystemStateListener);
|
||||
mClockProxy = clockProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -270,7 +270,7 @@ public class TelecomSystem {
|
|||
EmergencyCallHelper emergencyCallHelper) {
|
||||
return new InCallController(context, lock, callsManager, systemStateProvider,
|
||||
defaultDialerCache, timeoutsAdapter, emergencyCallHelper,
|
||||
new CarModeTracker());
|
||||
new CarModeTracker(), clockProxy);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ public class NotificationChannelManager {
|
|||
public static final String CHANNEL_ID_CALL_BLOCKING = "TelecomCallBlocking";
|
||||
public static final String CHANNEL_ID_AUDIO_PROCESSING = "TelecomBackgroundAudioProcessing";
|
||||
public static final String CHANNEL_ID_DISCONNECTED_CALLS = "TelecomDisconnectedCalls";
|
||||
public static final String CHANNEL_ID_IN_CALL_SERVICE_CRASH = "TelecomInCallServiceCrash";
|
||||
|
||||
private BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
|
@ -61,6 +62,7 @@ public class NotificationChannelManager {
|
|||
createOrUpdateChannel(context, CHANNEL_ID_CALL_BLOCKING);
|
||||
createOrUpdateChannel(context, CHANNEL_ID_AUDIO_PROCESSING);
|
||||
createOrUpdateChannel(context, CHANNEL_ID_DISCONNECTED_CALLS);
|
||||
createOrUpdateChannel(context, CHANNEL_ID_IN_CALL_SERVICE_CRASH);
|
||||
}
|
||||
|
||||
private void createOrUpdateChannel(Context context, String channelId) {
|
||||
|
@ -118,6 +120,13 @@ public class NotificationChannelManager {
|
|||
vibration = true;
|
||||
sound = silentRingtone;
|
||||
break;
|
||||
case CHANNEL_ID_IN_CALL_SERVICE_CRASH:
|
||||
name = context.getText(R.string.notification_channel_in_call_service_crash);
|
||||
importance = NotificationManager.IMPORTANCE_DEFAULT;
|
||||
canShowBadge = true;
|
||||
lights = true;
|
||||
vibration = true;
|
||||
sound = null;
|
||||
}
|
||||
|
||||
NotificationChannel channel = new NotificationChannel(channelId, name, importance);
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package com.android.server.telecom.testapps;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.telecom.Call;
|
||||
import android.telecom.CallAudioState;
|
||||
|
|
|
@ -16,8 +16,14 @@
|
|||
|
||||
package com.android.server.telecom.tests;
|
||||
|
||||
import static com.android.server.telecom.InCallController.IN_CALL_SERVICE_NOTIFICATION_ID;
|
||||
import static com.android.server.telecom.InCallController.NOTIFICATION_TAG;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.matches;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import static org.mockito.Matchers.any;
|
||||
|
@ -33,6 +39,8 @@ import static org.mockito.Mockito.verify;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
|
@ -44,12 +52,14 @@ import android.content.pm.PackageManager;
|
|||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.UserHandle;
|
||||
import android.telecom.InCallService;
|
||||
import android.telecom.Log;
|
||||
import android.telecom.ParcelableCall;
|
||||
import android.telecom.PhoneAccountHandle;
|
||||
import android.telecom.TelecomManager;
|
||||
|
@ -64,6 +74,7 @@ import com.android.server.telecom.BluetoothHeadsetProxy;
|
|||
import com.android.server.telecom.Call;
|
||||
import com.android.server.telecom.CallsManager;
|
||||
import com.android.server.telecom.CarModeTracker;
|
||||
import com.android.server.telecom.ClockProxy;
|
||||
import com.android.server.telecom.DefaultDialerCache;
|
||||
import com.android.server.telecom.EmergencyCallHelper;
|
||||
import com.android.server.telecom.InCallController;
|
||||
|
@ -85,23 +96,10 @@ import org.mockito.MockitoAnnotations;
|
|||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.matches;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class InCallControllerTests extends TelecomTestCase {
|
||||
@Mock CallsManager mMockCallsManager;
|
||||
|
@ -115,6 +113,9 @@ public class InCallControllerTests extends TelecomTestCase {
|
|||
@Mock Timeouts.Adapter mTimeoutsAdapter;
|
||||
@Mock DefaultDialerCache mDefaultDialerCache;
|
||||
@Mock RoleManagerAdapter mMockRoleManagerAdapter;
|
||||
@Mock ClockProxy mClockProxy;
|
||||
@Mock Analytics.CallInfoImpl mCallInfo;
|
||||
@Mock NotificationManager mNotificationManager;
|
||||
|
||||
private static final int CURRENT_USER_ID = 900973;
|
||||
private static final String DEF_PKG = "defpkg";
|
||||
|
@ -159,7 +160,9 @@ public class InCallControllerTests extends TelecomTestCase {
|
|||
when(mMockCallsManager.getRoleManagerAdapter()).thenReturn(mMockRoleManagerAdapter);
|
||||
mInCallController = new InCallController(mMockContext, mLock, mMockCallsManager,
|
||||
mMockSystemStateHelper, mDefaultDialerCache, mTimeoutsAdapter,
|
||||
mEmergencyCallHelper, new CarModeTracker());
|
||||
mEmergencyCallHelper, new CarModeTracker(), mClockProxy);
|
||||
when(mMockContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
|
||||
.thenReturn(mNotificationManager);
|
||||
// Companion Apps don't have CONTROL_INCALL_EXPERIENCE permission.
|
||||
doAnswer(invocation -> {
|
||||
int uid = invocation.getArgument(0);
|
||||
|
@ -472,6 +475,58 @@ public class InCallControllerTests extends TelecomTestCase {
|
|||
assertEquals(SYS_CLASS, bindIntent.getComponent().getClassName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindToService_NullBinding_FallBackToSystem() throws Exception {
|
||||
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||
applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
|
||||
when(mMockCallsManager.isInEmergencyCall()).thenReturn(false);
|
||||
when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
|
||||
when(mMockCall.isIncoming()).thenReturn(false);
|
||||
when(mMockCall.isExternalCall()).thenReturn(false);
|
||||
when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
|
||||
when(mMockCall.getAnalytics()).thenReturn(mCallInfo);
|
||||
when(mMockContext.bindServiceAsUser(
|
||||
any(Intent.class), any(ServiceConnection.class), anyInt(), any(UserHandle.class)))
|
||||
.thenReturn(true);
|
||||
when(mMockContext.getApplicationInfo()).thenReturn(applicationInfo);
|
||||
|
||||
setupMockPackageManager(true /* default */, true /* system */, false /* external calls */);
|
||||
mInCallController.bindToServices(mMockCall);
|
||||
|
||||
ArgumentCaptor<Intent> bindIntentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||
ArgumentCaptor<ServiceConnection> serviceConnectionCaptor =
|
||||
ArgumentCaptor.forClass(ServiceConnection.class);
|
||||
verify(mMockContext, times(1)).bindServiceAsUser(
|
||||
bindIntentCaptor.capture(),
|
||||
serviceConnectionCaptor.capture(),
|
||||
anyInt(),
|
||||
any(UserHandle.class));
|
||||
ServiceConnection serviceConnection = serviceConnectionCaptor.getValue();
|
||||
ComponentName defDialerComponentName = new ComponentName(DEF_PKG, DEF_CLASS);
|
||||
ComponentName sysDialerComponentName = new ComponentName(SYS_PKG, SYS_CLASS);
|
||||
|
||||
IBinder mockBinder = mock(IBinder.class);
|
||||
IInCallService mockInCallService = mock(IInCallService.class);
|
||||
when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockInCallService);
|
||||
|
||||
serviceConnection.onServiceConnected(defDialerComponentName, mockBinder);
|
||||
// verify(mockInCallService).setInCallAdapter(any(IInCallAdapter.class));
|
||||
serviceConnection.onNullBinding(defDialerComponentName);
|
||||
|
||||
verify(mNotificationManager).notify(eq(NOTIFICATION_TAG),
|
||||
eq(IN_CALL_SERVICE_NOTIFICATION_ID), any(Notification.class));
|
||||
verify(mCallInfo).addInCallService(eq(sysDialerComponentName.flattenToShortString()),
|
||||
anyInt(), anyLong(), eq(true));
|
||||
|
||||
ArgumentCaptor<Intent> bindIntentCaptor2 = ArgumentCaptor.forClass(Intent.class);
|
||||
verify(mMockContext, times(2)).bindServiceAsUser(
|
||||
bindIntentCaptor2.capture(),
|
||||
any(ServiceConnection.class),
|
||||
eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
|
||||
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS),
|
||||
eq(UserHandle.CURRENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the {@link InCallController} will bind to an {@link InCallService} which
|
||||
* supports external calls.
|
||||
|
|
Loading…
Reference in New Issue