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