1 /* 2 * Copyright (C) 2023 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.telecom.cts.apps; 18 19 import android.app.Instrumentation; 20 import android.content.ComponentName; 21 import android.os.ParcelFileDescriptor; 22 import android.os.UserHandle; 23 import android.os.UserManager; 24 import android.telecom.PhoneAccountHandle; 25 import android.util.Log; 26 27 import java.io.BufferedReader; 28 import java.io.FileInputStream; 29 import java.io.InputStream; 30 import java.io.InputStreamReader; 31 import java.nio.charset.StandardCharsets; 32 33 /** 34 * This class should be used in Telecom CTS test classes to statically execute shell commands. 35 */ 36 public class ShellCommandExecutor { 37 private static final String sTAG = ShellCommandExecutor.class.getSimpleName(); 38 public static final String COMMAND_RESET_CAR = "cmd telecom cleanup"; 39 public static final String COMMAND_GET_DEFAULT_DIALER = "cmd telecom get-default-dialer"; 40 public static final String COMMAND_SET_DEFAULT_DIALER = "cmd telecom set-default-dialer "; 41 public static final String COMMAND_ENABLE = "cmd telecom set-phone-account-enabled "; 42 public static final String COMMAND_CLEANUP_STUCK_CALLS = "cmd telecom cleanup-stuck-calls"; 43 public static final String COMMAND_SET_DEFAULT_PHONE_ACCOUNT = 44 "cmd telecom set-user-selected-outgoing-phone-account "; 45 public static final String COMMAND_DUMP_TELECOM = "dumpsys telecom"; 46 public static final String COMMAND_WAIT_FOR_AUDIO_OPS_COMPLETE = 47 "cmd telecom wait-for-audio-ops-complete"; 48 public static final String COMMAND_WAIT_FOR_AUDIO_ACTIVE = "cmd telecom wait-for-audio-active"; 49 50 /** Emergency call related setup constants */ 51 private static final String COMMAND_SET_SYSTEM_DIALER = "telecom set-system-dialer "; 52 53 private static final String INCALL_COMPONENT = 54 "com.google.android.dialer" + "/com.android.incallui.InCallServiceImpl"; 55 private static final String COMMAND_ADD_TEST_EMERGENCY_NUMBER = 56 "cmd phone emergency-number-test-mode -a "; 57 private static final String COMMAND_CLEAR_TEST_EMERGENCY_NUMBERS = 58 "cmd phone emergency-number-test-mode -c"; 59 private static final String COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_NAME_FILTER = 60 "telecom set-test-emergency-phone-account-package-filter "; 61 private static final String COMMAND_REGISTER_SIM = "telecom register-sim-phone-account "; 62 63 /** 64 * Executes the given shell command and returns the output in a string. Note that even 65 * if we don't care about the output, we have to read the stream completely to make the 66 * command execute. 67 */ executeShellCommand(Instrumentation instrumentation, String command)68 public static String executeShellCommand(Instrumentation instrumentation, 69 String command) throws Exception { 70 final ParcelFileDescriptor pfd = 71 instrumentation.getUiAutomation().executeShellCommand(command); 72 BufferedReader br = null; 73 try (InputStream in = new FileInputStream(pfd.getFileDescriptor())) { 74 br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); 75 String str = null; 76 StringBuilder out = new StringBuilder(); 77 while ((str = br.readLine()) != null) { 78 out.append(str); 79 } 80 return out.toString(); 81 } finally { 82 if (br != null) { 83 closeQuietly(br); 84 } 85 closeQuietly(pfd); 86 } 87 } 88 closeQuietly(AutoCloseable closeable)89 private static void closeQuietly(AutoCloseable closeable) { 90 if (closeable != null) { 91 try { 92 closeable.close(); 93 } catch (RuntimeException rethrown) { 94 throw rethrown; 95 } catch (Exception ignored) { 96 Log.w(sTAG, "closeQuietly: exception thrown: e=" + ignored); 97 } 98 } 99 } 100 dumpTelecom(Instrumentation instrumentation)101 public static void dumpTelecom(Instrumentation instrumentation) throws Exception { 102 executeShellCommand(instrumentation, COMMAND_DUMP_TELECOM); 103 } 104 setDefaultDialer(Instrumentation instrumentation, String packageName)105 public static String setDefaultDialer(Instrumentation instrumentation, String packageName) 106 throws Exception { 107 return executeShellCommand(instrumentation, COMMAND_SET_DEFAULT_DIALER + packageName); 108 } 109 getDefaultDialer(Instrumentation instrumentation)110 public static String getDefaultDialer(Instrumentation instrumentation) throws Exception { 111 return executeShellCommand(instrumentation, COMMAND_GET_DEFAULT_DIALER); 112 } 113 getSystemDialer(Instrumentation instrumentation)114 public static String getSystemDialer(Instrumentation instrumentation) throws Exception { 115 return executeShellCommand(instrumentation, "telecom get-system-dialer"); 116 } 117 setSystemDialerOverride( Instrumentation instrumentation, String packageName)118 public static String setSystemDialerOverride( 119 Instrumentation instrumentation, String packageName) throws Exception { 120 return executeShellCommand(instrumentation, COMMAND_SET_SYSTEM_DIALER + packageName); 121 } 122 clearSystemDialerOverride(Instrumentation instrumentation)123 public static String clearSystemDialerOverride(Instrumentation instrumentation) 124 throws Exception { 125 return executeShellCommand(instrumentation, COMMAND_SET_SYSTEM_DIALER + "default"); 126 } 127 addTestEmergencyNumber(Instrumentation instr, String testNumber)128 public static void addTestEmergencyNumber(Instrumentation instr, String testNumber) 129 throws Exception { 130 executeShellCommand(instr, COMMAND_ADD_TEST_EMERGENCY_NUMBER + testNumber); 131 } 132 clearTestEmergencyNumbers(Instrumentation instr)133 public static void clearTestEmergencyNumbers(Instrumentation instr) throws Exception { 134 executeShellCommand(instr, COMMAND_CLEAR_TEST_EMERGENCY_NUMBERS); 135 } 136 registerEmergencyPhoneAccount( Instrumentation instrumentation, PhoneAccountHandle handle, String label, String address)137 public static void registerEmergencyPhoneAccount( 138 Instrumentation instrumentation, 139 PhoneAccountHandle handle, 140 String label, 141 String address) 142 throws Exception { 143 final ComponentName component = handle.getComponentName(); 144 final long currentUserSerial = getUserSerialNumber(instrumentation, handle.getUserHandle()); 145 executeShellCommand( 146 instrumentation, 147 COMMAND_REGISTER_SIM 148 + "-e " 149 + component.getPackageName() 150 + "/" 151 + component.getClassName() 152 + " " 153 + handle.getId() 154 + " " 155 + currentUserSerial 156 + " " 157 + label 158 + " " 159 + address); 160 } 161 setTestEmergencyPhoneAccountPackageFilter( Instrumentation instr, String packageName)162 public static void setTestEmergencyPhoneAccountPackageFilter( 163 Instrumentation instr, String packageName) throws Exception { 164 executeShellCommand( 165 instr, COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_NAME_FILTER + packageName); 166 } 167 clearTestEmergencyPhoneAccountPackageFilter(Instrumentation instr)168 public static void clearTestEmergencyPhoneAccountPackageFilter(Instrumentation instr) 169 throws Exception { 170 executeShellCommand(instr, COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_NAME_FILTER); 171 } 172 enablePhoneAccount(Instrumentation instrumentation, PhoneAccountHandle handle)173 public static void enablePhoneAccount(Instrumentation instrumentation, 174 PhoneAccountHandle handle) throws Exception { 175 final ComponentName component = handle.getComponentName(); 176 final long userSerial = getUserSerialNumber(instrumentation, handle.getUserHandle()); 177 executeShellCommand(instrumentation, COMMAND_ENABLE 178 + component.getPackageName() + "/" + component.getClassName() + " " 179 + handle.getId() + " " + userSerial); 180 } 181 getUserSerialNumber(Instrumentation instrumentation, UserHandle handle)182 private static long getUserSerialNumber(Instrumentation instrumentation, UserHandle handle) { 183 UserManager userManager = 184 instrumentation.getContext().getSystemService(UserManager.class); 185 return userManager.getSerialNumberForUser(handle); 186 } 187 } 188