Loading core/java/android/app/ActivityThread.java +71 −5 Original line number Diff line number Diff line Loading @@ -161,7 +161,7 @@ public final class ActivityThread { return metrics; } Resources getTopLevelResources(String appDir) { Resources getTopLevelResources(String appDir, float applicationScale) { synchronized (mPackages) { //Log.w(TAG, "getTopLevelResources: " + appDir); WeakReference<Resources> wr = mActiveResources.get(appDir); Loading @@ -181,7 +181,27 @@ public final class ActivityThread { return null; } DisplayMetrics metrics = getDisplayMetricsLocked(false); r = new Resources(assets, metrics, getConfiguration()); // density used to load resources // scaledDensity is calculated in Resources constructor // boolean usePreloaded = true; // TODO: use explicit flag to indicate the compatibility mode. if (applicationScale != 1.0f) { usePreloaded = false; DisplayMetrics newMetrics = new DisplayMetrics(); newMetrics.setTo(metrics); float invertedScale = 1.0f / applicationScale; newMetrics.density *= invertedScale; newMetrics.xdpi *= invertedScale; newMetrics.ydpi *= invertedScale; newMetrics.widthPixels *= invertedScale; newMetrics.heightPixels *= invertedScale; metrics = newMetrics; } //Log.i(TAG, "Resource:" + appDir + ", density " + newMetrics.density + ", orig density:" + // metrics.density); r = new Resources(assets, metrics, getConfiguration(), usePreloaded); //Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration()); // XXX need to remove entries when weak references go away mActiveResources.put(appDir, new WeakReference<Resources>(r)); Loading Loading @@ -209,6 +229,8 @@ public final class ActivityThread { private Resources mResources; private ClassLoader mClassLoader; private Application mApplication; private float mApplicationScale; private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers = new HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>>(); private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mUnregisteredReceivers Loading Loading @@ -250,6 +272,8 @@ public final class ActivityThread { mClassLoader = mSystemContext.getClassLoader(); mResources = mSystemContext.getResources(); } mApplicationScale = -1.0f; } public PackageInfo(ActivityThread activityThread, String name, Loading @@ -268,6 +292,7 @@ public final class ActivityThread { mIncludeCode = true; mClassLoader = systemContext.getClassLoader(); mResources = systemContext.getResources(); mApplicationScale = systemContext.getApplicationScale(); } public String getPackageName() { Loading @@ -278,6 +303,47 @@ public final class ActivityThread { return mSecurityViolation; } public float getApplicationScale() { if (mApplicationScale > 0.0f) { return mApplicationScale; } DisplayMetrics metrics = mActivityThread.getDisplayMetricsLocked(false); // Find out the density scale (relative to 160) of the supported density that // is closest to the system's density. try { ApplicationInfo ai = getPackageManager().getApplicationInfo( mPackageName, PackageManager.GET_SUPPORTS_DENSITIES); float appScale = -1.0f; if (ai.supportsDensities != null) { // TODO: precompute this in DisplayMetrics float systemDensityDpi = metrics.density * DisplayMetrics.DEFAULT_DENSITY; int minDiff = Integer.MAX_VALUE; for (int density : ai.supportsDensities) { int tmpDiff = (int) Math.abs(systemDensityDpi - density); if (tmpDiff == 0) { appScale = 1.0f; break; } // prefer higher density (appScale>1.0), unless that's only option. if (tmpDiff < minDiff && appScale < 1.0f) { appScale = systemDensityDpi / density; minDiff = tmpDiff; } } } if (appScale < 0.0f) { mApplicationScale = metrics.density; } else { mApplicationScale = appScale; } } catch (RemoteException e) { throw new AssertionError(e); } if (localLOGV) Log.v(TAG, "appScale=" + mApplicationScale + ", pkg=" + mPackageName); return mApplicationScale; } /** * Gets the array of shared libraries that are listed as * used by the given package. Loading Loading @@ -435,7 +501,7 @@ public final class ActivityThread { public Resources getResources(ActivityThread mainThread) { if (mResources == null) { mResources = mainThread.getTopLevelResources(mResDir); mResources = mainThread.getTopLevelResources(mResDir, getApplicationScale()); } return mResources; } Loading core/java/android/app/ApplicationContext.java +16 −1 Original line number Diff line number Diff line Loading @@ -550,6 +550,19 @@ class ApplicationContext extends Context { } } /** * @hide */ @Override public float getApplicationScale() { if (mPackageInfo != null) { return mPackageInfo.getApplicationScale(); } else { // same as system density return 1.0f; } } @Override public void setWallpaper(Bitmap bitmap) throws IOException { try { Loading Loading @@ -2008,9 +2021,11 @@ class ApplicationContext extends Context { if (app.packageName.equals("system")) { return mContext.mMainThread.getSystemContext().getResources(); } ActivityThread.PackageInfo pi = mContext.mMainThread.getPackageInfoNoCheck(app); Resources r = mContext.mMainThread.getTopLevelResources( app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir); : app.publicSourceDir, pi.getApplicationScale()); if (r != null) { return r; } Loading core/java/android/content/Context.java +10 −0 Original line number Diff line number Diff line Loading @@ -526,6 +526,16 @@ public abstract class Context { */ public abstract int getWallpaperDesiredMinimumHeight(); /** * Returns the scale in which the application will be drawn on the * screen. This is usually 1.0f if the application supports the device's * resolution/density. This will be 1.5f, for example, if the application * that supports only 160 density runs on 240 density screen. * * @hide */ public abstract float getApplicationScale(); /** * Change the current system wallpaper to a bitmap. The given bitmap is * converted to a PNG and stored as the wallpaper. On success, the intent Loading core/java/android/content/ContextWrapper.java +8 −0 Original line number Diff line number Diff line Loading @@ -419,4 +419,12 @@ public class ContextWrapper extends Context { throws PackageManager.NameNotFoundException { return mBase.createPackageContext(packageName, flags); } /** * @hide */ @Override public float getApplicationScale() { return mBase.getApplicationScale(); } } core/java/android/content/res/Resources.java +39 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.graphics.Movie; import android.graphics.drawable.Drawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.os.SystemProperties; Loading Loading @@ -56,12 +57,14 @@ public class Resources { // Information about preloaded resources. Note that they are not // protected by a lock, because while preloading in zygote we are all // single-threaded, and after that these are immutable. private static final SparseArray<Drawable.ConstantState> mPreloadedDrawables private static final SparseArray<Drawable.ConstantState> sPreloadedDrawables = new SparseArray<Drawable.ConstantState>(); private static final SparseArray<ColorStateList> mPreloadedColorStateLists = new SparseArray<ColorStateList>(); private static boolean mPreloaded; private final SparseArray<Drawable.ConstantState> mPreloadedDrawables; /*package*/ final TypedValue mTmpValue = new TypedValue(); // These are protected by the mTmpValue lock. Loading @@ -82,6 +85,22 @@ public class Resources { /*package*/ final DisplayMetrics mMetrics = new DisplayMetrics(); PluralRules mPluralRule; private static final SparseArray<Object> EMPTY_ARRAY = new SparseArray<Object>() { @Override public void put(int k, Object o) { throw new UnsupportedOperationException(); } @Override public void append(int k, Object o) { throw new UnsupportedOperationException(); } }; @SuppressWarnings("unchecked") private static <T> SparseArray<T> emptySparseArray() { return (SparseArray<T>) EMPTY_ARRAY; } /** * This exception is thrown by the resource APIs when a requested resource * can not be found. Loading @@ -107,11 +126,27 @@ public class Resources { */ public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) { this(assets, metrics, config, true); } /** * Create a resource with an additional flag for preloaded * drawable cache. Used by {@link ActivityThread}. * * @hide */ public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config, boolean usePreloadedCache) { mAssets = assets; mConfiguration.setToDefaults(); mMetrics.setToDefaults(); updateConfiguration(config, metrics); assets.ensureStringBlocks(); if (usePreloadedCache) { mPreloadedDrawables = sPreloadedDrawables; } else { mPreloadedDrawables = emptySparseArray(); } } /** Loading Loading @@ -1218,6 +1253,7 @@ public class Resources { mMetrics.setTo(metrics); } mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; String locale = null; if (mConfiguration.locale != null) { locale = mConfiguration.locale.getLanguage(); Loading Loading @@ -1653,7 +1689,7 @@ public class Resources { cs = dr.getConstantState(); if (cs != null) { if (mPreloading) { mPreloadedDrawables.put(key, cs); sPreloadedDrawables.put(key, cs); } else { synchronized (mTmpValue) { //Log.i(TAG, "Saving cached drawable @ #" + Loading Loading @@ -1883,6 +1919,6 @@ public class Resources { mMetrics.setToDefaults(); updateConfiguration(null, null); mAssets.ensureStringBlocks(); mPreloadedDrawables = sPreloadedDrawables; } } Loading
core/java/android/app/ActivityThread.java +71 −5 Original line number Diff line number Diff line Loading @@ -161,7 +161,7 @@ public final class ActivityThread { return metrics; } Resources getTopLevelResources(String appDir) { Resources getTopLevelResources(String appDir, float applicationScale) { synchronized (mPackages) { //Log.w(TAG, "getTopLevelResources: " + appDir); WeakReference<Resources> wr = mActiveResources.get(appDir); Loading @@ -181,7 +181,27 @@ public final class ActivityThread { return null; } DisplayMetrics metrics = getDisplayMetricsLocked(false); r = new Resources(assets, metrics, getConfiguration()); // density used to load resources // scaledDensity is calculated in Resources constructor // boolean usePreloaded = true; // TODO: use explicit flag to indicate the compatibility mode. if (applicationScale != 1.0f) { usePreloaded = false; DisplayMetrics newMetrics = new DisplayMetrics(); newMetrics.setTo(metrics); float invertedScale = 1.0f / applicationScale; newMetrics.density *= invertedScale; newMetrics.xdpi *= invertedScale; newMetrics.ydpi *= invertedScale; newMetrics.widthPixels *= invertedScale; newMetrics.heightPixels *= invertedScale; metrics = newMetrics; } //Log.i(TAG, "Resource:" + appDir + ", density " + newMetrics.density + ", orig density:" + // metrics.density); r = new Resources(assets, metrics, getConfiguration(), usePreloaded); //Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration()); // XXX need to remove entries when weak references go away mActiveResources.put(appDir, new WeakReference<Resources>(r)); Loading Loading @@ -209,6 +229,8 @@ public final class ActivityThread { private Resources mResources; private ClassLoader mClassLoader; private Application mApplication; private float mApplicationScale; private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers = new HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>>(); private final HashMap<Context, HashMap<BroadcastReceiver, ReceiverDispatcher>> mUnregisteredReceivers Loading Loading @@ -250,6 +272,8 @@ public final class ActivityThread { mClassLoader = mSystemContext.getClassLoader(); mResources = mSystemContext.getResources(); } mApplicationScale = -1.0f; } public PackageInfo(ActivityThread activityThread, String name, Loading @@ -268,6 +292,7 @@ public final class ActivityThread { mIncludeCode = true; mClassLoader = systemContext.getClassLoader(); mResources = systemContext.getResources(); mApplicationScale = systemContext.getApplicationScale(); } public String getPackageName() { Loading @@ -278,6 +303,47 @@ public final class ActivityThread { return mSecurityViolation; } public float getApplicationScale() { if (mApplicationScale > 0.0f) { return mApplicationScale; } DisplayMetrics metrics = mActivityThread.getDisplayMetricsLocked(false); // Find out the density scale (relative to 160) of the supported density that // is closest to the system's density. try { ApplicationInfo ai = getPackageManager().getApplicationInfo( mPackageName, PackageManager.GET_SUPPORTS_DENSITIES); float appScale = -1.0f; if (ai.supportsDensities != null) { // TODO: precompute this in DisplayMetrics float systemDensityDpi = metrics.density * DisplayMetrics.DEFAULT_DENSITY; int minDiff = Integer.MAX_VALUE; for (int density : ai.supportsDensities) { int tmpDiff = (int) Math.abs(systemDensityDpi - density); if (tmpDiff == 0) { appScale = 1.0f; break; } // prefer higher density (appScale>1.0), unless that's only option. if (tmpDiff < minDiff && appScale < 1.0f) { appScale = systemDensityDpi / density; minDiff = tmpDiff; } } } if (appScale < 0.0f) { mApplicationScale = metrics.density; } else { mApplicationScale = appScale; } } catch (RemoteException e) { throw new AssertionError(e); } if (localLOGV) Log.v(TAG, "appScale=" + mApplicationScale + ", pkg=" + mPackageName); return mApplicationScale; } /** * Gets the array of shared libraries that are listed as * used by the given package. Loading Loading @@ -435,7 +501,7 @@ public final class ActivityThread { public Resources getResources(ActivityThread mainThread) { if (mResources == null) { mResources = mainThread.getTopLevelResources(mResDir); mResources = mainThread.getTopLevelResources(mResDir, getApplicationScale()); } return mResources; } Loading
core/java/android/app/ApplicationContext.java +16 −1 Original line number Diff line number Diff line Loading @@ -550,6 +550,19 @@ class ApplicationContext extends Context { } } /** * @hide */ @Override public float getApplicationScale() { if (mPackageInfo != null) { return mPackageInfo.getApplicationScale(); } else { // same as system density return 1.0f; } } @Override public void setWallpaper(Bitmap bitmap) throws IOException { try { Loading Loading @@ -2008,9 +2021,11 @@ class ApplicationContext extends Context { if (app.packageName.equals("system")) { return mContext.mMainThread.getSystemContext().getResources(); } ActivityThread.PackageInfo pi = mContext.mMainThread.getPackageInfoNoCheck(app); Resources r = mContext.mMainThread.getTopLevelResources( app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir); : app.publicSourceDir, pi.getApplicationScale()); if (r != null) { return r; } Loading
core/java/android/content/Context.java +10 −0 Original line number Diff line number Diff line Loading @@ -526,6 +526,16 @@ public abstract class Context { */ public abstract int getWallpaperDesiredMinimumHeight(); /** * Returns the scale in which the application will be drawn on the * screen. This is usually 1.0f if the application supports the device's * resolution/density. This will be 1.5f, for example, if the application * that supports only 160 density runs on 240 density screen. * * @hide */ public abstract float getApplicationScale(); /** * Change the current system wallpaper to a bitmap. The given bitmap is * converted to a PNG and stored as the wallpaper. On success, the intent Loading
core/java/android/content/ContextWrapper.java +8 −0 Original line number Diff line number Diff line Loading @@ -419,4 +419,12 @@ public class ContextWrapper extends Context { throws PackageManager.NameNotFoundException { return mBase.createPackageContext(packageName, flags); } /** * @hide */ @Override public float getApplicationScale() { return mBase.getApplicationScale(); } }
core/java/android/content/res/Resources.java +39 −3 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import org.xmlpull.v1.XmlPullParserException; import android.graphics.Movie; import android.graphics.drawable.Drawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.os.SystemProperties; Loading Loading @@ -56,12 +57,14 @@ public class Resources { // Information about preloaded resources. Note that they are not // protected by a lock, because while preloading in zygote we are all // single-threaded, and after that these are immutable. private static final SparseArray<Drawable.ConstantState> mPreloadedDrawables private static final SparseArray<Drawable.ConstantState> sPreloadedDrawables = new SparseArray<Drawable.ConstantState>(); private static final SparseArray<ColorStateList> mPreloadedColorStateLists = new SparseArray<ColorStateList>(); private static boolean mPreloaded; private final SparseArray<Drawable.ConstantState> mPreloadedDrawables; /*package*/ final TypedValue mTmpValue = new TypedValue(); // These are protected by the mTmpValue lock. Loading @@ -82,6 +85,22 @@ public class Resources { /*package*/ final DisplayMetrics mMetrics = new DisplayMetrics(); PluralRules mPluralRule; private static final SparseArray<Object> EMPTY_ARRAY = new SparseArray<Object>() { @Override public void put(int k, Object o) { throw new UnsupportedOperationException(); } @Override public void append(int k, Object o) { throw new UnsupportedOperationException(); } }; @SuppressWarnings("unchecked") private static <T> SparseArray<T> emptySparseArray() { return (SparseArray<T>) EMPTY_ARRAY; } /** * This exception is thrown by the resource APIs when a requested resource * can not be found. Loading @@ -107,11 +126,27 @@ public class Resources { */ public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) { this(assets, metrics, config, true); } /** * Create a resource with an additional flag for preloaded * drawable cache. Used by {@link ActivityThread}. * * @hide */ public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config, boolean usePreloadedCache) { mAssets = assets; mConfiguration.setToDefaults(); mMetrics.setToDefaults(); updateConfiguration(config, metrics); assets.ensureStringBlocks(); if (usePreloadedCache) { mPreloadedDrawables = sPreloadedDrawables; } else { mPreloadedDrawables = emptySparseArray(); } } /** Loading Loading @@ -1218,6 +1253,7 @@ public class Resources { mMetrics.setTo(metrics); } mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale; String locale = null; if (mConfiguration.locale != null) { locale = mConfiguration.locale.getLanguage(); Loading Loading @@ -1653,7 +1689,7 @@ public class Resources { cs = dr.getConstantState(); if (cs != null) { if (mPreloading) { mPreloadedDrawables.put(key, cs); sPreloadedDrawables.put(key, cs); } else { synchronized (mTmpValue) { //Log.i(TAG, "Saving cached drawable @ #" + Loading Loading @@ -1883,6 +1919,6 @@ public class Resources { mMetrics.setToDefaults(); updateConfiguration(null, null); mAssets.ensureStringBlocks(); mPreloadedDrawables = sPreloadedDrawables; } }