in libresource/ResourceTypes.cpp [2181:2442]
bool ResTable_config::isBetterThan(const ResTable_config& o,
const ResTable_config* requested) const {
if (requested) {
if (imsi || o.imsi) {
if ((mcc != o.mcc) && requested->mcc) {
return (mcc);
}
if ((mnc != o.mnc) && requested->mnc) {
return (mnc);
}
}
if (locale || o.locale) {
if ((language[0] != o.language[0]) && requested->language[0]) {
return (language[0]);
}
if ((country[0] != o.country[0]) && requested->country[0]) {
return (country[0]);
}
}
if (localeScript[0] || o.localeScript[0]) {
if (localeScript[0] != o.localeScript[0] && requested->localeScript[0]) {
return localeScript[0];
}
}
if (localeVariant[0] || o.localeVariant[0]) {
if (localeVariant[0] != o.localeVariant[0] && requested->localeVariant[0]) {
return localeVariant[0];
}
}
if (screenLayout || o.screenLayout) {
if (((screenLayout^o.screenLayout) & MASK_LAYOUTDIR) != 0
&& (requested->screenLayout & MASK_LAYOUTDIR)) {
int myLayoutDir = screenLayout & MASK_LAYOUTDIR;
int oLayoutDir = o.screenLayout & MASK_LAYOUTDIR;
return (myLayoutDir > oLayoutDir);
}
}
if (smallestScreenWidthDp || 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 (screenSizeDp || 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 (requested->screenWidthDp) {
myDelta += requested->screenWidthDp - screenWidthDp;
otherDelta += requested->screenWidthDp - o.screenWidthDp;
}
if (requested->screenHeightDp) {
myDelta += requested->screenHeightDp - screenHeightDp;
otherDelta += requested->screenHeightDp - o.screenHeightDp;
}
if (kDebugTableSuperNoisy) {
ALOGI("Comparing this %dx%d to other %dx%d in %dx%d: myDelta=%d otherDelta=%d",
screenWidthDp, screenHeightDp, o.screenWidthDp, o.screenHeightDp,
requested->screenWidthDp, requested->screenHeightDp, myDelta, otherDelta);
}
if (myDelta != otherDelta) {
return myDelta < otherDelta;
}
}
if (screenLayout || o.screenLayout) {
if (((screenLayout^o.screenLayout) & MASK_SCREENSIZE) != 0
&& (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
&& (requested->screenLayout & MASK_SCREENLONG)) {
return (screenLayout & MASK_SCREENLONG);
}
}
if ((orientation != o.orientation) && requested->orientation) {
return (orientation);
}
if (uiMode || o.uiMode) {
if (((uiMode^o.uiMode) & MASK_UI_MODE_TYPE) != 0
&& (requested->uiMode & MASK_UI_MODE_TYPE)) {
return (uiMode & MASK_UI_MODE_TYPE);
}
if (((uiMode^o.uiMode) & MASK_UI_MODE_NIGHT) != 0
&& (requested->uiMode & MASK_UI_MODE_NIGHT)) {
return (uiMode & MASK_UI_MODE_NIGHT);
}
}
if (screenType || o.screenType) {
if (density != o.density) {
// Use the system default density (DENSITY_MEDIUM, 160dpi) if none specified.
const int thisDensity = density ? density : int(ResTable_config::DENSITY_MEDIUM);
const int otherDensity = o.density ? o.density : int(ResTable_config::DENSITY_MEDIUM);
// We always prefer DENSITY_ANY over scaling a density bucket.
if (thisDensity == ResTable_config::DENSITY_ANY) {
return true;
} else if (otherDensity == ResTable_config::DENSITY_ANY) {
return false;
}
int requestedDensity = requested->density;
if (requested->density == 0 ||
requested->density == ResTable_config::DENSITY_ANY) {
requestedDensity = ResTable_config::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;
bool 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) && requested->touchscreen) {
return (touchscreen);
}
}
if (input || o.input) {
const int keysHidden = inputFlags & MASK_KEYSHIDDEN;
const int oKeysHidden = o.inputFlags & MASK_KEYSHIDDEN;
if (keysHidden != oKeysHidden) {
const int reqKeysHidden =
requested->inputFlags & MASK_KEYSHIDDEN;
if (reqKeysHidden) {
if (!keysHidden) return false;
if (!oKeysHidden) 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;
}
}
const int navHidden = inputFlags & MASK_NAVHIDDEN;
const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
if (navHidden != oNavHidden) {
const int reqNavHidden =
requested->inputFlags & MASK_NAVHIDDEN;
if (reqNavHidden) {
if (!navHidden) return false;
if (!oNavHidden) return true;
}
}
if ((keyboard != o.keyboard) && requested->keyboard) {
return (keyboard);
}
if ((navigation != o.navigation) && requested->navigation) {
return (navigation);
}
}
if (screenSize || 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 (requested->screenWidth) {
myDelta += requested->screenWidth - screenWidth;
otherDelta += requested->screenWidth - o.screenWidth;
}
if (requested->screenHeight) {
myDelta += requested->screenHeight - screenHeight;
otherDelta += requested->screenHeight - o.screenHeight;
}
if (myDelta != otherDelta) {
return myDelta < otherDelta;
}
}
if (version || o.version) {
if ((sdkVersion != o.sdkVersion) && requested->sdkVersion) {
return (sdkVersion > o.sdkVersion);
}
if ((minorVersion != o.minorVersion) &&
requested->minorVersion) {
return (minorVersion);
}
}
return false;
}
return isMoreSpecificThan(o);
}