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.services.telephony.rcs;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.mockito.ArgumentMatchers.any;
21 import static org.mockito.ArgumentMatchers.anyInt;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.times;
25 import static org.mockito.Mockito.verify;
26 
27 import android.net.InetAddresses;
28 import android.telephony.ims.DelegateRegistrationState;
29 import android.telephony.ims.FeatureTagState;
30 import android.telephony.ims.SipDelegateConfiguration;
31 import android.telephony.ims.SipDelegateManager;
32 import android.telephony.ims.aidl.ISipDelegate;
33 import android.telephony.ims.aidl.ISipDelegateConnectionStateCallback;
34 import android.util.ArraySet;
35 
36 import androidx.test.filters.SmallTest;
37 import androidx.test.runner.AndroidJUnit4;
38 
39 import com.android.TelephonyTestBase;
40 import com.android.internal.telephony.metrics.RcsStats;
41 
42 import org.junit.After;
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.mockito.ArgumentCaptor;
47 import org.mockito.Mock;
48 
49 import java.net.InetSocketAddress;
50 import java.util.ArrayList;
51 import java.util.List;
52 import java.util.Set;
53 
54 @RunWith(AndroidJUnit4.class)
55 public class DelegateStateTrackerTest extends TelephonyTestBase {
56     private static final int TEST_SUB_ID = 1;
57 
58     @Mock private ISipDelegate mSipDelegate;
59     @Mock private ISipDelegateConnectionStateCallback mAppCallback;
60     @Mock private RcsStats mRcsStats;
61 
62     @Before
setUp()63     public void setUp() throws Exception {
64         super.setUp();
65     }
66 
67     @After
tearDown()68     public void tearDown() throws Exception {
69         super.tearDown();
70     }
71 
72     /**
73      * When an underlying SipDelegate is created, the app should only receive one onCreated callback
74      * independent of how many times sipDelegateConnected is called. Once created, registration
75      * and IMS configuration events should propagate up to the app as well.
76      */
77     @SmallTest
78     @Test
testDelegateCreated()79     public void testDelegateCreated() throws Exception {
80         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
81                 mSipDelegate, mRcsStats);
82         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
83         Set<String> supportedTags = getSupportedTags();
84         stateTracker.sipDelegateConnected(supportedTags, deniedTags);
85         // Calling connected multiple times should not generate multiple onCreated events.
86         stateTracker.sipDelegateConnected(supportedTags, deniedTags);
87         verify(mAppCallback).onCreated(mSipDelegate);
88         verify(mRcsStats).createSipDelegateStats(TEST_SUB_ID, supportedTags);
89 
90         // Ensure status updates are sent to app as expected.
91         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
92                 .addRegisteredFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG)
93                 .build();
94         InetSocketAddress localAddr = new InetSocketAddress(
95                 InetAddresses.parseNumericAddress("1.1.1.1"), 80);
96         InetSocketAddress serverAddr = new InetSocketAddress(
97                 InetAddresses.parseNumericAddress("2.2.2.2"), 81);
98         SipDelegateConfiguration c = new SipDelegateConfiguration.Builder(1,
99                 SipDelegateConfiguration.SIP_TRANSPORT_TCP, localAddr, serverAddr).build();
100         stateTracker.onRegistrationStateChanged(regState);
101         stateTracker.onConfigurationChanged(c);
102         verify(mAppCallback).onFeatureTagStatusChanged(eq(regState),
103                 eq(new ArrayList<>(deniedTags)));
104         verify(mRcsStats).onSipTransportFeatureTagStats(TEST_SUB_ID, deniedTags,
105                 regState.getDeregisteredFeatureTags(),
106                 regState.getRegisteredFeatureTags());
107         verify(mAppCallback).onConfigurationChanged(c);
108         verify(mAppCallback, never()).onDestroyed(anyInt());
109     }
110 
111     /**
112      * onDestroyed should be called when sipDelegateDestroyed is called.
113      */
114     @SmallTest
115     @Test
testDelegateDestroyed()116     public void testDelegateDestroyed() throws Exception {
117         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
118                 mSipDelegate, mRcsStats);
119         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
120         Set<String> supportedTags = getSupportedTags();
121         stateTracker.sipDelegateConnected(supportedTags, deniedTags);
122         verify(mRcsStats).createSipDelegateStats(eq(TEST_SUB_ID), eq(supportedTags));
123 
124         stateTracker.sipDelegateDestroyed(
125                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
126         verify(mAppCallback).onDestroyed(
127                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
128         verify(mRcsStats).onSipDelegateStats(eq(TEST_SUB_ID), eq(supportedTags),
129                 eq(SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP));
130     }
131 
132     /**
133      * When a SipDelegate is created and then an event occurs that will destroy->create a new
134      * SipDelegate underneath, we need to move the state of the features that are reporting
135      * registered to DEREGISTERING_REASON_FEATURE_TAGS_CHANGING so that the app can close dialogs on
136      * it. Once the new underlying SipDelegate is created, we must verify that the new registration
137      * is propagated up without any overrides.
138      */
139     @SmallTest
140     @Test
testDelegateChangingRegisteredTagsOverride()141     public void testDelegateChangingRegisteredTagsOverride() throws Exception {
142         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
143                 mSipDelegate, mRcsStats);
144         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
145         Set<String> supportedTags = getSupportedTags();
146         stateTracker.sipDelegateConnected(supportedTags, deniedTags);
147         // SipDelegate created
148         verify(mAppCallback).onCreated(mSipDelegate);
149         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
150                 .addRegisteredFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG)
151                 .addDeregisteringFeatureTag(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG,
152                         DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE)
153                 .addDeregisteredFeatureTag(ImsSignallingUtils.GROUP_CHAT_TAG,
154                         DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED)
155                 .build();
156         stateTracker.onRegistrationStateChanged(regState);
157         // Simulate underlying SipDelegate switch
158         stateTracker.sipDelegateChanging(
159                 DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING);
160         // onFeatureTagStatusChanged should now be called with registered features overridden with
161         // DEREGISTERING_REASON_FEATURE_TAGS_CHANGING
162         DelegateRegistrationState overrideRegState = new DelegateRegistrationState.Builder()
163                 .addDeregisteringFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG,
164                         DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING)
165                 // Already Deregistering/Deregistered tags should not be overridden.
166                 .addDeregisteringFeatureTag(ImsSignallingUtils.FILE_TRANSFER_HTTP_TAG,
167                         DelegateRegistrationState.DEREGISTERING_REASON_PROVISIONING_CHANGE)
168                 .addDeregisteredFeatureTag(ImsSignallingUtils.GROUP_CHAT_TAG,
169                         DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED)
170                 .build();
171         // new underlying SipDelegate created
172         stateTracker.sipDelegateConnected(supportedTags, deniedTags);
173         stateTracker.onRegistrationStateChanged(regState);
174 
175         // Verify registration state through the process:
176         ArgumentCaptor<DelegateRegistrationState> regCaptor =
177                 ArgumentCaptor.forClass(DelegateRegistrationState.class);
178         verify(mAppCallback, times(3)).onFeatureTagStatusChanged(
179                 regCaptor.capture(), eq(new ArrayList<>(deniedTags)));
180         List<DelegateRegistrationState> testStates = regCaptor.getAllValues();
181         // feature tags should first be registered
182         assertEquals(regState, testStates.get(0));
183         // registered feature tags should have moved to deregistering
184         assertEquals(overrideRegState, testStates.get(1));
185         // and then moved back to registered after underlying FT change done.
186         assertEquals(regState, testStates.get(2));
187 
188         //onCreate should only have been called once and onDestroy should have never been called.
189         verify(mAppCallback).onCreated(mSipDelegate);
190         verify(mAppCallback, never()).onDestroyed(anyInt());
191     }
192 
193     /**
194      * Test the case that when the underlying Denied tags change in the SipDelegate, the change is
195      * properly shown in the registration update event.
196      */
197     @SmallTest
198     @Test
testDelegateChangingDeniedTagsChanged()199     public void testDelegateChangingDeniedTagsChanged() throws Exception {
200         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
201                 mSipDelegate, mRcsStats);
202         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
203         Set<String> supportedTags = getSupportedTags();
204         stateTracker.sipDelegateConnected(supportedTags, deniedTags);
205         // SipDelegate created
206         verify(mAppCallback).onCreated(mSipDelegate);
207         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
208                 .addRegisteredFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG)
209                 .build();
210         stateTracker.onRegistrationStateChanged(regState);
211         // Simulate underlying SipDelegate switch
212         stateTracker.sipDelegateChanging(
213                 DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING);
214         // onFeatureTagStatusChanged should now be called with registered features overridden with
215         // DEREGISTERING_REASON_FEATURE_TAGS_CHANGING
216         DelegateRegistrationState overrideRegState = new DelegateRegistrationState.Builder()
217                 .addDeregisteringFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG,
218                         DelegateRegistrationState.DEREGISTERING_REASON_FEATURE_TAGS_CHANGING)
219                 .build();
220         // Verify registration state so far.
221         ArgumentCaptor<DelegateRegistrationState> regCaptor =
222                 ArgumentCaptor.forClass(DelegateRegistrationState.class);
223         verify(mAppCallback, times(2)).onFeatureTagStatusChanged(
224                 regCaptor.capture(), eq(new ArrayList<>(deniedTags)));
225         List<DelegateRegistrationState> testStates = regCaptor.getAllValues();
226         assertEquals(2, testStates.size());
227         // feature tags should first be registered
228         assertEquals(regState, testStates.get(0));
229         // registered feature tags should have moved to deregistering
230         assertEquals(overrideRegState, testStates.get(1));
231 
232         // new underlying SipDelegate created, but SipDelegate denied one to one chat
233         deniedTags.add(new FeatureTagState(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG,
234                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
235         stateTracker.sipDelegateConnected(supportedTags, deniedTags);
236         DelegateRegistrationState fullyDeniedRegState = new DelegateRegistrationState.Builder()
237                 .build();
238         // In this special case, it will be the SipDelegateConnectionBase that will trigger
239         // reg state change.
240         stateTracker.onRegistrationStateChanged(fullyDeniedRegState);
241         verify(mAppCallback).onFeatureTagStatusChanged(regCaptor.capture(),
242                 eq(new ArrayList<>(deniedTags)));
243         // now all feature tags denied, so we should see only denied tags.
244         assertEquals(fullyDeniedRegState, regCaptor.getValue());
245 
246         //onCreate should only have been called once and onDestroy should have never been called.
247         verify(mAppCallback).onCreated(mSipDelegate);
248         verify(mAppCallback, never()).onDestroyed(anyInt());
249     }
250 
251     /**
252      * Test that when we move from changing tags state to the delegate being destroyed, we get the
253      * correct onDestroy event sent to the app.
254      */
255     @SmallTest
256     @Test
testDelegateChangingDeniedTagsChangingToDestroy()257     public void testDelegateChangingDeniedTagsChangingToDestroy() throws Exception {
258         DelegateStateTracker stateTracker = new DelegateStateTracker(TEST_SUB_ID, mAppCallback,
259                 mSipDelegate, mRcsStats);
260         Set<FeatureTagState> deniedTags = getMmTelDeniedTag();
261         Set<String> supportedTags = getSupportedTags();
262         stateTracker.sipDelegateConnected(supportedTags, deniedTags);
263         // SipDelegate created
264         verify(mAppCallback).onCreated(mSipDelegate);
265         DelegateRegistrationState regState = new DelegateRegistrationState.Builder()
266                 .addRegisteredFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG)
267                 .addDeregisteredFeatureTag(ImsSignallingUtils.GROUP_CHAT_TAG,
268                         DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED)
269                 .build();
270         stateTracker.onRegistrationStateChanged(regState);
271         verify(mAppCallback).onFeatureTagStatusChanged(any(),
272                 eq(new ArrayList<>(deniedTags)));
273         // Simulate underlying SipDelegate switch
274         stateTracker.sipDelegateChanging(
275                 DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING);
276         // Destroy
277         stateTracker.sipDelegateDestroyed(
278                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
279 
280         // onFeatureTagStatusChanged should now be called with registered features overridden with
281         // DEREGISTERING_REASON_DESTROY_PENDING
282         DelegateRegistrationState overrideRegState = new DelegateRegistrationState.Builder()
283                 .addDeregisteringFeatureTag(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG,
284                         DelegateRegistrationState.DEREGISTERING_REASON_DESTROY_PENDING)
285                 // Deregistered should stay the same.
286                 .addDeregisteredFeatureTag(ImsSignallingUtils.GROUP_CHAT_TAG,
287                         DelegateRegistrationState.DEREGISTERED_REASON_NOT_PROVISIONED)
288                 .build();
289         // Verify registration state through process:
290         ArgumentCaptor<DelegateRegistrationState> regCaptor =
291                 ArgumentCaptor.forClass(DelegateRegistrationState.class);
292         verify(mAppCallback, times(2)).onFeatureTagStatusChanged(regCaptor.capture(),
293                 eq(new ArrayList<>(deniedTags)));
294         List<DelegateRegistrationState> testStates = regCaptor.getAllValues();
295         assertEquals(2, testStates.size());
296         // feature tags should first be registered
297         assertEquals(regState, testStates.get(0));
298         // registered feature tags should have moved to deregistering
299         assertEquals(overrideRegState, testStates.get(1));
300         //onCreate/onDestroy should only be called once.
301         verify(mAppCallback).onCreated(mSipDelegate);
302         verify(mAppCallback).onDestroyed(
303                 SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_REQUESTED_BY_APP);
304     }
305 
getMmTelDeniedTag()306     private Set<FeatureTagState> getMmTelDeniedTag() {
307         Set<FeatureTagState> deniedTags = new ArraySet<>();
308         deniedTags.add(new FeatureTagState(ImsSignallingUtils.MMTEL_TAG,
309                 SipDelegateManager.DENIED_REASON_NOT_ALLOWED));
310         return deniedTags;
311     }
312 
getSupportedTags()313     private Set<String> getSupportedTags() {
314         Set<String> supportedTags = new ArraySet<>();
315         supportedTags.add(ImsSignallingUtils.ONE_TO_ONE_CHAT_TAG);
316         supportedTags.add(ImsSignallingUtils.GROUP_CHAT_TAG);
317         return supportedTags;
318     }
319 }
320