in resources/src/main/java/org/robolectric/res/android/ResTable_config.java [1179:1436]
public boolean isBetterThan(
ResTable_config o, ResTable_config requested) {
if (isTruthy(requested)) {
if (isTruthy(imsi()) || isTruthy(o.imsi())) {
if ((mcc != o.mcc) && isTruthy(requested.mcc)) {
return (isTruthy(mcc));
}
if ((mnc != o.mnc) && isTruthy(requested.mnc)) {
return (isTruthy(mnc));
}
}
if (isLocaleBetterThan(o, requested)) {
return true;
}
if (isTruthy(screenLayout) || isTruthy(o.screenLayout)) {
if (isTruthy((screenLayout^o.screenLayout) & MASK_LAYOUTDIR)
&& isTruthy(requested.screenLayout & MASK_LAYOUTDIR)) {
int myLayoutDir = screenLayout & MASK_LAYOUTDIR;
int oLayoutDir = o.screenLayout & MASK_LAYOUTDIR;
return (myLayoutDir > oLayoutDir);
}
}
if (isTruthy(smallestScreenWidthDp) || isTruthy(o.smallestScreenWidthDp)) {
// The configuration closest to the actual size is best.
// We assume that larger configs have already been filtered
// out at this point. That means we just want the largest one.
if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
return smallestScreenWidthDp > o.smallestScreenWidthDp;
}
}
if (isTruthy(screenSizeDp()) || isTruthy(o.screenSizeDp())) {
// "Better" is based on the sum of the difference between both
// width and height from the requested dimensions. We are
// assuming the invalid configs (with smaller dimens) have
// already been filtered. Note that if a particular dimension
// is unspecified, we will end up with a large value (the
// difference between 0 and the requested dimension), which is
// good since we will prefer a config that has specified a
// dimension value.
int myDelta = 0, otherDelta = 0;
if (isTruthy(requested.screenWidthDp)) {
myDelta += requested.screenWidthDp - screenWidthDp;
otherDelta += requested.screenWidthDp - o.screenWidthDp;
}
if (isTruthy(requested.screenHeightDp)) {
myDelta += requested.screenHeightDp - screenHeightDp;
otherDelta += requested.screenHeightDp - o.screenHeightDp;
}
if (myDelta != otherDelta) {
return myDelta < otherDelta;
}
}
if (isTruthy(screenLayout) || isTruthy(o.screenLayout)) {
if (isTruthy((screenLayout^o.screenLayout) & MASK_SCREENSIZE)
&& isTruthy(requested.screenLayout & MASK_SCREENSIZE)) {
// A little backwards compatibility here: undefined is
// considered equivalent to normal. But only if the
// requested size is at least normal; otherwise, small
// is better than the default.
int mySL = (screenLayout & MASK_SCREENSIZE);
int oSL = (o.screenLayout & MASK_SCREENSIZE);
int fixedMySL = mySL;
int fixedOSL = oSL;
if ((requested.screenLayout & MASK_SCREENSIZE) >= SCREENSIZE_NORMAL) {
if (fixedMySL == 0) fixedMySL = SCREENSIZE_NORMAL;
if (fixedOSL == 0) fixedOSL = SCREENSIZE_NORMAL;
}
// For screen size, the best match is the one that is
// closest to the requested screen size, but not over
// (the not over part is dealt with in match() below).
if (fixedMySL == fixedOSL) {
// If the two are the same, but 'this' is actually
// undefined, then the other is really a better match.
if (mySL == 0) return false;
return true;
}
if (fixedMySL != fixedOSL) {
return fixedMySL > fixedOSL;
}
}
if (((screenLayout^o.screenLayout) & MASK_SCREENLONG) != 0
&& isTruthy(requested.screenLayout & MASK_SCREENLONG)) {
return isTruthy(screenLayout & MASK_SCREENLONG);
}
}
if (isTruthy(screenLayout2) || isTruthy(o.screenLayout2)) {
if (((screenLayout2^o.screenLayout2) & MASK_SCREENROUND) != 0 &&
isTruthy(requested.screenLayout2 & MASK_SCREENROUND)) {
return isTruthy(screenLayout2 & MASK_SCREENROUND);
}
}
if (isTruthy(colorMode) || isTruthy(o.colorMode)) {
if (((colorMode^o.colorMode) & MASK_WIDE_COLOR_GAMUT) != 0 &&
isTruthy((requested.colorMode & MASK_WIDE_COLOR_GAMUT))) {
return isTruthy(colorMode & MASK_WIDE_COLOR_GAMUT);
}
if (((colorMode^o.colorMode) & MASK_HDR) != 0 &&
isTruthy((requested.colorMode & MASK_HDR))) {
return isTruthy(colorMode & MASK_HDR);
}
}
if ((orientation != o.orientation) && isTruthy(requested.orientation)) {
return isTruthy(orientation);
}
if (isTruthy(uiMode) || isTruthy(o.uiMode)) {
if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
&& isTruthy(requested.uiMode & MASK_UI_MODE_TYPE)) {
return isTruthy(uiMode & MASK_UI_MODE_TYPE);
}
if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
&& isTruthy(requested.uiMode & MASK_UI_MODE_NIGHT)) {
return isTruthy(uiMode & MASK_UI_MODE_NIGHT);
}
}
if (isTruthy(screenType()) || isTruthy(o.screenType())) {
if (density != o.density) {
// Use the system default density (DENSITY_MEDIUM, 160dpi) if none specified.
final int thisDensity = isTruthy(density) ? density : DENSITY_MEDIUM;
final int otherDensity = isTruthy(o.density) ? o.density : DENSITY_MEDIUM;
// We always prefer DENSITY_ANY over scaling a density bucket.
if (thisDensity == DENSITY_ANY) {
return true;
} else if (otherDensity == DENSITY_ANY) {
return false;
}
int requestedDensity = requested.density;
if (requested.density == 0 ||
requested.density == DENSITY_ANY) {
requestedDensity = DENSITY_MEDIUM;
}
// DENSITY_ANY is now dealt with. We should look to
// pick a density bucket and potentially scale it.
// Any density is potentially useful
// because the system will scale it. Scaling down
// is generally better than scaling up.
int h = thisDensity;
int l = otherDensity;
boolean bImBigger = true;
if (l > h) {
int t = h;
h = l;
l = t;
bImBigger = false;
}
if (requestedDensity >= h) {
// requested value higher than both l and h, give h
return bImBigger;
}
if (l >= requestedDensity) {
// requested value lower than both l and h, give l
return !bImBigger;
}
// saying that scaling down is 2x better than up
if (((2 * l) - requestedDensity) * h > requestedDensity * requestedDensity) {
return !bImBigger;
} else {
return bImBigger;
}
}
if ((touchscreen != o.touchscreen) && isTruthy(requested.touchscreen)) {
return isTruthy(touchscreen);
}
}
if (isTruthy(input()) || isTruthy(o.input())) {
final int keysHidden = inputFlags & MASK_KEYSHIDDEN;
final int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
if (keysHidden != oKeysHidden) {
final int reqKeysHidden =
requested.inputFlags & MASK_KEYSHIDDEN;
if (isTruthy(reqKeysHidden)) {
if (keysHidden == 0) return false;
if (oKeysHidden == 0) return true;
// For compatibility, we count KEYSHIDDEN_NO as being
// the same as KEYSHIDDEN_SOFT. Here we disambiguate
// these by making an exact match more specific.
if (reqKeysHidden == keysHidden) return true;
if (reqKeysHidden == oKeysHidden) return false;
}
}
final int navHidden = inputFlags & MASK_NAVHIDDEN;
final int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
if (navHidden != oNavHidden) {
final int reqNavHidden =
requested.inputFlags & MASK_NAVHIDDEN;
if (isTruthy(reqNavHidden)) {
if (navHidden == 0) return false;
if (oNavHidden == 0) return true;
}
}
if ((keyboard != o.keyboard) && isTruthy(requested.keyboard)) {
return isTruthy(keyboard);
}
if ((navigation != o.navigation) && isTruthy(requested.navigation)) {
return isTruthy(navigation);
}
}
if (isTruthy(screenSize()) || isTruthy(o.screenSize())) {
// "Better" is based on the sum of the difference between both
// width and height from the requested dimensions. We are
// assuming the invalid configs (with smaller sizes) have
// already been filtered. Note that if a particular dimension
// is unspecified, we will end up with a large value (the
// difference between 0 and the requested dimension), which is
// good since we will prefer a config that has specified a
// size value.
int myDelta = 0, otherDelta = 0;
if (isTruthy(requested.screenWidth)) {
myDelta += requested.screenWidth - screenWidth;
otherDelta += requested.screenWidth - o.screenWidth;
}
if (isTruthy(requested.screenHeight)) {
myDelta += requested.screenHeight - screenHeight;
otherDelta += requested.screenHeight - o.screenHeight;
}
if (myDelta != otherDelta) {
return myDelta < otherDelta;
}
}
if (isTruthy(version()) || isTruthy(o.version())) {
if ((sdkVersion != o.sdkVersion) && isTruthy(requested.sdkVersion)) {
return (sdkVersion > o.sdkVersion);
}
if ((minorVersion != o.minorVersion) &&
isTruthy(requested.minorVersion)) {
return isTruthy(minorVersion);
}
}
return false;
}
return isMoreSpecificThan(o);
}