blob: d5f088a9de9e19dc4cc5e47cdccd800b329ba064 [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 android.telecom.cts;
import static android.telecom.cts.TestUtils.TEST_PHONE_ACCOUNT_HANDLE;
import static android.telecom.cts.TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import android.app.UiModeManager;
import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.telecom.TelecomManager;
import android.telecom.cts.thirdptyincallservice.CtsThirdPartyInCallService;
import android.telecom.cts.thirdptyincallservice.CtsThirdPartyInCallServiceControl;
import android.telecom.cts.thirdptyincallservice.ICtsThirdPartyInCallServiceControl;
import android.text.TextUtils;
import android.util.Log;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class ThirdPartyInCallServiceTest extends BaseTelecomTestWithMockServices {
private static final String TAG = ThirdPartyInCallServiceTest.class.getSimpleName();
private static final String ROLE_COMPANION_APP = "android.app.role.CALL_COMPANION";
private static final Uri sTestUri = Uri.parse("tel:555-TEST");
private Context mContext;
private UiModeManager mUiModeManager;
private TelecomManager mTelecomManager;
private CtsRoleManagerAdapter mCtsRoleManagerAdapter;
ICtsThirdPartyInCallServiceControl mICtsThirdPartyInCallServiceControl;
private boolean mSkipNullUnboundLatch;
private String mPreviousRoleHolder;
private String mThirdPartyPackageName;
@Override
public void setUp() throws Exception {
super.setUp();
mContext = getInstrumentation().getContext();
mCtsRoleManagerAdapter = new CtsRoleManagerAdapter(getInstrumentation());
mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
mUiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
setUpControl();
mICtsThirdPartyInCallServiceControl.resetLatchForServiceBound(false);
mSkipNullUnboundLatch = false;
mThirdPartyPackageName = CtsThirdPartyInCallService.class.getPackage().getName();
// Ensure no ThirdPartyInCallService serves as a companion app.
// (Probably from previous test failures, if any.)
mCtsRoleManagerAdapter.removeCompanionAppRoleHolder(mThirdPartyPackageName);
}
@Override
public void tearDown() throws Exception {
mICtsThirdPartyInCallServiceControl.resetCalls();
// Remove the third party companion app before tear down.
mCtsRoleManagerAdapter.removeCompanionAppRoleHolder(mThirdPartyPackageName);
super.tearDown();
if (!mSkipNullUnboundLatch) {
assertBindStatus(/* true: bind, false: unbind */false, /* expected result */true);
}
}
public void doNotTestCallWithoutThirdPartyApp() throws Exception {
// No companion apps
List<String> previousHolders = mCtsRoleManagerAdapter.getRoleHolders(ROLE_COMPANION_APP);
assertEquals(0, previousHolders.size());
// No car mode dialer
assertFalse(mThirdPartyPackageName.equals(mPreviousRoleHolder));
int previousCallCount = mICtsThirdPartyInCallServiceControl.getLocalCallCount();
addAndVerifyNewIncomingCall(sTestUri, null);
assertBindStatus(/* true: bind, false: unbind */true, /* expected result */false);
assertCallCount(previousCallCount);
// Third Party InCallService hasn't been bound yet, unbound latch can be null when tearDown.
mSkipNullUnboundLatch = true;
}
public void doNotTestCallWithCompanionApps() throws Exception {
// Set companion app default.
mCtsRoleManagerAdapter.addCompanionAppRoleHolder(mThirdPartyPackageName);
List<String> previousHolders = mCtsRoleManagerAdapter.getRoleHolders(ROLE_COMPANION_APP);
assertEquals(1, previousHolders.size());
assertEquals(mThirdPartyPackageName, previousHolders.get(0));
int previousCallCount = mICtsThirdPartyInCallServiceControl.getLocalCallCount();
addAndVerifyNewIncomingCall(sTestUri, null);
assertBindStatus(/* true: bind, false: unbind */true, /* expected result */true);
assertCallCount(previousCallCount + 1);
mICtsThirdPartyInCallServiceControl.resetLatchForServiceBound(true);
}
private void addAndVerifyNewIncomingCallInCarMode(Uri incomingHandle, Bundle extras)
throws RemoteException {
int currentCallCount = mICtsThirdPartyInCallServiceControl.getLocalCallCount();
if (extras == null) {
extras = new Bundle();
}
extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle);
mTelecomManager.addNewIncomingCall(TEST_PHONE_ACCOUNT_HANDLE, extras);
assertBindStatus(/* true: bind, false: unbind */true, /* expected result */true);
assertCallCount(currentCallCount + 1);
}
/**
*
* @param bind: check the status of InCallService bind latches.
* Values: true (bound latch), false (unbound latch).
* @param success: whether the latch should have counted down.
*/
private void assertBindStatus(boolean bind, boolean success) {
waitUntilConditionIsTrueOrTimeout(new Condition() {
@Override
public Object expected() {
return success;
}
@Override
public Object actual() {
try {
return mICtsThirdPartyInCallServiceControl.checkBindStatus(bind);
} catch (RemoteException re) {
Log.e(TAG, "Remote exception when checking bind status: " + re);
return false;
}
}
}, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, "Unable to " + (bind ? "Bind" : "Unbind")
+ " third party in call service");
}
private void assertCallCount(int expected) {
waitUntilConditionIsTrueOrTimeout(new Condition() {
@Override
public Object expected() {
return expected;
}
@Override
public Object actual() {
try {
return mICtsThirdPartyInCallServiceControl.getLocalCallCount();
} catch (RemoteException re) {
Log.e(TAG, "Remote exception when getting local call count: " + re);
return -1;
}
}
}, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
"Failed to match localCallCount and expected: " + expected);
}
private void setUpControl() throws InterruptedException {
Intent bindIntent = new Intent(CtsThirdPartyInCallServiceControl.CONTROL_INTERFACE_ACTION);
// mContext is android.telecom.cts, which doesn't include thirdptyincallservice.
ComponentName controlComponentName =
ComponentName.createRelative(
CtsThirdPartyInCallServiceControl.class.getPackage().getName(),
CtsThirdPartyInCallServiceControl.class.getName());
bindIntent.setComponent(controlComponentName);
final CountDownLatch bindLatch = new CountDownLatch(1);
boolean success = mContext.bindService(bindIntent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "Service Connected: " + name);
mICtsThirdPartyInCallServiceControl =
ICtsThirdPartyInCallServiceControl.Stub.asInterface(service);
bindLatch.countDown();
}
@Override
public void onServiceDisconnected(ComponentName name) {
mICtsThirdPartyInCallServiceControl = null;
}
}, Context.BIND_AUTO_CREATE);
if (!success) {
fail("Failed to get control interface -- bind error");
}
bindLatch.await(WAIT_FOR_STATE_CHANGE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
private void cacheCurrentRoleHolder(String roleName) {
runWithShellPermissionIdentity(() -> {
List<String> previousHolders = mCtsRoleManagerAdapter.getRoleHolders(roleName);
if (previousHolders == null || previousHolders.isEmpty()) {
mPreviousRoleHolder = null;
} else {
mPreviousRoleHolder = previousHolders.get(0);
}
});
}
}