Merge "Clarify InCallController Log message"
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index 9e1b5c7..86d2aaa 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -357,7 +357,11 @@
if (mCallAudioManager.startRinging()) {
mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
- mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+ // Do not set MODE_RINGTONE if we were previously in the CALL_SCREENING mode -- this
+ // trips up the audio system.
+ if (mAudioManager.getMode() != NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING) {
+ mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+ }
mCallAudioManager.setCallAudioRouteFocusState(
CallAudioRouteStateMachine.RINGING_FOCUS);
} else {
diff --git a/src/com/android/server/telecom/CallIdMapper.java b/src/com/android/server/telecom/CallIdMapper.java
index da2c199..2cd5c79 100644
--- a/src/com/android/server/telecom/CallIdMapper.java
+++ b/src/com/android/server/telecom/CallIdMapper.java
@@ -20,6 +20,7 @@
import com.android.internal.annotations.VisibleForTesting;
+import java.util.Collection;
import java.util.Map;
/** Utility to map {@link Call} objects to unique IDs. IDs are generated when a call is added. */
@@ -71,6 +72,10 @@
return mSecondaryMap.get(value);
}
+ public Collection<V> getValues() {
+ return mPrimaryMap.values();
+ }
+
public void clear() {
mPrimaryMap.clear();
mSecondaryMap.clear();
@@ -132,6 +137,10 @@
return mCalls.getValue(callId);
}
+ Collection<Call> getCalls() {
+ return mCalls.getValues();
+ }
+
void clear() {
mCalls.clear();
}
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 02df33a..158c7e1 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -20,9 +20,11 @@
import android.annotation.NonNull;
import android.app.Notification;
import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -44,6 +46,7 @@
import android.telecom.TelecomManager;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
// TODO: Needed for move to system service: import com.android.internal.R;
@@ -59,6 +62,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -323,7 +327,10 @@
String packageName = mInCallServiceInfo.getComponentName().getPackageName();
mContext.unbindService(mServiceConnection);
mIsConnected = false;
- if (mIsNullBinding) {
+ if (mIsNullBinding && mInCallServiceInfo.getType() != IN_CALL_SERVICE_TYPE_NON_UI) {
+ // Non-UI InCallServices are allowed to return null from onBind if they don't
+ // want to handle calls at the moment, so don't report them to the user as
+ // crashed.
sendCrashedInCallServiceNotification(packageName);
}
if (mCall != null) {
@@ -722,6 +729,20 @@
}
pw.decreaseIndent();
}
+
+ public void addConnections(List<InCallServiceBindingConnection> newConnections) {
+ // connect() needs to be called with a Call object. Since we're in the middle of any
+ // possible number of calls right now, choose an arbitrary one from the ones that
+ // InCallController is tracking.
+ if (mCallIdMapper.getCalls().isEmpty()) {
+ Log.w(InCallController.this, "No calls tracked while adding new NonUi incall");
+ return;
+ }
+ Call callToConnectWith = mCallIdMapper.getCalls().iterator().next();
+ for (InCallServiceBindingConnection newConnection : newConnections) {
+ newConnection.connect(callToConnectWith);
+ }
+ }
}
private final Call.Listener mCallListener = new Call.ListenerBase() {
@@ -848,6 +869,38 @@
}
};
+ private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.startSession("ICC.pCR");
+ try {
+ if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())) {
+ synchronized (mLock) {
+ String changedPackage = intent.getData().getSchemeSpecificPart();
+ List<InCallServiceBindingConnection> componentsToBind =
+ Arrays.stream(intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST))
+ .map((className) ->
+ ComponentName.createRelative(changedPackage,
+ className))
+ .filter(mKnownNonUiInCallServices::contains)
+ .flatMap(componentName -> getInCallServiceComponents(
+ componentName,
+ IN_CALL_SERVICE_TYPE_NON_UI).stream())
+ .map(InCallServiceBindingConnection::new)
+ .collect(Collectors.toList());
+
+ if (mNonUIInCallServiceConnections != null) {
+ mNonUIInCallServiceConnections.addConnections(componentsToBind);
+ }
+ }
+ }
+ } finally {
+ Log.endSession();
+ }
+ }
+ };
+
private final SystemStateListener mSystemStateListener =
(priority, packageName, isCarMode) -> InCallController.this.handleCarModeChange(
priority, packageName, isCarMode);
@@ -876,6 +929,11 @@
private NonUIInCallServiceConnectionCollection mNonUIInCallServiceConnections;
private final ClockProxy mClockProxy;
+ // A set of known non-UI in call services on the device, including those that are disabled.
+ // We track this so that we can efficiently bind to them when we're notified that a new
+ // component has been enabled.
+ private Set<ComponentName> mKnownNonUiInCallServices = new ArraySet<>();
+
// 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.
private CompletableFuture<Boolean> mBindingFuture = CompletableFuture.completedFuture(true);
@@ -1231,6 +1289,7 @@
* Unbinds an existing bound connection to the in-call app.
*/
private void unbindFromServices() {
+ mContext.unregisterReceiver(mPackageChangedReceiver);
if (mInCallServiceConnection != null) {
mInCallServiceConnection.disconnect();
mInCallServiceConnection = null;
@@ -1316,6 +1375,10 @@
}
mNonUIInCallServiceConnections = new NonUIInCallServiceConnectionCollection(nonUIInCalls);
mNonUIInCallServiceConnections.connect(call);
+
+ IntentFilter packageChangedFilter = new IntentFilter(Intent.ACTION_PACKAGE_CHANGED);
+ packageChangedFilter.addDataScheme("package");
+ mContext.registerReceiver(mPackageChangedReceiver, packageChangedFilter);
}
private InCallServiceInfo getDefaultDialerComponent() {
@@ -1389,7 +1452,7 @@
PackageManager packageManager = mContext.getPackageManager();
for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
serviceIntent,
- PackageManager.GET_META_DATA,
+ PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS,
mCallsManager.getCurrentUserHandle().getIdentifier())) {
ServiceInfo serviceInfo = entry.serviceInfo;
if (serviceInfo != null) {
@@ -1402,14 +1465,13 @@
int currentType = getInCallServiceType(entry.serviceInfo, packageManager,
packageName);
- if (requestedType == 0 || requestedType == currentType) {
- if (requestedType == IN_CALL_SERVICE_TYPE_NON_UI) {
- // We enforce the rule that self-managed calls are not supported by non-ui
- // InCallServices.
- isSelfManageCallsSupported = false;
- }
- retval.add(new InCallServiceInfo(
- new ComponentName(serviceInfo.packageName, serviceInfo.name),
+ ComponentName foundComponentName =
+ new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ if (requestedType == IN_CALL_SERVICE_TYPE_NON_UI) {
+ mKnownNonUiInCallServices.add(foundComponentName);
+ }
+ if (serviceInfo.enabled && (requestedType == 0 || requestedType == currentType)) {
+ retval.add(new InCallServiceInfo(foundComponentName,
isExternalCallsSupported, isSelfManageCallsSupported, requestedType));
}
}
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 5952c25..77a412e 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -842,7 +842,7 @@
// current state as tracked by PhoneStateBroadcaster, any failure to properly
// track the current call state there could result in the wrong ringing state
// being reported by this API.
- return mCallsManager.hasRingingCall();
+ return mCallsManager.hasRingingOrSimulatedRingingCall();
}
} finally {
Log.endSession();
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
index 5ab204e..c7e5aa9 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioModeTransitionTests.java
@@ -137,6 +137,11 @@
resetMocks();
when(mCallAudioManager.startRinging()).thenReturn(true);
+ if (mParams.initialAudioState
+ == CallAudioModeStateMachine.ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING) {
+ when(mAudioManager.getMode())
+ .thenReturn(CallAudioModeStateMachine.NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING);
+ }
sm.sendMessage(mParams.messageType, mParams.externalState);
waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
@@ -815,7 +820,7 @@
.build(),
CallAudioModeStateMachine.RING_STATE_NAME, // expectedFinalStateName
FOCUS_RING, // expectedFocus
- AudioManager.MODE_RINGTONE, // expectedMode
+ NO_CHANGE, // expectedMode
ON, // expectedRingingInteraction
// We expect a call to stopCallWaiting because it happens whenever the ringer starts
OFF // expectedCallWaitingInteraction
@@ -836,7 +841,7 @@
.build(),
CallAudioModeStateMachine.RING_STATE_NAME, // expectedFinalStateName
FOCUS_RING, // expectedFocus
- AudioManager.MODE_RINGTONE, // expectedMode
+ NO_CHANGE, // expectedMode
ON, // expectedRingingInteraction
// We expect a call to stopCallWaiting because it happens whenever the ringer starts
OFF // expectedCallWaitingInteraction
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index e16b598..c31761f 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -291,7 +291,8 @@
ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
queryIntentCaptor.capture(),
- eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
// Verify call for default dialer InCallService
assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -350,7 +351,8 @@
ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
queryIntentCaptor.capture(),
- eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
// Verify call for default dialer InCallService
assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -428,7 +430,8 @@
ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
queryIntentCaptor.capture(),
- eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
// Verify call for default dialer InCallService
assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -510,7 +513,8 @@
ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
queryIntentCaptor.capture(),
- eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
// Verify call for default dialer InCallService
assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -634,7 +638,8 @@
ArgumentCaptor<Intent> queryIntentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mMockPackageManager, times(4)).queryIntentServicesAsUser(
queryIntentCaptor.capture(),
- eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ eq(PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS),
+ eq(CURRENT_USER_ID));
// Verify call for default dialer InCallService
assertEquals(DEF_PKG, queryIntentCaptor.getAllValues().get(0).getPackage());
@@ -1038,6 +1043,7 @@
serviceInfo.applicationInfo = new ApplicationInfo();
serviceInfo.applicationInfo.uid = DEF_UID;
serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+ serviceInfo.enabled = true;
serviceInfo.metaData = new Bundle();
serviceInfo.metaData.putBoolean(
TelecomManager.METADATA_IN_CALL_SERVICE_UI, true);
@@ -1065,6 +1071,7 @@
serviceInfo.applicationInfo.uid = CAR2_UID;
}
serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
+ serviceInfo.enabled = true;
serviceInfo.metaData = new Bundle();
serviceInfo.metaData.putBoolean(
TelecomManager.METADATA_IN_CALL_SERVICE_CAR_MODE_UI, true);
@@ -1086,6 +1093,7 @@
serviceInfo.name = SYS_CLASS;
serviceInfo.applicationInfo = new ApplicationInfo();
serviceInfo.applicationInfo.uid = SYS_UID;
+ serviceInfo.enabled = true;
serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
}};
}
@@ -1097,6 +1105,7 @@
serviceInfo.name = COMPANION_CLASS;
serviceInfo.applicationInfo = new ApplicationInfo();
serviceInfo.applicationInfo.uid = COMPANION_UID;
+ serviceInfo.enabled = true;
serviceInfo.permission = Manifest.permission.BIND_INCALL_SERVICE;
}};
}
@@ -1149,7 +1158,7 @@
return resolveInfo;
}
}).when(mMockPackageManager).queryIntentServicesAsUser(
- any(Intent.class), eq(PackageManager.GET_META_DATA), eq(CURRENT_USER_ID));
+ any(Intent.class), anyInt(), eq(CURRENT_USER_ID));
}
private void setupMockPackageManagerLocationPermission(final String pkg,