Loading src/com/android/server/telecom/Call.java +21 −9 Original line number Original line Diff line number Diff line Loading @@ -461,7 +461,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, * Indicates whether the {@link PhoneAccount} associated with this call supports video calling. * Indicates whether the {@link PhoneAccount} associated with this call supports video calling. * {@code True} if the phone account supports video calling, {@code false} otherwise. * {@code True} if the phone account supports video calling, {@code false} otherwise. */ */ private boolean mIsVideoCallingSupported = false; private boolean mIsVideoCallingSupportedByPhoneAccount = false; private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; Loading Loading @@ -1229,8 +1229,19 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, return mUseCallRecordingTone; return mUseCallRecordingTone; } } public boolean isVideoCallingSupported() { /** return mIsVideoCallingSupported; * @return {@code true} if the {@link Call}'s {@link #getTargetPhoneAccount()} supports video. */ public boolean isVideoCallingSupportedByPhoneAccount() { return mIsVideoCallingSupportedByPhoneAccount; } /** * @return {@code true} if the {@link Call} locally supports video. */ public boolean isLocallyVideoCapable() { return (getConnectionCapabilities() & Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL) == Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL; } } public boolean isSelfManaged() { public boolean isSelfManaged() { Loading Loading @@ -1332,16 +1343,16 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, if (mTargetPhoneAccountHandle == null) { if (mTargetPhoneAccountHandle == null) { // If no target phone account handle is specified, assume we can potentially perform a // If no target phone account handle is specified, assume we can potentially perform a // video call; once the phone account is set, we can confirm that it is video capable. // video call; once the phone account is set, we can confirm that it is video capable. mIsVideoCallingSupported = true; mIsVideoCallingSupportedByPhoneAccount = true; Log.d(this, "checkIfVideoCapable: no phone account selected; assume video capable."); Log.d(this, "checkIfVideoCapable: no phone account selected; assume video capable."); return; return; } } PhoneAccount phoneAccount = PhoneAccount phoneAccount = phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle); phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle); mIsVideoCallingSupported = phoneAccount != null && phoneAccount.hasCapabilities( mIsVideoCallingSupportedByPhoneAccount = phoneAccount != null && phoneAccount.hasCapabilities( PhoneAccount.CAPABILITY_VIDEO_CALLING); PhoneAccount.CAPABILITY_VIDEO_CALLING); if (!mIsVideoCallingSupported && VideoProfile.isVideo(getVideoState())) { if (!mIsVideoCallingSupportedByPhoneAccount && VideoProfile.isVideo(getVideoState())) { // The PhoneAccount for the Call was set to one which does not support video calling, // The PhoneAccount for the Call was set to one which does not support video calling, // and the current call is configured to be a video call; downgrade to audio-only. // and the current call is configured to be a video call; downgrade to audio-only. setVideoState(VideoProfile.STATE_AUDIO_ONLY); setVideoState(VideoProfile.STATE_AUDIO_ONLY); Loading Loading @@ -1444,7 +1455,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, if (forceUpdate || mConnectionCapabilities != connectionCapabilities) { if (forceUpdate || mConnectionCapabilities != connectionCapabilities) { // If the phone account does not support video calling, and the connection capabilities // If the phone account does not support video calling, and the connection capabilities // passed in indicate that the call supports video, remove those video capabilities. // passed in indicate that the call supports video, remove those video capabilities. if (!isVideoCallingSupported() && doesCallSupportVideo(connectionCapabilities)) { if (!isVideoCallingSupportedByPhoneAccount() && doesCallSupportVideo(connectionCapabilities)) { Log.w(this, "setConnectionCapabilities: attempt to set connection as video " + Log.w(this, "setConnectionCapabilities: attempt to set connection as video " + "capable when not supported by the phone account."); "capable when not supported by the phone account."); connectionCapabilities = removeVideoCapabilities(connectionCapabilities); connectionCapabilities = removeVideoCapabilities(connectionCapabilities); Loading Loading @@ -1880,7 +1892,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, // Check to verify that the call is still in the ringing state. A call can change states // Check to verify that the call is still in the ringing state. A call can change states // between the time the user hits 'answer' and Telecom receives the command. // between the time the user hits 'answer' and Telecom receives the command. if (isRinging("answer")) { if (isRinging("answer")) { if (!isVideoCallingSupported() && VideoProfile.isVideo(videoState)) { if (!isVideoCallingSupportedByPhoneAccount() && VideoProfile.isVideo(videoState)) { // Video calling is not supported, yet the InCallService is attempting to answer as // Video calling is not supported, yet the InCallService is attempting to answer as // video. We will simply answer as audio-only. // video. We will simply answer as audio-only. videoState = VideoProfile.STATE_AUDIO_ONLY; videoState = VideoProfile.STATE_AUDIO_ONLY; Loading Loading @@ -2784,7 +2796,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, public void setVideoState(int videoState) { public void setVideoState(int videoState) { // If the phone account associated with this call does not support video calling, then we // If the phone account associated with this call does not support video calling, then we // will automatically set the video state to audio-only. // will automatically set the video state to audio-only. if (!isVideoCallingSupported()) { if (!isVideoCallingSupportedByPhoneAccount()) { Log.d(this, "setVideoState: videoState=%s defaulted to audio (video not supported)", Log.d(this, "setVideoState: videoState=%s defaulted to audio (video not supported)", VideoProfile.videoStateToString(videoState)); VideoProfile.videoStateToString(videoState)); videoState = VideoProfile.STATE_AUDIO_ONLY; videoState = VideoProfile.STATE_AUDIO_ONLY; Loading src/com/android/server/telecom/VideoProviderProxy.java +17 −13 Original line number Original line Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.Manifest; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.content.Context; import android.content.Context; import android.net.Uri; import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Build; import android.os.IBinder; import android.os.IBinder; import android.os.Looper; import android.os.Looper; Loading @@ -33,6 +32,7 @@ import android.telecom.VideoProfile; import android.text.TextUtils; import android.text.TextUtils; import android.view.Surface; import android.view.Surface; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telecom.IVideoCallback; import com.android.internal.telecom.IVideoCallback; import com.android.internal.telecom.IVideoProvider; import com.android.internal.telecom.IVideoProvider; Loading @@ -40,8 +40,6 @@ import java.util.Collections; import java.util.Set; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap; import static android.Manifest.permission.CALL_PHONE; /** /** * Proxies video provider messages from {@link InCallService.VideoCall} * Proxies video provider messages from {@link InCallService.VideoCall} * implementations to the underlying {@link Connection.VideoProvider} implementation. Also proxies * implementations to the underlying {@link Connection.VideoProvider} implementation. Also proxies Loading @@ -55,7 +53,7 @@ public class VideoProviderProxy extends Connection.VideoProvider { /** /** * Listener for Telecom components interested in callbacks from the video provider. * Listener for Telecom components interested in callbacks from the video provider. */ */ interface Listener { public interface Listener { void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile); void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile); } } Loading Loading @@ -112,7 +110,7 @@ public class VideoProviderProxy extends Connection.VideoProvider { * @param call The current call. * @param call The current call. * @throws RemoteException Remote exception. * @throws RemoteException Remote exception. */ */ VideoProviderProxy(TelecomSystem.SyncRoot lock, public VideoProviderProxy(TelecomSystem.SyncRoot lock, IVideoProvider videoProvider, Call call, CurrentUserProxy currentUserProxy) IVideoProvider videoProvider, Call call, CurrentUserProxy currentUserProxy) throws RemoteException { throws RemoteException { Loading @@ -136,11 +134,16 @@ public class VideoProviderProxy extends Connection.VideoProvider { } } } } @VisibleForTesting public VideoCallListenerBinder getVideoCallListenerBinder() { return mVideoCallListenerBinder; } /** /** * IVideoCallback stub implementation. An instance of this class receives callbacks from the * IVideoCallback stub implementation. An instance of this class receives callbacks from the * {@code ConnectionService}'s video provider. * {@code ConnectionService}'s video provider. */ */ private final class VideoCallListenerBinder extends IVideoCallback.Stub { public final class VideoCallListenerBinder extends IVideoCallback.Stub { /** /** * Proxies a request from the {@link #mConectionServiceVideoProvider} to the * Proxies a request from the {@link #mConectionServiceVideoProvider} to the * {@link InCallService} when a session modification request is received. * {@link InCallService} when a session modification request is received. Loading @@ -160,13 +163,14 @@ public class VideoProviderProxy extends Connection.VideoProvider { Analytics.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST, Analytics.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST, videoProfile.getVideoState()); videoProfile.getVideoState()); if (!mCall.isVideoCallingSupported() && if ((!mCall.isVideoCallingSupportedByPhoneAccount() VideoProfile.isVideo(videoProfile.getVideoState())) { || !mCall.isLocallyVideoCapable()) // If video calling is not supported by the phone account, and we receive && VideoProfile.isVideo(videoProfile.getVideoState())) { // a request to upgrade to video, automatically reject it without informing // If video calling is not supported by the phone account, or is not // the InCallService. // locally video capable and we receive a request to upgrade to video, // automatically reject it without informing the InCallService. Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_RESPONSE, "video not supported"); Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_RESPONSE, "video not supported"); VideoProfile responseProfile = new VideoProfile( VideoProfile responseProfile = new VideoProfile( VideoProfile.STATE_AUDIO_ONLY); VideoProfile.STATE_AUDIO_ONLY); try { try { Loading tests/src/com/android/server/telecom/tests/BasicCallTests.java +4 −5 Original line number Original line Diff line number Diff line Loading @@ -26,7 +26,6 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isNull; import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; Loading Loading @@ -921,12 +920,12 @@ public class BasicCallTests extends TelecomSystemTest { Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); .iterator().next(); assert(call.isVideoCallingSupported()); assert(call.isVideoCallingSupportedByPhoneAccount()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); // Change the phone account to one which supports video calling. // Change the phone account to one which supports video calling. call.setTargetPhoneAccount(mPhoneAccountA1.getAccountHandle()); call.setTargetPhoneAccount(mPhoneAccountA1.getAccountHandle()); assert(call.isVideoCallingSupported()); assert(call.isVideoCallingSupportedByPhoneAccount()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); } } Loading @@ -944,12 +943,12 @@ public class BasicCallTests extends TelecomSystemTest { Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); .iterator().next(); assert(call.isVideoCallingSupported()); assert(call.isVideoCallingSupportedByPhoneAccount()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); // Change the phone account to one which does not support video calling. // Change the phone account to one which does not support video calling. call.setTargetPhoneAccount(mPhoneAccountA2.getAccountHandle()); call.setTargetPhoneAccount(mPhoneAccountA2.getAccountHandle()); assert(!call.isVideoCallingSupported()); assert(!call.isVideoCallingSupportedByPhoneAccount()); assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState()); assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState()); } } Loading tests/src/com/android/server/telecom/tests/VideoProviderProxyTest.java 0 → 100644 +119 −0 Original line number Original line Diff line number Diff line /* * 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 static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.os.IBinder; import android.telecom.VideoProfile; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telecom.IVideoProvider; import com.android.server.telecom.Analytics; import com.android.server.telecom.Call; import com.android.server.telecom.CurrentUserProxy; import com.android.server.telecom.TelecomSystem; import com.android.server.telecom.VideoProviderProxy; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; public class VideoProviderProxyTest extends TelecomTestCase { private TelecomSystem.SyncRoot mLock; private VideoProviderProxy mVideoProviderProxy; @Mock private IVideoProvider mVideoProvider; @Mock private IBinder mIBinder; @Mock private Call mCall; @Mock private Analytics.CallInfo mCallInfo; @Mock private CurrentUserProxy mCurrentUserProxy; @Mock private VideoProviderProxy.Listener mListener; @Override @Before public void setUp() throws Exception { super.setUp(); MockitoAnnotations.initMocks(this); mLock = new TelecomSystem.SyncRoot() { }; when(mVideoProvider.asBinder()).thenReturn(mIBinder); doNothing().when(mIBinder).linkToDeath(any(), anyInt()); when(mCall.getAnalytics()).thenReturn(mCallInfo); doNothing().when(mCallInfo).addVideoEvent(anyInt(), anyInt()); mVideoProviderProxy = new VideoProviderProxy(mLock, mVideoProvider, mCall, mCurrentUserProxy); mVideoProviderProxy.addListener(mListener); } /** * Tests the case where we receive a request to upgrade to video, except: * 1. Phone account says we support video. * 2. Call says we don't support video. * * Ensures that we send back a response immediately to indicate the call should remain as * audio-only. * @throws Exception */ @SmallTest @Test public void testReceiveUpgradeRequestWhenLocalDoesntSupportVideo() throws Exception { // Given a call which supports video at the phone account level, but is not currently // marked as supporting video locally. when(mCall.isLocallyVideoCapable()).thenReturn(false); when(mCall.isVideoCallingSupportedByPhoneAccount()).thenReturn(true); // Simulate receiving a request to upgrade to video. mVideoProviderProxy.getVideoCallListenerBinder().receiveSessionModifyRequest( new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL)); // Make sure that we send back a response rejecting the request. ArgumentCaptor<VideoProfile> capturedProfile = ArgumentCaptor.forClass(VideoProfile.class); verify(mVideoProvider).sendSessionModifyResponse(capturedProfile.capture()); assertEquals(VideoProfile.STATE_AUDIO_ONLY, capturedProfile.getValue().getVideoState()); } /** * Tests the case where we receive a request to upgrade to video and video is supported. * @throws Exception */ @SmallTest @Test public void testReceiveUpgradeRequestWhenVideoIsSupported() throws Exception { // Given a call which supports video at the phone account level, and is currently marked as // supporting video locally. when(mCall.isLocallyVideoCapable()).thenReturn(true); when(mCall.isVideoCallingSupportedByPhoneAccount()).thenReturn(true); // Simulate receiving a request to upgrade to video. mVideoProviderProxy.getVideoCallListenerBinder().receiveSessionModifyRequest( new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL)); // Ensure it gets proxied back to the caller. ArgumentCaptor<VideoProfile> capturedProfile = ArgumentCaptor.forClass(VideoProfile.class); verify(mListener).onSessionModifyRequestReceived(any(), capturedProfile.capture()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, capturedProfile.getValue().getVideoState()); } } Loading
src/com/android/server/telecom/Call.java +21 −9 Original line number Original line Diff line number Diff line Loading @@ -461,7 +461,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, * Indicates whether the {@link PhoneAccount} associated with this call supports video calling. * Indicates whether the {@link PhoneAccount} associated with this call supports video calling. * {@code True} if the phone account supports video calling, {@code false} otherwise. * {@code True} if the phone account supports video calling, {@code false} otherwise. */ */ private boolean mIsVideoCallingSupported = false; private boolean mIsVideoCallingSupportedByPhoneAccount = false; private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; private PhoneNumberUtilsAdapter mPhoneNumberUtilsAdapter; Loading Loading @@ -1229,8 +1229,19 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, return mUseCallRecordingTone; return mUseCallRecordingTone; } } public boolean isVideoCallingSupported() { /** return mIsVideoCallingSupported; * @return {@code true} if the {@link Call}'s {@link #getTargetPhoneAccount()} supports video. */ public boolean isVideoCallingSupportedByPhoneAccount() { return mIsVideoCallingSupportedByPhoneAccount; } /** * @return {@code true} if the {@link Call} locally supports video. */ public boolean isLocallyVideoCapable() { return (getConnectionCapabilities() & Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL) == Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL; } } public boolean isSelfManaged() { public boolean isSelfManaged() { Loading Loading @@ -1332,16 +1343,16 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, if (mTargetPhoneAccountHandle == null) { if (mTargetPhoneAccountHandle == null) { // If no target phone account handle is specified, assume we can potentially perform a // If no target phone account handle is specified, assume we can potentially perform a // video call; once the phone account is set, we can confirm that it is video capable. // video call; once the phone account is set, we can confirm that it is video capable. mIsVideoCallingSupported = true; mIsVideoCallingSupportedByPhoneAccount = true; Log.d(this, "checkIfVideoCapable: no phone account selected; assume video capable."); Log.d(this, "checkIfVideoCapable: no phone account selected; assume video capable."); return; return; } } PhoneAccount phoneAccount = PhoneAccount phoneAccount = phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle); phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle); mIsVideoCallingSupported = phoneAccount != null && phoneAccount.hasCapabilities( mIsVideoCallingSupportedByPhoneAccount = phoneAccount != null && phoneAccount.hasCapabilities( PhoneAccount.CAPABILITY_VIDEO_CALLING); PhoneAccount.CAPABILITY_VIDEO_CALLING); if (!mIsVideoCallingSupported && VideoProfile.isVideo(getVideoState())) { if (!mIsVideoCallingSupportedByPhoneAccount && VideoProfile.isVideo(getVideoState())) { // The PhoneAccount for the Call was set to one which does not support video calling, // The PhoneAccount for the Call was set to one which does not support video calling, // and the current call is configured to be a video call; downgrade to audio-only. // and the current call is configured to be a video call; downgrade to audio-only. setVideoState(VideoProfile.STATE_AUDIO_ONLY); setVideoState(VideoProfile.STATE_AUDIO_ONLY); Loading Loading @@ -1444,7 +1455,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, if (forceUpdate || mConnectionCapabilities != connectionCapabilities) { if (forceUpdate || mConnectionCapabilities != connectionCapabilities) { // If the phone account does not support video calling, and the connection capabilities // If the phone account does not support video calling, and the connection capabilities // passed in indicate that the call supports video, remove those video capabilities. // passed in indicate that the call supports video, remove those video capabilities. if (!isVideoCallingSupported() && doesCallSupportVideo(connectionCapabilities)) { if (!isVideoCallingSupportedByPhoneAccount() && doesCallSupportVideo(connectionCapabilities)) { Log.w(this, "setConnectionCapabilities: attempt to set connection as video " + Log.w(this, "setConnectionCapabilities: attempt to set connection as video " + "capable when not supported by the phone account."); "capable when not supported by the phone account."); connectionCapabilities = removeVideoCapabilities(connectionCapabilities); connectionCapabilities = removeVideoCapabilities(connectionCapabilities); Loading Loading @@ -1880,7 +1892,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, // Check to verify that the call is still in the ringing state. A call can change states // Check to verify that the call is still in the ringing state. A call can change states // between the time the user hits 'answer' and Telecom receives the command. // between the time the user hits 'answer' and Telecom receives the command. if (isRinging("answer")) { if (isRinging("answer")) { if (!isVideoCallingSupported() && VideoProfile.isVideo(videoState)) { if (!isVideoCallingSupportedByPhoneAccount() && VideoProfile.isVideo(videoState)) { // Video calling is not supported, yet the InCallService is attempting to answer as // Video calling is not supported, yet the InCallService is attempting to answer as // video. We will simply answer as audio-only. // video. We will simply answer as audio-only. videoState = VideoProfile.STATE_AUDIO_ONLY; videoState = VideoProfile.STATE_AUDIO_ONLY; Loading Loading @@ -2784,7 +2796,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, public void setVideoState(int videoState) { public void setVideoState(int videoState) { // If the phone account associated with this call does not support video calling, then we // If the phone account associated with this call does not support video calling, then we // will automatically set the video state to audio-only. // will automatically set the video state to audio-only. if (!isVideoCallingSupported()) { if (!isVideoCallingSupportedByPhoneAccount()) { Log.d(this, "setVideoState: videoState=%s defaulted to audio (video not supported)", Log.d(this, "setVideoState: videoState=%s defaulted to audio (video not supported)", VideoProfile.videoStateToString(videoState)); VideoProfile.videoStateToString(videoState)); videoState = VideoProfile.STATE_AUDIO_ONLY; videoState = VideoProfile.STATE_AUDIO_ONLY; Loading
src/com/android/server/telecom/VideoProviderProxy.java +17 −13 Original line number Original line Diff line number Diff line Loading @@ -20,7 +20,6 @@ import android.Manifest; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.content.Context; import android.content.Context; import android.net.Uri; import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Build; import android.os.IBinder; import android.os.IBinder; import android.os.Looper; import android.os.Looper; Loading @@ -33,6 +32,7 @@ import android.telecom.VideoProfile; import android.text.TextUtils; import android.text.TextUtils; import android.view.Surface; import android.view.Surface; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telecom.IVideoCallback; import com.android.internal.telecom.IVideoCallback; import com.android.internal.telecom.IVideoProvider; import com.android.internal.telecom.IVideoProvider; Loading @@ -40,8 +40,6 @@ import java.util.Collections; import java.util.Set; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap; import static android.Manifest.permission.CALL_PHONE; /** /** * Proxies video provider messages from {@link InCallService.VideoCall} * Proxies video provider messages from {@link InCallService.VideoCall} * implementations to the underlying {@link Connection.VideoProvider} implementation. Also proxies * implementations to the underlying {@link Connection.VideoProvider} implementation. Also proxies Loading @@ -55,7 +53,7 @@ public class VideoProviderProxy extends Connection.VideoProvider { /** /** * Listener for Telecom components interested in callbacks from the video provider. * Listener for Telecom components interested in callbacks from the video provider. */ */ interface Listener { public interface Listener { void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile); void onSessionModifyRequestReceived(Call call, VideoProfile videoProfile); } } Loading Loading @@ -112,7 +110,7 @@ public class VideoProviderProxy extends Connection.VideoProvider { * @param call The current call. * @param call The current call. * @throws RemoteException Remote exception. * @throws RemoteException Remote exception. */ */ VideoProviderProxy(TelecomSystem.SyncRoot lock, public VideoProviderProxy(TelecomSystem.SyncRoot lock, IVideoProvider videoProvider, Call call, CurrentUserProxy currentUserProxy) IVideoProvider videoProvider, Call call, CurrentUserProxy currentUserProxy) throws RemoteException { throws RemoteException { Loading @@ -136,11 +134,16 @@ public class VideoProviderProxy extends Connection.VideoProvider { } } } } @VisibleForTesting public VideoCallListenerBinder getVideoCallListenerBinder() { return mVideoCallListenerBinder; } /** /** * IVideoCallback stub implementation. An instance of this class receives callbacks from the * IVideoCallback stub implementation. An instance of this class receives callbacks from the * {@code ConnectionService}'s video provider. * {@code ConnectionService}'s video provider. */ */ private final class VideoCallListenerBinder extends IVideoCallback.Stub { public final class VideoCallListenerBinder extends IVideoCallback.Stub { /** /** * Proxies a request from the {@link #mConectionServiceVideoProvider} to the * Proxies a request from the {@link #mConectionServiceVideoProvider} to the * {@link InCallService} when a session modification request is received. * {@link InCallService} when a session modification request is received. Loading @@ -160,13 +163,14 @@ public class VideoProviderProxy extends Connection.VideoProvider { Analytics.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST, Analytics.RECEIVE_REMOTE_SESSION_MODIFY_REQUEST, videoProfile.getVideoState()); videoProfile.getVideoState()); if (!mCall.isVideoCallingSupported() && if ((!mCall.isVideoCallingSupportedByPhoneAccount() VideoProfile.isVideo(videoProfile.getVideoState())) { || !mCall.isLocallyVideoCapable()) // If video calling is not supported by the phone account, and we receive && VideoProfile.isVideo(videoProfile.getVideoState())) { // a request to upgrade to video, automatically reject it without informing // If video calling is not supported by the phone account, or is not // the InCallService. // locally video capable and we receive a request to upgrade to video, // automatically reject it without informing the InCallService. Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_RESPONSE, "video not supported"); Log.addEvent(mCall, LogUtils.Events.SEND_VIDEO_RESPONSE, "video not supported"); VideoProfile responseProfile = new VideoProfile( VideoProfile responseProfile = new VideoProfile( VideoProfile.STATE_AUDIO_ONLY); VideoProfile.STATE_AUDIO_ONLY); try { try { Loading
tests/src/com/android/server/telecom/tests/BasicCallTests.java +4 −5 Original line number Original line Diff line number Diff line Loading @@ -26,7 +26,6 @@ import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isNull; import static org.mockito.Matchers.isNull; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.times; Loading Loading @@ -921,12 +920,12 @@ public class BasicCallTests extends TelecomSystemTest { Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); .iterator().next(); assert(call.isVideoCallingSupported()); assert(call.isVideoCallingSupportedByPhoneAccount()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); // Change the phone account to one which supports video calling. // Change the phone account to one which supports video calling. call.setTargetPhoneAccount(mPhoneAccountA1.getAccountHandle()); call.setTargetPhoneAccount(mPhoneAccountA1.getAccountHandle()); assert(call.isVideoCallingSupported()); assert(call.isVideoCallingSupportedByPhoneAccount()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); } } Loading @@ -944,12 +943,12 @@ public class BasicCallTests extends TelecomSystemTest { Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); .iterator().next(); assert(call.isVideoCallingSupported()); assert(call.isVideoCallingSupportedByPhoneAccount()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, call.getVideoState()); // Change the phone account to one which does not support video calling. // Change the phone account to one which does not support video calling. call.setTargetPhoneAccount(mPhoneAccountA2.getAccountHandle()); call.setTargetPhoneAccount(mPhoneAccountA2.getAccountHandle()); assert(!call.isVideoCallingSupported()); assert(!call.isVideoCallingSupportedByPhoneAccount()); assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState()); assertEquals(VideoProfile.STATE_AUDIO_ONLY, call.getVideoState()); } } Loading
tests/src/com/android/server/telecom/tests/VideoProviderProxyTest.java 0 → 100644 +119 −0 Original line number Original line Diff line number Diff line /* * 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 static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.os.IBinder; import android.telecom.VideoProfile; import android.test.suitebuilder.annotation.SmallTest; import com.android.internal.telecom.IVideoProvider; import com.android.server.telecom.Analytics; import com.android.server.telecom.Call; import com.android.server.telecom.CurrentUserProxy; import com.android.server.telecom.TelecomSystem; import com.android.server.telecom.VideoProviderProxy; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; public class VideoProviderProxyTest extends TelecomTestCase { private TelecomSystem.SyncRoot mLock; private VideoProviderProxy mVideoProviderProxy; @Mock private IVideoProvider mVideoProvider; @Mock private IBinder mIBinder; @Mock private Call mCall; @Mock private Analytics.CallInfo mCallInfo; @Mock private CurrentUserProxy mCurrentUserProxy; @Mock private VideoProviderProxy.Listener mListener; @Override @Before public void setUp() throws Exception { super.setUp(); MockitoAnnotations.initMocks(this); mLock = new TelecomSystem.SyncRoot() { }; when(mVideoProvider.asBinder()).thenReturn(mIBinder); doNothing().when(mIBinder).linkToDeath(any(), anyInt()); when(mCall.getAnalytics()).thenReturn(mCallInfo); doNothing().when(mCallInfo).addVideoEvent(anyInt(), anyInt()); mVideoProviderProxy = new VideoProviderProxy(mLock, mVideoProvider, mCall, mCurrentUserProxy); mVideoProviderProxy.addListener(mListener); } /** * Tests the case where we receive a request to upgrade to video, except: * 1. Phone account says we support video. * 2. Call says we don't support video. * * Ensures that we send back a response immediately to indicate the call should remain as * audio-only. * @throws Exception */ @SmallTest @Test public void testReceiveUpgradeRequestWhenLocalDoesntSupportVideo() throws Exception { // Given a call which supports video at the phone account level, but is not currently // marked as supporting video locally. when(mCall.isLocallyVideoCapable()).thenReturn(false); when(mCall.isVideoCallingSupportedByPhoneAccount()).thenReturn(true); // Simulate receiving a request to upgrade to video. mVideoProviderProxy.getVideoCallListenerBinder().receiveSessionModifyRequest( new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL)); // Make sure that we send back a response rejecting the request. ArgumentCaptor<VideoProfile> capturedProfile = ArgumentCaptor.forClass(VideoProfile.class); verify(mVideoProvider).sendSessionModifyResponse(capturedProfile.capture()); assertEquals(VideoProfile.STATE_AUDIO_ONLY, capturedProfile.getValue().getVideoState()); } /** * Tests the case where we receive a request to upgrade to video and video is supported. * @throws Exception */ @SmallTest @Test public void testReceiveUpgradeRequestWhenVideoIsSupported() throws Exception { // Given a call which supports video at the phone account level, and is currently marked as // supporting video locally. when(mCall.isLocallyVideoCapable()).thenReturn(true); when(mCall.isVideoCallingSupportedByPhoneAccount()).thenReturn(true); // Simulate receiving a request to upgrade to video. mVideoProviderProxy.getVideoCallListenerBinder().receiveSessionModifyRequest( new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL)); // Ensure it gets proxied back to the caller. ArgumentCaptor<VideoProfile> capturedProfile = ArgumentCaptor.forClass(VideoProfile.class); verify(mListener).onSessionModifyRequestReceived(any(), capturedProfile.capture()); assertEquals(VideoProfile.STATE_BIDIRECTIONAL, capturedProfile.getValue().getVideoState()); } }