1 package org.robolectric.shadows; 2 3 import static android.os.Build.VERSION_CODES.P; 4 import static android.os.Build.VERSION_CODES.Q; 5 import static android.os.Build.VERSION_CODES.R; 6 import static org.robolectric.util.reflector.Reflector.reflector; 7 8 import android.os.Build.VERSION; 9 import android.telephony.NetworkRegistrationInfo; 10 import android.telephony.ServiceState; 11 import androidx.annotation.RequiresApi; 12 import java.util.List; 13 import org.robolectric.RuntimeEnvironment; 14 import org.robolectric.util.reflector.Accessor; 15 import org.robolectric.util.reflector.ForType; 16 17 /** Builder class to create instance of {@link ServiceState}. */ 18 public class ServiceStateBuilder { 19 private ServiceState serviceState = new ServiceState(); 20 newBuilder()21 public static ServiceStateBuilder newBuilder() { 22 return new ServiceStateBuilder(); 23 } 24 newBuilder(ServiceState serviceState)25 public static ServiceStateBuilder newBuilder(ServiceState serviceState) { 26 ServiceStateBuilder builder = new ServiceStateBuilder(); 27 builder.serviceState = serviceState; 28 return builder; 29 } 30 build()31 public ServiceState build() { 32 return serviceState; 33 } 34 setVoiceRegState(int value)35 public ServiceStateBuilder setVoiceRegState(int value) { 36 serviceState.setVoiceRegState(value); 37 return this; 38 } 39 setDataRegState(int value)40 public ServiceStateBuilder setDataRegState(int value) { 41 serviceState.setDataRegState(value); 42 return this; 43 } 44 setNrFrequencyRange(int value)45 public ServiceStateBuilder setNrFrequencyRange(int value) { 46 assertIsAtLeast(Q); 47 serviceState.setNrFrequencyRange(value); 48 return this; 49 } 50 setIsManualSelection(boolean value)51 public ServiceStateBuilder setIsManualSelection(boolean value) { 52 serviceState.setIsManualSelection(value); 53 return this; 54 } 55 setOperatorName(String longName, String shortName, String numeric)56 public ServiceStateBuilder setOperatorName(String longName, String shortName, String numeric) { 57 assertIsAtLeast(R); 58 serviceState.setOperatorName(longName, shortName, numeric); 59 return this; 60 } 61 setIwlanPreferred(boolean value)62 public ServiceStateBuilder setIwlanPreferred(boolean value) { 63 assertIsAtLeast(R); 64 serviceState.setIwlanPreferred(value); 65 return this; 66 } 67 setEmergencyOnly(boolean value)68 public ServiceStateBuilder setEmergencyOnly(boolean value) { 69 serviceState.setEmergencyOnly(value); 70 return this; 71 } 72 setDataRoamingFromRegistration(boolean value)73 public ServiceStateBuilder setDataRoamingFromRegistration(boolean value) { 74 assertIsAtLeast(R); 75 serviceState.setDataRoamingFromRegistration(value); 76 return this; 77 } 78 79 /** 80 * Use this method to control return value of {@link ServiceState#isUsingCarrierAggregation()} (up 81 * to P). On APIs > P, use {@link ServiceStateBuilder#setNetworkRegistrationInfoList()}. 82 */ setIsUsingCarrierAggregation(boolean value)83 public ServiceStateBuilder setIsUsingCarrierAggregation(boolean value) { 84 assertIsAtLeast(P); 85 // {@link NetworkRegistrationInfo} was first made a @SystemApi in Q then finally exposed as 86 // public in R. For SDK later than Q, call 87 // {@link ServiceStateBuilder#setNetworkRegistrationInfoList} to set this value. Downstream test 88 // code will have to specify NRIs in the builder to set this value. But the "actual" 89 // implementation code under test would still be looking at the non-NRI getters 90 // on {@link ServiceState}, assuming it's restricted to only public APIs. 91 if (VERSION.SDK_INT >= Q) { 92 throw new UnsupportedOperationException( 93 "Newer SDKs must specify carrier aggregation by constructing an appropriate " 94 + "NetworkRegistrationInfo and calling #setNetworkRegistrationInfoList instead"); 95 } else { 96 reflector(ServiceStateReflector.class, serviceState).setIsUsingCarrierAggregation(value); 97 } 98 return this; 99 } 100 101 @RequiresApi(Q) setNetworkRegistrationInfoList(List<NetworkRegistrationInfo> value)102 public ServiceStateBuilder setNetworkRegistrationInfoList(List<NetworkRegistrationInfo> value) { 103 assertIsAtLeast(Q); 104 reflector(ServiceStateReflector.class, serviceState).setNetworkRegistrationInfos(value); 105 return this; 106 } 107 setRoaming(boolean value)108 public ServiceStateBuilder setRoaming(boolean value) { 109 serviceState.setRoaming(value); 110 return this; 111 } 112 setChannelNumber(int value)113 public ServiceStateBuilder setChannelNumber(int value) { 114 serviceState.setChannelNumber(value); 115 return this; 116 } 117 setCellBandwidths(int[] value)118 public ServiceStateBuilder setCellBandwidths(int[] value) { 119 serviceState.setCellBandwidths(value); 120 return this; 121 } 122 123 // TODO Find a proper way to set radio tech values. 124 assertIsAtLeast(int sdk)125 private void assertIsAtLeast(int sdk) { 126 if (VERSION.SDK_INT < sdk) { 127 throw new IllegalStateException( 128 "This method is not available on SDK : " + RuntimeEnvironment.getApiLevel()); 129 } 130 } 131 132 @ForType(ServiceState.class) 133 private interface ServiceStateReflector { 134 135 @Accessor("mIsUsingCarrierAggregation") setIsUsingCarrierAggregation(boolean value)136 public void setIsUsingCarrierAggregation(boolean value); 137 138 @Accessor("mNetworkRegistrationInfos") setNetworkRegistrationInfos(List<NetworkRegistrationInfo> value)139 public void setNetworkRegistrationInfos(List<NetworkRegistrationInfo> value); 140 } 141 } 142