Merge "Fixed CtsVerifier'd telecom test"
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
index 0b70f1b..2fc401b 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
@@ -21,6 +21,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.media.AudioManager;
+import android.net.Uri;
 import android.telecom.Call;
 import android.telecom.Connection;
 import android.telecom.ConnectionService;
@@ -34,12 +35,16 @@
  */
 public class ConnectionServiceTest extends BaseTelecomTestWithMockServices {
 
+    private static final Uri SELF_MANAGED_TEST_ADDRESS =
+            Uri.fromParts("sip", "call1@test.com", null);
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getInstrumentation().getContext();
         if (mShouldTestTelecom) {
             setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+            mTelecomManager.registerPhoneAccount(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1);
         }
     }
 
@@ -124,6 +129,86 @@
         assertEquals(AudioManager.MODE_IN_CALL, audioManager.getMode());
     }
 
+    public void testConnectionServiceFocusGainedWithNoConnectionService() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // WHEN place a managed call
+        placeAndVerifyCall();
+
+        // THEN managed connection service has gained the focus
+        assertTrue(connectionService.waitForEvent(
+                MockConnectionService.EVENT_CONNECTION_SERVICE_FOCUS_GAINED));
+    }
+
+    public void testConnectionServiceFocusGainedWithSameConnectionService() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // GIVEN a managed call
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall().setActive();
+        assertTrue(connectionService.waitForEvent(
+                MockConnectionService.EVENT_CONNECTION_SERVICE_FOCUS_GAINED));
+
+        // WHEN place another call has the same ConnectionService as the existing call
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall();
+
+        // THEN the ConnectionService has not gained the focus again
+        assertFalse(connectionService.waitForEvent(
+                MockConnectionService.EVENT_CONNECTION_SERVICE_FOCUS_GAINED));
+        // and the ConnectionService didn't lose the focus
+        assertFalse(connectionService.waitForEvent(
+                MockConnectionService.EVENT_CONNECTION_SERVICE_FOCUS_LOST));
+    }
+
+    public void testConnectionServiceFocusGainedWithDifferentConnectionService() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // GIVEN an existing managed call
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall().setActive();
+        assertTrue(connectionService.waitForEvent(
+                MockConnectionService.EVENT_CONNECTION_SERVICE_FOCUS_GAINED));
+
+        // WHEN a self-managed call is coming
+        SelfManagedConnection selfManagedConnection =
+                addIncomingSelfManagedCall(TEST_SELF_MANAGED_HANDLE_1, SELF_MANAGED_TEST_ADDRESS);
+
+        // THEN the managed ConnectionService has lost the focus
+        assertTrue(connectionService.waitForEvent(
+                MockConnectionService.EVENT_CONNECTION_SERVICE_FOCUS_LOST));
+        // and the self-managed ConnectionService has gained the focus
+        assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
+                        CtsSelfManagedConnectionService.FOCUS_GAINED_LOCK));
+
+        // Disconnected the self-managed call
+        selfManagedConnection.disconnectAndDestroy();
+    }
+
+    private SelfManagedConnection addIncomingSelfManagedCall(
+            PhoneAccountHandle pah, Uri address) {
+
+        TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager, pah, address);
+
+        // Ensure Telecom bound to the self managed CS
+        if (!CtsSelfManagedConnectionService.waitForBinding()) {
+            fail("Could not bind to Self-Managed ConnectionService");
+        }
+
+        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(address);
+
+        // Active the call
+        connection.setActive();
+
+        return connection;
+    }
+
     public void testGetAllConnections() {
         if (!mShouldTestTelecom) {
             return;
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index 329031a..d93d431 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -176,6 +176,24 @@
     }
 
     @Override
+    public void onConnectionServiceFocusGained() {
+        synchronized (sLock) {
+            if (sConnectionService != null) {
+                sConnectionService.onConnectionServiceFocusGained();
+            }
+        }
+    }
+
+    @Override
+    public void onConnectionServiceFocusLost() {
+        synchronized (sLock) {
+            if (sConnectionService != null) {
+                sConnectionService.onConnectionServiceFocusLost();
+            }
+        }
+    }
+
+    @Override
     public boolean onUnbind(Intent intent) {
         Log.i(LOG_TAG, "Service has been unbound");
         sServiceUnBoundLatch.countDown();
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsSelfManagedConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsSelfManagedConnectionService.java
index 6610705..b057648 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsSelfManagedConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsSelfManagedConnectionService.java
@@ -43,7 +43,10 @@
     public static int CREATE_INCOMING_CONNECTION_FAILED_LOCK = 1;
     public static int CREATE_OUTGOING_CONNECTION_FAILED_LOCK = 2;
     public static int HANDOVER_FAILED_LOCK = 3;
-    private static int NUM_LOCKS = HANDOVER_FAILED_LOCK + 1;
+    public static int FOCUS_GAINED_LOCK = 4;
+    public static int FOCUS_LOST_LOCK = 5;
+
+    private static int NUM_LOCKS = FOCUS_LOST_LOCK + 1;
 
     private static CtsSelfManagedConnectionService sConnectionService;
 
@@ -132,6 +135,16 @@
     }
 
 
+    @Override
+    public void onConnectionServiceFocusGained() {
+        mLocks[FOCUS_GAINED_LOCK].countDown();
+    }
+
+    @Override
+    public void onConnectionServiceFocusLost() {
+        mLocks[FOCUS_LOST_LOCK].countDown();
+    }
+
     public void tearDown() {
         synchronized(mLock) {
             if (mConnections != null && mConnections.size() > 0) {
@@ -150,6 +163,8 @@
         SelfManagedConnection connection = new SelfManagedConnection(isIncoming,
                 mConnectionListener);
         connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED);
+        connection.setConnectionCapabilities(
+                Connection.CAPABILITY_HOLD | Connection.CAPABILITY_SUPPORT_HOLD);
         connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
         connection.setExtras(request.getExtras());
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
index 6e022e6..6523bac 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
@@ -27,6 +27,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Default implementation of a {@link CtsConnectionService}. This is used for the majority
@@ -36,6 +37,16 @@
 public class MockConnectionService extends ConnectionService {
     public static final int CONNECTION_PRESENTATION =  TelecomManager.PRESENTATION_ALLOWED;
 
+    public static final int EVENT_CONNECTION_SERVICE_FOCUS_GAINED = 0;
+    public static final int EVENT_CONNECTION_SERVICE_FOCUS_LOST = 1;
+
+    // Next event id is 2
+    private static final int TOTAL_EVENT = EVENT_CONNECTION_SERVICE_FOCUS_LOST + 1;
+
+    private static final int DEFAULT_EVENT_TIMEOUT_MS = 2000;
+
+    private final Semaphore[] mEventLock = initializeSemaphore(TOTAL_EVENT);
+
     /**
      * Used to control whether the {@link MockVideoProvider} will be created when connections are
      * created.  Used by {@link VideoCallTest#testVideoCallDelayProvider()} to test scenario where
@@ -131,7 +142,39 @@
         remoteConferences.add(conference);
     }
 
+    @Override
+    public void onConnectionServiceFocusGained() {
+        mEventLock[EVENT_CONNECTION_SERVICE_FOCUS_GAINED].release();
+    }
+
+    @Override
+    public void onConnectionServiceFocusLost() {
+        mEventLock[EVENT_CONNECTION_SERVICE_FOCUS_LOST].release();
+    }
+
     public void setCreateVideoProvider(boolean createVideoProvider) {
         mCreateVideoProvider = createVideoProvider;
     }
+
+    /** Returns true if the given {@code event} is happened before the default timeout. */
+    public boolean waitForEvent(int event) {
+        if (event < 0 || event >= mEventLock.length) {
+            return false;
+        }
+
+        try {
+            return mEventLock[event].tryAcquire(DEFAULT_EVENT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            // No interaction for the given event within the given timeout.
+            return false;
+        }
+    }
+
+    private static final Semaphore[] initializeSemaphore(int total) {
+        Semaphore[] locks = new Semaphore[total];
+        for (int i = 0; i < total; i++) {
+            locks[i] = new Semaphore(0);
+        }
+        return locks;
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index 41bf986..2b67f95 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
@@ -19,6 +19,7 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.telecom.CallAudioState;
+import android.telecom.Connection;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
@@ -52,7 +53,6 @@
             mTelecomManager.registerPhoneAccount(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1);
             mTelecomManager.registerPhoneAccount(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_2);
         }
-
     }
 
     @Override
@@ -107,7 +107,7 @@
         // enabled, and the one we get back after registration is.
         assertPhoneAccountEquals(TestUtils.TEST_SELF_MANAGED_PHONE_ACCOUNT_1, registeredAccount);
 
-        // An important asumption is that self-managed PhoneAccounts are automatically
+        // An important assumption is that self-managed PhoneAccounts are automatically
         // enabled by default.
         assertTrue("Self-managed PhoneAccounts must be enabled by default.",
                 registeredAccount.isEnabled());
@@ -219,6 +219,32 @@
     }
 
     /**
+     * Tests ensures that Telecom disallow to place outgoing self-managed call when the ongoing
+     * managed call can not be held.
+     */
+    public void testDisallowOutgoingCallWhileOngoingManagedCallCanNotBeHeld() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // GIVEN an ongoing managed call that can not be held
+        addAndVerifyNewIncomingCall(createTestNumber(), null);
+        Connection connection = verifyConnectionForIncomingCall();
+        int capabilities = connection.getConnectionCapabilities();
+        capabilities &= ~Connection.CAPABILITY_HOLD;
+        connection.setConnectionCapabilities(capabilities);
+        connection.setActive();
+
+        // WHEN place a self-managed outgoing call
+        TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
+                TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+
+        // THEN the new outgoing call is failed.
+        assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
+                CtsSelfManagedConnectionService.CREATE_OUTGOING_CONNECTION_FAILED_LOCK));
+    }
+
+    /**
      * Tests ability to add a new self-managed outgoing connection.
      */
     public void testAddSelfManagedOutgoingConnection() throws Exception {
@@ -296,11 +322,11 @@
     }
 
     /**
-     * Tests that Telecom will disallow an outgoing call when there is already an ongoing call in
-     * another third-party app.
+     * Tests that Telecom will allow the incoming call while the number of self-managed call is not
+     * exceed the limit.
      * @throws Exception
      */
-    public void testDisallowOutgoingCall() throws Exception {
+    public void testIncomingWhileOngoingWithinLimit() throws Exception {
         if (!mShouldTestTelecom) {
             return;
         }
@@ -311,33 +337,7 @@
         SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
         setActiveAndVerify(connection);
 
-        // Attempt to create a new outgoing call for the other PhoneAccount; it should fail.
-        TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
-                TestUtils.TEST_SELF_MANAGED_HANDLE_2, TEST_ADDRESS_2);
-        assertTrue("Expected onCreateOutgoingConnectionFailed callback",
-                CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
-                    CtsSelfManagedConnectionService.CREATE_OUTGOING_CONNECTION_FAILED_LOCK));
-
-        setDisconnectedAndVerify(connection);
-    }
-
-    /**
-     * Tests that Telecom will disallow an outgoing call when there is already an ongoing call in
-     * another third-party app.
-     * @throws Exception
-     */
-    public void testIncomingWhileOngoing() throws Exception {
-        if (!mShouldTestTelecom) {
-            return;
-        }
-
-        // Create an ongoing call in the first self-managed PhoneAccount.
-        TestUtils.placeOutgoingCall(getInstrumentation(), mTelecomManager,
-                TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
-        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
-        setActiveAndVerify(connection);
-
-        // Attempt to create a new outgoing call for the other PhoneAccount; it should succeed.
+        // Attempt to create a new incoming call for the other PhoneAccount; it should succeed.
         TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
                 TestUtils.TEST_SELF_MANAGED_HANDLE_2, TEST_ADDRESS_2);
         SelfManagedConnection connection2 = TestUtils.waitForAndGetConnection(TEST_ADDRESS_2);
@@ -347,6 +347,76 @@
     }
 
     /**
+     * Tests the self-managed ConnectionService has gained the focus when it become active.
+     */
+    public void testSelfManagedConnectionServiceGainedFocus() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // Attempt to create a new Incoming self-managed call
+        TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
+                TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
+        setActiveAndVerify(connection);
+
+        // The ConnectionService has gained the focus
+        assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
+                CtsSelfManagedConnectionService.FOCUS_GAINED_LOCK));
+
+        setDisconnectedAndVerify(connection);
+    }
+
+    public void testSelfManagedConnectionServiceLostFocus() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // GIVEN an ongoing self-managed call
+        TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
+                TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
+        setActiveAndVerify(connection);
+        assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
+                CtsSelfManagedConnectionService.FOCUS_GAINED_LOCK));
+
+        // WHEN place a managed call
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall().setActive();
+        assertTrue(connectionService.waitForEvent(
+                MockConnectionService.EVENT_CONNECTION_SERVICE_FOCUS_GAINED));
+
+        // THEN the self-managed ConnectionService lost the focus
+
+        connection.disconnectAndDestroy();
+        assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
+                CtsSelfManagedConnectionService.FOCUS_LOST_LOCK));
+    }
+
+    /**
+     * Tests that Telecom will disallow the incoming call while the ringing call is existed.
+     */
+    public void testRingCallLimitForOnePhoneAccount() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // GIVEN a self-managed call which state is ringing
+        TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
+                TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+        SelfManagedConnection connection = TestUtils.waitForAndGetConnection(TEST_ADDRESS_1);
+        connection.setRinging();
+
+        // WHEN create a new incoming call for the the same PhoneAccount
+        TestUtils.addIncomingCall(getInstrumentation(), mTelecomManager,
+                TestUtils.TEST_SELF_MANAGED_HANDLE_1, TEST_ADDRESS_1);
+
+        // THEN the new incoming call is denied
+        assertTrue(CtsSelfManagedConnectionService.getConnectionService().waitForUpdate(
+                CtsSelfManagedConnectionService.CREATE_INCOMING_CONNECTION_FAILED_LOCK));
+    }
+
+    /**
      * Tests that Telecom enforces a maximum number of calls for a self-managed ConnectionService.
      *
      * @throws Exception