1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.LOLLIPOP; 4 import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; 5 import static android.os.Build.VERSION_CODES.M; 6 7 import android.content.ComponentName; 8 import android.content.Context; 9 import android.net.Uri; 10 import android.os.Bundle; 11 import android.telecom.PhoneAccount; 12 import android.telecom.PhoneAccountHandle; 13 import android.telecom.TelecomManager; 14 import com.google.common.collect.ImmutableList; 15 import java.util.ArrayList; 16 import java.util.HashSet; 17 import java.util.LinkedHashMap; 18 import java.util.List; 19 import java.util.Set; 20 import org.robolectric.annotation.HiddenApi; 21 import org.robolectric.annotation.Implementation; 22 import org.robolectric.annotation.Implements; 23 import org.robolectric.annotation.RealObject; 24 import org.robolectric.util.ReflectionHelpers; 25 26 @Implements(value = TelecomManager.class, minSdk = LOLLIPOP) 27 public class ShadowTelecomManager { 28 29 @RealObject 30 private TelecomManager realObject; 31 32 private PhoneAccountHandle simCallManager; 33 private LinkedHashMap<PhoneAccountHandle, PhoneAccount> accounts = new LinkedHashMap(); 34 private List<CallRecord> incomingCalls = new ArrayList<>(); 35 private List<CallRecord> unknownCalls = new ArrayList<>(); 36 private String defaultDialerPackageName; 37 private boolean isInCall; 38 39 @Implementation getDefaultOutgoingPhoneAccount(String uriScheme)40 protected PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) { 41 return null; 42 } 43 44 @Implementation 45 @HiddenApi getUserSelectedOutgoingPhoneAccount()46 public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() { 47 return null; 48 } 49 50 @Implementation 51 @HiddenApi setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle)52 public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) { 53 } 54 55 @Implementation getSimCallManager()56 protected PhoneAccountHandle getSimCallManager() { 57 return simCallManager; 58 } 59 60 @Implementation(minSdk = M) 61 @HiddenApi getSimCallManager(int userId)62 public PhoneAccountHandle getSimCallManager(int userId) { 63 return null; 64 } 65 66 @Implementation 67 @HiddenApi getConnectionManager()68 public PhoneAccountHandle getConnectionManager() { 69 return this.getSimCallManager(); 70 } 71 72 @Implementation 73 @HiddenApi getPhoneAccountsSupportingScheme(String uriScheme)74 public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) { 75 List<PhoneAccountHandle> result = new ArrayList<>(); 76 77 for (PhoneAccountHandle handle : accounts.keySet()) { 78 PhoneAccount phoneAccount = accounts.get(handle); 79 if(phoneAccount.getSupportedUriSchemes().contains(uriScheme)) { 80 result.add(handle); 81 } 82 } 83 return result; 84 } 85 86 @Implementation(minSdk = M) getCallCapablePhoneAccounts()87 protected List<PhoneAccountHandle> getCallCapablePhoneAccounts() { 88 return this.getCallCapablePhoneAccounts(false); 89 } 90 91 @Implementation(minSdk = M) 92 @HiddenApi getCallCapablePhoneAccounts(boolean includeDisabledAccounts)93 public List<PhoneAccountHandle> getCallCapablePhoneAccounts(boolean includeDisabledAccounts) { 94 List<PhoneAccountHandle> result = new ArrayList<>(); 95 96 for (PhoneAccountHandle handle : accounts.keySet()) { 97 PhoneAccount phoneAccount = accounts.get(handle); 98 if(!phoneAccount.isEnabled() && !includeDisabledAccounts) { 99 continue; 100 } 101 result.add(handle); 102 } 103 return result; 104 } 105 106 @Implementation 107 @HiddenApi getPhoneAccountsForPackage()108 public List<PhoneAccountHandle> getPhoneAccountsForPackage() { 109 Context context = ReflectionHelpers.getField(realObject, "mContext"); 110 111 List<PhoneAccountHandle> results = new ArrayList<>(); 112 for (PhoneAccountHandle handle : accounts.keySet()) { 113 if (handle.getComponentName().getPackageName().equals(context.getPackageName())) { 114 results.add(handle); 115 } 116 } 117 return results; 118 } 119 120 @Implementation getPhoneAccount(PhoneAccountHandle account)121 protected PhoneAccount getPhoneAccount(PhoneAccountHandle account) { 122 return accounts.get(account); 123 } 124 125 @Implementation 126 @HiddenApi getAllPhoneAccountsCount()127 public int getAllPhoneAccountsCount() { 128 return accounts.size(); 129 } 130 131 @Implementation 132 @HiddenApi getAllPhoneAccounts()133 public List<PhoneAccount> getAllPhoneAccounts() { 134 return ImmutableList.copyOf(accounts.values()); 135 } 136 137 @Implementation 138 @HiddenApi getAllPhoneAccountHandles()139 public List<PhoneAccountHandle> getAllPhoneAccountHandles() { 140 return ImmutableList.copyOf(accounts.keySet()); 141 } 142 143 @Implementation registerPhoneAccount(PhoneAccount account)144 protected void registerPhoneAccount(PhoneAccount account) { 145 accounts.put(account.getAccountHandle(), account); 146 } 147 148 @Implementation unregisterPhoneAccount(PhoneAccountHandle accountHandle)149 protected void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { 150 accounts.remove(accountHandle); 151 } 152 153 /** @deprecated */ 154 @Deprecated 155 @Implementation 156 @HiddenApi clearAccounts()157 public void clearAccounts() { 158 accounts.clear(); 159 } 160 161 162 @Implementation(minSdk = LOLLIPOP_MR1) 163 @HiddenApi clearAccountsForPackage(String packageName)164 public void clearAccountsForPackage(String packageName) { 165 Set<PhoneAccountHandle> phoneAccountHandlesInPackage = new HashSet<>(); 166 167 for (PhoneAccountHandle handle : accounts.keySet()) { 168 if (handle.getComponentName().getPackageName().equals(packageName)) { 169 phoneAccountHandlesInPackage.add(handle); 170 } 171 } 172 173 for (PhoneAccountHandle handle : phoneAccountHandlesInPackage) { 174 accounts.remove(handle); 175 } 176 } 177 178 /** @deprecated */ 179 @Deprecated 180 @Implementation 181 @HiddenApi getDefaultPhoneApp()182 public ComponentName getDefaultPhoneApp() { 183 return null; 184 } 185 186 @Implementation(minSdk = M) getDefaultDialerPackage()187 protected String getDefaultDialerPackage() { 188 return defaultDialerPackageName; 189 } 190 191 @Implementation(minSdk = M) 192 @HiddenApi setDefaultDialer(String packageName)193 public boolean setDefaultDialer(String packageName) { 194 this.defaultDialerPackageName = packageName; 195 return true; 196 } 197 198 @Implementation(minSdk = M) 199 @HiddenApi getSystemDialerPackage()200 public String getSystemDialerPackage() { 201 return null; 202 } 203 204 @Implementation(minSdk = LOLLIPOP_MR1) isVoiceMailNumber(PhoneAccountHandle accountHandle, String number)205 protected boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) { 206 return false; 207 } 208 209 @Implementation(minSdk = M) getVoiceMailNumber(PhoneAccountHandle accountHandle)210 protected String getVoiceMailNumber(PhoneAccountHandle accountHandle) { 211 return null; 212 } 213 214 @Implementation(minSdk = LOLLIPOP_MR1) getLine1Number(PhoneAccountHandle accountHandle)215 protected String getLine1Number(PhoneAccountHandle accountHandle) { 216 return null; 217 } 218 219 /** Sets the return value for {@link TelecomManager#isInCall}. */ setIsInCall(boolean isInCall)220 public void setIsInCall(boolean isInCall) { 221 this.isInCall = isInCall; 222 } 223 224 /** 225 * Overrides behavior of {@link TelecomManager#isInCall} to return pre-set result. 226 * 227 * @return Value set by calling {@link ShadowTelecomManager#setIsInCall}. If setIsInCall has not 228 * previously been called, will return false. 229 */ 230 @Implementation isInCall()231 protected boolean isInCall() { 232 return isInCall; 233 } 234 235 @Implementation 236 @HiddenApi getCallState()237 public int getCallState() { 238 return 0; 239 } 240 241 @Implementation 242 @HiddenApi isRinging()243 public boolean isRinging() { 244 for (CallRecord callRecord : incomingCalls) { 245 if (callRecord.isRinging) { 246 return true; 247 } 248 } 249 for (CallRecord callRecord : unknownCalls) { 250 if (callRecord.isRinging) { 251 return true; 252 } 253 } 254 return false; 255 } 256 257 @Implementation 258 @HiddenApi endCall()259 public boolean endCall() { 260 return false; 261 } 262 263 @Implementation acceptRingingCall()264 protected void acceptRingingCall() {} 265 266 @Implementation silenceRinger()267 protected void silenceRinger() { 268 for (CallRecord callRecord : incomingCalls) { 269 callRecord.isRinging = false; 270 } 271 for (CallRecord callRecord : unknownCalls) { 272 callRecord.isRinging = false; 273 } 274 } 275 276 @Implementation isTtySupported()277 protected boolean isTtySupported() { 278 return false; 279 } 280 281 @Implementation 282 @HiddenApi getCurrentTtyMode()283 public int getCurrentTtyMode() { 284 return 0; 285 } 286 287 @Implementation addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras)288 protected void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) { 289 incomingCalls.add(new CallRecord(phoneAccount, extras)); 290 } 291 getAllIncomingCalls()292 public List<CallRecord> getAllIncomingCalls() { 293 return incomingCalls; 294 } 295 296 @Implementation 297 @HiddenApi addNewUnknownCall(PhoneAccountHandle phoneAccount, Bundle extras)298 public void addNewUnknownCall(PhoneAccountHandle phoneAccount, Bundle extras) { 299 unknownCalls.add(new CallRecord(phoneAccount, extras)); 300 } 301 getAllUnknownCalls()302 public List<CallRecord> getAllUnknownCalls() { 303 return unknownCalls; 304 } 305 306 @Implementation handleMmi(String dialString)307 protected boolean handleMmi(String dialString) { 308 return false; 309 } 310 311 @Implementation(minSdk = M) handleMmi(String dialString, PhoneAccountHandle accountHandle)312 protected boolean handleMmi(String dialString, PhoneAccountHandle accountHandle) { 313 return false; 314 } 315 316 @Implementation(minSdk = LOLLIPOP_MR1) getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle)317 protected Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) { 318 return Uri.parse("content://icc/adn"); 319 } 320 321 @Implementation cancelMissedCallsNotification()322 protected void cancelMissedCallsNotification() {} 323 324 @Implementation showInCallScreen(boolean showDialpad)325 protected void showInCallScreen(boolean showDialpad) {} 326 327 @Implementation(minSdk = M) placeCall(Uri address, Bundle extras)328 protected void placeCall(Uri address, Bundle extras) {} 329 330 @Implementation(minSdk = M) 331 @HiddenApi enablePhoneAccount(PhoneAccountHandle handle, boolean isEnabled)332 public void enablePhoneAccount(PhoneAccountHandle handle, boolean isEnabled) { 333 } 334 setSimCallManager(PhoneAccountHandle simCallManager)335 public void setSimCallManager(PhoneAccountHandle simCallManager) { 336 this.simCallManager = simCallManager; 337 } 338 339 public static class CallRecord { 340 public final PhoneAccountHandle phoneAccount; 341 public final Bundle bundle; 342 private boolean isRinging = true; 343 CallRecord(PhoneAccountHandle phoneAccount, Bundle extras)344 public CallRecord(PhoneAccountHandle phoneAccount, Bundle extras) { 345 this.phoneAccount = phoneAccount; 346 this.bundle = extras; 347 } 348 } 349 350 } 351