• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18 
19 import static android.media.ToneGenerator.TONE_PROP_PROMPT;
20 import static android.media.ToneGenerator.TONE_SUP_BUSY;
21 
22 import static junit.framework.Assert.assertNotNull;
23 import static junit.framework.TestCase.assertEquals;
24 
25 import static org.testng.Assert.assertFalse;
26 import static org.testng.Assert.assertTrue;
27 
28 import android.content.Context;
29 import android.content.res.Configuration;
30 import android.content.res.Resources;
31 import android.os.PersistableBundle;
32 import android.telephony.CarrierConfigManager;
33 import android.telephony.DisconnectCause;
34 
35 import androidx.test.InstrumentationRegistry;
36 import androidx.test.runner.AndroidJUnit4;
37 
38 import com.android.TelephonyTestBase;
39 import com.android.internal.telephony.CallFailCause;
40 import com.android.phone.R;
41 
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 
46 import java.util.Locale;
47 
48 @RunWith(AndroidJUnit4.class)
49 public class DisconnectCauseUtilTest extends TelephonyTestBase {
50 
51     // constants
52     public static final int PHONE_ID = 123;
53     public static final String EMPTY_STRING = "";
54 
55     private final FlagsAdapter mFeatureFlags = new FlagsAdapter(){
56         @Override
57         public boolean doNotOverridePreciseLabel() {
58             return true;
59         }
60     };
61 
62     @Before
setUp()63     public void setUp() throws Exception {
64         super.setUp();
65     }
66 
67     /**
68      * Verifies that a call drop due to loss of WIFI results in a disconnect cause of error and that
69      * the label, description and tone are all present.
70      */
71     @Test
testDropDueToWifiLoss()72     public void testDropDueToWifiLoss() {
73         android.telecom.DisconnectCause tcCause = DisconnectCauseUtil.toTelecomDisconnectCause(
74                 DisconnectCause.WIFI_LOST);
75         assertEquals(android.telecom.DisconnectCause.ERROR, tcCause.getCode());
76         assertEquals(TONE_PROP_PROMPT, tcCause.getTone());
77         assertNotNull(tcCause.getDescription());
78         assertNotNull(tcCause.getReason());
79     }
80 
81     /**
82      *  ensure the default behavior was not changed when a disconnect cause comes in as
83      *  DisconnectCause.ERROR_UNSPECIFIED
84      */
85     @Test
testDefaultDisconnectCauseBehaviorForCauseNotInCarrierBusyToneArray()86     public void testDefaultDisconnectCauseBehaviorForCauseNotInCarrierBusyToneArray() {
87         android.telecom.DisconnectCause tcCause = DisconnectCauseUtil.toTelecomDisconnectCause(
88                 DisconnectCause.ERROR_UNSPECIFIED, -1, EMPTY_STRING, PHONE_ID, null, mFeatureFlags);
89         // CODE
90         assertEquals(android.telecom.DisconnectCause.ERROR, tcCause.getCode());
91         // LABEL
92         safeAssertLabel(null, tcCause);
93         // TONE
94         assertEquals(TONE_PROP_PROMPT, tcCause.getTone());
95     }
96 
97     /**
98      * verify that if a precise label is given Telephony, the label is not overridden by Telecom
99      */
100     @Test
testDefaultPhoneConfig_NoPreciseLabelGiven()101     public void testDefaultPhoneConfig_NoPreciseLabelGiven() {
102         android.telecom.DisconnectCause tcCause =
103                 DisconnectCauseUtil.toTelecomDisconnectCause(DisconnectCause.BUSY,
104                         -1 /*  precise label is NOT given */,
105                         EMPTY_STRING, PHONE_ID, null /* carrier config is NOT set */,
106                         mFeatureFlags);
107         assertBusyCauseWithTargetLabel(R.string.callFailed_userBusy, tcCause);
108     }
109 
110     /**
111      * verify that if a precise label is given Telephony, the label is not overridden by Telecom
112      */
113     @Test
testDefaultPhoneConfig_PreciseLabelProvided()114     public void testDefaultPhoneConfig_PreciseLabelProvided() {
115         android.telecom.DisconnectCause tcCause =
116                 DisconnectCauseUtil.toTelecomDisconnectCause(DisconnectCause.BUSY,
117                         CallFailCause.USER_BUSY /* Telephony defined a precise label */,
118                         EMPTY_STRING, PHONE_ID, null /* carrier config is NOT set */,
119                         mFeatureFlags);
120         // Note: The precise label should not be overridden even though the carrier defined
121         // the cause to play a busy tone
122         assertBusyCauseWithTargetLabel(R.string.clh_callFailed_user_busy_txt, tcCause);
123     }
124 
125     /**
126      * special case: The Carrier has re-defined a disconnect code that should play a busy tone.
127      * Thus, the code, label, and tone should be remapped.
128      * <p>
129      * <p>
130      * Verify that if the disconnect cause is in the carrier busy tone array that the expected
131      * label, tone, and code are returned.
132      */
133     @Test
testCarrierSetBusyToneArray_NoPreciseLabelGiven()134     public void testCarrierSetBusyToneArray_NoPreciseLabelGiven() {
135         android.telecom.DisconnectCause tcCause =
136                 DisconnectCauseUtil.toTelecomDisconnectCause(
137                         DisconnectCause.BUSY, -1 /*  precise label is NOT given */,
138                         EMPTY_STRING, PHONE_ID, null, getBundleWithBusyToneArray(), mFeatureFlags,
139                         false);
140 
141         assertBusyCauseWithTargetLabel(R.string.callFailed_userBusy, tcCause);
142     }
143 
144     /**
145      * special case: The Carrier has re-defined a disconnect code that should play a busy tone.
146      * Thus, the code, label, and tone should be remapped.
147      * <p>
148      * <p>
149      * Verify that if the disconnect cause is in the carrier busy tone array and the Telephony
150      * stack has provided a precise label, the label is not overridden.
151      */
152     @Test
testCarrierSetBusyToneArray_PreciseLabelProvided()153     public void testCarrierSetBusyToneArray_PreciseLabelProvided() {
154         android.telecom.DisconnectCause tcCause =
155                 DisconnectCauseUtil.toTelecomDisconnectCause(DisconnectCause.BUSY,
156                         CallFailCause.USER_BUSY /* Telephony defined a precise label */,
157                         EMPTY_STRING, PHONE_ID, null, getBundleWithBusyToneArray(), mFeatureFlags,
158                         false);
159         // Note: The precise label should not be overridden even though the carrier defined
160         // the cause to play a busy tone
161         assertBusyCauseWithTargetLabel(R.string.clh_callFailed_user_busy_txt, tcCause);
162     }
163 
164     /**
165      * Ensure the helper doesCarrierClassifyDisconnectCauseAsBusyCause does not hit a NPE if a
166      * NULL carrier config is passed in.
167      */
168     @Test
testDoesCarrierClassifyDisconnectCauseAsBusyCause_nullConfig()169     public void testDoesCarrierClassifyDisconnectCauseAsBusyCause_nullConfig() {
170         assertFalse(DisconnectCauseUtil.doesCarrierClassifyDisconnectCauseAsBusyCause(-1, null));
171     }
172 
173     /**
174      * Ensure the helper doesCarrierClassifyDisconnectCauseAsBusyCause does not hit a NPE if an
175      * EMPTY carrier config is passed in.
176      */
177     @Test
testDoesCarrierClassifyDisconnectCauseAsBusyCause_ConfigDoesNotDefineArray()178     public void testDoesCarrierClassifyDisconnectCauseAsBusyCause_ConfigDoesNotDefineArray() {
179         PersistableBundle config = new PersistableBundle();
180         assertFalse(DisconnectCauseUtil.doesCarrierClassifyDisconnectCauseAsBusyCause(-1, config));
181     }
182 
183     /**
184      * Ensure the helper doesCarrierClassifyDisconnectCauseAsBusyCause does not hit a NPE if an
185      * EMPTY array is defined for KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY.
186      */
187     @Test
testDoesCarrierClassifyDisconnectCauseAsBusyCause_ConfigHasEmptyArray()188     public void testDoesCarrierClassifyDisconnectCauseAsBusyCause_ConfigHasEmptyArray() {
189         PersistableBundle config = new PersistableBundle();
190         int[] carrierBusyArr = {}; // NOTE: This is intentionally let empty
191 
192         config.putIntArray(
193                 CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
194                 carrierBusyArr);
195 
196         assertFalse(DisconnectCauseUtil.doesCarrierClassifyDisconnectCauseAsBusyCause(-1, config));
197     }
198 
199     /**
200      * Ensure {@link DisconnectCauseUtil#doesCarrierClassifyDisconnectCauseAsBusyCause} returns
201      * FALSE is the passed in disconnect cause is NOT the busy tone array
202      */
203     @Test
testDoesCarrierClassifyDisconnectCauseAsBusyCause_ConfigHasBusyToneButNotMatch()204     public void testDoesCarrierClassifyDisconnectCauseAsBusyCause_ConfigHasBusyToneButNotMatch() {
205         assertFalse(DisconnectCauseUtil.doesCarrierClassifyDisconnectCauseAsBusyCause(-1,
206                 getBundleWithBusyToneArray()));
207     }
208 
209     /**
210      * Ensure {@link DisconnectCauseUtil#doesCarrierClassifyDisconnectCauseAsBusyCause} returns
211      * TRUE if the disconnect cause is defined in the busy tone array (by the Carrier)
212      */
213     @Test
testDoesCarrierClassifyDisconnectCauseAsBusyCause_ConfigHasBusyTone()214     public void testDoesCarrierClassifyDisconnectCauseAsBusyCause_ConfigHasBusyTone() {
215         assertTrue(DisconnectCauseUtil.doesCarrierClassifyDisconnectCauseAsBusyCause(
216                 DisconnectCause.BUSY, getBundleWithBusyToneArray()));
217     }
218 
assertBusyCauseWithTargetLabel(Integer targetLabel, android.telecom.DisconnectCause disconnectCause)219     private void assertBusyCauseWithTargetLabel(Integer targetLabel,
220             android.telecom.DisconnectCause disconnectCause) {
221         // CODE: Describes the cause of a disconnected call
222         assertEquals(android.telecom.DisconnectCause.BUSY, disconnectCause.getCode());
223         // LABEL: This is the label that the user sees
224         safeAssertLabel(targetLabel, disconnectCause);
225         // TONE: This is the DTMF tone being played to the user
226         assertEquals(TONE_SUP_BUSY, disconnectCause.getTone());
227     }
228 
getBundleWithBusyToneArray()229     private PersistableBundle getBundleWithBusyToneArray() {
230         int[] carrierBusyArr = {DisconnectCause.BUSY};
231         PersistableBundle config = new PersistableBundle();
232 
233         config.putIntArray(
234                 CarrierConfigManager.KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY,
235                 carrierBusyArr);
236         return config;
237     }
238 
getResourcesForLocale(Context context, Locale locale)239     private Resources getResourcesForLocale(Context context, Locale locale) {
240         Configuration config = new Configuration();
241         config.setToDefaults();
242         config.setLocale(locale);
243         Context localeContext = context.createConfigurationContext(config);
244         return localeContext.getResources();
245     }
246 
safeAssertLabel(Integer resourceId, android.telecom.DisconnectCause disconnectCause)247     private void safeAssertLabel(Integer resourceId,
248             android.telecom.DisconnectCause disconnectCause) {
249         Resources r = getResourcesForLocale(InstrumentationRegistry.getTargetContext(), Locale.US);
250         if (resourceId == null || r == null) {
251             return;
252         }
253         String label = r.getString(resourceId);
254         assertEquals(label, disconnectCause.getLabel());
255     }
256 
257     /**
258      * Verifies that an ICC_ERROR disconnect cause generates a message which mentions there is no
259      * SIM.
260      */
261     @Test
testIccError()262     public void testIccError() {
263         android.telecom.DisconnectCause tcCause = DisconnectCauseUtil.toTelecomDisconnectCause(
264                 DisconnectCause.ICC_ERROR);
265         assertEquals(android.telecom.DisconnectCause.ERROR, tcCause.getCode());
266         assertNotNull(tcCause.getLabel());
267         assertNotNull(tcCause.getDescription());
268     }
269 }
270