Ensure connection video capabilities can only be set if video supported.

Add check in setConnectionCapabilities to ensure that video capabilities
are not added to a Call if the underlying PhoneAccount does not
support video.  This is to protect against errors originating from lower
layers.

Bug: 28233279
Change-Id: I822445d1bb4459f3fa4a582bd9f9996d8b736ca3
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 010b8c2..fb61e15 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -374,6 +374,12 @@
     private boolean mIsRemotelyHeld = false;
 
     /**
+     * Indicates whether the {@link PhoneAccount} associated with this call supports video calling.
+     * {@code True} if the phone account supports video calling, {@code false} otherwise.
+     */
+    private boolean mIsVideoCallingSupported = false;
+
+    /**
      * Persists the specified parameters and initializes the new instance.
      *
      * @param context The context.
@@ -855,6 +861,7 @@
                 l.onTargetPhoneAccountChanged(this);
             }
             configureIsWorkCall();
+            checkIfVideoCapable();
         }
     }
 
@@ -872,6 +879,10 @@
         return mIsWorkCall;
     }
 
+    public boolean isVideoCallingSupported() {
+        return mIsVideoCallingSupported;
+    }
+
     private void configureIsWorkCall() {
         PhoneAccountRegistrar phoneAccountRegistrar = mCallsManager.getPhoneAccountRegistrar();
         boolean isWorkCall = false;
@@ -891,6 +902,18 @@
         mIsWorkCall = isWorkCall;
     }
 
+    /**
+     * Caches the state of the {@link PhoneAccount#CAPABILITY_VIDEO_CALLING} {@link PhoneAccount}
+     * capability.
+     */
+    private void checkIfVideoCapable() {
+        PhoneAccountRegistrar phoneAccountRegistrar = mCallsManager.getPhoneAccountRegistrar();
+        PhoneAccount phoneAccount =
+                phoneAccountRegistrar.getPhoneAccountUnchecked(mTargetPhoneAccountHandle);
+        mIsVideoCallingSupported = phoneAccount != null && phoneAccount.hasCapabilities(
+                    PhoneAccount.CAPABILITY_VIDEO_CALLING);
+    }
+
     boolean shouldAttachToExistingConnection() {
         return mShouldAttachToExistingConnection;
     }
@@ -951,7 +974,15 @@
         Log.v(this, "setConnectionCapabilities: %s", Connection.capabilitiesToString(
                 connectionCapabilities));
         if (forceUpdate || mConnectionCapabilities != connectionCapabilities) {
-           mConnectionCapabilities = connectionCapabilities;
+            // 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.
+            if (!isVideoCallingSupported() && doesCallSupportVideo(connectionCapabilities)) {
+                Log.w(this, "setConnectionCapabilities: attempt to set connection as video " +
+                        "capable when not supported by the phone account.");
+                connectionCapabilities = removeVideoCapabilities(connectionCapabilities);
+            }
+
+            mConnectionCapabilities = connectionCapabilities;
             for (Listener l : mListeners) {
                 l.onConnectionCapabilitiesChanged(this);
             }
@@ -1099,6 +1130,7 @@
         setHandle(connection.getHandle(), connection.getHandlePresentation());
         setCallerDisplayName(
                 connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
+
         setConnectionCapabilities(connection.getConnectionCapabilities());
         setConnectionProperties(connection.getConnectionProperties());
         setVideoProvider(connection.getVideoProvider());
@@ -2067,4 +2099,27 @@
             }
         }
     }
+
+    /**
+     * Determines if a {@link Call}'s capabilities bitmask indicates that video is supported either
+     * remotely or locally.
+     *
+     * @param capabilities The {@link Connection} capabilities for the call.
+     * @return {@code true} if video is supported, {@code false} otherwise.
+     */
+    private boolean doesCallSupportVideo(int capabilities) {
+        return (capabilities & Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL) != 0 ||
+                (capabilities & Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL) != 0;
+    }
+
+    /**
+     * Remove any video capabilities set on a {@link Connection} capabilities bitmask.
+     *
+     * @param capabilities The capabilities.
+     * @return The bitmask with video capabilities removed.
+     */
+    private int removeVideoCapabilities(int capabilities) {
+        return capabilities & ~(Connection.CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL |
+                Connection.CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL);
+    }
 }