blob: 0a896a8ce92af2bafe4ef9c3e0c086b2d04569ac [file] [log] [blame]
/*
* Copyright (C) 2018 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.server.telecom.tests;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
import android.telecom.GatewayInfo;
import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
import com.android.internal.telecom.ICallRedirectionAdapter;
import com.android.internal.telecom.ICallRedirectionService;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallsManager;
import com.android.server.telecom.PhoneAccountRegistrar;
import com.android.server.telecom.SystemStateHelper;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;
import com.android.server.telecom.callredirection.CallRedirectionProcessor;
import com.android.server.telecom.callredirection.CallRedirectionProcessorHelper;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.junit.Before;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(JUnit4.class)
public class CallRedirectionProcessorTest extends TelecomTestCase {
@Mock private Context mContext;
@Mock private CallsManager mCallsManager;
@Mock private PhoneAccountRegistrar mPhoneAccountRegistrar;
@Mock private PhoneAccountHandle mPhoneAccountHandle;
private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
@Mock private Call mCall;
@Mock private PackageManager mPackageManager;
@Mock private TelephonyManager mTelephonyManager;
@Mock private IBinder mBinder;
@Mock private ICallRedirectionService mCallRedirectionService;
@Mock private SystemStateHelper mSystemStateHelper;
@Mock private CallRedirectionProcessorHelper mCallRedirectionProcessorHelper;
@Mock private Uri mHandle;
@Mock private GatewayInfo mGatewayInfo;
@Mock private UserHandle mUserHandle;
@Mock private ContentResolver mContentResolver;
@Mock private Timeouts.Adapter mTimeoutsAdapter;
private static final Uri ORIGINAL_NUMBER_WITH_POST_DIAL = Uri.parse("tel:6505551212,,,1234");
private static final Uri ORIGINAL_NUMBER_NO_POST_DIAL = Uri.parse("tel:6505551212");
private static final Uri REDIRECTED_GATEWAY_NUMBER = Uri.parse("tel:6505551213");
private static final Uri REDIRECTED_GATEWAY_NUMBER_WITH_POST_DIAL =
Uri.parse("tel:6505551213,,,1234");
private static final String USER_DEFINED_PKG_NAME = "user_defined_pkg";
private static final String USER_DEFINED_CLS_NAME = "user_defined_cls";
private static final String CARRIER_PKG_NAME = "carrier_pkg";
private static final String CARRIER_CLS_NAME = "carrier_cls";
private static final long HANDLER_TIMEOUT_DELAY = 5000;
private static final long USER_DEFINED_SHORT_TIMEOUT_MS = 1200;
private static final long CARRIER_SHORT_TIMEOUT_MS = 400;
private static final long CODE_EXECUTION_DELAY = 500;
// TODO integerate with a test user-defined service
private static final ComponentName USER_DEFINED_SERVICE_TEST_COMPONENT_NAME =
new ComponentName(USER_DEFINED_PKG_NAME, USER_DEFINED_CLS_NAME);
// TODO integerate with a test carrier service
private static final ComponentName CARRIER_SERVICE_TEST_COMPONENT_NAME =
new ComponentName(CARRIER_PKG_NAME, CARRIER_CLS_NAME);
private static final boolean SPEAKER_PHONE_ON = true;
private static final int VIDEO_STATE = 0;
private CallRedirectionProcessor mProcessor;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
when(mCall.getTargetPhoneAccount()).thenReturn(mPhoneAccountHandle);
when(mCallsManager.getCurrentUserHandle()).thenReturn(UserHandle.CURRENT);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getContentResolver()).thenReturn(mContentResolver);
doReturn(mCallRedirectionService).when(mBinder).queryLocalInterface(anyString());
when(mCallsManager.getSystemStateHelper()).thenReturn(mSystemStateHelper);
when(mCallsManager.getTimeoutsAdapter()).thenReturn(mTimeoutsAdapter);
when(mTimeoutsAdapter.getUserDefinedCallRedirectionTimeoutMillis(mContentResolver))
.thenReturn(USER_DEFINED_SHORT_TIMEOUT_MS);
when(mTimeoutsAdapter.getCarrierCallRedirectionTimeoutMillis(mContentResolver))
.thenReturn(CARRIER_SHORT_TIMEOUT_MS);
when(mCallsManager.getLock()).thenReturn(mLock);
when(mCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
when(mTelephonyManager.getNetworkCountryIso()).thenReturn("");
when(mContext.bindServiceAsUser(nullable(Intent.class), nullable(ServiceConnection.class),
anyInt(), eq(UserHandle.CURRENT))).thenReturn(true);
}
@Override
@After
public void tearDown() throws Exception {
mProcessor.getHandler().removeCallbacksAndMessages(null);
waitForHandlerAction(new Handler(Looper.getMainLooper()), TelecomSystemTest.TEST_TIMEOUT);
super.tearDown();
}
private void setIsInCarMode(boolean isInCarMode) {
when(mSystemStateHelper.isCarModeOrProjectionActive()).thenReturn(isInCarMode);
}
private void enableUserDefinedCallRedirectionService() {
when(mCallRedirectionProcessorHelper.getUserDefinedCallRedirectionService()).thenReturn(
USER_DEFINED_SERVICE_TEST_COMPONENT_NAME);
}
private void enableCarrierCallRedirectionService() {
when(mCallRedirectionProcessorHelper.getCarrierCallRedirectionService(
any(PhoneAccountHandle.class))).thenReturn(CARRIER_SERVICE_TEST_COMPONENT_NAME);
}
private void disableUserDefinedCallRedirectionService() {
when(mCallRedirectionProcessorHelper.getUserDefinedCallRedirectionService()).thenReturn(
null);
}
private void disableCarrierCallRedirectionService() {
when(mCallRedirectionProcessorHelper.getCarrierCallRedirectionService(any())).thenReturn(
null);
}
private void startProcessWithNoGateWayInfo() {
startProcessWithNoGateWayInfo(mHandle);
}
private void startProcessWithNoGateWayInfo(Uri handle) {
mProcessor = new CallRedirectionProcessor(mContext, mCallsManager, mCall, handle,
mPhoneAccountRegistrar, null, SPEAKER_PHONE_ON, VIDEO_STATE);
mProcessor.setCallRedirectionServiceHelper(mCallRedirectionProcessorHelper);
}
private void startProcessWithGateWayInfo() {
mProcessor = new CallRedirectionProcessor(mContext, mCallsManager, mCall, mHandle,
mPhoneAccountRegistrar, mGatewayInfo, SPEAKER_PHONE_ON, VIDEO_STATE);
mProcessor.setCallRedirectionServiceHelper(mCallRedirectionProcessorHelper);
}
@Test
public void testNoUserDefinedServiceNoCarrierSerivce() {
startProcessWithNoGateWayInfo();
disableUserDefinedCallRedirectionService();
disableCarrierCallRedirectionService();
mProcessor.performCallRedirection();
verify(mContext, times(0)).bindServiceAsUser(any(Intent.class),
any(ServiceConnection.class), anyInt(), any(UserHandle.class));
verify(mCallsManager, times(1)).onCallRedirectionComplete(eq(mCall), eq(mHandle),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_NO_ACTION));
}
@Test
public void testCarrierServiceTimeoutNoUserDefinedService() throws Exception {
startProcessWithNoGateWayInfo();
// To make sure tests are not flaky, clean all the previous handler messages
waitForHandlerAction(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY);
disableUserDefinedCallRedirectionService();
enableCarrierCallRedirectionService();
mProcessor.performCallRedirection();
verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
any(ServiceConnection.class), anyInt(), any(UserHandle.class));
verify(mCallsManager, times(0)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_NO_ACTION));
waitForHandlerActionDelayed(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY,
CARRIER_SHORT_TIMEOUT_MS + CODE_EXECUTION_DELAY);
verify(mCallsManager, times(1)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_NO_ACTION));
}
@Test
public void testUserDefinedServiceTimeoutNoCarrierService() throws Exception {
startProcessWithNoGateWayInfo();
// To make sure tests are not flaky, clean all the previous handler messages
waitForHandlerAction(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY);
enableUserDefinedCallRedirectionService();
disableCarrierCallRedirectionService();
mProcessor.performCallRedirection();
verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
any(ServiceConnection.class), anyInt(), any(UserHandle.class));
verify(mCallsManager, times(0)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT));
// Test it is waiting for a User-defined timeout, not a Carrier timeout
Thread.sleep(CARRIER_SHORT_TIMEOUT_MS + CODE_EXECUTION_DELAY);
verify(mCallsManager, times(0)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT));
// Wait for the rest of user-defined timeout time.
waitForHandlerActionDelayed(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY,
USER_DEFINED_SHORT_TIMEOUT_MS - CARRIER_SHORT_TIMEOUT_MS + CODE_EXECUTION_DELAY);
verify(mCallsManager, times(1)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(true), eq(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT));
}
@Test
public void testUserDefinedServiceTimeoutAndCarrierServiceTimeout() throws Exception {
startProcessWithNoGateWayInfo();
// To make sure tests are not flaky, clean all the previous handler messages
waitForHandlerAction(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY);
enableUserDefinedCallRedirectionService();
enableCarrierCallRedirectionService();
mProcessor.performCallRedirection();
verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
any(ServiceConnection.class), anyInt(), any(UserHandle.class));
verify(mCallsManager, times(0)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT));
// Test it is waiting for a User-defined timeout, not a Carrier timeout
Thread.sleep(CARRIER_SHORT_TIMEOUT_MS + CODE_EXECUTION_DELAY);
verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
any(ServiceConnection.class), anyInt(), any(UserHandle.class));
verify(mCallsManager, times(0)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT));
// Wait for the rest of user-defined timeout time.
waitForHandlerActionDelayed(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY,
USER_DEFINED_SHORT_TIMEOUT_MS - CARRIER_SHORT_TIMEOUT_MS + CODE_EXECUTION_DELAY);
verify(mCallsManager, times(1)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(true), eq(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT));
// Wait for another carrier timeout time, but should not expect any carrier service request
// is triggered.
Thread.sleep(CARRIER_SHORT_TIMEOUT_MS + CODE_EXECUTION_DELAY);
verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
any(ServiceConnection.class), anyInt(), any(UserHandle.class));
verify(mCallsManager, times(1)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(true), eq(CallRedirectionProcessor.UI_TYPE_USER_DEFINED_TIMEOUT));
}
@Test
public void testProcessGatewayCall() {
startProcessWithGateWayInfo();
enableUserDefinedCallRedirectionService();
enableCarrierCallRedirectionService();
mProcessor.performCallRedirection();
verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
any(ServiceConnection.class), anyInt(), any(UserHandle.class));
verify(mCallsManager, times(0)).onCallRedirectionComplete(eq(mCall), any(),
eq(mPhoneAccountHandle), eq(null), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_NO_ACTION));
waitForHandlerActionDelayed(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY,
CARRIER_SHORT_TIMEOUT_MS + CODE_EXECUTION_DELAY);
verify(mCallsManager, times(1)).onCallRedirectionComplete(eq(mCall), eq(mHandle),
eq(mPhoneAccountHandle), eq(mGatewayInfo), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_NO_ACTION));
}
@Test
public void testStripPostDialDigits() throws Exception {
startProcessWithNoGateWayInfo(ORIGINAL_NUMBER_WITH_POST_DIAL);
enableUserDefinedCallRedirectionService();
disableCarrierCallRedirectionService();
mProcessor.performCallRedirection();
// Capture binding and mock it out.
ArgumentCaptor<ServiceConnection> serviceConnectionCaptor = ArgumentCaptor.forClass(
ServiceConnection.class);
verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
serviceConnectionCaptor.capture(), anyInt(), any(UserHandle.class));
// Mock out a service which performed a redirection
IBinder mockBinder = mock(IBinder.class);
ICallRedirectionService mockCallRedirectionService = mock(ICallRedirectionService.class);
when(mockBinder.queryLocalInterface(anyString())).thenReturn(mockCallRedirectionService);
serviceConnectionCaptor.getValue().onServiceConnected(
USER_DEFINED_SERVICE_TEST_COMPONENT_NAME, mockBinder);
ArgumentCaptor<ICallRedirectionAdapter> redirectionAdapterCaptor = ArgumentCaptor.forClass(
ICallRedirectionAdapter.class);
ArgumentCaptor<Uri> uriArgumentCaptor = ArgumentCaptor.forClass(Uri.class);
verify(mockCallRedirectionService, times(1)).placeCall(redirectionAdapterCaptor.capture(),
uriArgumentCaptor.capture(), any(), anyBoolean());
// Verify the service did not get passed post-dial digits.
assertEquals(ORIGINAL_NUMBER_NO_POST_DIAL, uriArgumentCaptor.getValue());
// Pretend it was verified.
redirectionAdapterCaptor.getValue().redirectCall(REDIRECTED_GATEWAY_NUMBER,
mPhoneAccountHandle, false);
waitForHandlerAction(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY);
ArgumentCaptor<GatewayInfo> gatewayInfoArgumentCaptor = ArgumentCaptor.forClass(
GatewayInfo.class);
verify(mCallsManager, times(1)).onCallRedirectionComplete(eq(mCall),
eq(ORIGINAL_NUMBER_WITH_POST_DIAL), eq(mPhoneAccountHandle),
gatewayInfoArgumentCaptor.capture(), eq(SPEAKER_PHONE_ON), eq(VIDEO_STATE),
eq(false), eq(CallRedirectionProcessor.UI_TYPE_NO_ACTION));
assertEquals(REDIRECTED_GATEWAY_NUMBER_WITH_POST_DIAL,
gatewayInfoArgumentCaptor.getValue().getGatewayAddress());
}
}