Video API CTS tests.

- Make test phone account video capable.
- Add placeAndVerifyCall prototype that accepts a videoState.
- Add "doWorkAndWaitUntilConditionIsTrueOrTimeout" method (builds on
"waitUntilConditionISTrue..." method.  This method will attempt to perform
some work (defined by interface Work) and check if the expected value is
found.  If it is not, the work is done again after a short sleep and the
condition is checked again.  This is used for some of the VideoProvider
tests where we need to get the VideoProvider to call some callbacks.
Ideally calling these callbacks should be posted to the VideoProvider's
Handler, but the Handler isn't accessible in the sub-classes. More
comments are in VideoCallTest.java.
- Add ability to create MockVideoProvider for connections.
- Add MockVideoProvider and MockVideoCallCallback.
- Add VideoCallTest class containing video call tests.
- Add VideoProfile helper tests.

Bug: 21802841
Change-Id: Ie35d53cfb1e1e4a8d11576a17e86123c2ec14498
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index a569058..f24860c 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -31,6 +31,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telecom.VideoProfile;
 import android.telecom.cts.MockConnectionService.ConnectionServiceCallbacks;
 import android.telecom.cts.MockInCallService.InCallServiceCallbacks;
 import android.test.InstrumentationTestCase;
@@ -52,7 +53,8 @@
             TEST_PHONE_ACCOUNT_HANDLE, LABEL)
             .setAddress(Uri.parse("tel:555-TEST"))
             .setSubscriptionAddress(Uri.parse("tel:555-TEST"))
-            .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+            .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
             .setHighlightColor(Color.RED)
             .setShortDescription(LABEL)
             .setSupportedUriSchemes(Arrays.asList("tel"))
@@ -160,9 +162,27 @@
     /**
      *  Puts Telecom in a state where there is an active call provided by the
      *  {@link MockConnectionService} which can be tested.
+     *
+     *  @param videoState the video state of the call.
+     */
+    void placeAndVerifyCall(int videoState) {
+        placeAndVerifyCall(null, videoState);
+    }
+
+    /**
+     *  Puts Telecom in a state where there is an active call provided by the
+     *  {@link MockConnectionService} which can be tested.
      */
     void placeAndVerifyCall(Bundle extras) {
-        placeNewCallWithPhoneAccount(extras);
+        placeAndVerifyCall(extras, VideoProfile.STATE_AUDIO_ONLY);
+    }
+
+    /**
+     *  Puts Telecom in a state where there is an active call provided by the
+     *  {@link MockConnectionService} which can be tested.
+     */
+    void placeAndVerifyCall(Bundle extras, int videoState) {
+        placeNewCallWithPhoneAccount(extras, videoState);
 
         try {
             if (!mInCallCallbacks.lock.tryAcquire(3, TimeUnit.SECONDS)) {
@@ -244,11 +264,16 @@
     /**
      * Place a new outgoing call via the {@link MockConnectionService}
      */
-    private void placeNewCallWithPhoneAccount(Bundle extras) {
+    private void placeNewCallWithPhoneAccount(Bundle extras, int videoState) {
         if (extras == null) {
             extras = new Bundle();
         }
         extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, TEST_PHONE_ACCOUNT_HANDLE);
+
+        if (!VideoProfile.isAudioOnly(videoState)) {
+            extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
+        }
+
         mTelecomManager.placeCall(getTestNumber(), extras);
     }
 
@@ -416,8 +441,33 @@
         assertEquals(description, condition.expected(), condition.actual());
     }
 
-    private interface Condition {
+    /**
+     * Performs some work, and waits for the condition to be met.  If the condition is not met in
+     * each step of the loop, the work is performed again.
+     *
+     * @param work The work to perform.
+     * @param condition The condition.
+     * @param timeout The timeout.
+     * @param description Description of the work being performed.
+     */
+    void doWorkAndWaitUntilConditionIsTrueOrTimeout(Work work, Condition condition, long timeout,
+            String description) {
+        final long start = System.currentTimeMillis();
+        work.doWork();
+        while (!condition.expected().equals(condition.actual())
+                && System.currentTimeMillis() - start < timeout) {
+            sleep(50);
+            work.doWork();
+        }
+        assertEquals(description, condition.expected(), condition.actual());
+    }
+
+    protected interface Condition {
         Object expected();
         Object actual();
     }
+
+    protected interface Work {
+        void doWork();
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
index 67a0fe0..29eea46 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnection.java
@@ -20,6 +20,7 @@
 import android.telecom.CallAudioState;
 import android.telecom.Connection;
 import android.telecom.DisconnectCause;
+import android.telecom.VideoProfile;
 import android.util.Log;
 
 /**
@@ -32,6 +33,7 @@
             new CallAudioState(false, CallAudioState.ROUTE_EARPIECE, ROUTE_EARPIECE | ROUTE_SPEAKER);
     private int mState = STATE_NEW;
     private String mDtmfString = "";
+    private MockVideoProvider mMockVideoProvider;
 
     @Override
     public void onAnswer() {
@@ -89,4 +91,45 @@
     public String getDtmfString() {
         return mDtmfString;
     }
+
+    /**
+     * Creates a mock video provider for this connection.
+     */
+    public void createMockVideoProvider() {
+        final MockVideoProvider mockVideoProvider = new MockVideoProvider(this);
+        mMockVideoProvider = mockVideoProvider;
+        setVideoProvider(mockVideoProvider);
+    }
+
+    public void sendMockVideoQuality(int videoQuality) {
+        if (mMockVideoProvider == null) {
+            return;
+        }
+        mMockVideoProvider.sendMockVideoQuality(videoQuality);
+    }
+
+    public void sendMockCallSessionEvent(int event) {
+        if (mMockVideoProvider == null) {
+            return;
+        }
+        mMockVideoProvider.sendMockCallSessionEvent(event);
+    }
+
+    public void sendMockPeerWidth(int width) {
+        if (mMockVideoProvider == null) {
+            return;
+        }
+        mMockVideoProvider.sendMockPeerWidth(width);
+    }
+
+    public void sendMockSessionModifyRequest(VideoProfile request) {
+        if (mMockVideoProvider == null) {
+            return;
+        }
+        mMockVideoProvider.sendMockSessionModifyRequest(request);
+    }
+
+    public MockVideoProvider getMockVideoProvider() {
+        return mMockVideoProvider;
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
index d6d6b67..6dbea7c 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
@@ -36,6 +36,13 @@
 public class MockConnectionService extends ConnectionService {
     private static ConnectionServiceCallbacks sCallbacks;
     private static ConnectionService sConnectionService;
+
+    /**
+     * Used to control whether the {@link MockVideoProvider} will be created when connections are
+     * created.  Used by {@link VideoCallTest#testVideoCallDelayProvider()} to test scenario where
+     * the {@link MockVideoProvider} is not created immediately when the Connection is created.
+     */
+    private static boolean sCreateVideoProvider = true;
     private static Object sLock = new Object();
 
     public static abstract class ConnectionServiceCallbacks {
@@ -86,6 +93,12 @@
         }
         final MockConnection connection = new MockConnection();
         connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
+        if (sCreateVideoProvider) {
+            connection.createMockVideoProvider();
+        } else {
+            sCreateVideoProvider = true;
+        }
+        connection.setVideoState(request.getVideoState());
 
         final ConnectionServiceCallbacks callbacks = getCallbacks();
         if (callbacks != null) {
@@ -108,6 +121,8 @@
 
         final MockConnection connection = new MockConnection();
         connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
+        connection.createMockVideoProvider();
+        connection.setVideoState(request.getVideoState());
 
         final ConnectionServiceCallbacks callbacks = getCallbacks();
         if (callbacks != null) {
@@ -132,4 +147,8 @@
             return sCallbacks;
         }
     }
+
+    public static void setCreateVideoProvider(boolean createVideoProvider) {
+        sCreateVideoProvider = createVideoProvider;
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
index 3c48ddd..89b84ac 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
@@ -17,15 +17,21 @@
 package android.telecom.cts;
 
 import android.content.Intent;
+import android.os.Binder;
 import android.telecom.Call;
 import android.telecom.InCallService;
+import android.util.ArrayMap;
+import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Map;
 import java.util.concurrent.Semaphore;
 
 public class MockInCallService extends InCallService {
     private ArrayList<Call> mCalls = new ArrayList<>();
     private static InCallServiceCallbacks sCallbacks;
+    private Map<Call, MockVideoCallCallback> mVideoCallCallbacks =
+            new ArrayMap<Call, MockVideoCallCallback>();
 
     private static final Object sLock = new Object();
 
@@ -58,8 +64,25 @@
                 getCallbacks().onCallStateChanged(call, state);
             }
         }
+
+        @Override
+        public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {
+            saveVideoCall(call, videoCall);
+        }
     };
 
+    private void saveVideoCall(Call call, VideoCall videoCall) {
+        if (videoCall != null) {
+            if (!mVideoCallCallbacks.containsKey(call)) {
+                MockVideoCallCallback listener = new MockVideoCallCallback(call);
+                videoCall.registerCallback(listener);
+                mVideoCallCallbacks.put(call, listener);
+            }
+        } else {
+            mVideoCallCallbacks.remove(call);
+        }
+    }
+
     @Override
     public android.os.IBinder onBind(android.content.Intent intent) {
         if (getCallbacks() != null) {
@@ -81,6 +104,11 @@
         if (!mCalls.contains(call)) {
             mCalls.add(call);
             call.registerCallback(mCallCallback);
+
+            VideoCall videoCall = call.getVideoCall();
+            if (videoCall != null) {
+                saveVideoCall(call, videoCall);
+            }
         }
         if (getCallbacks() != null) {
             getCallbacks().onCallAdded(call, mCalls.size());
@@ -92,6 +120,7 @@
         mCalls.remove(call);
         if (getCallbacks() != null) {
             getCallbacks().onCallRemoved(call, mCalls.size());
+            saveVideoCall(call, null /* remove videoCall */);
         }
     }
 
@@ -133,4 +162,23 @@
             return sCallbacks;
         }
     }
+
+    /**
+     * Determines if a video callback has been registered for the passed in call.
+     *
+     * @param call The call.
+     * @return {@code true} if a video callback has been registered.
+     */
+    public boolean isVideoCallbackRegistered(Call call) {
+        return mVideoCallCallbacks.containsKey(call);
+    }
+
+    /**
+     * Retrieves the video callbacks associated with a call.
+     * @param call The call.
+     * @return The {@link MockVideoCallCallback} instance associated with the call.
+     */
+    public MockVideoCallCallback getVideoCallCallback(Call call) {
+        return mVideoCallCallbacks.get(call);
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockVideoCallCallback.java b/tests/tests/telecom/src/android/telecom/cts/MockVideoCallCallback.java
new file mode 100644
index 0000000..07e159c
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/MockVideoCallCallback.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2015 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 android.telecom.cts;
+
+import android.telecom.Call;
+import android.telecom.InCallService;
+import android.telecom.VideoProfile;
+import android.telecom.VideoProfile.CameraCapabilities;
+
+/**
+ * Mock video call Callback class.
+ */
+public class MockVideoCallCallback extends InCallService.VideoCall.Callback {
+    private Call mCall;
+    private CameraCapabilities mCameraCapabilities;
+    private long mDataUsage = MockVideoProvider.DATA_USAGE_UNDEFINED;
+    private int mVideoQuality = MockVideoProvider.VIDEO_QUALITY_UNDEFINED;
+    private int mCallSessionEvent = MockVideoProvider.SESSION_EVENT_UNDEFINED;
+    private int mPeerWidth = MockVideoProvider.PEER_WIDTH_UNDEFINED;
+    private VideoProfile mResponseProfile = null;
+    private VideoProfile mRequestProfile = null;
+
+    public MockVideoCallCallback(Call call) {
+        mCall = call;
+    }
+
+    /**
+     * Store incoming session modify request so tests can inspect it.
+     *
+     * @param videoProfile The requested video profile.
+     */
+    @Override
+    public void onSessionModifyRequestReceived(VideoProfile videoProfile) {
+        mRequestProfile = videoProfile;
+    }
+
+    /**
+     * Store incoming session modify response so tests can inspect it.
+     *
+     * @param status Status of the session modify request.
+     * @param requestedProfile The original request which was sent to the peer device.
+     * @param responseProfile The actual profile changes made by the peer device.
+     */
+    @Override
+    public void onSessionModifyResponseReceived(int status, VideoProfile requestedProfile,
+            VideoProfile responseProfile) {
+        mResponseProfile = responseProfile;
+    }
+
+    /**
+     * Store incoming session event so tests can inspect it.
+     *
+     * @param event The event.
+     */
+    @Override
+    public void onCallSessionEvent(int event) {
+        mCallSessionEvent = event;
+    }
+
+    /**
+     * Store incoming peer dimensions so tests can inspect them.
+     *
+     * @param width  The updated peer video width.
+     * @param height The updated peer video height.
+     */
+    @Override
+    public void onPeerDimensionsChanged(int width, int height) {
+        mPeerWidth = width;
+    }
+
+    /**
+     * Store incoming video quality so tests can inspect them.
+     *
+     * @param videoQuality  The updated peer video quality.  Valid values:
+     *      {@link VideoProfile#QUALITY_HIGH},
+     *      {@link VideoProfile#QUALITY_MEDIUM},
+     *      {@link VideoProfile#QUALITY_LOW},
+     */
+    @Override
+    public void onVideoQualityChanged(int videoQuality) {
+        mVideoQuality = videoQuality;
+    }
+
+    /**
+     * Store incoming call data usage so tests can inspect it.
+     *
+     * @param dataUsage The updated data usage (in bytes).
+     */
+    @Override
+    public void onCallDataUsageChanged(long dataUsage) {
+        mDataUsage = dataUsage;
+    }
+
+    /**
+     * Store incoming camera capabilities so tests can inspect them.
+     *
+     * @param cameraCapabilities The changed camera capabilities.
+     */
+    @Override
+    public void onCameraCapabilitiesChanged(CameraCapabilities cameraCapabilities) {
+        mCameraCapabilities = cameraCapabilities;
+    }
+
+    /**
+     * Returns the last received {@link CameraCapabilities}.
+     *
+     * @return The {@link CameraCapabilities}.
+     */
+    public CameraCapabilities getCameraCapabilities() {
+        return mCameraCapabilities;
+    }
+
+    /**
+     * Returns the last received data usage.
+     *
+     * @return The data usage.
+     */
+    public long getDataUsage() {
+        return mDataUsage;
+    }
+
+    /**
+     * Returns the last received video quality.
+     *
+     * @return The video quality.
+     */
+    public int getVideoQuality()
+    {
+        return mVideoQuality;
+    }
+
+    /**
+     * Returns the last received call session event.
+     *
+     * @return The call session event.
+     */
+    public int getCallSessionEvent()
+    {
+        return mCallSessionEvent;
+    }
+
+    /**
+     * Returns the last received peer width.
+     *
+     * @return The call session event.
+     */
+    public int getPeerWidth()
+    {
+        return mPeerWidth;
+    }
+
+    /**
+     * Returns the last received response video profile.
+     *
+     * @return The video profile.
+     */
+    public VideoProfile getResponseProfile() {
+        return mResponseProfile;
+    }
+
+    /**
+     * Returns the last requested video profile.
+     *
+     * @return The video profile.
+     */
+    public VideoProfile getRequestProfile() {
+        return mRequestProfile;
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockVideoProvider.java b/tests/tests/telecom/src/android/telecom/cts/MockVideoProvider.java
new file mode 100644
index 0000000..8ed422f
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/MockVideoProvider.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2015 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 android.telecom.cts;
+
+import android.net.Uri;
+import android.telecom.Connection;
+import android.telecom.VideoProfile;
+import android.view.Surface;
+
+import android.telecom.Connection.VideoProvider;
+
+/**
+ * Implements a mock video provider implementation.
+ */
+public class MockVideoProvider extends VideoProvider {
+    public static final String CAMERA_NONE = "none";
+    public static final String CAMERA_FRONT = "front";
+    public static final String CAMERA_BACK = "back";
+    public static final int CAMERA_FRONT_DIMENSIONS = 1024;
+    public static final int CAMERA_BACK_DIMENSIONS = 2048;
+    public static final long DATA_USAGE = 1024;
+    public static final long DATA_USAGE_UNDEFINED = -1;
+    public static final int VIDEO_QUALITY_UNDEFINED = -1;
+    public static final int SESSION_EVENT_UNDEFINED = -1;
+    public static final int PEER_WIDTH_UNDEFINED = -1;
+    public static final int DEVICE_ORIENTATION_UNDEFINED = -1;
+    public static final float ZOOM_UNDEFINED = -1.0f;
+
+    private Uri mPauseImageUri;
+    private String mCameraId = CAMERA_NONE;
+    private MockConnection mMockConnection;
+    private int mDeviceOrientation = DEVICE_ORIENTATION_UNDEFINED;
+    private float mZoom = ZOOM_UNDEFINED;
+    private Surface mPreviewSurface = null;
+    private Surface mDisplaySurface = null;
+    private VideoProfile mSessionModifyResponse = null;
+
+    public MockVideoProvider(MockConnection mockConnection) {
+        mMockConnection = mockConnection;
+    }
+
+    @Override
+    public void onSetCamera(String cameraId) {
+        handleCameraChange(cameraId);
+    }
+
+    @Override
+    public void onSetPreviewSurface(Surface surface) {
+        mPreviewSurface = surface;
+    }
+
+    @Override
+    public void onSetDisplaySurface(Surface surface) {
+        mDisplaySurface = surface;
+    }
+
+    @Override
+    public void onSetDeviceOrientation(int rotation) {
+        mDeviceOrientation = rotation;
+    }
+
+    @Override
+    public void onSetZoom(float value) {
+        mZoom = value;
+    }
+
+    /**
+     * Handles a session modification request from the {@link MockInCallService}. Assumes the peer
+     * has accepted the proposed video profile.
+     *
+     * @param fromProfile The video properties prior to the request.
+     * @param toProfile The video properties with the requested changes made.
+     */
+    @Override
+    public void onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
+        receiveSessionModifyResponse(Connection.VideoProvider.SESSION_MODIFY_REQUEST_SUCCESS,
+                toProfile, toProfile);
+        mMockConnection.setVideoState(toProfile.getVideoState());
+    }
+
+    @Override
+    public void onSendSessionModifyResponse(VideoProfile responseProfile) {
+        mSessionModifyResponse = responseProfile;
+    }
+
+    /**
+     * Responds with the current camera capabilities.
+     */
+    @Override
+    public void onRequestCameraCapabilities() {
+        handleCameraChange(mCameraId);
+    }
+
+    /**
+     * Handles requests to retrieve the connection data usage by returning a fixed usage amount of
+     * {@code 1024} bytes.
+     */
+    @Override
+    public void onRequestConnectionDataUsage() {
+        setCallDataUsage(DATA_USAGE);
+    }
+
+    @Override
+    public void onSetPauseImage(Uri uri) {
+        mPauseImageUri = uri;
+    }
+
+    /**
+     * Handles a change to the current camera selection.  Responds by reporting the capabilities of
+     * the camera.
+     */
+    private void handleCameraChange(String cameraId) {
+        mCameraId = cameraId;
+        if (CAMERA_FRONT.equals(mCameraId)) {
+            changeCameraCapabilities(new VideoProfile.CameraCapabilities(CAMERA_FRONT_DIMENSIONS,
+                    CAMERA_FRONT_DIMENSIONS));
+        } else if (CAMERA_BACK.equals(mCameraId)) {
+            changeCameraCapabilities(new VideoProfile.CameraCapabilities(CAMERA_BACK_DIMENSIONS,
+                    CAMERA_BACK_DIMENSIONS));
+        }
+    }
+
+    /**
+     * Sends a mock video quality value from the provider.
+     *
+     * @param videoQuality The video quality.
+     */
+    public void sendMockVideoQuality(int videoQuality) {
+        changeVideoQuality(videoQuality);
+    }
+
+    /**
+     * Sends a mock call session event from the provider.
+     *
+     * @param event The call session event.
+     */
+    public void sendMockCallSessionEvent(int event) {
+        handleCallSessionEvent(event);
+    }
+
+    /**
+     * Sends a mock peer width from the provider.
+     *
+     * @param width The peer width.
+     */
+    public void sendMockPeerWidth(int width) {
+        changePeerDimensions(width, width);
+    }
+
+    /**
+     * Sends a mock session modify request from the provider.
+     *
+     * @param request The requested profile.
+     */
+    public void sendMockSessionModifyRequest(VideoProfile request) {
+        receiveSessionModifyRequest(request);
+    }
+
+    public int getDeviceOrientation() {
+        return mDeviceOrientation;
+    }
+
+    public float getZoom() {
+        return mZoom;
+    }
+
+    public Surface getPreviewSurface() {
+        return mPreviewSurface;
+    }
+
+    public Surface getDisplaySurface() {
+        return mDisplaySurface;
+    }
+
+    public VideoProfile getSessionModifyResponse() {
+        return mSessionModifyResponse;
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java b/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
new file mode 100644
index 0000000..a925f6b
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
@@ -0,0 +1,785 @@
+/*
+ * Copyright (C) 2015 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 android.telecom.cts;
+
+import android.graphics.SurfaceTexture;
+import android.telecom.Call;
+import android.telecom.Connection;
+import android.telecom.InCallService;
+import android.telecom.VideoProfile;
+import android.util.Log;
+import android.view.Surface;
+import android.view.TextureView;
+
+import static android.telecom.cts.TestUtils.shouldTestTelecom;
+
+/**
+ * Suites of tests that use {@link MockVideoProvider} and {@link MockVideoCallCallback} to verify
+ * the functionality of the video APIs.
+ *
+ * Note: You'll notice the use of {@code work}, and
+ * {@code doWorkAndWaitUntilConditionIsTrueOrTimeout} here.  The problem is the
+ * {@link MockVideoProvider} is running using a Handler.  To get it to emit mock data that is
+ * in sync with the setup operations performed on the handler, we'd need access to its handler.
+ * The handler of the {@link Connection.VideoProvider} is, however, not public.  As a workaround
+ * we will call local methods on the MockVideoProvider.  This means there is a chance the
+ * VideoProvider will emit the data we're interested in before the callbacks (on the handler)
+ * are even set up.  Consequently, the callbacks we're depending on in our test may not get
+ * called.  To compensate we will call the test methods on the provider repeatedly until we
+ * hear back via our callback.  Suboptimal, but it works.
+ */
+public class VideoCallTest extends BaseTelecomTestWithMockServices {
+    @Override
+    protected void tearDown() throws Exception {
+        if (shouldTestTelecom(mContext)) {
+            cleanupAndVerifyUnbind();
+        }
+        super.tearDown();
+    }
+
+    /**
+     * Tests ability to start a 2-way video call and retrieve its video state.
+     */
+    public void testMakeTwoWayVideoCall() {
+
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+
+        assertCallState(call, Call.STATE_ACTIVE);
+        assertVideoState(call, VideoProfile.STATE_BIDIRECTIONAL);
+        assertVideoCallbackRegistered(inCallService, call, true);
+    }
+
+    /**
+     * Tests ability to start a 1-way video call and retrieve its video state.
+     */
+    public void testMakeOneWayVideoCall() {
+        placeAndVerifyCall(VideoProfile.STATE_TX_ENABLED);
+        verifyConnectionForOutgoingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+
+        assertVideoState(call, VideoProfile.STATE_TX_ENABLED);
+        assertVideoCallbackRegistered(inCallService, call, true);
+    }
+
+    /**
+     * Tests ability to upgrade an audio-only call to a video call.
+     */
+    public void testUpgradeToVideo() {
+        placeAndVerifyCall(VideoProfile.STATE_AUDIO_ONLY);
+        verifyConnectionForOutgoingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoState(call, VideoProfile.STATE_AUDIO_ONLY);
+        assertVideoCallbackRegistered(inCallService, call, true);
+
+        // Send request to upgrade to video.
+        InCallService.VideoCall videoCall = call.getVideoCall();
+        videoCall.sendSessionModifyRequest(new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL));
+        assertVideoState(call, VideoProfile.STATE_BIDIRECTIONAL);
+        assertResponseVideoProfileReceived(inCallService.getVideoCallCallback(call),
+                VideoProfile.STATE_BIDIRECTIONAL);
+    }
+
+    /**
+     * Tests ability to receive a session modification request.
+     */
+    public void testReceiveSessionModifyRequest() {
+        placeAndVerifyCall(VideoProfile.STATE_AUDIO_ONLY);
+        verifyConnectionForOutgoingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+        assertVideoState(call, VideoProfile.STATE_AUDIO_ONLY);
+        assertVideoCallbackRegistered(inCallService, call, true);
+
+        // Have the video profile mock reception of a request.
+        assertRequestVideoProfileReceived(inCallService.getVideoCallCallback(call),
+                VideoProfile.STATE_BIDIRECTIONAL,
+                new Work() {
+                    @Override
+                    public void doWork() {
+                        connection.sendMockSessionModifyRequest(
+                                new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL));
+                    }
+                });
+    }
+
+    /**
+     * Tests ability to send a session modification response.
+     */
+    public void testSendSessionModifyResponse() {
+        placeAndVerifyCall(VideoProfile.STATE_AUDIO_ONLY);
+        verifyConnectionForOutgoingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+        final MockVideoProvider mockVideoProvider = connection.getMockVideoProvider();
+        assertVideoState(call, VideoProfile.STATE_AUDIO_ONLY);
+        assertVideoCallbackRegistered(inCallService, call, true);
+
+        InCallService.VideoCall videoCall = call.getVideoCall();
+        videoCall.sendSessionModifyResponse(new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL));
+        assertSessionModifyResponse(mockVideoProvider, VideoProfile.STATE_BIDIRECTIONAL);
+    }
+
+    /**
+     * Tests ability to start a video call, delaying the creation of the provider until after
+     * the call has been initiated (rather than immediately when the call is created).  This more
+     * closely mimics the lifespan of a {@code VideoProvider} instance as it is reasonable to
+     * expect there will be some overhead associated with configuring the camera at the start of
+     * the call.
+     */
+    public void testVideoCallDelayProvider() {
+        // Don't create video provider when call is created initially; we will do this later.
+        try {
+            MockConnectionService.setCreateVideoProvider(false);
+            placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+            verifyConnectionForOutgoingCall();
+
+            final MockInCallService inCallService = mInCallCallbacks.getService();
+            final Call call = inCallService.getLastCall();
+            final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+
+            assertVideoState(call, VideoProfile.STATE_BIDIRECTIONAL);
+            // After initial connection creation there should not be a video provider or callbacks
+            // registered.
+            assertVideoCallbackRegistered(inCallService, call, false);
+
+            // Trigger delayed creation of video provider and registration of callbacks and assert that
+            // it happened.
+            connection.createMockVideoProvider();
+            assertVideoCallbackRegistered(inCallService, call, true);
+
+            // Ensure video providers are created in the future.
+        } finally {
+            MockConnectionService.setCreateVideoProvider(true);
+        }
+    }
+
+
+    /**
+     * Tests ability to change the current camera.  Ensures that the camera capabilities are sent
+     * back in response.
+     */
+    public void testChangeCamera() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+        final InCallService.VideoCall videoCall = call.getVideoCall();
+
+        videoCall.setCamera(MockVideoProvider.CAMERA_FRONT);
+        assertCameraCapabilitiesReceived(inCallService.getVideoCallCallback(call),
+                MockVideoProvider.CAMERA_FRONT_DIMENSIONS);
+
+        videoCall.setCamera(MockVideoProvider.CAMERA_BACK);
+        assertCameraCapabilitiesReceived(inCallService.getVideoCallCallback(call),
+                MockVideoProvider.CAMERA_BACK_DIMENSIONS);
+    }
+
+    /**
+     * Tests ability to request the camera capabilities from the video provider.
+     */
+    public void testRequestCameraCapabilities() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+        final InCallService.VideoCall videoCall = call.getVideoCall();
+
+        // First, set the camera.
+        videoCall.setCamera(MockVideoProvider.CAMERA_FRONT);
+        // Retrieve the camera capabilities that are automatically send when the camera is set --
+        // ensures the cached value is cleared first.
+        inCallService.getVideoCallCallback(call).getCameraCapabilities();
+
+        // Now, request capabilities.
+        videoCall.requestCameraCapabilities();
+        assertCameraCapabilitiesReceived(inCallService.getVideoCallCallback(call),
+                MockVideoProvider.CAMERA_FRONT_DIMENSIONS);
+    }
+
+    /**
+     * Tests ability to request data usage from the video provider.
+     */
+    public void testRequestDataUsage() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+        final InCallService.VideoCall videoCall = call.getVideoCall();
+
+        videoCall.requestCallDataUsage();
+        assertCallDataUsageReceived(inCallService.getVideoCallCallback(call),
+                MockVideoProvider.DATA_USAGE);
+    }
+
+    /**
+     * Tests ability to receive changes to the video quality from the video provider.
+     */
+    public void testReceiveVideoQuality() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+
+        assertVideoQualityReceived(inCallService.getVideoCallCallback(call),
+                VideoProfile.QUALITY_HIGH,
+                new Work() {
+                    @Override
+                    public void doWork() {
+                        connection
+                                .sendMockVideoQuality(VideoProfile.QUALITY_HIGH);
+                    }
+                });
+
+        assertVideoQualityReceived(inCallService.getVideoCallCallback(call),
+                VideoProfile.QUALITY_MEDIUM,
+                new Work() {
+                    @Override
+                    public void doWork() {
+                        connection
+                                .sendMockVideoQuality(VideoProfile.QUALITY_MEDIUM);
+                    }
+                });
+    }
+
+    /**
+     * Tests ability to receive call session events from the video provider.
+     */
+    public void testReceiveCallSessionEvent() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+
+        assertCallSessionEventReceived(inCallService.getVideoCallCallback(call),
+                Connection.VideoProvider.SESSION_EVENT_CAMERA_READY,
+                new Work() {
+                    @Override
+                    public void doWork() {
+                        connection.sendMockCallSessionEvent(
+                                Connection.VideoProvider.SESSION_EVENT_CAMERA_READY);
+                    }
+                });
+    }
+
+    /**
+     * Tests ability to receive changes to the peer dimensions from the video provider.
+     */
+    public void testReceivePeerDimensionChange() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+
+        assertPeerWidthChanged(inCallService.getVideoCallCallback(call),
+                MockVideoProvider.CAMERA_BACK_DIMENSIONS,
+                new Work() {
+                    @Override
+                    public void doWork() {
+                        connection.sendMockPeerWidth(MockVideoProvider.CAMERA_BACK_DIMENSIONS);
+                    }
+                });
+    }
+
+    /**
+     * Tests ability to set the device orientation via the provider.
+     */
+    public void testSetDeviceOrientation() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+        final MockVideoProvider mockVideoProvider = connection.getMockVideoProvider();
+        final InCallService.VideoCall videoCall = call.getVideoCall();
+
+        // Set device orientation and ensure provider knows about it.
+        videoCall.setDeviceOrientation(90);
+        assertDeviceOrientationChanged(mockVideoProvider, 90);
+    }
+
+    /**
+     * Tests ability to set the preview surface via the provider.
+     */
+    public void testSetPreviewSurface() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+        final MockVideoProvider mockVideoProvider = connection.getMockVideoProvider();
+        final InCallService.VideoCall videoCall = call.getVideoCall();
+
+        Surface surface = new Surface(new SurfaceTexture(1));
+        // Set a surface
+        videoCall.setPreviewSurface(surface);
+        assertPreviewSurfaceChanged(mockVideoProvider, true);
+
+        // Clear the surface
+        videoCall.setPreviewSurface(null);
+        assertPreviewSurfaceChanged(mockVideoProvider, false);
+    }
+
+    /**
+     * Tests ability to set the display surface via the provider.
+     */
+    public void testSetDisplaySurface() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+        final MockVideoProvider mockVideoProvider = connection.getMockVideoProvider();
+        final InCallService.VideoCall videoCall = call.getVideoCall();
+
+        // Set a surface
+        Surface surface = new Surface(new SurfaceTexture(1));
+        videoCall.setDisplaySurface(surface);
+        assertDisplaySurfaceChanged(mockVideoProvider, true);
+
+        // Clear the surface
+        videoCall.setDisplaySurface(null);
+        assertDisplaySurfaceChanged(mockVideoProvider, false);
+    }
+
+    /**
+     * Tests ability to set the camera zoom via the provider.
+     */
+    public void testSetZoom() {
+        placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
+        verifyConnectionForOutgoingCall();
+
+        final MockConnection connection = mConnectionCallbacks.outgoingConnection;
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertVideoCallbackRegistered(inCallService, call, true);
+        final MockVideoProvider mockVideoProvider = connection.getMockVideoProvider();
+        final InCallService.VideoCall videoCall = call.getVideoCall();
+
+        videoCall.setZoom(0.0f);
+        assertZoomChanged(mockVideoProvider, 0.0f);
+
+        videoCall.setZoom(10.0f);
+        assertZoomChanged(mockVideoProvider, 10.0f);
+
+        call.disconnect();
+    }
+
+    /**
+     * Asserts that a call video state is as expected.
+     *
+     * @param call The call.
+     * @param videoState The expected video state.
+     */
+    private void assertVideoState(final Call call, final int videoState) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return videoState;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return call.getDetails().getVideoState();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Call should be in videoState " + videoState
+        );
+    }
+
+    /**
+     * Asserts whether the InCallService has registered a video call back (and hence a video call)
+     * for a call.
+     *
+     * @param inCallService The incall service.
+     * @param call The call.
+     * @param isRegistered The expected registration state.
+     */
+    private void assertVideoCallbackRegistered(final MockInCallService inCallService,
+            final Call call, final Boolean isRegistered) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return isRegistered;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return inCallService.isVideoCallbackRegistered(call);
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Video callback registration state should be " + isRegistered
+        );
+    }
+
+    /**
+     * Asserts whether the camera capabilities have changed to an expected value.  Compares the
+     * camera height only (the {@link MockVideoProvider} sets height and width to be the same.
+     *
+     * @param videoCallCallback The video call callback.
+     * @param expectedCameraWidthHeight The expected width and height.
+     */
+    private void assertCameraCapabilitiesReceived(final MockVideoCallCallback videoCallCallback,
+            final int expectedCameraWidthHeight) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expectedCameraWidthHeight;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        VideoProfile.CameraCapabilities cameraCapabilities =
+                                videoCallCallback.getCameraCapabilities();
+                        return cameraCapabilities == null ? 0 : cameraCapabilities.getHeight();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Camera width and height should be " + expectedCameraWidthHeight
+        );
+    }
+
+    /**
+     * Asserts whether the call data usage has changed to the expected value.
+     *
+     * @param videoCallCallback The video call callback.
+     * @param expectedDataUsage The expected data usage.
+     */
+    private void assertCallDataUsageReceived(final MockVideoCallCallback videoCallCallback,
+            final long expectedDataUsage) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expectedDataUsage;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return videoCallCallback.getDataUsage();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Data usage should be " + expectedDataUsage
+        );
+    }
+
+    /**
+     * Asserts whether the video quality has changed to the expected value.
+     *
+     * @param videoCallCallback The video call callback.
+     * @param expectedVideoQuality The expected video quality.
+     * @param work The work to perform to have the provider emit the video quality.
+     */
+    private void assertVideoQualityReceived(final MockVideoCallCallback videoCallCallback,
+            final int expectedVideoQuality, final Work work) {
+        doWorkAndWaitUntilConditionIsTrueOrTimeout(
+                work,
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expectedVideoQuality;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return videoCallCallback.getVideoQuality();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Video quality should be " + expectedVideoQuality
+        );
+    }
+
+    /**
+     * Asserts whether the call session event has changed to the expected value.
+     *
+     * @param videoCallCallback The video call callback.
+     * @param expectedEvent The expected event.
+     * @param work The work to be performed to send the call session event from the provider.
+     */
+    private void assertCallSessionEventReceived(final MockVideoCallCallback videoCallCallback,
+            final int expectedEvent, final Work work) {
+        doWorkAndWaitUntilConditionIsTrueOrTimeout(
+                work,
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expectedEvent;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return videoCallCallback.getCallSessionEvent();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Call session event should be " + expectedEvent
+        );
+    }
+
+    /**
+     * Asserts whether the peer width has changed to the expected value.
+     *
+     * @param videoCallCallback The video call callback.
+     * @param expectedWidth The expected width.
+     * @param work The work to be performed to send the peer width from the provider.
+     */
+    private void assertPeerWidthChanged(final MockVideoCallCallback videoCallCallback,
+            final int expectedWidth, final Work work) {
+        doWorkAndWaitUntilConditionIsTrueOrTimeout(
+                work,
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expectedWidth;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return videoCallCallback.getPeerWidth();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Peer width should be " + expectedWidth
+        );
+    }
+
+    /**
+     * Asserts whether the device orientation has changed to the expected value.
+     *
+     * @param mockVideoProvider The mock video provider.
+     * @param expected The expected device orientation.
+     */
+    private void assertDeviceOrientationChanged(final MockVideoProvider mockVideoProvider,
+            final int expected) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expected;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return mockVideoProvider.getDeviceOrientation();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Orientation should be " + expected
+        );
+    }
+
+    /**
+     * Asserts whether the preview surface has been set or not.
+     *
+     * @param mockVideoProvider The mock video provider.
+     * @param expected {@code true} if it is expected the preview surface is not null, {@code false}
+     *                             if it is expected the preview surface is null.
+     */
+    private void assertPreviewSurfaceChanged(final MockVideoProvider mockVideoProvider,
+            final boolean expected) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expected;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return mockVideoProvider.getPreviewSurface() != null;
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Preview should be set? " + expected
+        );
+    }
+
+    /**
+     * Asserts whether the display surface has been set or not.
+     *
+     * @param mockVideoProvider The mock video provider.
+     * @param expected {@code true} if it is expected the display surface is not null, {@code false}
+     *                             if it is expected the display surface is null.
+     */
+    private void assertDisplaySurfaceChanged(final MockVideoProvider mockVideoProvider,
+            final boolean expected) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expected;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        return mockVideoProvider.getDisplaySurface() != null;
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Display should be set? " + expected
+        );
+    }
+
+    /**
+     * Asserts whether the zoom has changed to the expected value.  Note: To make comparisons easier
+     * the floats are cast to ints, so ensure only whole values are used.
+     *
+     * @param mockVideoProvider The mock video provider.
+     * @param expected The expected zoom.
+     */
+    private void assertZoomChanged(final MockVideoProvider mockVideoProvider,
+            final float expected) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        // Cast to int so we're not doing float equality
+                        return (int)expected;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        // Cast to int so we're not doing float equality
+                        return (int)mockVideoProvider.getZoom();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Zoom should be " + expected
+        );
+    }
+
+    /**
+     * Asserts whether a response video profile has been received
+     *
+     * @param videoCallCallback The video call callback.
+     * @param expected The expected video state.
+     */
+    private void assertResponseVideoProfileReceived(final MockVideoCallCallback videoCallCallback,
+            final int expected) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expected;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        VideoProfile videoProfile = videoCallCallback.getResponseProfile();
+                        return videoProfile == null ? -1 : videoProfile.getVideoState();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Video state should be " + expected
+        );
+    }
+
+    /**
+     * Asserts whether a session modification request has been received.
+     *
+     * @param videoCallCallback The video call callback.
+     * @param expected The expected video state.
+     * @param work The work to be performed to cause the session modification request to be emit
+     *             from the provider.
+     */
+    private void assertRequestVideoProfileReceived(final MockVideoCallCallback videoCallCallback,
+            final int expected, final Work work) {
+        doWorkAndWaitUntilConditionIsTrueOrTimeout(
+                work,
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expected;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        VideoProfile videoProfile = videoCallCallback.getRequestProfile();
+                        return videoProfile == null ? -1 : videoProfile.getVideoState();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Video state should be " + expected
+        );
+    }
+
+    /**
+     * Asserts whether the provider got a session modify response with the expected value.
+     *
+     * @param mockVideoProvider The mock video provider.
+     * @param expected The expected video state of the session modify response.
+     */
+    private void assertSessionModifyResponse(final MockVideoProvider mockVideoProvider,
+            final int expected) {
+        waitUntilConditionIsTrueOrTimeout(
+                new Condition() {
+                    @Override
+                    public Object expected() {
+                        return expected;
+                    }
+
+                    @Override
+                    public Object actual() {
+                        VideoProfile responseProfile = mockVideoProvider.getSessionModifyResponse();
+                        return responseProfile == null ? -1 : responseProfile.getVideoState();
+                    }
+                },
+                TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+                "Session modify response video state should be " + expected
+        );
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/VideoProfileTest.java b/tests/tests/telecom/src/android/telecom/cts/VideoProfileTest.java
new file mode 100644
index 0000000..6c16abb
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/VideoProfileTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 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 android.telecom.cts;
+
+import android.telecom.VideoProfile;
+import android.test.AndroidTestCase;
+
+/**
+ * Tests helper methods in the {@link VideoProfile} class.
+ */
+public class VideoProfileTest extends AndroidTestCase {
+    public void testIsAudioOnly() {
+        assertTrue(VideoProfile.isAudioOnly(VideoProfile.STATE_AUDIO_ONLY));
+        assertTrue(VideoProfile.isAudioOnly(VideoProfile.STATE_PAUSED));
+
+        assertFalse(VideoProfile.isAudioOnly(VideoProfile.STATE_BIDIRECTIONAL));
+        assertFalse(VideoProfile.isAudioOnly(VideoProfile.STATE_TX_ENABLED));
+        assertFalse(VideoProfile.isAudioOnly(VideoProfile.STATE_RX_ENABLED));
+        assertFalse(VideoProfile
+                .isAudioOnly(VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED));
+        assertFalse(VideoProfile
+                .isAudioOnly(VideoProfile.STATE_TX_ENABLED | VideoProfile.STATE_PAUSED));
+        assertFalse(VideoProfile
+                .isAudioOnly(VideoProfile.STATE_RX_ENABLED | VideoProfile.STATE_PAUSED));
+    }
+
+    public void testIsVideo() {
+        assertTrue(VideoProfile.isVideo(VideoProfile.STATE_BIDIRECTIONAL));
+        assertTrue(VideoProfile.isVideo(VideoProfile.STATE_RX_ENABLED));
+        assertTrue(VideoProfile.isVideo(VideoProfile.STATE_TX_ENABLED));
+        assertTrue(VideoProfile.isVideo(VideoProfile.STATE_BIDIRECTIONAL |
+                VideoProfile.STATE_PAUSED));
+        assertTrue(VideoProfile.isVideo(VideoProfile.STATE_RX_ENABLED | VideoProfile.STATE_PAUSED));
+        assertTrue(VideoProfile.isVideo(VideoProfile.STATE_TX_ENABLED | VideoProfile.STATE_PAUSED));
+
+        assertFalse(VideoProfile.isVideo(VideoProfile.STATE_AUDIO_ONLY));
+        assertFalse(VideoProfile.isVideo(VideoProfile.STATE_PAUSED));
+    }
+
+    public void testIsBidirectional() {
+        assertTrue(VideoProfile.isBidirectional(VideoProfile.STATE_BIDIRECTIONAL));
+        assertTrue(VideoProfile.isBidirectional(VideoProfile.STATE_BIDIRECTIONAL |
+                VideoProfile.STATE_PAUSED));
+
+        assertFalse(VideoProfile.isBidirectional(VideoProfile.STATE_TX_ENABLED));
+        assertFalse(VideoProfile.isBidirectional(VideoProfile.STATE_TX_ENABLED |
+                VideoProfile.STATE_PAUSED));
+        assertFalse(VideoProfile.isBidirectional(VideoProfile.STATE_RX_ENABLED));
+        assertFalse(VideoProfile.isBidirectional(VideoProfile.STATE_RX_ENABLED |
+                VideoProfile.STATE_PAUSED));
+    }
+
+    public void testIsPaused() {
+        assertTrue(VideoProfile.isPaused(VideoProfile.STATE_PAUSED));
+        assertTrue(VideoProfile.isPaused(VideoProfile.STATE_BIDIRECTIONAL |
+                VideoProfile.STATE_PAUSED));
+        assertTrue(VideoProfile.isPaused(VideoProfile.STATE_TX_ENABLED |
+                VideoProfile.STATE_PAUSED));
+        assertTrue(VideoProfile.isPaused(VideoProfile.STATE_RX_ENABLED |
+                VideoProfile.STATE_PAUSED));
+
+        assertFalse(VideoProfile.isPaused(VideoProfile.STATE_AUDIO_ONLY));
+        assertFalse(VideoProfile.isPaused(VideoProfile.STATE_TX_ENABLED));
+        assertFalse(VideoProfile.isPaused(VideoProfile.STATE_RX_ENABLED));
+        assertFalse(VideoProfile.isPaused(VideoProfile.STATE_BIDIRECTIONAL));
+    }
+
+    public void testIsReceptionEnabled() {
+        assertTrue(VideoProfile.isReceptionEnabled(VideoProfile.STATE_RX_ENABLED));
+        assertTrue(VideoProfile.isReceptionEnabled(VideoProfile.STATE_BIDIRECTIONAL));
+        assertTrue(VideoProfile.isReceptionEnabled(VideoProfile.STATE_RX_ENABLED |
+                VideoProfile.STATE_PAUSED));
+        assertTrue(VideoProfile.isReceptionEnabled(VideoProfile.STATE_BIDIRECTIONAL |
+                VideoProfile.STATE_PAUSED));
+
+        assertFalse(VideoProfile.isReceptionEnabled(VideoProfile.STATE_AUDIO_ONLY));
+        assertFalse(VideoProfile.isReceptionEnabled(VideoProfile.STATE_TX_ENABLED));
+        assertFalse(VideoProfile.isReceptionEnabled(VideoProfile.STATE_PAUSED));
+    }
+
+    public void testIsTransmissionEnabled() {
+        assertTrue(VideoProfile.isTransmissionEnabled(VideoProfile.STATE_TX_ENABLED));
+        assertTrue(VideoProfile.isTransmissionEnabled(VideoProfile.STATE_BIDIRECTIONAL));
+        assertTrue(VideoProfile.isTransmissionEnabled(VideoProfile.STATE_TX_ENABLED |
+                VideoProfile.STATE_PAUSED));
+        assertTrue(VideoProfile.isTransmissionEnabled(VideoProfile.STATE_BIDIRECTIONAL |
+                VideoProfile.STATE_PAUSED));
+
+        assertFalse(VideoProfile.isTransmissionEnabled(VideoProfile.STATE_AUDIO_ONLY));
+        assertFalse(VideoProfile.isTransmissionEnabled(VideoProfile.STATE_RX_ENABLED));
+        assertFalse(VideoProfile.isTransmissionEnabled(VideoProfile.STATE_PAUSED));
+    }
+}