Merge "Fix a race condition in BT device handling"
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index e110be8..628df84 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -1251,6 +1251,23 @@
}
/**
+ * Sets whether video calling is supported by the current phone account. Since video support
+ * can change during a call, this method facilitates updating call video state.
+ * @param isVideoCallingSupported Sets whether video calling is supported.
+ */
+ public void setVideoCallingSupportedByPhoneAccount(boolean isVideoCallingSupported) {
+ if (mIsVideoCallingSupportedByPhoneAccount == isVideoCallingSupported) {
+ return;
+ }
+ Log.i(this, "setVideoCallingSupportedByPhoneAccount: isSupp=%b", isVideoCallingSupported);
+ mIsVideoCallingSupportedByPhoneAccount = isVideoCallingSupported;
+
+ // Force an update of the connection capabilities so that the dialer is informed of the new
+ // video capabilities based on the phone account's support for video.
+ setConnectionCapabilities(getConnectionCapabilities(), true /* force */);
+ }
+
+ /**
* @return {@code true} if the {@link Call} locally supports video.
*/
public boolean isLocallyVideoCapable() {
@@ -1363,8 +1380,8 @@
}
PhoneAccount phoneAccount =
phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle);
- mIsVideoCallingSupportedByPhoneAccount = phoneAccount != null && phoneAccount.hasCapabilities(
- PhoneAccount.CAPABILITY_VIDEO_CALLING);
+ mIsVideoCallingSupportedByPhoneAccount = phoneAccount != null &&
+ phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING);
if (!mIsVideoCallingSupportedByPhoneAccount && VideoProfile.isVideo(getVideoState())) {
// The PhoneAccount for the Call was set to one which does not support video calling,
@@ -1455,7 +1472,7 @@
mConnectElapsedTimeMillis = connectElapsedTimeMillis;
}
- int getConnectionCapabilities() {
+ public int getConnectionCapabilities() {
return mConnectionCapabilities;
}
@@ -1463,7 +1480,7 @@
return mConnectionProperties;
}
- void setConnectionCapabilities(int connectionCapabilities) {
+ public void setConnectionCapabilities(int connectionCapabilities) {
setConnectionCapabilities(connectionCapabilities, false /* forceUpdate */);
}
@@ -3178,4 +3195,18 @@
public CallIdentification getCallIdentification() {
return mCallIdentification;
}
+
+ /**
+ * When upgrading a call to video via
+ * {@link VideoProviderProxy#onSendSessionModifyRequest(VideoProfile, VideoProfile)}, if the
+ * upgrade is from audio to video, potentially auto-engage the speakerphone.
+ * @param newVideoState The proposed new video state for the call.
+ */
+ public void maybeEnableSpeakerForVideoUpgrade(@VideoProfile.VideoState int newVideoState) {
+ if (mCallsManager.isSpeakerphoneAutoEnabledForVideoCalls(newVideoState)) {
+ Log.i(this, "maybeEnableSpeakerForVideoCall; callId=%s, auto-enable speaker for call"
+ + " upgraded to video.");
+ mCallsManager.setAudioRoute(CallAudioState.ROUTE_SPEAKER, null);
+ }
+ }
}
diff --git a/src/com/android/server/telecom/CallLogManager.java b/src/com/android/server/telecom/CallLogManager.java
index d355a65..cfb5e80 100755
--- a/src/com/android/server/telecom/CallLogManager.java
+++ b/src/com/android/server/telecom/CallLogManager.java
@@ -82,7 +82,7 @@
int features, PhoneAccountHandle accountHandle, long creationDate,
long durationInMillis, Long dataUsage, UserHandle initiatingUser, boolean isRead,
@Nullable LogCallCompletedListener logCallCompletedListener, int callBlockReason,
- String callScreeningAppName, String callScreeningComponentName,
+ CharSequence callScreeningAppName, String callScreeningComponentName,
CallIdentification callIdentification) {
this.context = context;
this.callerInfo = callerInfo;
@@ -125,7 +125,7 @@
public final LogCallCompletedListener logCallCompletedListener;
public final int callBockReason;
- public final String callScreeningAppName;
+ public final CharSequence callScreeningAppName;
public final String callScreeningComponentName;
public final CallIdentification callIdentification;
@@ -359,7 +359,7 @@
boolean isSelfManaged,
@Nullable LogCallCompletedListener logCallCompletedListener,
int callBlockReason,
- String callScreeningAppName,
+ CharSequence callScreeningAppName,
String callScreeningComponentName,
@Nullable CallIdentification callIdentification) {
diff --git a/src/com/android/server/telecom/CallScreeningServiceHelper.java b/src/com/android/server/telecom/CallScreeningServiceHelper.java
index b2f76c4..cb50b86 100644
--- a/src/com/android/server/telecom/CallScreeningServiceHelper.java
+++ b/src/com/android/server/telecom/CallScreeningServiceHelper.java
@@ -51,7 +51,7 @@
* app.
*/
public interface AppLabelProxy {
- String getAppLabel(String packageName);
+ CharSequence getAppLabel(String packageName);
}
/**
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 7653968..4b9e63c 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -340,6 +340,12 @@
PhoneAccountHandle handle) {
broadcastUnregisterIntent(handle);
}
+
+ @Override
+ public void onPhoneAccountChanged(PhoneAccountRegistrar registrar,
+ PhoneAccount phoneAccount) {
+ handlePhoneAccountChanged(registrar, phoneAccount);
+ }
};
/**
@@ -595,11 +601,11 @@
new TelecomServiceImpl.SettingsSecureAdapterImpl(), mCallerInfoLookupHelper,
new CallScreeningServiceHelper.AppLabelProxy() {
@Override
- public String getAppLabel(String packageName) {
+ public CharSequence getAppLabel(String packageName) {
PackageManager pm = mContext.getPackageManager();
try {
ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
- return (String) pm.getApplicationLabel(info);
+ return pm.getApplicationLabel(info);
} catch (PackageManager.NameNotFoundException nnfe) {
Log.w(this, "Could not determine package name.");
}
@@ -925,6 +931,11 @@
}
@VisibleForTesting
+ public PhoneAccountRegistrar.Listener getPhoneAccountListener() {
+ return mPhoneAccountListener;
+ }
+
+ @VisibleForTesting
public boolean hasEmergencyCall() {
for (Call call : mCalls) {
if (call.isEmergencyCall()) {
@@ -1534,12 +1545,12 @@
theCall,
new CallScreeningServiceHelper.AppLabelProxy() {
@Override
- public String getAppLabel(String packageName) {
+ public CharSequence getAppLabel(String packageName) {
PackageManager pm = mContext.getPackageManager();
try {
ApplicationInfo info = pm.getApplicationInfo(
packageName, 0);
- return (String) pm.getApplicationLabel(info);
+ return pm.getApplicationLabel(info);
} catch (PackageManager.NameNotFoundException nnfe) {
Log.w(this, "Could not determine package name.");
}
@@ -4461,4 +4472,23 @@
errorIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivityAsUser(errorIntent, UserHandle.CURRENT);
}
+
+ /**
+ * Handles changes to a {@link PhoneAccount}.
+ *
+ * Checks for changes to video calling availability and updates whether calls for that phone
+ * account are video capable.
+ *
+ * @param registrar The {@link PhoneAccountRegistrar} originating the change.
+ * @param phoneAccount The {@link PhoneAccount} which changed.
+ */
+ private void handlePhoneAccountChanged(PhoneAccountRegistrar registrar,
+ PhoneAccount phoneAccount) {
+ Log.i(this, "handlePhoneAccountChanged: phoneAccount=%s", phoneAccount);
+ boolean isVideoNowSupported = phoneAccount.hasCapabilities(
+ PhoneAccount.CAPABILITY_VIDEO_CALLING);
+ mCalls.stream()
+ .filter(c -> phoneAccount.getAccountHandle().equals(c.getTargetPhoneAccount()))
+ .forEach(c -> c.setVideoCallingSupportedByPhoneAccount(isVideoNowSupported));
+ }
}
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index afe5609..951a5ed 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -126,6 +126,8 @@
PhoneAccountHandle handle) {}
public void onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar,
PhoneAccountHandle handle) {}
+ public void onPhoneAccountChanged(PhoneAccountRegistrar registrar,
+ PhoneAccount phoneAccount) {}
}
/**
@@ -743,6 +745,8 @@
fireAccountsChanged();
if (isNewAccount) {
fireAccountRegistered(account.getAccountHandle());
+ } else {
+ fireAccountChanged(account);
}
}
@@ -804,6 +808,12 @@
}
}
+ private void fireAccountChanged(PhoneAccount account) {
+ for (Listener l : mListeners) {
+ l.onPhoneAccountChanged(this, account);
+ }
+ }
+
private void fireAccountUnRegistered(PhoneAccountHandle handle) {
for (Listener l : mListeners) {
l.onPhoneAccountUnRegistered(this, handle);
diff --git a/src/com/android/server/telecom/VideoProviderProxy.java b/src/com/android/server/telecom/VideoProviderProxy.java
index 6e1f01d..364e0f4 100644
--- a/src/com/android/server/telecom/VideoProviderProxy.java
+++ b/src/com/android/server/telecom/VideoProviderProxy.java
@@ -438,6 +438,11 @@
logFromInCall("sendSessionModifyRequest: from=" + fromProfile + " to=" + toProfile);
Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_REQUEST,
VideoProfile.videoStateToString(toProfile.getVideoState()));
+ if (!VideoProfile.isVideo(fromProfile.getVideoState())
+ && VideoProfile.isVideo(toProfile.getVideoState())) {
+ // Upgrading to video; change to speaker potentially.
+ mCall.maybeEnableSpeakerForVideoUpgrade(toProfile.getVideoState());
+ }
mCall.getAnalytics().addVideoEvent(
Analytics.SEND_LOCAL_SESSION_MODIFY_REQUEST,
toProfile.getVideoState());
diff --git a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
index 1213131..6c37fd4 100644
--- a/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
+++ b/src/com/android/server/telecom/callfiltering/CallFilteringResult.java
@@ -26,7 +26,7 @@
public boolean shouldAddToCallLog;
public boolean shouldShowNotification;
public int mCallBlockReason = CallLog.Calls.BLOCK_REASON_NOT_BLOCKED;
- public String mCallScreeningAppName = null;
+ public CharSequence mCallScreeningAppName = null;
public String mCallScreeningComponentName = null;
public CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
@@ -38,8 +38,8 @@
}
public CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
- shouldAddToCallLog, boolean shouldShowNotification, int callBlockReason, String
- callScreeningAppName, String callScreeningComponentName) {
+ shouldAddToCallLog, boolean shouldShowNotification, int callBlockReason,
+ CharSequence callScreeningAppName, String callScreeningComponentName) {
this.shouldAllowCall = shouldAllowCall;
this.shouldReject = shouldReject;
this.shouldAddToCallLog = shouldAddToCallLog;
@@ -104,7 +104,7 @@
}
private CallFilteringResult getCombinedCallFilteringResult(CallFilteringResult other,
- int callBlockReason, String callScreeningAppName, String callScreeningComponentName) {
+ int callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName) {
return new CallFilteringResult(
shouldAllowCall && other.shouldAllowCall,
shouldReject || other.shouldReject,
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
index 3ec1569..3fcb684 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
@@ -184,7 +184,7 @@
private ICallScreeningService mService;
private ServiceConnection mConnection;
private String mPackageName;
- private String mAppName;
+ private CharSequence mAppName;
private boolean mHasFinished = false;
private CallFilteringResult mResult = new CallFilteringResult(
@@ -211,7 +211,7 @@
public void startCallScreeningFilter(Call call,
CallScreeningFilterResultCallback callback,
String packageName,
- String appName) {
+ CharSequence appName) {
if (mHasFinished) {
Log.w(this, "Attempting to reuse CallScreeningServiceFilter. Ignoring.");
return;
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java
index 1001d23..1a01a95 100644
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallScreeningServiceControllerTest.java
@@ -84,7 +84,7 @@
CallScreeningServiceHelper.AppLabelProxy mAppLabelProxy =
new CallScreeningServiceHelper.AppLabelProxy() {
@Override
- public String getAppLabel(String packageName) {
+ public CharSequence getAppLabel(String packageName) {
return APP_NAME;
}
};
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index d79ea33..bf8604a 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -16,6 +16,8 @@
package com.android.server.telecom.tests;
+import static junit.framework.TestCase.fail;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -102,9 +104,12 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
@RunWith(JUnit4.class)
public class CallsManagerTest extends TelecomTestCase {
+ private static final int TEST_TIMEOUT = 5000; // milliseconds
private static final PhoneAccountHandle SIM_1_HANDLE = new PhoneAccountHandle(
ComponentName.unflattenFromString("com.foo/.Blah"), "Sim1");
private static final PhoneAccountHandle SIM_2_HANDLE = new PhoneAccountHandle(
@@ -960,6 +965,67 @@
assertTrue(mCallsManager.isInEmergencyCall());
}
+ /**
+ * Verifies that changes to a {@link PhoneAccount}'s
+ * {@link PhoneAccount#CAPABILITY_VIDEO_CALLING} capability will be reflected on a call.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testPhoneAccountVideoAvailability() throws InterruptedException {
+ Call ongoingCall = addSpyCall(); // adds to SIM_2_ACCT
+ LinkedBlockingQueue<Integer> capabilitiesQueue = new LinkedBlockingQueue<>(1);
+ ongoingCall.addListener(new Call.ListenerBase() {
+ @Override
+ public void onConnectionCapabilitiesChanged(Call call) {
+ try {
+ Log.i("TYLER", "Listener got " + call.getConnectionCapabilities());
+ capabilitiesQueue.put(call.getConnectionCapabilities());
+ } catch (InterruptedException e) {
+ fail();
+ }
+ }
+ });
+
+ // Lets make the phone account video capable.
+ PhoneAccount videoCapableAccount = new PhoneAccount.Builder(SIM_2_ACCOUNT)
+ .setCapabilities(SIM_2_ACCOUNT.getCapabilities()
+ | PhoneAccount.CAPABILITY_VIDEO_CALLING)
+ .build();
+ mCallsManager.getPhoneAccountListener().onPhoneAccountChanged(mPhoneAccountRegistrar,
+ videoCapableAccount);
+ // Absorb first update; it'll be from when phone account changed initially (since we force
+ // a capabilities update.
+ int newCapabilities = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+
+ // Lets pretend the ConnectionService made it video capable as well.
+ ongoingCall.setConnectionCapabilities(
+ Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
+ newCapabilities = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertTrue(Connection.can(newCapabilities,
+ Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
+ assertTrue(ongoingCall.isVideoCallingSupportedByPhoneAccount());
+
+ // Fire a changed event for the phone account making it not capable.
+ mCallsManager.getPhoneAccountListener().onPhoneAccountChanged(mPhoneAccountRegistrar,
+ SIM_2_ACCOUNT);
+ newCapabilities = capabilitiesQueue.poll(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
+ assertFalse(Connection.can(newCapabilities,
+ Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
+ assertFalse(ongoingCall.isVideoCallingSupportedByPhoneAccount());
+
+ // Fire a change for an unrelated phone account.
+ PhoneAccount anotherVideoCapableAcct = new PhoneAccount.Builder(SIM_1_ACCOUNT)
+ .setCapabilities(SIM_2_ACCOUNT.getCapabilities()
+ | PhoneAccount.CAPABILITY_VIDEO_CALLING)
+ .build();
+ mCallsManager.getPhoneAccountListener().onPhoneAccountChanged(mPhoneAccountRegistrar,
+ anotherVideoCapableAcct);
+ // Call still should not be video capable
+ assertFalse(Connection.can(ongoingCall.getConnectionCapabilities(),
+ Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
+ }
+
private Call addSpyCallWithConnectionService(ConnectionServiceWrapper connSvr) {
Call call = addSpyCall();
doReturn(connSvr).when(call).getConnectionService();
diff --git a/tests/src/com/android/server/telecom/tests/VideoProviderProxyTest.java b/tests/src/com/android/server/telecom/tests/VideoProviderProxyTest.java
index a6eecf7..b09aa5b 100644
--- a/tests/src/com/android/server/telecom/tests/VideoProviderProxyTest.java
+++ b/tests/src/com/android/server/telecom/tests/VideoProviderProxyTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -62,6 +63,7 @@
doNothing().when(mIBinder).linkToDeath(any(), anyInt());
when(mCall.getAnalytics()).thenReturn(mCallInfo);
doNothing().when(mCallInfo).addVideoEvent(anyInt(), anyInt());
+ doNothing().when(mCall).maybeEnableSpeakerForVideoUpgrade(anyInt());
mVideoProviderProxy = new VideoProviderProxy(mLock, mVideoProvider, mCall,
mCurrentUserProxy);
mVideoProviderProxy.addListener(mListener);
@@ -116,4 +118,17 @@
verify(mListener).onSessionModifyRequestReceived(any(), capturedProfile.capture());
assertEquals(VideoProfile.STATE_BIDIRECTIONAL, capturedProfile.getValue().getVideoState());
}
+
+ /**
+ * Tests the case where dialer requests an upgrade to video; we should try to change to speaker.
+ * @throws Exception
+ */
+ @SmallTest
+ @Test
+ public void testTryToEnableSpeakerOnVideoUpgrade() throws Exception {
+ mVideoProviderProxy.onSendSessionModifyRequest(
+ new VideoProfile(VideoProfile.STATE_AUDIO_ONLY),
+ new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL));
+ verify(mCall).maybeEnableSpeakerForVideoUpgrade(eq(VideoProfile.STATE_BIDIRECTIONAL));
+ }
}