• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.cts.util;
18 
19 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
20 
21 import static org.junit.Assert.assertTrue;
22 
23 import android.annotation.NonNull;
24 import android.app.role.RoleManager;
25 import android.content.Context;
26 import android.content.pm.PackageManager;
27 import android.os.Process;
28 import android.os.UserHandle;
29 import android.telephony.TelephonyManager;
30 import android.text.TextUtils;
31 import android.util.Log;
32 
33 import androidx.test.core.app.ApplicationProvider;
34 
35 import com.android.compatibility.common.util.ShellIdentityUtils;
36 
37 import org.junit.Assume;
38 
39 import java.util.List;
40 import java.util.concurrent.Executor;
41 import java.util.concurrent.LinkedBlockingQueue;
42 import java.util.concurrent.TimeUnit;
43 
44 public class DefaultSmsAppHelper {
45     private static final String TAG = "DefaultSmsAppHelper";
46     private static final int ASYNC_TIMEOUT = 10000;
ensureDefaultSmsApp()47     public static void ensureDefaultSmsApp() {
48         Log.d(TAG, "ensureDefaultSmsApp");
49         if (!hasTelephony() || !hasSms()) {
50             Log.d(TAG, "ensureDefaultSmsApp: does not have telephony or sms feature.");
51             return;
52         }
53 
54         Context context = ApplicationProvider.getApplicationContext();
55         String packageName = context.getPackageName();
56         RoleManager roleManager = context.getSystemService(RoleManager.class);
57         Executor executor = context.getMainExecutor();
58         UserHandle user = Process.myUserHandle();
59         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
60         Log.d(TAG, "ensureDefaultSmsApp: user=" + user.getIdentifier()
61                 + " packageName=" + packageName);
62 
63         runWithShellPermissionIdentity(() -> {
64             roleManager.addRoleHolderAsUser(
65                     RoleManager.ROLE_SMS,
66                     packageName,
67                     RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
68                     user,
69                     executor,
70                     successful -> {
71                         Log.d(TAG, "ensureDefaultSmsApp: successful=" + successful);
72                         try {
73                             queue.put(successful);
74                         } catch (InterruptedException e) {
75                             e.printStackTrace();
76                             throw new RuntimeException(e.getMessage());
77                         }
78                     });
79         });
80 
81         boolean result;
82         try {
83             result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
84         } catch (InterruptedException e) {
85             e.printStackTrace();
86             throw new RuntimeException(e.getMessage());
87         }
88 
89         Log.d(TAG, "ensureDefaultSmsApp: result=" + result);
90         assertTrue(result);
91     }
92 
stopBeingDefaultSmsApp()93     public static void stopBeingDefaultSmsApp() {
94         Log.d(TAG, "stopBeingDefaultSmsApp");
95         if (!hasSms()) {
96             Log.d(TAG, "stopBeingDefaultSmsApp: does not have sms feature.");
97             return;
98         }
99 
100         Context context = ApplicationProvider.getApplicationContext();
101         String packageName = context.getPackageName();
102         RoleManager roleManager = context.getSystemService(RoleManager.class);
103         Executor executor = context.getMainExecutor();
104         UserHandle user = Process.myUserHandle();
105         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
106         Log.d(TAG, "stopBeingDefaultSmsApp: user=" + user.getIdentifier()
107                 + " packageName=" + packageName);
108 
109         runWithShellPermissionIdentity(() -> {
110             roleManager.removeRoleHolderAsUser(
111                     RoleManager.ROLE_SMS,
112                     packageName,
113                     RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
114                     user,
115                     executor,
116                     successful -> {
117                         Log.d(TAG, "stopBeingDefaultSmsApp: successful=" + successful);
118                         try {
119                             queue.put(successful);
120                         } catch (InterruptedException e) {
121                             e.printStackTrace();
122                             throw new RuntimeException(e.getMessage());
123                         }
124                     });
125         });
126 
127         boolean result;
128         try {
129             result = queue.poll(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS);
130         } catch (InterruptedException e) {
131             e.printStackTrace();
132             throw new RuntimeException(e.getMessage());
133         }
134 
135         Log.d(TAG, "stopBeingDefaultSmsApp: result=" + result);
136         assertTrue(result);
137     }
138 
139     /**
140      * Get the default SMS application configured on the device.
141      * @param context The context used for getting the default SMS application.
142      */
getDefaultSmsApp(@onNull Context context)143     public static String getDefaultSmsApp(@NonNull Context context) throws Exception {
144         RoleManager roleManager = context.getSystemService(RoleManager.class);
145         List<String> result = ShellIdentityUtils.invokeMethodWithShellPermissions(roleManager,
146                 (m) -> m.getRoleHolders(RoleManager.ROLE_SMS));
147         Log.d(TAG, "getDefaultSmsApp result: " + result);
148 
149         if (result.isEmpty()) {
150             // No default SMS app.
151             return null;
152         }
153         // There should only be one default sms app
154         return result.get(0);
155     }
156 
157     /**
158      * Set the default SMS application for the device.
159      * @param context The context used for setting the default SMS application.
160      * @param packageName The package name of the default SMS application to be set.
161      * @return {@code true} if success, {@code false} otherwise.
162      */
setDefaultSmsApp( @onNull Context context, String packageName)163     public static boolean setDefaultSmsApp(
164             @NonNull Context context, String packageName) throws Exception {
165         Log.d(TAG, "setDefaultSmsApp: packageName:" + packageName);
166         RoleManager roleManager = context.getSystemService(RoleManager.class);
167         Boolean result;
168         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue<>(1);
169         if (TextUtils.isEmpty(packageName)) {
170             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(roleManager,
171                     (m) -> m.clearRoleHoldersAsUser(RoleManager.ROLE_SMS,
172                             RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
173                             android.os.Process.myUserHandle(),
174                             // Run on calling binder thread.
175                             Runnable::run, queue::offer));
176         } else {
177             ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(roleManager,
178                     (m) -> m.addRoleHolderAsUser(RoleManager.ROLE_SMS, packageName, 0,
179                             android.os.Process.myUserHandle(),
180                             // Run on calling binder thread.
181                             Runnable::run, queue::offer));
182         }
183         result = queue.poll(10, TimeUnit.SECONDS);
184         Log.d(TAG, "setDefaultSmsApp result: " + result);
185         return result;
186     }
187 
assumeTelephony()188     public static void assumeTelephony() {
189         Assume.assumeTrue(hasTelephony());
190     }
191 
assumeMessaging()192     public static void assumeMessaging() {
193         Assume.assumeTrue(hasSms());
194     }
195 
hasTelephony()196     public static boolean hasTelephony() {
197         Context context = ApplicationProvider.getApplicationContext();
198         return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
199     }
200 
hasSms()201     public static boolean hasSms() {
202         TelephonyManager telephonyManager = (TelephonyManager)
203                 ApplicationProvider.getApplicationContext().getSystemService(
204                         Context.TELEPHONY_SERVICE);
205         return telephonyManager.isSmsCapable();
206     }
207 }
208