1 /*
2  * Copyright (C) 2019 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.telephony.ims.cts;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.PackageManager;
22 import android.content.pm.ResolveInfo;
23 import android.service.carrier.CarrierService;
24 import android.telephony.SubscriptionInfo;
25 import android.telephony.SubscriptionManager;
26 import android.telephony.TelephonyManager;
27 
28 import androidx.test.platform.app.InstrumentationRegistry;
29 
30 import com.android.compatibility.common.util.ShellIdentityUtils;
31 
32 import java.util.List;
33 import java.util.concurrent.Callable;
34 
35 public class ImsUtils {
36     public static final boolean VDBG = false;
37 
38     // ImsService rebind has an exponential backoff capping at 64 seconds. Wait for 70 seconds to
39     // allow for the new poll to happen in the framework.
40     public static final int TEST_TIMEOUT_MS = 70000;
41 
42     // Id for non compressed auto configuration xml.
43     public static final int ITEM_NON_COMPRESSED = 2000;
44     // Id for compressed auto configuration xml.
45     public static final int ITEM_COMPRESSED = 2001;
46 
shouldTestImsService()47     public static boolean shouldTestImsService() {
48         final PackageManager pm = InstrumentationRegistry.getInstrumentation().getContext()
49                 .getPackageManager();
50         boolean hasTelephony = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
51         boolean hasIms = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
52         return hasTelephony && hasIms;
53     }
54 
getPreferredActiveSubId()55     public static int getPreferredActiveSubId() {
56         Context context = InstrumentationRegistry.getInstrumentation().getContext();
57         SubscriptionManager sm = (SubscriptionManager) context.getSystemService(
58                 Context.TELEPHONY_SUBSCRIPTION_SERVICE);
59         List<SubscriptionInfo> infos = ShellIdentityUtils.invokeMethodWithShellPermissions(sm,
60                 SubscriptionManager::getActiveSubscriptionInfoList);
61 
62         int defaultSubId = SubscriptionManager.getDefaultVoiceSubscriptionId();
63         if (defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
64                 && isSubIdInInfoList(infos, defaultSubId)) {
65             return defaultSubId;
66         }
67 
68         defaultSubId = SubscriptionManager.getDefaultSubscriptionId();
69         if (defaultSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
70                 && isSubIdInInfoList(infos, defaultSubId)) {
71             return defaultSubId;
72         }
73 
74         // Couldn't resolve a default. We can try to resolve a default using the active
75         // subscriptions.
76         if (!infos.isEmpty()) {
77             return infos.get(0).getSubscriptionId();
78         }
79         // There must be at least one active subscription.
80         return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
81     }
82 
isSubIdInInfoList(List<SubscriptionInfo> infos, int subId)83     private static boolean isSubIdInInfoList(List<SubscriptionInfo> infos, int subId) {
84         return infos.stream().anyMatch(info -> info.getSubscriptionId() == subId);
85     }
86 
87     /**
88      * If a carrier app implements CarrierMessagingService it can choose to take care of handling
89      * SMS OTT so SMS over IMS APIs won't be triggered which would be WAI so we do not run the tests
90      * if there exist a carrier app that declares a CarrierMessagingService
91      */
shouldRunSmsImsTests(int subId)92     public static boolean shouldRunSmsImsTests(int subId) {
93         if (!shouldTestImsService()) {
94             return false;
95         }
96         Context context = InstrumentationRegistry.getInstrumentation().getContext();
97         TelephonyManager tm =
98                 (TelephonyManager) InstrumentationRegistry.getInstrumentation().getContext()
99                         .getSystemService(Context.TELEPHONY_SERVICE);
100         tm = tm.createForSubscriptionId(subId);
101         List<String> carrierPackages = tm.getCarrierPackageNamesForIntent(
102                 new Intent(CarrierService.CARRIER_SERVICE_INTERFACE));
103 
104         if (carrierPackages == null || carrierPackages.size() == 0) {
105             return true;
106         }
107         final PackageManager packageManager = context.getPackageManager();
108         Intent intent = new Intent("android.service.carrier.CarrierMessagingService");
109         List<ResolveInfo> resolveInfos = packageManager.queryIntentServices(intent, 0);
110         for (ResolveInfo info : resolveInfos) {
111             if (carrierPackages.contains(info.serviceInfo.packageName)) {
112                 return false;
113             }
114         }
115 
116         return true;
117     }
118 
119     /**
120      * Retry every 5 seconds until the condition is true or fail after TEST_TIMEOUT_MS seconds.
121      */
retryUntilTrue(Callable<Boolean> condition)122     public static boolean retryUntilTrue(Callable<Boolean> condition) throws Exception {
123         int retryCounter = 0;
124         while (retryCounter < (TEST_TIMEOUT_MS / 5000)) {
125             try {
126                 Boolean isSuccessful = condition.call();
127                 isSuccessful = (isSuccessful == null) ? false : isSuccessful;
128                 if (isSuccessful) return true;
129             } catch (Exception e) {
130                 // we will retry
131             }
132             Thread.sleep(5000);
133             retryCounter++;
134         }
135         return false;
136     }
137 }
138