Merge "Keep the BT devices cache of BluetoothDeviceManager updated" into main
diff --git a/flags/telecom_anomaly_report_flags.aconfig b/flags/telecom_anomaly_report_flags.aconfig
index b060ed0..5d42b86 100644
--- a/flags/telecom_anomaly_report_flags.aconfig
+++ b/flags/telecom_anomaly_report_flags.aconfig
@@ -16,3 +16,14 @@
description: "If a self-managed call is stuck in certain states, disconnect it"
bug: "360298368"
}
+
+# OWNER=tgunn TARGET=25Q2
+flag {
+ name: "dont_timeout_destroyed_calls"
+ namespace: "telecom"
+ description: "When create connection timeout is hit, if call is already destroyed, skip anomaly"
+ bug: "381684580"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/flags/telecom_api_flags.aconfig b/flags/telecom_api_flags.aconfig
index 75efdfa..2dfd878 100644
--- a/flags/telecom_api_flags.aconfig
+++ b/flags/telecom_api_flags.aconfig
@@ -73,3 +73,12 @@
description: "Formalizes the getLastKnownCellIdentity API that Telecom reliees on as a system api"
bug: "327454165"
}
+
+# OWNER=grantmenke TARGET=25Q2
+flag {
+ name: "allow_system_apps_resolve_voip_calls"
+ is_exported: true
+ namespace: "telecom"
+ description: "Allow system apps such as accessibility to accept and end VOIP calls."
+ bug: "353579043"
+}
diff --git a/src/com/android/server/telecom/CallAudioRouteController.java b/src/com/android/server/telecom/CallAudioRouteController.java
index 727d300..04f1934 100644
--- a/src/com/android/server/telecom/CallAudioRouteController.java
+++ b/src/com/android/server/telecom/CallAudioRouteController.java
@@ -1050,7 +1050,8 @@
mStatusBarNotifier.notifySpeakerphone(mCallsManager.hasAnyCalls());
} else {
if (mSpeakerDockRoute != null && getCallSupportedRoutes().contains(mSpeakerDockRoute)
- && mSpeakerDockRoute.getType() == AudioRoute.TYPE_SPEAKER) {
+ && mSpeakerDockRoute.getType() == AudioRoute.TYPE_SPEAKER
+ && mCurrentRoute.getType() != AudioRoute.TYPE_SPEAKER) {
routeTo(mIsActive, mSpeakerDockRoute);
// Since the route switching triggered by this message, we need to manually send it
// again so that we won't stuck in the pending route
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 14c8f62..260c238 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -130,11 +130,7 @@
synchronized (mLock) {
logIncoming("handleCreateConnectionComplete %s", callId);
Call call = mCallIdMapper.getCall(callId);
- if (call != null && mScheduledFutureMap.containsKey(call)) {
- ScheduledFuture<?> existingTimeout = mScheduledFutureMap.get(call);
- existingTimeout.cancel(false /* cancelIfRunning */);
- mScheduledFutureMap.remove(call);
- }
+ maybeRemoveCleanupFuture(call);
// Check status hints image for cross user access
if (connection.getStatusHints() != null) {
Icon icon = connection.getStatusHints().getIcon();
@@ -174,11 +170,7 @@
synchronized (mLock) {
logIncoming("handleCreateConferenceComplete %s", callId);
Call call = mCallIdMapper.getCall(callId);
- if (call != null && mScheduledFutureMap.containsKey(call)) {
- ScheduledFuture<?> existingTimeout = mScheduledFutureMap.get(call);
- existingTimeout.cancel(false /* cancelIfRunning */);
- mScheduledFutureMap.remove(call);
- }
+ maybeRemoveCleanupFuture(call);
// Check status hints image for cross user access
if (conference.getStatusHints() != null) {
Icon icon = conference.getStatusHints().getIcon();
@@ -1678,6 +1670,9 @@
Log.getExternalSession(TELECOM_ABBREVIATION));
} catch (RemoteException e) {
Log.e(this, e, "Failure to createConference -- %s", getComponentName());
+ if (mFlags.dontTimeoutDestroyedCalls()) {
+ maybeRemoveCleanupFuture(call);
+ }
mPendingResponses.remove(callId).handleCreateConferenceFailure(
new DisconnectCause(DisconnectCause.ERROR, e.toString()));
}
@@ -1708,6 +1703,9 @@
Log.i(ConnectionServiceWrapper.this, "Call not present"
+ " in call id mapper, maybe it was aborted before the bind"
+ " completed successfully?");
+ if (mFlags.dontTimeoutDestroyedCalls()) {
+ maybeRemoveCleanupFuture(call);
+ }
response.handleCreateConnectionFailure(
new DisconnectCause(DisconnectCause.CANCELED));
return;
@@ -1793,6 +1791,9 @@
mScheduledFutureMap.put(call, future);
try {
if (mFlags.cswServiceInterfaceIsNull() && mServiceInterface == null) {
+ if (mFlags.dontTimeoutDestroyedCalls()) {
+ maybeRemoveCleanupFuture(call);
+ }
mPendingResponses.remove(callId).handleCreateConnectionFailure(
new DisconnectCause(DisconnectCause.ERROR,
"CSW#oCC ServiceInterface is null"));
@@ -1807,6 +1808,9 @@
}
} catch (RemoteException e) {
Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
+ if (mFlags.dontTimeoutDestroyedCalls()) {
+ maybeRemoveCleanupFuture(call);
+ }
mPendingResponses.remove(callId).handleCreateConnectionFailure(
new DisconnectCause(DisconnectCause.ERROR, e.toString()));
}
@@ -2286,6 +2290,9 @@
if (response != null) {
response.handleCreateConnectionFailure(disconnectCause);
}
+ if (mFlags.dontTimeoutDestroyedCalls()) {
+ maybeRemoveCleanupFuture(mCallIdMapper.getCall(callId));
+ }
mCallIdMapper.removeCall(callId);
}
@@ -2295,6 +2302,9 @@
if (response != null) {
response.handleCreateConnectionFailure(disconnectCause);
}
+ if (mFlags.dontTimeoutDestroyedCalls()) {
+ maybeRemoveCleanupFuture(call);
+ }
mCallIdMapper.removeCall(call);
}
@@ -2754,4 +2764,20 @@
public void setAnomalyReporterAdapter(AnomalyReporterAdapter mAnomalyReporterAdapter){
mAnomalyReporter = mAnomalyReporterAdapter;
}
+
+ /**
+ * Given a call, unschedule and cancel the cleanup future.
+ * @param call the call.
+ */
+ private void maybeRemoveCleanupFuture(Call call) {
+ if (call == null) {
+ return;
+ }
+ ScheduledFuture<?> future = mScheduledFutureMap.remove(call);
+ if (future == null) {
+ return;
+ }
+ future.cancel(false /* interrupt */);
+
+ }
}
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 5eb05dc..488524f 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -160,6 +160,7 @@
private final FeatureFlags mFeatureFlags;
private final com.android.internal.telephony.flags.FeatureFlags mTelephonyFeatureFlags;
private final TelecomMetricsController mMetricsController;
+ private final String mSystemUiPackageName;
private AnomalyReporterAdapter mAnomalyReporter = new AnomalyReporterAdapterImpl();
private final Context mContext;
private final AppOpsManager mAppOpsManager;
@@ -1437,7 +1438,7 @@
// ensure the callingPackage is not spoofed
// skip check for privileged UIDs and throw SE if package does not match records
- if (!isPrivilegedUid(callingPackage)
+ if (!isPrivilegedUid()
&& !callingUidMatchesPackageManagerRecords(callingPackage)) {
EventLog.writeEvent(0x534e4554, "236813210", Binder.getCallingUid(),
"getCallStateUsingPackage");
@@ -1470,17 +1471,36 @@
}
}
- private boolean isPrivilegedUid(String callingPackage) {
+ private boolean isPrivilegedUid() {
int callingUid = Binder.getCallingUid();
- boolean isPrivileged = false;
- switch (callingUid) {
- case Process.ROOT_UID:
- case Process.SYSTEM_UID:
- case Process.SHELL_UID:
- isPrivileged = true;
- break;
+ return mFeatureFlags.allowSystemAppsResolveVoipCalls()
+ ? (UserHandle.isSameApp(callingUid, Process.ROOT_UID)
+ || UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+ || UserHandle.isSameApp(callingUid, Process.SHELL_UID))
+ : (callingUid == Process.ROOT_UID
+ || callingUid == Process.SYSTEM_UID
+ || callingUid == Process.SHELL_UID);
+ }
+
+ private boolean isSysUiUid() {
+ int callingUid = Binder.getCallingUid();
+ int systemUiUid;
+ if (mPackageManager != null && mSystemUiPackageName != null) {
+ try {
+ systemUiUid = mPackageManager.getPackageUid(mSystemUiPackageName, 0);
+ Log.i(TAG, "isSysUiUid: callingUid = " + callingUid + "; systemUiUid = "
+ + systemUiUid);
+ return UserHandle.isSameApp(callingUid, systemUiUid);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "isSysUiUid: caught PackageManager NameNotFoundException = " + e);
+ return false;
+ }
+ } else {
+ Log.w(TAG, "isSysUiUid: caught null check and returned false; "
+ + "mPackageManager = " + mPackageManager + "; mSystemUiPackageName = "
+ + mSystemUiPackageName);
}
- return isPrivileged;
+ return false;
}
/**
@@ -1496,11 +1516,18 @@
if (!enforceAnswerCallPermission(callingPackage, Binder.getCallingUid())) {
throw new SecurityException("requires ANSWER_PHONE_CALLS permission");
}
-
+ // Legacy behavior is to ignore whether the invocation is from a system app:
+ boolean isCallerPrivileged = false;
+ if (mFeatureFlags.allowSystemAppsResolveVoipCalls()) {
+ isCallerPrivileged = isPrivilegedUid() || isSysUiUid();
+ Log.i(TAG, "endCall: Binder.getCallingUid = [" +
+ Binder.getCallingUid() + "] isCallerPrivileged = " +
+ isCallerPrivileged);
+ }
long token = Binder.clearCallingIdentity();
event.setResult(ApiStats.RESULT_NORMAL);
try {
- return endCallInternal(callingPackage);
+ return endCallInternal(callingPackage, isCallerPrivileged);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1522,11 +1549,19 @@
Log.startSession("TSI.aRC", Log.getPackageAbbreviation(packageName));
synchronized (mLock) {
if (!enforceAnswerCallPermission(packageName, Binder.getCallingUid())) return;
-
+ // Legacy behavior is to ignore whether the invocation is from a system app:
+ boolean isCallerPrivileged = false;
+ if (mFeatureFlags.allowSystemAppsResolveVoipCalls()) {
+ isCallerPrivileged = isPrivilegedUid() || isSysUiUid();
+ Log.i(TAG, "acceptRingingCall: Binder.getCallingUid = [" +
+ Binder.getCallingUid() + "] isCallerPrivileged = " +
+ isCallerPrivileged);
+ }
long token = Binder.clearCallingIdentity();
event.setResult(ApiStats.RESULT_NORMAL);
try {
- acceptRingingCallInternal(DEFAULT_VIDEO_STATE, packageName);
+ acceptRingingCallInternal(DEFAULT_VIDEO_STATE, packageName,
+ isCallerPrivileged);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1549,11 +1584,18 @@
Log.startSession("TSI.aRCWVS", Log.getPackageAbbreviation(packageName));
synchronized (mLock) {
if (!enforceAnswerCallPermission(packageName, Binder.getCallingUid())) return;
-
+ // Legacy behavior is to ignore whether the invocation is from a system app:
+ boolean isCallerPrivileged = false;
+ if (mFeatureFlags.allowSystemAppsResolveVoipCalls()) {
+ isCallerPrivileged = isPrivilegedUid() || isSysUiUid();
+ Log.i(TAG, "acceptRingingCallWithVideoState: Binder.getCallingUid = "
+ + "[" + Binder.getCallingUid() + "] isCallerPrivileged = " +
+ isCallerPrivileged);
+ }
long token = Binder.clearCallingIdentity();
event.setResult(ApiStats.RESULT_NORMAL);
try {
- acceptRingingCallInternal(videoState, packageName);
+ acceptRingingCallInternal(videoState, packageName, isCallerPrivileged);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2918,7 +2960,8 @@
SettingsSecureAdapter settingsSecureAdapter,
FeatureFlags featureFlags,
com.android.internal.telephony.flags.FeatureFlags telephonyFeatureFlags,
- TelecomSystem.SyncRoot lock, TelecomMetricsController metricsController) {
+ TelecomSystem.SyncRoot lock, TelecomMetricsController metricsController,
+ String sysUiPackageName) {
mContext = context;
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
@@ -2940,6 +2983,7 @@
mSubscriptionManagerAdapter = subscriptionManagerAdapter;
mSettingsSecureAdapter = settingsSecureAdapter;
mMetricsController = metricsController;
+ mSystemUiPackageName = sysUiPackageName;
mDefaultDialerCache.observeDefaultDialerApplication(mContext.getMainExecutor(), userId -> {
String defaultDialer = mDefaultDialerCache.getDefaultDialerApplication(userId);
@@ -3054,13 +3098,14 @@
return false;
}
- private void acceptRingingCallInternal(int videoState, String packageName) {
+ private void acceptRingingCallInternal(int videoState, String packageName,
+ boolean isCallerPrivileged) {
Call call = mCallsManager.getFirstCallWithState(CallState.RINGING,
CallState.SIMULATED_RINGING);
if (call != null) {
- if (call.isSelfManaged()) {
+ if (call.isSelfManaged() && !isCallerPrivileged) {
Log.addEvent(call, LogUtils.Events.REQUEST_ACCEPT,
- "self-mgd accept ignored from " + packageName);
+ "self-mgd accept ignored from non-privileged app " + packageName);
return;
}
@@ -3075,7 +3120,7 @@
// Supporting methods for the ITelecomService interface implementation.
//
- private boolean endCallInternal(String callingPackage) {
+ private boolean endCallInternal(String callingPackage, boolean isCallerPrivileged) {
// Always operate on the foreground call if one exists, otherwise get the first call in
// priority order by call-state.
Call call = mCallsManager.getForegroundCall();
@@ -3095,9 +3140,10 @@
return false;
}
- if (call.isSelfManaged()) {
+ if (call.isSelfManaged() && !isCallerPrivileged) {
Log.addEvent(call, LogUtils.Events.REQUEST_DISCONNECT,
- "self-mgd disconnect ignored from " + callingPackage);
+ "self-mgd disconnect ignored from non-privileged app " +
+ callingPackage);
return false;
}
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index a714096..7020885 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -224,6 +224,7 @@
RoleManagerAdapter roleManagerAdapter,
ContactsAsyncHelper.Factory contactsAsyncHelperFactory,
DeviceIdleControllerAdapter deviceIdleControllerAdapter,
+ String sysUiPackageName,
Ringer.AccessibilityManagerAdapter accessibilityManagerAdapter,
Executor asyncTaskExecutor,
Executor asyncCallAudioTaskExecutor,
@@ -503,7 +504,8 @@
featureFlags,
null,
mLock,
- metricsController);
+ metricsController,
+ sysUiPackageName);
} finally {
Log.endSession();
}
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index 2d8c78e..4db3e14 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -81,10 +81,11 @@
Log.d(this, "onBind");
return new ITelecomLoader.Stub() {
@Override
- public ITelecomService createTelecomService(IInternalServiceRetriever retriever) {
+ public ITelecomService createTelecomService(IInternalServiceRetriever retriever,
+ String sysUiPackageName) {
InternalServiceRetrieverAdapter adapter =
new InternalServiceRetrieverAdapter(retriever);
- initializeTelecomSystem(TelecomService.this, adapter);
+ initializeTelecomSystem(TelecomService.this, adapter, sysUiPackageName);
synchronized (getTelecomSystem().getLock()) {
return getTelecomSystem().getTelecomServiceImpl().getBinder();
}
@@ -103,7 +104,7 @@
* @param context
*/
static void initializeTelecomSystem(Context context,
- InternalServiceRetrieverAdapter internalServiceRetriever) {
+ InternalServiceRetrieverAdapter internalServiceRetriever, String sysUiPackageName) {
if (TelecomSystem.getInstance() == null) {
FeatureFlags featureFlags = new FeatureFlagsImpl();
NotificationChannelManager notificationChannelManager =
@@ -204,6 +205,7 @@
(RoleManager) context.getSystemService(Context.ROLE_SERVICE)),
new ContactsAsyncHelper.Factory(),
internalServiceRetriever.getDeviceIdleController(),
+ sysUiPackageName,
new Ringer.AccessibilityManagerAdapter() {
@Override
public boolean startFlashNotificationSequence(
diff --git a/src/com/android/server/telecom/metrics/ApiStats.java b/src/com/android/server/telecom/metrics/ApiStats.java
index f0b5dc7..4b23e47 100644
--- a/src/com/android/server/telecom/metrics/ApiStats.java
+++ b/src/com/android/server/telecom/metrics/ApiStats.java
@@ -191,6 +191,8 @@
Arrays.stream(mPulledAtoms.telecomApiStats).forEach(v -> data.add(
TelecomStatsLog.buildStatsEvent(getTag(),
v.getApiName(), v.getUid(), v.getApiResult(), v.getCount())));
+ mApiStatsMap.clear();
+ onAggregate();
return StatsManager.PULL_SUCCESS;
} else {
return StatsManager.PULL_SKIP;
diff --git a/src/com/android/server/telecom/metrics/AudioRouteStats.java b/src/com/android/server/telecom/metrics/AudioRouteStats.java
index 21624f1..4611b22 100644
--- a/src/com/android/server/telecom/metrics/AudioRouteStats.java
+++ b/src/com/android/server/telecom/metrics/AudioRouteStats.java
@@ -99,6 +99,8 @@
TelecomStatsLog.buildStatsEvent(getTag(),
v.getCallAudioRouteSource(), v.getCallAudioRouteDest(),
v.getSuccess(), v.getRevert(), v.getCount(), v.getAverageLatencyMs())));
+ mAudioRouteStatsMap.clear();
+ onAggregate();
return StatsManager.PULL_SUCCESS;
} else {
return StatsManager.PULL_SKIP;
diff --git a/src/com/android/server/telecom/metrics/CallStats.java b/src/com/android/server/telecom/metrics/CallStats.java
index 7ebeba6..8bdeffb 100644
--- a/src/com/android/server/telecom/metrics/CallStats.java
+++ b/src/com/android/server/telecom/metrics/CallStats.java
@@ -81,6 +81,8 @@
v.getCallDirection(), v.getExternalCall(), v.getEmergencyCall(),
v.getMultipleAudioAvailable(), v.getAccountType(), v.getUid(),
v.getCount(), v.getAverageDurationMs())));
+ mCallStatsMap.clear();
+ onAggregate();
return StatsManager.PULL_SUCCESS;
} else {
return StatsManager.PULL_SKIP;
diff --git a/src/com/android/server/telecom/metrics/ErrorStats.java b/src/com/android/server/telecom/metrics/ErrorStats.java
index f70f6d8..f334710 100644
--- a/src/com/android/server/telecom/metrics/ErrorStats.java
+++ b/src/com/android/server/telecom/metrics/ErrorStats.java
@@ -140,6 +140,8 @@
Arrays.stream(mPulledAtoms.telecomErrorStats).forEach(v -> data.add(
TelecomStatsLog.buildStatsEvent(getTag(),
v.getSubmodule(), v.getError(), v.getCount())));
+ mErrorStatsMap.clear();
+ onAggregate();
return StatsManager.PULL_SUCCESS;
} else {
return StatsManager.PULL_SKIP;
diff --git a/tests/src/com/android/server/telecom/tests/TelecomPulledAtomTest.java b/tests/src/com/android/server/telecom/tests/TelecomPulledAtomTest.java
index 8ae734c..d3c7859 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomPulledAtomTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomPulledAtomTest.java
@@ -207,12 +207,14 @@
createTestFileForApiStats(System.currentTimeMillis() - MIN_PULL_INTERVAL_MILLIS - 1);
ApiStats apiStats = spy(new ApiStats(mSpyContext, mLooper));
final List<StatsEvent> data = new ArrayList<>();
+ int sizePulled = apiStats.mPulledAtoms.telecomApiStats.length;
int result = apiStats.pull(data);
assertEquals(StatsManager.PULL_SUCCESS, result);
verify(apiStats).onPull(eq(data));
- assertEquals(data.size(), apiStats.mPulledAtoms.telecomApiStats.length);
+ assertEquals(data.size(), sizePulled);
+ assertEquals(apiStats.mPulledAtoms.telecomApiStats.length, 0);
}
@Test
@@ -233,12 +235,14 @@
createTestFileForAudioRouteStats(System.currentTimeMillis() - MIN_PULL_INTERVAL_MILLIS - 1);
AudioRouteStats audioRouteStats = spy(new AudioRouteStats(mSpyContext, mLooper));
final List<StatsEvent> data = new ArrayList<>();
+ int sizePulled = audioRouteStats.mPulledAtoms.callAudioRouteStats.length;
int result = audioRouteStats.pull(data);
assertEquals(StatsManager.PULL_SUCCESS, result);
verify(audioRouteStats).onPull(eq(data));
- assertEquals(data.size(), audioRouteStats.mPulledAtoms.callAudioRouteStats.length);
+ assertEquals(data.size(), sizePulled);
+ assertEquals(audioRouteStats.mPulledAtoms.callAudioRouteStats.length, 0);
}
@Test
@@ -259,12 +263,14 @@
createTestFileForCallStats(System.currentTimeMillis() - MIN_PULL_INTERVAL_MILLIS - 1);
CallStats callStats = spy(new CallStats(mSpyContext, mLooper));
final List<StatsEvent> data = new ArrayList<>();
+ int sizePulled = callStats.mPulledAtoms.callStats.length;
int result = callStats.pull(data);
assertEquals(StatsManager.PULL_SUCCESS, result);
verify(callStats).onPull(eq(data));
- assertEquals(data.size(), callStats.mPulledAtoms.callStats.length);
+ assertEquals(data.size(), sizePulled);
+ assertEquals(callStats.mPulledAtoms.callStats.length, 0);
}
@Test
@@ -285,12 +291,14 @@
createTestFileForErrorStats(System.currentTimeMillis() - MIN_PULL_INTERVAL_MILLIS - 1);
ErrorStats errorStats = spy(new ErrorStats(mSpyContext, mLooper));
final List<StatsEvent> data = new ArrayList<>();
+ int sizePulled = errorStats.mPulledAtoms.telecomErrorStats.length;
int result = errorStats.pull(data);
assertEquals(StatsManager.PULL_SUCCESS, result);
verify(errorStats).onPull(eq(data));
- assertEquals(data.size(), errorStats.mPulledAtoms.telecomErrorStats.length);
+ assertEquals(data.size(), sizePulled);
+ assertEquals(errorStats.mPulledAtoms.telecomErrorStats.length, 0);
}
@Test
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 07a12c4..6b0555c 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -209,6 +209,7 @@
private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
+ private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
private static final String DEFAULT_DIALER_PACKAGE = "com.google.android.dialer";
private static final UserHandle USER_HANDLE_16 = new UserHandle(16);
private static final UserHandle USER_HANDLE_17 = new UserHandle(17);
@@ -260,7 +261,8 @@
mFeatureFlags,
mTelephonyFeatureFlags,
mLock,
- mMockTelecomMetricsController);
+ mMockTelecomMetricsController,
+ SYSTEM_UI_PACKAGE);
telecomServiceImpl.setTransactionManager(mTransactionManager);
telecomServiceImpl.setAnomalyReporterAdapter(mAnomalyReporterAdapter);
mTSIBinder = telecomServiceImpl.getBinder();
@@ -2307,7 +2309,8 @@
}
/**
- * Ensure self-managed calls cannot be ended using {@link TelecomManager#endCall()}.
+ * Ensure self-managed calls cannot be ended using {@link TelecomManager#endCall()} when the
+ * caller of this method is not considered privileged.
* @throws Exception
*/
@SmallTest
@@ -2324,7 +2327,8 @@
/**
* Ensure self-managed calls cannot be answered using {@link TelecomManager#acceptRingingCall()}
- * or {@link TelecomManager#acceptRingingCall(int)}.
+ * or {@link TelecomManager#acceptRingingCall(int)} when the caller of these methods is not
+ * considered privileged.
* @throws Exception
*/
@SmallTest
@@ -2339,6 +2343,53 @@
verify(mFakeCallsManager, never()).answerCall(eq(call), anyInt());
}
+ /**
+ * Ensure self-managed calls can be answered using {@link TelecomManager#acceptRingingCall()}
+ * or {@link TelecomManager#acceptRingingCall(int)} if the caller of these methods is
+ * privileged.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testCanAnswerSelfManagedCallIfPrivileged() throws Exception {
+ when(mFeatureFlags.allowSystemAppsResolveVoipCalls()).thenReturn(true);
+ // Configure the test so that the caller of acceptRingingCall is considered privileged:
+ when(mPackageManager.getPackageUid(SYSTEM_UI_PACKAGE, 0))
+ .thenReturn(Binder.getCallingUid());
+
+ // Ensure that the call is successfully accepted:
+ Call call = mock(Call.class);
+ when(call.isSelfManaged()).thenReturn(true);
+ when(call.getState()).thenReturn(CallState.ACTIVE);
+ when(mFakeCallsManager.getFirstCallWithState(any()))
+ .thenReturn(call);
+ mTSIBinder.acceptRingingCall(TEST_PACKAGE);
+ verify(mFakeCallsManager).answerCall(eq(call), anyInt());
+ }
+
+ /**
+ * Ensure self-managed calls can be ended using {@link TelecomManager#endCall()} when the
+ * caller of these methods is privileged.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testCanEndSelfManagedCallIfPrivileged() throws Exception {
+ when(mFeatureFlags.allowSystemAppsResolveVoipCalls()).thenReturn(true);
+ // Configure the test so that the caller of endCall is considered privileged:
+ when(mPackageManager.getPackageUid(SYSTEM_UI_PACKAGE, 0))
+ .thenReturn(Binder.getCallingUid());
+ // Set up the call:
+ Call call = mock(Call.class);
+ when(call.isSelfManaged()).thenReturn(true);
+ when(call.getState()).thenReturn(CallState.ACTIVE);
+ when(mFakeCallsManager.getFirstCallWithState(any()))
+ .thenReturn(call);
+ // Ensure that the call is successfully ended:
+ assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
+ verify(mFakeCallsManager).disconnectCall(eq(call));
+ }
+
@SmallTest
@Test
public void testGetAdnUriForPhoneAccount() throws Exception {
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 4463d65..1e65011 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -224,6 +224,7 @@
@Mock
com.android.internal.telephony.flags.FeatureFlags mTelephonyFlags;
+ private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
final ComponentName mInCallServiceComponentNameX =
new ComponentName(
"incall-service-package-X",
@@ -580,7 +581,8 @@
ContactsAsyncHelper.ContentResolverAdapter adapter) {
return new ContactsAsyncHelper(adapter, mHandlerThread.getLooper());
}
- }, mDeviceIdleControllerAdapter, mAccessibilityManagerAdapter,
+ }, mDeviceIdleControllerAdapter, SYSTEM_UI_PACKAGE,
+ mAccessibilityManagerAdapter,
Runnable::run,
Runnable::run,
mBlockedNumbersAdapter,