1 package org.robolectric.shadows; 2 3 import android.os.SystemProperties; 4 import com.google.common.base.Preconditions; 5 import java.io.IOException; 6 import java.io.InputStream; 7 import java.net.URL; 8 import java.util.Properties; 9 import org.robolectric.annotation.Implementation; 10 import org.robolectric.annotation.Implements; 11 import org.robolectric.annotation.Resetter; 12 13 @Implements(value = SystemProperties.class, isInAndroidSdk = false) 14 public class ShadowSystemProperties { 15 private static Properties buildProperties = null; 16 17 @Implementation 18 public static String native_get(String key) { 19 return native_get(key, ""); 20 } 21 22 @Implementation 23 public static String native_get(String key, String def) { 24 String value = getProperty(key); 25 return value == null ? def : value; 26 } 27 28 @Implementation 29 public static int native_get_int(String key, int def) { 30 String stringValue = getProperty(key); 31 return stringValue == null ? def : Integer.parseInt(stringValue); 32 } 33 34 @Implementation 35 public static long native_get_long(String key, long def) { 36 String stringValue = getProperty(key); 37 return stringValue == null ? def : Long.parseLong(stringValue); 38 } 39 40 @Implementation 41 public static boolean native_get_boolean(String key, boolean def) { 42 String stringValue = getProperty(key); 43 if (stringValue == null) { 44 return def; 45 } 46 47 switch (stringValue) { 48 case "1": 49 case "y": 50 case "on": 51 case "yes": 52 case "true": 53 return true; 54 default: 55 return false; 56 } 57 } 58 59 @Implementation 60 public static void native_set(String key, String val) { 61 if (val == null) { 62 loadProperties().remove(key); 63 } else { 64 loadProperties().setProperty(key, val); 65 } 66 } 67 68 // ignored/unimplemented methods 69 // private static native void native_add_change_callback(); 70 // private static native void native_report_sysprop_change(); 71 72 private static synchronized String getProperty(String key) { 73 return loadProperties().getProperty(key); 74 } 75 76 private static synchronized Properties loadProperties() { 77 if (buildProperties == null) { 78 // load the prop from classpath 79 ClassLoader cl = SystemProperties.class.getClassLoader(); 80 try (InputStream is = cl.getResourceAsStream("build.prop")) { 81 Preconditions.checkNotNull(is, "could not find build.prop"); 82 buildProperties = new Properties(); 83 buildProperties.load(is); 84 setDefaults(buildProperties); 85 } catch (IOException e) { 86 throw new RuntimeException("failed to load build.prop", e); 87 } 88 } 89 return buildProperties; 90 } 91 92 private static void setDefaults(Properties buildProperties) { 93 // The default generated build.prop can make this look like the emulator. 94 // Override common default properties to indicate platform is robolectric 95 // TODO: put these values directly in build.prop generated from build system 96 buildProperties.setProperty("ro.build.fingerprint", "robolectric"); 97 buildProperties.setProperty("ro.product.device", "robolectric"); 98 buildProperties.setProperty("ro.product.name", "robolectric"); 99 buildProperties.setProperty("ro.product.model", "robolectric"); 100 buildProperties.setProperty("ro.hardware", "robolectric"); 101 buildProperties.setProperty("ro.build.characteristics", "robolectric"); 102 103 // for backwards-compatibility reasons, set CPUS to unknown/ARM 104 buildProperties.setProperty("ro.product.cpu.abi", "unknown"); 105 buildProperties.setProperty("ro.product.cpu.abi2", "unknown"); 106 buildProperties.setProperty("ro.product.cpu.abilist", "armeabi-v7a"); 107 buildProperties.setProperty("ro.product.cpu.abilist32", "armeabi-v7a,armeabi"); 108 buildProperties.setProperty("ro.product.cpu.abilist64", "armeabi-v7a,armeabi"); 109 } 110 111 @Resetter 112 public static synchronized void reset() { 113 buildProperties = null; 114 } 115 } 116