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 import static android.os.Build.VERSION_CODES.R; 7 8 import android.net.Network; 9 import com.google.common.base.Preconditions; 10 import java.io.FileDescriptor; 11 import java.net.DatagramSocket; 12 import java.net.Socket; 13 import java.util.HashSet; 14 import java.util.Set; 15 import org.robolectric.RuntimeEnvironment; 16 import org.robolectric.annotation.Implementation; 17 import org.robolectric.annotation.Implements; 18 import org.robolectric.annotation.RealObject; 19 import org.robolectric.shadow.api.Shadow; 20 import org.robolectric.util.ReflectionHelpers; 21 22 @Implements(value = Network.class, minSdk = LOLLIPOP) 23 public class ShadowNetwork { 24 25 @RealObject private Network realObject; 26 27 private final Set<Socket> boundSockets = new HashSet<>(); 28 private final Set<DatagramSocket> boundDatagramSockets = new HashSet<>(); 29 private final Set<FileDescriptor> boundFileDescriptors = new HashSet<>(); 30 31 /** 32 * Creates new instance of {@link Network}, because its constructor is hidden. 33 * 34 * <p>Requires API 21 (Lollipop) and above. 35 * 36 * @param netId The netId. 37 * @return The Network instance. 38 */ newInstance(int netId)39 public static Network newInstance(int netId) { 40 Preconditions.checkState( 41 RuntimeEnvironment.getApiLevel() >= LOLLIPOP, 42 "android.net.Network requires API 21 (Lollipop) or above"); 43 return Shadow.newInstance(Network.class, new Class[] {int.class}, new Object[] {netId}); 44 } 45 46 /** Checks if the {@code socket} was previously bound to this network. */ isSocketBound(Socket socket)47 public boolean isSocketBound(Socket socket) { 48 return boundSockets.contains(socket); 49 } 50 51 /** Checks if the {@code datagramSocket} was previously bound to this network. */ isSocketBound(DatagramSocket socket)52 public boolean isSocketBound(DatagramSocket socket) { 53 return boundDatagramSockets.contains(socket); 54 } 55 56 /** Checks if the {@code fileDescriptor} was previously bound to this network. */ isSocketBound(FileDescriptor fd)57 public boolean isSocketBound(FileDescriptor fd) { 58 return boundFileDescriptors.contains(fd); 59 } 60 61 /** Returns the total number of sockets bound to this network interface. */ boundSocketCount()62 public int boundSocketCount() { 63 return boundSockets.size() + boundDatagramSockets.size() + boundFileDescriptors.size(); 64 } 65 66 /** 67 * Simulates a socket bind. isSocketBound can be called to verify that the socket was bound to 68 * this network interface, and boundSocketCount() will increment for any unique socket. 69 */ 70 @Implementation(minSdk = LOLLIPOP_MR1) bindSocket(DatagramSocket socket)71 protected void bindSocket(DatagramSocket socket) { 72 boundDatagramSockets.add(socket); 73 } 74 75 /** 76 * Simulates a socket bind. isSocketBound can be called to verify that the socket was bound to 77 * this network interface, and boundSocketCount() will increment for any unique socket. 78 */ 79 @Implementation bindSocket(Socket socket)80 protected void bindSocket(Socket socket) { 81 boundSockets.add(socket); 82 } 83 84 /** 85 * Simulates a socket bind. isSocketBound can be called to verify that the fd was bound to 86 * this network interface, and boundSocketCount() will increment for any unique socket. 87 */ 88 @Implementation(minSdk = M) bindSocket(FileDescriptor fd)89 protected void bindSocket(FileDescriptor fd) { 90 boundFileDescriptors.add(fd); 91 } 92 93 /** 94 * Allows to get the stored netId. 95 * 96 * @return The netId. 97 */ 98 @Implementation(minSdk = R) getNetId()99 public int getNetId() { 100 return ReflectionHelpers.getField(realObject, "netId"); 101 } 102 } 103