1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.R; 4 import static android.os.Build.VERSION_CODES.S; 5 import static org.robolectric.util.reflector.Reflector.reflector; 6 7 import android.net.Uri; 8 import android.telephony.ims.RcsContactUceCapability; 9 import android.telephony.ims.RcsUceAdapter; 10 import com.google.auto.value.AutoValue; 11 import com.google.common.collect.ImmutableList; 12 import java.util.Collection; 13 import java.util.HashMap; 14 import java.util.HashSet; 15 import java.util.Map; 16 import java.util.Set; 17 import java.util.concurrent.Executor; 18 import org.robolectric.annotation.Implementation; 19 import org.robolectric.annotation.Implements; 20 import org.robolectric.annotation.RealObject; 21 import org.robolectric.annotation.Resetter; 22 import org.robolectric.util.reflector.Accessor; 23 import org.robolectric.util.reflector.ForType; 24 25 /** A shadow for {@link RcsUceAdapter}. */ 26 @Implements( 27 value = RcsUceAdapter.class, 28 // turn off shadowOf generation 29 isInAndroidSdk = false, 30 minSdk = R) 31 public class ShadowRcsUceAdapter { 32 private static final Set<Integer> subscriptionIdsWithUceSettingEnabled = new HashSet<>(); 33 private static final Map<Uri, RcsContactUceCapability> capabilitiesMap = new HashMap<>(); 34 private static final Map<Uri, CapabilityFailureInfo> capabilitiesFailureMap = new HashMap<>(); 35 36 @RealObject private RcsUceAdapter realRcsUceAdapter; 37 38 /** 39 * Overrides the value returned by {@link RcsUceAdapter#isUceSettingEnabled()} for RcsUceAdapters 40 * associated with {@code subscriptionId}. 41 */ setUceSettingEnabledForSubscriptionId( int subscriptionId, boolean uceSettingEnabled)42 public static void setUceSettingEnabledForSubscriptionId( 43 int subscriptionId, boolean uceSettingEnabled) { 44 if (uceSettingEnabled) { 45 subscriptionIdsWithUceSettingEnabled.add(subscriptionId); 46 } else { 47 subscriptionIdsWithUceSettingEnabled.remove(subscriptionId); 48 } 49 } 50 51 @Resetter reset()52 public static void reset() { 53 subscriptionIdsWithUceSettingEnabled.clear(); 54 capabilitiesMap.clear(); 55 capabilitiesFailureMap.clear(); 56 } 57 58 /** 59 * Returns the value specified for the {@code subscriptionId} corresponding to the {@link 60 * RcsUceAdapter} by {@link ShadowRcsUceAdapter#setUceSettingEnabledForSubscriptionId(int, 61 * boolean)}. If no value has been specified, returns false. 62 */ 63 @Implementation isUceSettingEnabled()64 protected boolean isUceSettingEnabled() { 65 int subscriptionId = reflector(ReflectorRcsUceAdapter.class, realRcsUceAdapter).getSubId(); 66 return subscriptionIdsWithUceSettingEnabled.contains(subscriptionId); 67 } 68 setCapabilitiesForUri(Uri uri, RcsContactUceCapability capabilities)69 public static void setCapabilitiesForUri(Uri uri, RcsContactUceCapability capabilities) { 70 capabilitiesMap.put(uri, capabilities); 71 } 72 setCapabilitiesFailureForUri(Uri uri, CapabilityFailureInfo failureInfo)73 public static void setCapabilitiesFailureForUri(Uri uri, CapabilityFailureInfo failureInfo) { 74 capabilitiesFailureMap.put(uri, failureInfo); 75 } 76 77 @Implementation(minSdk = S) requestCapabilities( Collection<Uri> contactNumbers, Executor executor, RcsUceAdapter.CapabilitiesCallback c)78 protected void requestCapabilities( 79 Collection<Uri> contactNumbers, Executor executor, RcsUceAdapter.CapabilitiesCallback c) { 80 boolean completedSuccessfully = true; 81 for (Uri contact : contactNumbers) { 82 if (capabilitiesFailureMap.containsKey(contact)) { 83 CapabilityFailureInfo failureInfo = capabilitiesFailureMap.get(contact); 84 executor.execute(() -> c.onError(failureInfo.errorCode(), failureInfo.retryMillis())); 85 completedSuccessfully = false; 86 break; 87 } 88 if (capabilitiesMap.containsKey(contact)) { 89 executor.execute( 90 () -> c.onCapabilitiesReceived(ImmutableList.of(capabilitiesMap.get(contact)))); 91 } else { 92 executor.execute( 93 () -> 94 c.onCapabilitiesReceived( 95 ImmutableList.of(new RcsContactUceCapability.OptionsBuilder(contact).build()))); 96 } 97 } 98 if (completedSuccessfully) { 99 executor.execute(c::onComplete); 100 } 101 } 102 103 @Implementation(minSdk = S) requestAvailability( Uri contactNumber, Executor executor, RcsUceAdapter.CapabilitiesCallback c)104 protected void requestAvailability( 105 Uri contactNumber, Executor executor, RcsUceAdapter.CapabilitiesCallback c) { 106 requestCapabilities(ImmutableList.of(contactNumber), executor, c); 107 } 108 109 /** A data class holding the info for a failed capabilities exchange */ 110 @AutoValue 111 public abstract static class CapabilityFailureInfo { create(int errorCode, long retryMillis)112 public static CapabilityFailureInfo create(int errorCode, long retryMillis) { 113 return new AutoValue_ShadowRcsUceAdapter_CapabilityFailureInfo(errorCode, retryMillis); 114 } 115 errorCode()116 public abstract int errorCode(); 117 retryMillis()118 public abstract long retryMillis(); 119 } 120 121 /** Accessor interface for {@link RcsUceAdapter}'s internals. */ 122 @ForType(RcsUceAdapter.class) 123 private interface ReflectorRcsUceAdapter { 124 @Accessor("mSubId") getSubId()125 int getSubId(); 126 } 127 } 128