1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package android.telecom.cts; 18 19 import android.content.Intent; 20 import android.os.Bundle; 21 import android.telecom.Connection; 22 import android.telecom.ConnectionRequest; 23 import android.telecom.ConnectionService; 24 import android.telecom.DisconnectCause; 25 import android.telecom.PhoneAccountHandle; 26 import android.telecom.TelecomManager; 27 import android.util.Log; 28 29 import androidx.annotation.Nullable; 30 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import java.util.List; 34 import java.util.concurrent.CountDownLatch; 35 36 /** 37 * CTS test self-managed {@link ConnectionService} implementation. 38 */ 39 public class CtsSelfManagedConnectionService extends ConnectionService { 40 public static final String LOG_TAG = "CtsSMConnectionService"; 41 // Constants used to address into the mLocks array. 42 public static int CONNECTION_CREATED_LOCK = 0; 43 public static int CREATE_INCOMING_CONNECTION_FAILED_LOCK = 1; 44 public static int CREATE_OUTGOING_CONNECTION_FAILED_LOCK = 2; 45 public static int HANDOVER_FAILED_LOCK = 3; 46 public static int FOCUS_GAINED_LOCK = 4; 47 public static int FOCUS_LOST_LOCK = 5; 48 49 private static int NUM_LOCKS = FOCUS_LOST_LOCK + 1; 50 private static final String TAG = "CtsSelfManagedConnectionService"; 51 52 private static CtsSelfManagedConnectionService sConnectionService; 53 54 // Lock used to determine when binding to CS is complete. 55 private static CountDownLatch sBindingLock = new CountDownLatch(1); 56 57 private SelfManagedConnection.Listener mConnectionListener = 58 new SelfManagedConnection.Listener() { 59 @Override 60 void onDestroyed(SelfManagedConnection connection) { 61 mConnections.remove(connection); 62 } 63 }; 64 65 private CountDownLatch[] mLocks = new CountDownLatch[NUM_LOCKS]; 66 67 private final Object mLock = new Object(); 68 private List<SelfManagedConnection> mConnections = new ArrayList<>(); 69 private TestUtils.InvokeCounter mOnCreateIncomingHandoverConnectionCounter = 70 new TestUtils.InvokeCounter("incomingHandoverConnection"); 71 private TestUtils.InvokeCounter mOnCreateOutgoingHandoverConnectionCounter = 72 new TestUtils.InvokeCounter("outgoingHandoverConnection"); 73 getConnectionService()74 public static CtsSelfManagedConnectionService getConnectionService() { 75 return sConnectionService; 76 } 77 78 @Override onBindClient(@ullable Intent intent)79 public void onBindClient(@Nullable Intent intent) { 80 Log.i(LOG_TAG, "onBindClient with intent: " + intent); 81 sConnectionService = this; 82 Arrays.setAll(mLocks, i -> new CountDownLatch(1)); 83 84 // Inform anyone waiting on binding that we're bound. 85 sBindingLock.countDown(); 86 } 87 88 @Override onUnbind(Intent intent)89 public boolean onUnbind(Intent intent) { 90 Log.i(LOG_TAG, "onUnbind with intent: " + intent); 91 sBindingLock = new CountDownLatch(1); 92 return super.onUnbind(intent); 93 } 94 95 @Override onCreateOutgoingConnection(PhoneAccountHandle connectionManagerAccount, final ConnectionRequest request)96 public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerAccount, 97 final ConnectionRequest request) { 98 99 return createSelfManagedConnection(request, false); 100 } 101 102 @Override onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request)103 public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount, 104 ConnectionRequest request) { 105 return createSelfManagedConnection(request, true); 106 } 107 108 @Override onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerHandle, ConnectionRequest request)109 public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerHandle, 110 ConnectionRequest request) { 111 mLocks[CREATE_INCOMING_CONNECTION_FAILED_LOCK].countDown(); 112 } 113 114 @Override onCreateOutgoingConnectionFailed(PhoneAccountHandle connectionManagerHandle, ConnectionRequest request)115 public void onCreateOutgoingConnectionFailed(PhoneAccountHandle connectionManagerHandle, 116 ConnectionRequest request) { 117 mLocks[CREATE_OUTGOING_CONNECTION_FAILED_LOCK].countDown(); 118 } 119 120 @Override onCreateIncomingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle, ConnectionRequest request)121 public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle, 122 ConnectionRequest request) { 123 mOnCreateIncomingHandoverConnectionCounter.invoke(fromPhoneAccountHandle, request); 124 return createSelfManagedConnection(request, true /* incoming */); 125 } 126 127 @Override onCreateOutgoingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle, ConnectionRequest request)128 public Connection onCreateOutgoingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle, 129 ConnectionRequest request) { 130 mOnCreateOutgoingHandoverConnectionCounter.invoke(fromPhoneAccountHandle, request); 131 return createSelfManagedConnection(request, false /* incoming */); 132 } 133 134 @Override onHandoverFailed(ConnectionRequest request, int error)135 public void onHandoverFailed(ConnectionRequest request, int error) { 136 mLocks[HANDOVER_FAILED_LOCK].countDown(); 137 } 138 139 140 @Override onConnectionServiceFocusGained()141 public void onConnectionServiceFocusGained() { 142 Log.i(TAG, "onConnectionServiceFocusGained"); 143 mLocks[FOCUS_GAINED_LOCK].countDown(); 144 } 145 146 @Override onConnectionServiceFocusLost()147 public void onConnectionServiceFocusLost() { 148 Log.i(TAG, "onConnectionServiceFocusLost"); 149 mLocks[FOCUS_LOST_LOCK].countDown(); 150 connectionServiceFocusReleased(); 151 } 152 tearDown()153 public void tearDown() { 154 synchronized(mLock) { 155 if (mConnections != null && mConnections.size() > 0) { 156 Log.w(LOG_TAG, "disconnecting non-disconnected calls: " + mConnections); 157 mConnections.forEach(connection -> { 158 connection.setDisconnected(new DisconnectCause(DisconnectCause.LOCAL)); 159 connection.destroy(); 160 } 161 ); 162 mConnections.clear(); 163 } 164 } 165 } 166 createSelfManagedConnection(ConnectionRequest request, boolean isIncoming)167 private Connection createSelfManagedConnection(ConnectionRequest request, boolean isIncoming) { 168 SelfManagedConnection connection = new SelfManagedConnection(isIncoming, 169 mConnectionListener); 170 connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED); 171 connection.setConnectionCapabilities( 172 Connection.CAPABILITY_HOLD | Connection.CAPABILITY_SUPPORT_HOLD); 173 connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED); 174 connection.setExtras(request.getExtras()); 175 176 Bundle moreExtras = new Bundle(); 177 moreExtras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, 178 request.getAccountHandle()); 179 connection.putExtras(moreExtras); 180 connection.setVideoState(request.getVideoState()); 181 182 if (isIncoming) { 183 connection.setRinging(); 184 } else { 185 connection.setInitializing(); 186 } 187 188 synchronized(mLock) { 189 mConnections.add(connection); 190 } 191 mLocks[CONNECTION_CREATED_LOCK].countDown(); 192 return connection; 193 } 194 getConnections()195 public List<SelfManagedConnection> getConnections() { 196 synchronized(mLock) { 197 return new ArrayList<>(mConnections); 198 } 199 } 200 201 /** 202 * Waits on a lock for maximum of 5 seconds. 203 * 204 * @param lock one of the {@code *_LOCK} constants defined above. 205 * @return {@code true} if the lock was released within the time limit, {@code false} if the 206 * timeout expired without the lock being released. 207 */ waitForUpdate(int lock)208 public boolean waitForUpdate(int lock) { 209 mLocks[lock] = TestUtils.waitForLock(mLocks[lock]); 210 return mLocks[lock] != null; 211 } 212 213 /** 214 * Waits for the {@link ConnectionService} to be found. 215 * @return {@code true} if binding happened within the time limit, or {@code false} otherwise. 216 */ waitForBinding()217 public static boolean waitForBinding() { 218 return TestUtils.waitForLatchCountDown(sBindingLock); 219 } 220 getOnCreateIncomingHandoverConnectionCounter()221 public TestUtils.InvokeCounter getOnCreateIncomingHandoverConnectionCounter() { 222 return mOnCreateIncomingHandoverConnectionCounter; 223 } 224 getOnCreateOutgoingHandoverConnectionCounter()225 public TestUtils.InvokeCounter getOnCreateOutgoingHandoverConnectionCounter() { 226 return mOnCreateOutgoingHandoverConnectionCounter; 227 } 228 } 229