1 package org.robolectric.android; 2 3 import static android.content.res.Configuration.KEYBOARDHIDDEN_SOFT; 4 import static android.content.res.Configuration.KEYBOARDHIDDEN_YES; 5 import static android.content.res.Configuration.KEYBOARD_12KEY; 6 import static android.content.res.Configuration.KEYBOARD_NOKEYS; 7 import static android.content.res.Configuration.NAVIGATIONHIDDEN_YES; 8 import static android.content.res.Configuration.NAVIGATION_DPAD; 9 import static android.content.res.Configuration.NAVIGATION_NONAV; 10 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 11 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 12 import static android.content.res.Configuration.SCREENLAYOUT_LAYOUTDIR_LTR; 13 import static android.content.res.Configuration.SCREENLAYOUT_LAYOUTDIR_MASK; 14 import static android.content.res.Configuration.SCREENLAYOUT_LAYOUTDIR_RTL; 15 import static android.content.res.Configuration.SCREENLAYOUT_LONG_MASK; 16 import static android.content.res.Configuration.SCREENLAYOUT_LONG_NO; 17 import static android.content.res.Configuration.SCREENLAYOUT_LONG_YES; 18 import static android.content.res.Configuration.SCREENLAYOUT_ROUND_MASK; 19 import static android.content.res.Configuration.SCREENLAYOUT_ROUND_NO; 20 import static android.content.res.Configuration.SCREENLAYOUT_ROUND_YES; 21 import static android.content.res.Configuration.SCREENLAYOUT_SIZE_MASK; 22 import static android.content.res.Configuration.SCREENLAYOUT_SIZE_NORMAL; 23 import static android.content.res.Configuration.SCREENLAYOUT_SIZE_XLARGE; 24 import static android.content.res.Configuration.TOUCHSCREEN_FINGER; 25 import static android.content.res.Configuration.TOUCHSCREEN_NOTOUCH; 26 import static android.content.res.Configuration.UI_MODE_NIGHT_MASK; 27 import static android.content.res.Configuration.UI_MODE_NIGHT_NO; 28 import static android.content.res.Configuration.UI_MODE_NIGHT_YES; 29 import static android.content.res.Configuration.UI_MODE_TYPE_APPLIANCE; 30 import static android.content.res.Configuration.UI_MODE_TYPE_MASK; 31 import static android.content.res.Configuration.UI_MODE_TYPE_UNDEFINED; 32 import static android.os.Build.VERSION_CODES.JELLY_BEAN; 33 import static android.view.Surface.ROTATION_0; 34 import static android.view.Surface.ROTATION_90; 35 import static org.assertj.core.api.Assertions.assertThat; 36 import static org.junit.Assert.fail; 37 38 import android.content.Context; 39 import android.content.res.Configuration; 40 import android.hardware.display.DisplayManager; 41 import android.os.Build; 42 import android.util.DisplayMetrics; 43 import android.view.Display; 44 import android.view.DisplayInfo; 45 import java.util.Locale; 46 import org.junit.Before; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 import org.robolectric.RobolectricTestRunner; 50 import org.robolectric.RuntimeEnvironment; 51 import org.robolectric.annotation.Config; 52 53 @RunWith(RobolectricTestRunner.class) 54 public class BootstrapTest { 55 56 private Configuration configuration; 57 private DisplayMetrics displayMetrics; 58 59 @Before 60 public void setUp() throws Exception { 61 configuration = new Configuration(); 62 displayMetrics = new DisplayMetrics(); 63 } 64 65 @Test 66 @Config(qualifiers = "w480dp-h640dp") 67 public void shouldSetUpRealisticDisplay() throws Exception { 68 if (Build.VERSION.SDK_INT > JELLY_BEAN) { 69 DisplayManager displayManager = (DisplayManager) RuntimeEnvironment.application 70 .getSystemService(Context.DISPLAY_SERVICE); 71 DisplayInfo displayInfo = new DisplayInfo(); 72 Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 73 display.getDisplayInfo(displayInfo); 74 75 assertThat(displayInfo.name).isEqualTo("Built-in screen"); 76 assertThat(displayInfo.appWidth).isEqualTo(480); 77 assertThat(displayInfo.appHeight).isEqualTo(640); 78 assertThat(displayInfo.smallestNominalAppWidth).isEqualTo(480); 79 assertThat(displayInfo.smallestNominalAppHeight).isEqualTo(480); 80 assertThat(displayInfo.largestNominalAppWidth).isEqualTo(640); 81 assertThat(displayInfo.largestNominalAppHeight).isEqualTo(640); 82 assertThat(displayInfo.logicalWidth).isEqualTo(480); 83 assertThat(displayInfo.logicalHeight).isEqualTo(640); 84 assertThat(displayInfo.rotation).isEqualTo(ROTATION_0); 85 assertThat(displayInfo.logicalDensityDpi).isEqualTo(160); 86 assertThat(displayInfo.physicalXDpi).isEqualTo(160f); 87 assertThat(displayInfo.physicalYDpi).isEqualTo(160f); 88 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { 89 assertThat(displayInfo.state).isEqualTo(Display.STATE_ON); 90 } 91 } 92 93 DisplayMetrics displayMetrics = RuntimeEnvironment.application.getResources() 94 .getDisplayMetrics(); 95 assertThat(displayMetrics.widthPixels).isEqualTo(480); 96 assertThat(displayMetrics.heightPixels).isEqualTo(640); 97 } 98 99 @Test 100 @Config(qualifiers = "w480dp-h640dp-land-hdpi") 101 public void shouldSetUpRealisticDisplay_landscapeHighDensity() throws Exception { 102 if (Build.VERSION.SDK_INT > JELLY_BEAN) { 103 DisplayManager displayManager = (DisplayManager) RuntimeEnvironment.application 104 .getSystemService(Context.DISPLAY_SERVICE); 105 DisplayInfo displayInfo = new DisplayInfo(); 106 Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY); 107 display.getDisplayInfo(displayInfo); 108 109 assertThat(displayInfo.name).isEqualTo("Built-in screen"); 110 assertThat(displayInfo.appWidth).isEqualTo(960); 111 assertThat(displayInfo.appHeight).isEqualTo(720); 112 assertThat(displayInfo.smallestNominalAppWidth).isEqualTo(720); 113 assertThat(displayInfo.smallestNominalAppHeight).isEqualTo(720); 114 assertThat(displayInfo.largestNominalAppWidth).isEqualTo(960); 115 assertThat(displayInfo.largestNominalAppHeight).isEqualTo(960); 116 assertThat(displayInfo.logicalWidth).isEqualTo(960); 117 assertThat(displayInfo.logicalHeight).isEqualTo(720); 118 assertThat(displayInfo.rotation).isEqualTo(ROTATION_90); 119 assertThat(displayInfo.logicalDensityDpi).isEqualTo(240); 120 assertThat(displayInfo.physicalXDpi).isEqualTo(240f); 121 assertThat(displayInfo.physicalYDpi).isEqualTo(240f); 122 if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { 123 assertThat(displayInfo.state).isEqualTo(Display.STATE_ON); 124 } 125 } 126 127 DisplayMetrics displayMetrics = RuntimeEnvironment.application.getResources() 128 .getDisplayMetrics(); 129 assertThat(displayMetrics.widthPixels).isEqualTo(960); 130 assertThat(displayMetrics.heightPixels).isEqualTo(720); 131 } 132 133 @Test 134 public void applyQualifiers_shouldAddDefaults() { 135 Bootstrap.applyQualifiers("", Build.VERSION.RESOURCES_SDK_INT, configuration, displayMetrics); 136 String outQualifiers = ConfigurationV25.resourceQualifierString(configuration, displayMetrics); 137 138 assertThat(outQualifiers) 139 .isEqualTo("en-rUS-ldltr-sw320dp-w320dp-h470dp-normal-notlong-notround-port-notnight-mdpi" + 140 "-finger-keyssoft-nokeys-navhidden-nonav-v" + Build.VERSION.RESOURCES_SDK_INT); 141 142 assertThat(configuration.mcc).isEqualTo(0); 143 assertThat(configuration.mnc).isEqualTo(0); 144 assertThat(configuration.locale).isEqualTo(new Locale("en", "US")); 145 assertThat(configuration.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK).isEqualTo(SCREENLAYOUT_LAYOUTDIR_LTR); 146 assertThat(configuration.smallestScreenWidthDp).isEqualTo(320); 147 assertThat(configuration.screenWidthDp).isEqualTo(320); 148 assertThat(configuration.screenHeightDp).isEqualTo(470); 149 assertThat(configuration.screenLayout & SCREENLAYOUT_SIZE_MASK).isEqualTo(SCREENLAYOUT_SIZE_NORMAL); 150 assertThat(configuration.screenLayout & SCREENLAYOUT_LONG_MASK).isEqualTo(SCREENLAYOUT_LONG_NO); 151 assertThat(configuration.screenLayout & SCREENLAYOUT_ROUND_MASK).isEqualTo(SCREENLAYOUT_ROUND_NO); 152 assertThat(configuration.orientation).isEqualTo(ORIENTATION_PORTRAIT); 153 assertThat(configuration.uiMode & UI_MODE_TYPE_MASK).isEqualTo(UI_MODE_TYPE_UNDEFINED); 154 assertThat(configuration.uiMode & UI_MODE_NIGHT_MASK).isEqualTo(UI_MODE_NIGHT_NO); 155 156 if (RuntimeEnvironment.getApiLevel() > JELLY_BEAN) { 157 assertThat(configuration.densityDpi).isEqualTo(DisplayMetrics.DENSITY_DEFAULT); 158 } else { 159 assertThat(displayMetrics.densityDpi).isEqualTo(DisplayMetrics.DENSITY_DEFAULT); 160 assertThat(displayMetrics.density).isEqualTo(1.0f); 161 } 162 163 assertThat(configuration.touchscreen).isEqualTo(TOUCHSCREEN_FINGER); 164 assertThat(configuration.keyboardHidden).isEqualTo(KEYBOARDHIDDEN_SOFT); 165 assertThat(configuration.keyboard).isEqualTo(KEYBOARD_NOKEYS); 166 assertThat(configuration.navigationHidden).isEqualTo(NAVIGATIONHIDDEN_YES); 167 assertThat(configuration.navigation).isEqualTo(NAVIGATION_NONAV); 168 } 169 170 @Test 171 public void applyQualifiers_shouldHonorSpecifiedQualifiers() { 172 Bootstrap.applyQualifiers( 173 "mcc310-mnc004-fr-rFR-ldrtl-sw400dp-w480dp-h456dp-xlarge-long-round-land-" 174 + "appliance-night-hdpi-notouch-keyshidden-12key-navhidden-dpad", 175 Build.VERSION.RESOURCES_SDK_INT, 176 configuration, 177 displayMetrics); 178 String outQualifiers = ConfigurationV25.resourceQualifierString(configuration, displayMetrics); 179 180 if (RuntimeEnvironment.getApiLevel() > JELLY_BEAN) { 181 assertThat(outQualifiers).isEqualTo("mcc310-mnc4-fr-rFR-ldltr-sw400dp-w480dp-h456dp-xlarge" 182 + "-long-round-land-appliance-night-hdpi-notouch-keyshidden-12key-navhidden-dpad-v" 183 + Build.VERSION.RESOURCES_SDK_INT); 184 } else { 185 assertThat(outQualifiers).isEqualTo("mcc310-mnc4-fr-rFR-ldrtl-sw400dp-w480dp-h456dp-xlarge" 186 + "-long-round-land-appliance-night-hdpi-notouch-keyshidden-12key-navhidden-dpad-v" 187 + Build.VERSION.RESOURCES_SDK_INT); 188 } 189 190 assertThat(configuration.mcc).isEqualTo(310); 191 assertThat(configuration.mnc).isEqualTo(4); 192 assertThat(configuration.locale).isEqualTo(new Locale("fr", "FR")); 193 if (RuntimeEnvironment.getApiLevel() > JELLY_BEAN) { 194 // note that locale overrides ltr/rtl 195 assertThat(configuration.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) 196 .isEqualTo(SCREENLAYOUT_LAYOUTDIR_LTR); 197 } else { 198 // but not on Jelly Bean... 199 assertThat(configuration.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK) 200 .isEqualTo(SCREENLAYOUT_LAYOUTDIR_RTL); 201 } 202 assertThat(configuration.smallestScreenWidthDp).isEqualTo(400); 203 assertThat(configuration.screenWidthDp).isEqualTo(480); 204 assertThat(configuration.screenHeightDp).isEqualTo(456); 205 assertThat(configuration.screenLayout & SCREENLAYOUT_SIZE_MASK).isEqualTo(SCREENLAYOUT_SIZE_XLARGE); 206 assertThat(configuration.screenLayout & SCREENLAYOUT_LONG_MASK).isEqualTo(SCREENLAYOUT_LONG_YES); 207 assertThat(configuration.screenLayout & SCREENLAYOUT_ROUND_MASK).isEqualTo(SCREENLAYOUT_ROUND_YES); 208 assertThat(configuration.orientation).isEqualTo(ORIENTATION_LANDSCAPE); 209 assertThat(configuration.uiMode & UI_MODE_TYPE_MASK).isEqualTo(UI_MODE_TYPE_APPLIANCE); 210 assertThat(configuration.uiMode & UI_MODE_NIGHT_MASK).isEqualTo(UI_MODE_NIGHT_YES); 211 if (RuntimeEnvironment.getApiLevel() > JELLY_BEAN) { 212 assertThat(configuration.densityDpi).isEqualTo(DisplayMetrics.DENSITY_HIGH); 213 } else { 214 assertThat(displayMetrics.densityDpi).isEqualTo(DisplayMetrics.DENSITY_HIGH); 215 assertThat(displayMetrics.density).isEqualTo(1.5f); 216 } 217 assertThat(configuration.touchscreen).isEqualTo(TOUCHSCREEN_NOTOUCH); 218 assertThat(configuration.keyboardHidden).isEqualTo(KEYBOARDHIDDEN_YES); 219 assertThat(configuration.keyboard).isEqualTo(KEYBOARD_12KEY); 220 assertThat(configuration.navigationHidden).isEqualTo(NAVIGATIONHIDDEN_YES); 221 assertThat(configuration.navigation).isEqualTo(NAVIGATION_DPAD); 222 } 223 224 @Test 225 public void applyQualifiers_longShouldMakeScreenTaller() throws Exception { 226 Bootstrap.applyQualifiers("long", 227 RuntimeEnvironment.getApiLevel(), configuration, displayMetrics); 228 assertThat(configuration.smallestScreenWidthDp).isEqualTo(320); 229 assertThat(configuration.screenWidthDp).isEqualTo(320); 230 assertThat(configuration.screenHeightDp).isEqualTo(587); 231 assertThat(configuration.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) 232 .isEqualTo(Configuration.SCREENLAYOUT_LONG_YES); 233 } 234 235 @Test 236 public void whenScreenRationGreatherThan175Percent_applyQualifiers_ShouldSetLong() throws Exception { 237 Bootstrap.applyQualifiers("w400dp-h200dp", 238 RuntimeEnvironment.getApiLevel(), configuration, displayMetrics); 239 assertThat(configuration.screenWidthDp).isEqualTo(400); 240 assertThat(configuration.screenHeightDp).isEqualTo(200); 241 assertThat(configuration.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK) 242 .isEqualTo(Configuration.SCREENLAYOUT_LONG_YES); 243 } 244 245 @Test 246 public void applyQualifiers_shouldRejectUnknownQualifiers() { 247 try { 248 Bootstrap.applyQualifiers("notareal-qualifier-sw400dp-w480dp-more-wrong-stuff", 249 RuntimeEnvironment.getApiLevel(), configuration, displayMetrics); 250 fail("should have thrown"); 251 } catch (IllegalArgumentException e) { 252 // expected 253 assertThat(e.getMessage()).contains("notareal"); 254 } 255 } 256 257 @Test 258 public void applyQualifiers_shouldRejectSdkVersion() { 259 try { 260 Bootstrap.applyQualifiers("sw400dp-w480dp-v7", 261 RuntimeEnvironment.getApiLevel(), configuration, displayMetrics); 262 fail("should have thrown"); 263 } catch (IllegalArgumentException e) { 264 // expected 265 assertThat(e.getMessage()).contains("Cannot specify conflicting platform version"); 266 } 267 } 268 269 @Test 270 public void applyQualifiers_shouldRejectAnydpi() { 271 try { 272 Bootstrap.applyQualifiers("anydpi", 273 RuntimeEnvironment.getApiLevel(), configuration, displayMetrics); 274 fail("should have thrown"); 275 } catch (IllegalArgumentException e) { 276 // expected 277 assertThat(e.getMessage()).contains("'anydpi' isn't actually a dpi"); 278 } 279 } 280 281 @Test 282 public void applyQualifiers_shouldRejectNodpi() { 283 try { 284 Bootstrap.applyQualifiers("nodpi", 285 RuntimeEnvironment.getApiLevel(), configuration, displayMetrics); 286 fail("should have thrown"); 287 } catch (IllegalArgumentException e) { 288 // expected 289 assertThat(e.getMessage()).contains("'nodpi' isn't actually a dpi"); 290 } 291 } 292 293 @Test 294 @Config(sdk = JELLY_BEAN) 295 public void applyQualifiers_densityOnJellyBean() { 296 Bootstrap.applyQualifiers("hdpi", RuntimeEnvironment.getApiLevel(), configuration, 297 displayMetrics); 298 assertThat(displayMetrics.density).isEqualTo(1.5f); 299 assertThat(displayMetrics.densityDpi).isEqualTo(240); 300 } 301 302 @Test 303 public void applyQualifiers_shouldSetLocaleScript() throws Exception { 304 Bootstrap.applyQualifiers("b+sr+Latn", RuntimeEnvironment.getApiLevel(), 305 configuration, displayMetrics); 306 String outQualifiers = ConfigurationV25.resourceQualifierString(configuration, displayMetrics); 307 308 assertThat(configuration.locale.getScript()).isEqualTo("Latn"); 309 assertThat(outQualifiers).contains("b+sr+Latn"); 310 } 311 312 @Test 313 public void spaceSeparated_applyQualifiers_shouldReplaceQualifiers() throws Exception { 314 Bootstrap.applyQualifiers("ru-rRU-h123dp-large fr-w321dp", RuntimeEnvironment.getApiLevel(), 315 configuration, displayMetrics); 316 String outQualifiers = ConfigurationV25.resourceQualifierString(configuration, displayMetrics); 317 318 assertThat(outQualifiers).startsWith("fr-ldltr-sw321dp-w321dp-h470dp-normal"); 319 } 320 321 @Test 322 public void whenPrefixedWithPlus_applyQualifiers_shouldOverlayQualifiers() throws Exception { 323 Bootstrap.applyQualifiers("+en ru-rRU-h123dp-large +fr-w321dp-small", RuntimeEnvironment.getApiLevel(), 324 configuration, displayMetrics); 325 String outQualifiers = ConfigurationV25.resourceQualifierString(configuration, displayMetrics); 326 327 assertThat(outQualifiers).startsWith("fr-ldltr-sw321dp-w321dp-h426dp-small"); 328 } 329 330 @Test 331 public void whenAllPrefixedWithPlus_applyQualifiers_shouldOverlayQualifiers() throws Exception { 332 Bootstrap.applyQualifiers("+xxhdpi +ru-rRU-h123dp-large +fr-w321dp-small", RuntimeEnvironment.getApiLevel(), 333 configuration, displayMetrics); 334 String outQualifiers = ConfigurationV25.resourceQualifierString(configuration, displayMetrics); 335 336 assertThat(outQualifiers).startsWith("fr-ldltr-sw321dp-w321dp-h426dp-small") 337 .contains("-xxhdpi-"); 338 } 339 } 340