From 723738cfaec3dd7b0fe152c872c41bebf94074c4 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 25 Jun 2009 19:48:04 -0700 Subject: [PATCH] Expand support for different screen sizes. Applications can now declare that they support small, normal, or large screens. Resource selection can also be done based on these sizes. By default, pre-Donut apps are false for small and large, and Donut or later apps are assumed to support all sizes. In either case they can use in their manifest to declare what they actually support. --- api/current.xml | 153 ++++++++++++++---- .../java/android/content/pm/ActivityInfo.java | 10 +- .../android/content/pm/ApplicationInfo.java | 29 +++- .../android/content/pm/PackageParser.java | 40 ++++- .../android/content/res/AssetManager.java | 2 +- .../content/res/CompatibilityInfo.java | 33 ++-- .../android/content/res/Configuration.java | 37 ++++- core/java/android/content/res/Resources.java | 5 +- core/java/android/util/DisplayMetrics.java | 61 +++---- core/jni/android_util_AssetManager.cpp | 5 +- core/res/res/values/attrs_manifest.xml | 58 ++++++- core/res/res/values/public.xml | 3 + include/utils/ResourceTypes.h | 50 +++++- libs/utils/ResourceTypes.cpp | 5 +- .../java/com/android/server/Watchdog.java | 2 + .../android/server/WindowManagerService.java | 38 ++++- tests/DpiTest/AndroidManifest.xml | 2 + .../res/values-largeScreen/strings.xml | 19 +++ .../res/values-normalScreen/strings.xml | 19 +++ .../res/values-smallScreen/strings.xml | 19 +++ tests/DpiTest/res/values/strings.xml | 19 +++ .../android/test/dpi/DpiTestActivity.java | 1 + tools/aapt/AaptAssets.cpp | 50 +++++- tools/aapt/AaptAssets.h | 3 + tools/aapt/Command.cpp | 39 +++++ .../layoutlib/bridge/BridgeAssetManager.java | 3 +- 26 files changed, 603 insertions(+), 102 deletions(-) create mode 100644 tests/DpiTest/res/values-largeScreen/strings.xml create mode 100644 tests/DpiTest/res/values-normalScreen/strings.xml create mode 100644 tests/DpiTest/res/values-smallScreen/strings.xml create mode 100644 tests/DpiTest/res/values/strings.xml diff --git a/api/current.xml b/api/current.xml index 66bdb28c4d64a..3c58ded77edd7 100644 --- a/api/current.xml +++ b/api/current.xml @@ -3452,39 +3452,6 @@ visibility="public" > - - - - - - + + + + + + + + + + + + + + + + + + + + + + outerDepth)) { @@ -876,8 +881,24 @@ public class PackageParser { XmlUtils.skipCurrentTag(parser); - } else if (tagName.equals("expandable")) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; + } else if (tagName.equals("supports-screens")) { + sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestSupportsScreens); + + // This is a trick to get a boolean and still able to detect + // if a value was actually set. + supportsSmallScreens = sa.getInteger( + com.android.internal.R.styleable.AndroidManifestSupportsScreens_smallScreens, + supportsSmallScreens); + supportsNormalScreens = sa.getInteger( + com.android.internal.R.styleable.AndroidManifestSupportsScreens_normalScreens, + supportsNormalScreens); + supportsLargeScreens = sa.getInteger( + com.android.internal.R.styleable.AndroidManifestSupportsScreens_largeScreens, + supportsLargeScreens); + + sa.recycle(); + XmlUtils.skipCurrentTag(parser); } else { Log.w(TAG, "Bad element under : " @@ -910,7 +931,20 @@ public class PackageParser { pkg.usesLibraryFiles = new String[pkg.usesLibraries.size()]; pkg.usesLibraries.toArray(pkg.usesLibraryFiles); } - // TODO: enable all density & expandable if target sdk is higher than donut + + if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 + && pkg.applicationInfo.targetSdkVersion + >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) { + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; + } + if (supportsNormalScreens != 0) { + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS; + } + if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 + && pkg.applicationInfo.targetSdkVersion + >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) { + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; + } int size = pkg.supportsDensityList.size(); if (size > 0) { diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 1c9173694d2bc..5c7b01fa0ccb0 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -601,7 +601,7 @@ public final class AssetManager { public native final void setConfiguration(int mcc, int mnc, String locale, int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, int screenWidth, int screenHeight, - int majorVersion); + int screenLayout, int majorVersion); /** * Retrieve the resource identifier for the given resource name. diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index 179b9bd4c1c9d..4e6fe07b9bf03 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -65,7 +65,7 @@ public class CompatibilityInfo { /** * A compatibility flags */ - private int compatibilityFlags; + private int mCompatibilityFlags; /** * A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f) @@ -101,7 +101,11 @@ public class CompatibilityInfo { */ public final float applicationInvertedScale; - + /** + * The flags from ApplicationInfo. + */ + public final int appFlags; + /** * Window size in Compatibility Mode, in real pixels. This is updated by * {@link DisplayMetrics#updateMetrics}. @@ -117,8 +121,10 @@ public class CompatibilityInfo { private int mXOffset; public CompatibilityInfo(ApplicationInfo appInfo) { + appFlags = appInfo.flags; + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS) != 0) { - compatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE; + mCompatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE; } float packageDensityScale = -1.0f; @@ -149,13 +155,16 @@ public class CompatibilityInfo { } applicationInvertedScale = 1.0f / applicationScale; if (applicationScale != 1.0f) { - compatibilityFlags |= SCALING_REQUIRED; + mCompatibilityFlags |= SCALING_REQUIRED; } } private CompatibilityInfo() { + appFlags = ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; applicationScale = applicationInvertedScale = 1.0f; - compatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE; + mCompatibilityFlags = EXPANDABLE | CONFIGURED_EXPANDABLE; } /** @@ -175,9 +184,9 @@ public class CompatibilityInfo { */ public void setExpandable(boolean expandable) { if (expandable) { - compatibilityFlags |= CompatibilityInfo.EXPANDABLE; + mCompatibilityFlags |= CompatibilityInfo.EXPANDABLE; } else { - compatibilityFlags &= ~CompatibilityInfo.EXPANDABLE; + mCompatibilityFlags &= ~CompatibilityInfo.EXPANDABLE; } } @@ -185,20 +194,20 @@ public class CompatibilityInfo { * @return true if the application is configured to be expandable. */ public boolean isConfiguredExpandable() { - return (compatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0; + return (mCompatibilityFlags & CompatibilityInfo.CONFIGURED_EXPANDABLE) != 0; } /** * @return true if the scaling is required */ public boolean isScalingRequired() { - return (compatibilityFlags & SCALING_REQUIRED) != 0; + return (mCompatibilityFlags & SCALING_REQUIRED) != 0; } @Override public String toString() { return "CompatibilityInfo{scale=" + applicationScale + - ", compatibility flag=" + compatibilityFlags + "}"; + ", compatibility flag=" + mCompatibilityFlags + "}"; } /** @@ -222,13 +231,13 @@ public class CompatibilityInfo { * @param params the window's parameter */ public Translator getTranslator(WindowManager.LayoutParams params) { - if ( (compatibilityFlags & CompatibilityInfo.SCALING_EXPANDABLE_MASK) + if ( (mCompatibilityFlags & CompatibilityInfo.SCALING_EXPANDABLE_MASK) == CompatibilityInfo.EXPANDABLE) { if (DBG) Log.d(TAG, "no translation required"); return null; } - if ((compatibilityFlags & CompatibilityInfo.EXPANDABLE) == 0) { + if ((mCompatibilityFlags & CompatibilityInfo.EXPANDABLE) == 0) { if ((params.flags & WindowManager.LayoutParams.FLAG_NO_COMPATIBILITY_SCALING) != 0) { if (DBG) Log.d(TAG, "translation for surface view selected"); return new Translator(X_SHIFT_WINDOW, false, 1.0f, 1.0f); diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index bb3486c205545..577aa600a19e1 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -116,6 +116,18 @@ public final class Configuration implements Parcelable, ComparablesetConfiguration(config, locale8); @@ -1567,7 +1568,7 @@ static JNINativeMethod gAssetManagerMethods[] = { (void*) android_content_AssetManager_setLocale }, { "getLocales", "()[Ljava/lang/String;", (void*) android_content_AssetManager_getLocales }, - { "setConfiguration", "(IILjava/lang/String;IIIIIIIII)V", + { "setConfiguration", "(IILjava/lang/String;IIIIIIIIII)V", (void*) android_content_AssetManager_setConfiguration }, { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", (void*) android_content_AssetManager_getResourceIdentifier }, diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 91cd9fdd1b1b9..7571e24536279 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -512,6 +512,9 @@ + + @@ -829,8 +832,59 @@

This appears as a child tag of the {@link #AndroidManifest manifest} tag. --> - - + + + + + + + + + + + + + + + + + + + + + + DpiTest: Large Screen + diff --git a/tests/DpiTest/res/values-normalScreen/strings.xml b/tests/DpiTest/res/values-normalScreen/strings.xml new file mode 100644 index 0000000000000..256d696df80ed --- /dev/null +++ b/tests/DpiTest/res/values-normalScreen/strings.xml @@ -0,0 +1,19 @@ + + + + + DpiTest: Normal Screen + diff --git a/tests/DpiTest/res/values-smallScreen/strings.xml b/tests/DpiTest/res/values-smallScreen/strings.xml new file mode 100644 index 0000000000000..cdb4ac9f60bd8 --- /dev/null +++ b/tests/DpiTest/res/values-smallScreen/strings.xml @@ -0,0 +1,19 @@ + + + + + DpiTest: Small Screen + diff --git a/tests/DpiTest/res/values/strings.xml b/tests/DpiTest/res/values/strings.xml new file mode 100644 index 0000000000000..ef924ac85a632 --- /dev/null +++ b/tests/DpiTest/res/values/strings.xml @@ -0,0 +1,19 @@ + + + + + DpiTest: Unknown Screen + diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java index 3759622bbbec2..5a9f3f548c7d8 100644 --- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java +++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java @@ -34,6 +34,7 @@ public class DpiTestActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + this.setTitle(R.string.act_title); LinearLayout root = new LinearLayout(this); root.setOrientation(LinearLayout.VERTICAL); diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index 6bc1ee6cbfbc5..67af116d372dc 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -187,6 +187,13 @@ AaptGroupEntry::parseNamePart(const String8& part, int* axis, uint32_t* value) return 0; } + // screen layout + if (getScreenLayoutName(part.string(), &config)) { + *axis = AXIS_SCREENLAYOUT; + *value = config.screenLayout; + return 0; + } + // version if (getVersionName(part.string(), &config)) { *axis = AXIS_VERSION; @@ -202,7 +209,7 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) { Vector parts; - String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, vers; + String8 mcc, mnc, loc, orient, den, touch, key, keysHidden, nav, size, layout, vers; const char *p = dir; const char *q; @@ -378,6 +385,18 @@ AaptGroupEntry::initFromDirName(const char* dir, String8* resType) //printf("not screen size: %s\n", part.string()); } + if (getScreenLayoutName(part.string())) { + layout = part; + + index++; + if (index == N) { + goto success; + } + part = parts[index]; + } else { + //printf("not screen layout: %s\n", part.string()); + } + if (getVersionName(part.string())) { vers = part; @@ -404,6 +423,7 @@ success: this->keyboard = key; this->navigation = nav; this->screenSize = size; + this->screenLayout = layout; this->version = vers; // what is this anyway? @@ -435,6 +455,8 @@ AaptGroupEntry::toString() const s += ","; s += screenSize; s += ","; + s += screenLayout; + s += ","; s += version; return s; } @@ -483,6 +505,10 @@ AaptGroupEntry::toDirName(const String8& resType) const s += "-"; s += screenSize; } + if (this->screenLayout != "") { + s += "-"; + s += screenLayout; + } if (this->version != "") { s += "-"; s += version; @@ -786,6 +812,26 @@ bool AaptGroupEntry::getScreenSizeName(const char* name, return true; } +bool AaptGroupEntry::getScreenLayoutName(const char* name, + ResTable_config* out) +{ + if (strcmp(name, kWildcardName) == 0) { + if (out) out->screenLayout = out->SCREENLAYOUT_ANY; + return true; + } else if (strcmp(name, "smallscreen") == 0) { + if (out) out->screenLayout = out->SCREENLAYOUT_SMALL; + return true; + } else if (strcmp(name, "normalscreen") == 0) { + if (out) out->screenLayout = out->SCREENLAYOUT_NORMAL; + return true; + } else if (strcmp(name, "largescreen") == 0) { + if (out) out->screenLayout = out->SCREENLAYOUT_LARGE; + return true; + } + + return false; +} + bool AaptGroupEntry::getVersionName(const char* name, ResTable_config* out) { @@ -828,6 +874,7 @@ int AaptGroupEntry::compare(const AaptGroupEntry& o) const if (v == 0) v = keyboard.compare(o.keyboard); if (v == 0) v = navigation.compare(o.navigation); if (v == 0) v = screenSize.compare(o.screenSize); + if (v == 0) v = screenLayout.compare(o.screenLayout); if (v == 0) v = version.compare(o.version); return v; } @@ -846,6 +893,7 @@ ResTable_config AaptGroupEntry::toParams() const getKeyboardName(keyboard.string(), ¶ms); getNavigationName(navigation.string(), ¶ms); getScreenSizeName(screenSize.string(), ¶ms); + getScreenLayoutName(screenLayout.string(), ¶ms); getVersionName(version.string(), ¶ms); return params; } diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index 01c8140b25ce0..3b96412c7c54a 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -37,6 +37,7 @@ enum { AXIS_KEYBOARD, AXIS_NAVIGATION, AXIS_SCREENSIZE, + AXIS_SCREENLAYOUT, AXIS_VERSION }; @@ -62,6 +63,7 @@ public: String8 keyboard; String8 navigation; String8 screenSize; + String8 screenLayout; String8 version; bool initFromDirName(const char* dir, String8* resType); @@ -78,6 +80,7 @@ public: static bool getKeyboardName(const char* name, ResTable_config* out = NULL); static bool getNavigationName(const char* name, ResTable_config* out = NULL); static bool getScreenSizeName(const char* name, ResTable_config* out = NULL); + static bool getScreenLayoutName(const char* name, ResTable_config* out = NULL); static bool getVersionName(const char* name, ResTable_config* out = NULL); int compare(const AaptGroupEntry& o) const; diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index 503f66157e62f..e04491d93b863 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -329,6 +329,9 @@ enum { TARGET_SDK_VERSION_ATTR = 0x01010270, TEST_ONLY_ATTR = 0x01010272, DENSITY_ATTR = 0x0101026c, + SMALL_SCREEN_ATTR = 0x01010284, + NORMAL_SCREEN_ATTR = 0x01010285, + LARGE_SCREEN_ATTR = 0x01010286, }; const char *getComponentName(String8 &pkgName, String8 &componentName) { @@ -499,6 +502,10 @@ int doDump(Bundle* bundle) bool isLauncherActivity = false; bool withinApplication = false; bool withinReceiver = false; + int targetSdk = 0; + int smallScreen = 1; + int normalScreen = 1; + int largeScreen = 1; String8 pkg; String8 activityName; String8 activityLabel; @@ -572,8 +579,10 @@ int doDump(Bundle* bundle) error.string()); goto bail; } + if (name == "Donut") targetSdk = 4; printf("sdkVersion:'%s'\n", name.string()); } else if (code != -1) { + targetSdk = code; printf("sdkVersion:'%d'\n", code); } code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error); @@ -585,8 +594,12 @@ int doDump(Bundle* bundle) error.string()); goto bail; } + if (name == "Donut" && targetSdk < 4) targetSdk = 4; printf("targetSdkVersion:'%s'\n", name.string()); } else if (code != -1) { + if (targetSdk < code) { + targetSdk = code; + } printf("targetSdkVersion:'%d'\n", code); } } else if (tag == "uses-configuration") { @@ -625,6 +638,13 @@ int doDump(Bundle* bundle) goto bail; } printf("supports-density:'%d'\n", dens); + } else if (tag == "supports-screens") { + smallScreen = getIntegerAttribute(tree, + SMALL_SCREEN_ATTR, NULL, 1); + normalScreen = getIntegerAttribute(tree, + NORMAL_SCREEN_ATTR, NULL, 1); + largeScreen = getIntegerAttribute(tree, + LARGE_SCREEN_ATTR, NULL, 1); } } else if (depth == 3 && withinApplication) { withinActivity = false; @@ -733,6 +753,25 @@ int doDump(Bundle* bundle) } } + // Determine default values for any unspecified screen sizes, + // based on the target SDK of the package. As of 4 (donut) + // the screen size support was introduced, so all default to + // enabled. + if (smallScreen > 0) { + smallScreen = targetSdk >= 4 ? -1 : 0; + } + if (normalScreen > 0) { + normalScreen = -1; + } + if (largeScreen > 0) { + largeScreen = targetSdk >= 4 ? -1 : 0; + } + printf("supports-screens:"); + if (smallScreen != 0) printf(" 'small'"); + if (normalScreen != 0) printf(" 'normal'"); + if (largeScreen != 0) printf(" 'large'"); + printf("\n"); + printf("locales:"); Vector locales; res.getLocales(&locales); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java index 1fa11af3f2299..06dd96f8e6288 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java @@ -59,7 +59,7 @@ public class BridgeAssetManager extends AssetManager { public void setConfiguration(int mcc, int mnc, String locale, int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, int screenWidth, int screenHeight, - int version) { + int screenLayout, int version) { Configuration c = new Configuration(); c.mcc = mcc; @@ -70,5 +70,6 @@ public class BridgeAssetManager extends AssetManager { c.keyboardHidden = keyboardHidden; c.navigation = navigation; c.orientation = orientation; + c.screenLayout = screenLayout; } }