1 /* 2 * Copyright (C) 2020 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 com.android.ims; 18 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertTrue; 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.anyBoolean; 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.never; 25 import static org.mockito.Mockito.times; 26 import static org.mockito.Mockito.verify; 27 28 import android.content.Context; 29 import android.os.Binder; 30 import android.os.IBinder; 31 import android.os.IInterface; 32 import android.telephony.SubscriptionInfo; 33 import android.telephony.SubscriptionManager; 34 35 import androidx.test.ext.junit.runners.AndroidJUnit4; 36 import androidx.test.filters.SmallTest; 37 38 import org.junit.After; 39 import org.junit.Before; 40 import org.junit.Test; 41 import org.junit.runner.RunWith; 42 43 import java.util.ArrayList; 44 import java.util.List; 45 46 @RunWith(AndroidJUnit4.class) 47 public class MmTelFeatureConnectionTest extends ImsTestBase { 48 49 private class TestCallback extends Binder implements IInterface { 50 51 @Override asBinder()52 public IBinder asBinder() { 53 return this; 54 } 55 } 56 57 private class CallbackManagerTest extends 58 ImsCallbackAdapterManager<TestCallback> { 59 60 List<TestCallback> mCallbacks = new ArrayList<>(); 61 CallbackManagerTest(Context context, Object lock)62 CallbackManagerTest(Context context, Object lock) { 63 super(context, lock, 0 /*slotId*/); 64 } 65 66 // A callback has been registered. Register that callback with the MmTelFeature. 67 @Override registerCallback(TestCallback localCallback)68 public void registerCallback(TestCallback localCallback) { 69 mCallbacks.add(localCallback); 70 } 71 72 // A callback has been removed, unregister that callback with the MmTelFeature. 73 @Override unregisterCallback(TestCallback localCallback)74 public void unregisterCallback(TestCallback localCallback) { 75 mCallbacks.remove(localCallback); 76 } 77 doesCallbackExist(TestCallback callback)78 public boolean doesCallbackExist(TestCallback callback) { 79 return mCallbacks.contains(callback); 80 } 81 } 82 private CallbackManagerTest mCallbackManagerUT; 83 84 @Before setUp()85 public void setUp() throws Exception { 86 super.setUp(); 87 mCallbackManagerUT = new CallbackManagerTest(mContext, this); 88 } 89 90 @After tearDown()91 public void tearDown() throws Exception { 92 mCallbackManagerUT = null; 93 super.tearDown(); 94 } 95 96 /** 97 * Basic test of deprecated functionality, ensure that adding the callback directly triggers the 98 * appropriate registerCallback and unregisterCallback calls. 99 */ 100 @Test 101 @SmallTest testCallbackAdapter_addAndRemoveCallback()102 public void testCallbackAdapter_addAndRemoveCallback() throws Exception { 103 TestCallback testCallback = new TestCallback(); 104 mCallbackManagerUT.addCallback(testCallback); 105 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback)); 106 // The subscriptions changed listener should only be added for callbacks that are being 107 // linked to a subscription. 108 verify(mSubscriptionManager, never()).addOnSubscriptionsChangedListener( 109 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 110 111 mCallbackManagerUT.removeCallback(testCallback); 112 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback)); 113 // The subscriptions changed listener should only be removed for callbacks that are 114 // linked to a subscription. 115 verify(mSubscriptionManager, never()).removeOnSubscriptionsChangedListener( 116 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 117 } 118 119 /** 120 * Ensure that adding the callback and linking subId triggers the appropriate registerCallback 121 * and unregisterCallback calls as well as the subscriptionChanged listener. 122 */ 123 @Test 124 @SmallTest testCallbackAdapter_addAndRemoveCallbackForSub()125 public void testCallbackAdapter_addAndRemoveCallbackForSub() throws Exception { 126 TestCallback testCallback = new TestCallback(); 127 int testSub = 1; 128 mCallbackManagerUT.addCallbackForSubscription(testCallback, testSub); 129 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback)); 130 verify(mSubscriptionManager, times(1)).addOnSubscriptionsChangedListener( 131 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 132 133 mCallbackManagerUT.removeCallbackForSubscription(testCallback, testSub); 134 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback)); 135 verify(mSubscriptionManager, times(1)).removeOnSubscriptionsChangedListener( 136 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 137 } 138 139 /** 140 * Ensure that adding the callback and linking multiple subIds trigger the appropriate 141 * registerCallback and unregisterCallback calls as well as the subscriptionChanged listener. 142 * When removing the callbacks, the subscriptionChanged listener shoud only be removed when all 143 * callbacks have been removed. 144 */ 145 @Test 146 @SmallTest testCallbackAdapter_addAndRemoveCallbackForMultipleSubs()147 public void testCallbackAdapter_addAndRemoveCallbackForMultipleSubs() throws Exception { 148 TestCallback testCallback1 = new TestCallback(); 149 TestCallback testCallback2 = new TestCallback(); 150 int testSub1 = 1; 151 int testSub2 = 2; 152 mCallbackManagerUT.addCallbackForSubscription(testCallback1, testSub1); 153 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback1)); 154 mCallbackManagerUT.addCallbackForSubscription(testCallback2, testSub2); 155 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback2)); 156 // This should only happen once. 157 verify(mSubscriptionManager, times(1)).addOnSubscriptionsChangedListener( 158 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 159 160 mCallbackManagerUT.removeCallbackForSubscription(testCallback1, testSub1); 161 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback1)); 162 // removing the listener should not happen until the second callback is removed. 163 verify(mSubscriptionManager, never()).removeOnSubscriptionsChangedListener( 164 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 165 166 mCallbackManagerUT.removeCallbackForSubscription(testCallback2, testSub2); 167 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback2)); 168 verify(mSubscriptionManager, times(1)).removeOnSubscriptionsChangedListener( 169 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 170 } 171 172 /** 173 * The subscriptions have changed, ensure that the callbacks registered to the original 174 * subscription testSub1 are removed, while keeping the callbacks for testSub2, since it was not 175 * removed. 176 */ 177 @Test 178 @SmallTest testCallbackAdapter_onSubscriptionsChangedMultipleSubs()179 public void testCallbackAdapter_onSubscriptionsChangedMultipleSubs() throws Exception { 180 TestCallback testCallback1 = new TestCallback(); 181 TestCallback testCallback2 = new TestCallback(); 182 int testSub1 = 1; 183 int testSub2 = 2; 184 int testSub3 = 3; 185 mCallbackManagerUT.addCallbackForSubscription(testCallback1, testSub1); 186 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback1)); 187 mCallbackManagerUT.addCallbackForSubscription(testCallback2, testSub2); 188 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback2)); 189 verify(mSubscriptionManager, times(1)).addOnSubscriptionsChangedListener( 190 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 191 192 // Simulate subscriptions changed, where testSub1 is no longer active 193 doReturn(createSubscriptionInfoList(new int[] {testSub2, testSub3})) 194 .when(mSubscriptionManager).getActiveSubscriptionInfoList(anyBoolean()); 195 mCallbackManagerUT.mSubChangedListener.onSubscriptionsChanged(); 196 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback1)); 197 // verify that the subscription changed listener is not removed, since we still have a 198 // callback on testSub2 199 verify(mSubscriptionManager, never()).removeOnSubscriptionsChangedListener( 200 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 201 } 202 203 /** 204 * The active subscription has changed, ensure that the callback registered to the original 205 * subscription testSub1 are removed as well as the subscription changed listener, since 206 * there are mo more active callbacks. 207 */ 208 @Test 209 @SmallTest testCallbackAdapter_onSubscriptionsChangedOneSub()210 public void testCallbackAdapter_onSubscriptionsChangedOneSub() throws Exception { 211 TestCallback testCallback1 = new TestCallback(); 212 int testSub1 = 1; 213 int testSub2 = 2; 214 mCallbackManagerUT.addCallbackForSubscription(testCallback1, testSub1); 215 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback1)); 216 verify(mSubscriptionManager, times(1)).addOnSubscriptionsChangedListener( 217 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 218 219 // Simulate subscriptions changed, where testSub1 is no longer active 220 doReturn(createSubscriptionInfoList(new int[] {testSub2})) 221 .when(mSubscriptionManager).getActiveSubscriptionInfoList(anyBoolean()); 222 mCallbackManagerUT.mSubChangedListener.onSubscriptionsChanged(); 223 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback1)); 224 // verify that the subscription listener is removed, since the only active callback has been 225 // removed. 226 verify(mSubscriptionManager, times(1)).removeOnSubscriptionsChangedListener( 227 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 228 } 229 230 /** 231 * The close() method has been called, so al callbacks should be cleaned up and notified 232 * that they have been removed. The subscriptions changed listener should also be removed. 233 */ 234 @Test 235 @SmallTest testCallbackAdapter_closeMultipleSubs()236 public void testCallbackAdapter_closeMultipleSubs() throws Exception { 237 TestCallback testCallback1 = new TestCallback(); 238 TestCallback testCallback2 = new TestCallback(); 239 int testSub1 = 1; 240 int testSub2 = 2; 241 mCallbackManagerUT.addCallbackForSubscription(testCallback1, testSub1); 242 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback1)); 243 mCallbackManagerUT.addCallbackForSubscription(testCallback2, testSub2); 244 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback2)); 245 verify(mSubscriptionManager, times(1)).addOnSubscriptionsChangedListener( 246 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 247 248 // Close the manager, ensure all subscription callbacks are removed 249 mCallbackManagerUT.close(); 250 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback1)); 251 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback2)); 252 // verify that the subscription changed listener is removed. 253 verify(mSubscriptionManager, times(1)).removeOnSubscriptionsChangedListener( 254 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 255 } 256 257 /** 258 * The close() method has been called, so all callbacks should be cleaned up. Since they are 259 * not associated with any subscriptions, no subscription based logic should be called. 260 */ 261 @Test 262 @SmallTest testCallbackAdapter_closeSlotBasedCallbacks()263 public void testCallbackAdapter_closeSlotBasedCallbacks() throws Exception { 264 TestCallback testCallback1 = new TestCallback(); 265 TestCallback testCallback2 = new TestCallback(); 266 mCallbackManagerUT.addCallback(testCallback1); 267 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback1)); 268 mCallbackManagerUT.addCallback(testCallback2); 269 assertTrue(mCallbackManagerUT.doesCallbackExist(testCallback2)); 270 // verify that the subscription changed listener is never called for these callbacks 271 // because they are not associated with any subscriptions. 272 verify(mSubscriptionManager, never()).addOnSubscriptionsChangedListener( 273 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 274 275 // Close the manager, ensure all subscription callbacks are removed 276 mCallbackManagerUT.close(); 277 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback1)); 278 assertFalse(mCallbackManagerUT.doesCallbackExist(testCallback2)); 279 // verify that the subscription changed removed method is never called 280 verify(mSubscriptionManager, never()).removeOnSubscriptionsChangedListener( 281 any(SubscriptionManager.OnSubscriptionsChangedListener.class)); 282 } 283 createSubscriptionInfoList(int[] subIds)284 private List<SubscriptionInfo> createSubscriptionInfoList(int[] subIds) { 285 List<SubscriptionInfo> infos = new ArrayList<>(); 286 for (int i = 0; i < subIds.length; i++) { 287 SubscriptionInfo info = new SubscriptionInfo(subIds[i], null, -1, null, null, -1, -1, 288 null, -1, null, null, null, null, false, null, null); 289 infos.add(info); 290 } 291 return infos; 292 } 293 } 294