* Moved supports-density tag under manifest

* Refactored Compatibility code
  * Added CompatibilityInfo class
  * Removed getApplicationScale from Context
  * Added Resources#getCompatibilityInfo so that RootView can get the compatibility info w/o going through Context
* Expandable support
  * Added expandable tag under manifest
  * Old application w/o expandable is given the default screen size  ([320, 480] x density).
  * The non-expandable window is centered.
This commit is contained in:
Mitsuru Oshima
2009-06-03 11:19:12 -07:00
parent eaeb663bcd
commit 9189cabb0b
17 changed files with 412 additions and 246 deletions

View File

@ -34943,6 +34943,16 @@
visibility="public"
>
</field>
<field name="expandable"
type="boolean"
transient="false"
volatile="false"
static="false"
final="false"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="flags"
type="int"
transient="false"
@ -36787,6 +36797,17 @@
visibility="public"
>
</field>
<field name="GET_EXPANDABLE"
type="int"
transient="false"
volatile="false"
value="131072"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="GET_GIDS"
type="int"
transient="false"

View File

@ -162,7 +162,7 @@ public final class ActivityThread {
return metrics;
}
Resources getTopLevelResources(String appDir, float applicationScale) {
Resources getTopLevelResources(String appDir, PackageInfo pkgInfo) {
synchronized (mPackages) {
//Log.w(TAG, "getTopLevelResources: " + appDir);
WeakReference<Resources> wr = mActiveResources.get(appDir);
@ -181,23 +181,17 @@ public final class ActivityThread {
if (assets.addAssetPath(appDir) == 0) {
return null;
}
DisplayMetrics metrics = getDisplayMetricsLocked(false);
// 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 newDensity = metrics.density / applicationScale;
newMetrics.updateDensity(newDensity);
metrics = newMetrics;
ApplicationInfo appInfo;
try {
appInfo = getPackageManager().getApplicationInfo(
pkgInfo.getPackageName(),
PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE);
} catch (RemoteException e) {
throw new AssertionError(e);
}
//Log.i(TAG, "Resource:" + appDir + ", display metrics=" + metrics);
r = new Resources(assets, metrics, getConfiguration(), usePreloaded);
DisplayMetrics metrics = getDisplayMetricsLocked(false);
r = new Resources(assets, metrics, getConfiguration(), appInfo);
//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));
@ -225,7 +219,6 @@ 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>>();
@ -268,8 +261,6 @@ public final class ActivityThread {
mClassLoader = mSystemContext.getClassLoader();
mResources = mSystemContext.getResources();
}
mApplicationScale = -1.0f;
}
public PackageInfo(ActivityThread activityThread, String name,
@ -288,7 +279,6 @@ public final class ActivityThread {
mIncludeCode = true;
mClassLoader = systemContext.getClassLoader();
mResources = systemContext.getResources();
mApplicationScale = systemContext.getApplicationScale();
}
public String getPackageName() {
@ -299,45 +289,6 @@ 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) {
int minDiff = Integer.MAX_VALUE;
for (int density : ai.supportsDensities) {
int tmpDiff = (int) Math.abs(DisplayMetrics.DEVICE_DENSITY - 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 = DisplayMetrics.DEVICE_DENSITY / 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.
@ -495,7 +446,7 @@ public final class ActivityThread {
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
mResources = mainThread.getTopLevelResources(mResDir, getApplicationScale());
mResources = mainThread.getTopLevelResources(mResDir, this);
}
return mResources;
}
@ -3606,8 +3557,6 @@ public final class ActivityThread {
}
mConfiguration.updateFrom(config);
DisplayMetrics dm = getDisplayMetricsLocked(true);
DisplayMetrics appDm = new DisplayMetrics();
appDm.setTo(dm);
// set it for java, this also affects newly created Resources
if (config.locale != null) {
@ -3627,11 +3576,7 @@ public final class ActivityThread {
WeakReference<Resources> v = it.next();
Resources r = v.get();
if (r != null) {
// keep the original density based on application cale.
appDm.updateDensity(r.getDisplayMetrics().density);
r.updateConfiguration(config, appDm);
// reset
appDm.setTo(dm);
r.updateConfiguration(config, dm);
//Log.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
} else {

View File

@ -551,19 +551,6 @@ 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 {
@ -2028,8 +2015,7 @@ class ApplicationContext extends Context {
ActivityThread.PackageInfo pi = mContext.mMainThread.getPackageInfoNoCheck(app);
Resources r = mContext.mMainThread.getTopLevelResources(
app.uid == Process.myUid() ? app.sourceDir
: app.publicSourceDir,
pi.getApplicationScale());
: app.publicSourceDir, pi);
if (r != null) {
return r;
}

View File

@ -526,16 +526,6 @@ 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

View File

@ -419,12 +419,4 @@ public class ContextWrapper extends Context {
throws PackageManager.NameNotFoundException {
return mBase.createPackageContext(packageName, flags);
}
/**
* @hide
*/
@Override
public float getApplicationScale() {
return mBase.getApplicationScale();
}
}

View File

@ -186,7 +186,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public int uid;
/**
* The list of densities in DPI that application supprots. This
* field is only set if the {@link PackageManager#GET_SUPPORTS_DENSITIES} flag was
@ -194,6 +193,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public int[] supportsDensities;
/**
* True when the application's window can be expanded over default window
* size in target density (320x480 for 1.0 density, 480x720 for 1.5 density etc)
*/
public boolean expandable = false;
/**
* The minimum SDK version this application targets. It may run on earilier
* versions, but it knows how to work with any new behavior added at this
@ -228,6 +233,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName);
pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes));
pw.println(prefix + "supportsDensities=" + supportsDensities);
pw.println(prefix + "expandable=" + expandable);
super.dumpBack(pw, prefix);
}
@ -275,6 +281,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
manageSpaceActivityName = orig.manageSpaceActivityName;
descriptionRes = orig.descriptionRes;
supportsDensities = orig.supportsDensities;
expandable = orig.expandable;
}
@ -307,6 +314,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeString(backupAgentName);
dest.writeInt(descriptionRes);
dest.writeIntArray(supportsDensities);
dest.writeInt(expandable ? 1 : 0);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
@ -338,6 +346,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
backupAgentName = source.readString();
descriptionRes = source.readInt();
supportsDensities = source.createIntArray();
expandable = source.readInt() != 0;
}
/**

View File

@ -179,6 +179,12 @@ public abstract class PackageManager {
*/
public static final int MATCH_DEFAULT_ONLY = 0x00010000;
/**
* {@link ApplicationInfo} flag: return the
* {link ApplicationInfo#expandable} boolean flag of the package.
*/
public static final int GET_EXPANDABLE = 0x00020000;
/**
* Permission check result: this is returned by {@link #checkPermission}
* if the permission has been granted to the given package.

View File

@ -835,6 +835,26 @@ public class PackageParser {
+ parser.getName();
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return null;
} else if (tagName.equals("supports-density")) {
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestSupportsDensity);
int density = sa.getInteger(
com.android.internal.R.styleable.AndroidManifestSupportsDensity_density, -1);
sa.recycle();
if (density != -1 && !pkg.supportsDensityList.contains(density)) {
pkg.supportsDensityList.add(density);
}
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("expandable")) {
pkg.expandable = true;
XmlUtils.skipCurrentTag(parser);
} else {
Log.w(TAG, "Bad element under <manifest>: "
+ parser.getName());
@ -866,7 +886,8 @@ 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
int size = pkg.supportsDensityList.size();
if (size > 0) {
int densities[] = pkg.supportsDensities = new int[size];
@ -1345,21 +1366,6 @@ public class PackageParser {
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("supports-density")) {
sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestSupportsDensity);
int density = sa.getInteger(
com.android.internal.R.styleable.AndroidManifestSupportsDensity_density, -1);
sa.recycle();
if (density != -1 && !owner.supportsDensityList.contains(density)) {
owner.supportsDensityList.add(density);
}
XmlUtils.skipCurrentTag(parser);
} else {
if (!RIGID_PARSER) {
Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
@ -2244,6 +2250,9 @@ public class PackageParser {
public final ArrayList<Integer> supportsDensityList = new ArrayList<Integer>();
public int[] supportsDensities = null;
// If the application's window is expandable.
public boolean expandable;
// If this is a 3rd party app, this is the path of the zip file.
public String mPath;
@ -2415,7 +2424,10 @@ public class PackageParser {
return true;
}
if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0
&& p.supportsDensities != null) {
&& p.supportsDensities != null) {
return true;
}
if ((flags & PackageManager.GET_EXPANDABLE) != 0) {
return true;
}
return false;
@ -2438,6 +2450,9 @@ public class PackageParser {
if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0) {
ai.supportsDensities = p.supportsDensities;
}
if ((flags & PackageManager.GET_EXPANDABLE) != 0) {
ai.expandable = p.expandable;
}
return ai;
}

View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.res;
import android.content.pm.ApplicationInfo;
import android.util.DisplayMetrics;
import android.view.Gravity;
/**
* CompatibilityInfo class keeps the information about compatibility mode that the application is
* running under.
*
* {@hide}
*/
public class CompatibilityInfo {
/** default compatibility info object for compatible applications */
public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = new CompatibilityInfo();
/**
* The default width of the screen in portrait mode.
*/
public static final int DEFAULT_PORTRAIT_WIDTH = 320;
/**
* The default height of the screen in portrait mode.
*/
public static final int DEFAULT_PORTRAIT_HEIGHT = 480;
/**
* Application's scale.
*/
public final float mApplicationScale;
/**
* Application's inverted scale.
*/
public final float mApplicationInvertedScale;
/**
*
* A boolean flag to indicates that the application can expand over the original size.
*/
public final boolean mExpandable;
/**
* A boolean flag to tell if the application needs scaling (when mApplicationScale != 1.0f)
*/
public final boolean mScalingRequired;
public CompatibilityInfo(ApplicationInfo appInfo) {
mExpandable = appInfo.expandable;
float packageDensityScale = -1.0f;
if (appInfo.supportsDensities != null) {
int minDiff = Integer.MAX_VALUE;
for (int density : appInfo.supportsDensities) {
int tmpDiff = Math.abs(DisplayMetrics.DEVICE_DENSITY - density);
if (tmpDiff == 0) {
packageDensityScale = 1.0f;
break;
}
// prefer higher density (appScale>1.0), unless that's only option.
if (tmpDiff < minDiff && packageDensityScale < 1.0f) {
packageDensityScale = DisplayMetrics.DEVICE_DENSITY / (float) density;
minDiff = tmpDiff;
}
}
}
if (packageDensityScale > 0.0f) {
mApplicationScale = packageDensityScale;
} else {
mApplicationScale = DisplayMetrics.DEVICE_DENSITY / (float) DisplayMetrics.DEFAULT_DENSITY;
}
mApplicationInvertedScale = 1.0f / mApplicationScale;
mScalingRequired = mApplicationScale != 1.0f;
}
private CompatibilityInfo() {
mApplicationScale = mApplicationInvertedScale = 1.0f;
mExpandable = true;
mScalingRequired = false;
}
@Override
public String toString() {
return "CompatibilityInfo{scale=" + mApplicationScale +
", expandable=" + mExpandable + "}";
}
}

View File

@ -22,6 +22,8 @@ import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.app.ActivityThread.PackageInfo;
import android.content.pm.ApplicationInfo;
import android.graphics.Movie;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
@ -84,7 +86,9 @@ public class Resources {
private final Configuration mConfiguration = new Configuration();
/*package*/ final DisplayMetrics mMetrics = new DisplayMetrics();
PluralRules mPluralRule;
private final CompatibilityInfo mCompatibilityInfo;
private static final SparseArray<Object> EMPTY_ARRAY = new SparseArray<Object>() {
@Override
public void put(int k, Object o) {
@ -126,23 +130,36 @@ public class Resources {
*/
public Resources(AssetManager assets, DisplayMetrics metrics,
Configuration config) {
this(assets, metrics, config, true);
this(assets, metrics, config, null);
}
/**
* Create a resource with an additional flag for preloaded
* drawable cache. Used by {@link ActivityThread}.
*
* Creates a new Resources object with ApplicationInfo.
*
* @param assets Previously created AssetManager.
* @param metrics Current display metrics to consider when
* selecting/computing resource values.
* @param config Desired device configuration to consider when
* selecting/computing resource values (optional).
* @param appInfo this resource's application info.
* @hide
*/
public Resources(AssetManager assets, DisplayMetrics metrics,
Configuration config, boolean usePreloadedCache) {
Configuration config, ApplicationInfo appInfo) {
mAssets = assets;
mConfiguration.setToDefaults();
mMetrics.setToDefaults();
if (appInfo != null) {
mCompatibilityInfo = new CompatibilityInfo(appInfo);
if (DEBUG_CONFIG) {
Log.d(TAG, "compatibility for " + appInfo.packageName + " : " + mCompatibilityInfo);
}
} else {
mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
}
updateConfiguration(config, metrics);
assets.ensureStringBlocks();
if (usePreloadedCache) {
if (!mCompatibilityInfo.mScalingRequired) {
mPreloadedDrawables = sPreloadedDrawables;
} else {
mPreloadedDrawables = emptySparseArray();
@ -1251,6 +1268,7 @@ public class Resources {
}
if (metrics != null) {
mMetrics.setTo(metrics);
mMetrics.updateMetrics(mCompatibilityInfo, mConfiguration);
}
mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
@ -1356,6 +1374,17 @@ public class Resources {
public Configuration getConfiguration() {
return mConfiguration;
}
/**
* Return the compatibility mode information for the application.
* The returned object should be treated as read-only.
*
* @return compatibility info. null if the app does not require compatibility mode.
* @hide
*/
public CompatibilityInfo getCompatibilityInfo() {
return mCompatibilityInfo;
}
/**
* Return a resource identifier for the given resource name. A fully
@ -1920,5 +1949,6 @@ public class Resources {
updateConfiguration(null, null);
mAssets.ensureStringBlocks();
mPreloadedDrawables = sPreloadedDrawables;
mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
}
}

View File

@ -16,6 +16,8 @@
package android.util;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.*;
@ -101,17 +103,46 @@ public class DisplayMetrics {
}
/**
* Set the display metrics' density and update parameters depend on it.
* @hide
* Update the display metrics based on the compatibility info and configuration.
* {@hide}
*/
public void updateDensity(float newDensity) {
float ratio = newDensity / density;
density = newDensity;
scaledDensity = density;
widthPixels *= ratio;
heightPixels *= ratio;
xdpi *= ratio;
ydpi *= ratio;
public void updateMetrics(CompatibilityInfo compatibilityInfo, Configuration configuration) {
if (compatibilityInfo.mScalingRequired) {
float invertedRatio = compatibilityInfo.mApplicationInvertedScale;
density *= invertedRatio;
scaledDensity *= invertedRatio;
xdpi *= invertedRatio;
ydpi *= invertedRatio;
widthPixels *= invertedRatio;
heightPixels *= invertedRatio;
}
if (!compatibilityInfo.mExpandable) {
// Note: this assume that configuration is updated before calling
// updateMetrics method.
int defaultWidth;
int defaultHeight;
switch (configuration.orientation) {
case Configuration.ORIENTATION_LANDSCAPE: {
defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
break;
}
case Configuration.ORIENTATION_UNDEFINED:
case Configuration.ORIENTATION_PORTRAIT:
case Configuration.ORIENTATION_SQUARE:
default: {
defaultWidth = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_WIDTH * density);
defaultHeight = (int)(CompatibilityInfo.DEFAULT_PORTRAIT_HEIGHT * density);
}
}
// adjust the size only when the device's screen is bigger.
if (defaultWidth < widthPixels) {
widthPixels = defaultWidth;
}
if (defaultHeight < heightPixels) {
heightPixels = defaultHeight;
}
}
}
public String toString() {

View File

@ -17,6 +17,7 @@
package android.view;
import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
@ -137,28 +138,24 @@ public class SurfaceView extends View {
int mFormat = -1;
int mType = -1;
final Rect mSurfaceFrame = new Rect();
private final float mAppScale;
private final float mAppScaleInverted;
private final CompatibilityInfo mCompatibilityInfo;
public SurfaceView(Context context) {
super(context);
setWillNotDraw(true);
mAppScale = context.getApplicationScale();
mAppScaleInverted = 1.0f / mAppScale;
mCompatibilityInfo = context.getResources().getCompatibilityInfo();
}
public SurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(true);
mAppScale = context.getApplicationScale();
mAppScaleInverted = 1.0f / mAppScale;
mCompatibilityInfo = context.getResources().getCompatibilityInfo();
}
public SurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setWillNotDraw(true);
mAppScale = context.getApplicationScale();
mAppScaleInverted = 1.0f / mAppScale;
mCompatibilityInfo = context.getResources().getCompatibilityInfo();
}
/**
@ -261,9 +258,9 @@ public class SurfaceView extends View {
public boolean dispatchTouchEvent(MotionEvent event) {
// SurfaceView uses pre-scaled size unless fixed size is requested. This hook
// scales the event back to the pre-scaled coordinates for such surface.
if (mRequestedWidth < 0 && mAppScale != 1.0f) {
if (mRequestedWidth < 0 && mCompatibilityInfo.mScalingRequired) {
MotionEvent scaledBack = MotionEvent.obtain(event);
scaledBack.scale(mAppScale);
scaledBack.scale(mCompatibilityInfo.mApplicationScale);
try {
return super.dispatchTouchEvent(scaledBack);
} finally {
@ -300,6 +297,7 @@ public class SurfaceView extends View {
if (!mHaveFrame) {
return;
}
float appScale = mCompatibilityInfo.mApplicationScale;
int myWidth = mRequestedWidth;
if (myWidth <= 0) myWidth = getWidth();
@ -307,9 +305,9 @@ public class SurfaceView extends View {
if (myHeight <= 0) myHeight = getHeight();
// Use original size for surface unless fixed size is requested.
if (mRequestedWidth <= 0) {
myWidth *= mAppScale;
myHeight *= mAppScale;
if (mRequestedWidth <= 0 && mCompatibilityInfo.mScalingRequired) {
myWidth *= appScale;
myHeight *= appScale;
}
getLocationInWindow(mLocation);
@ -337,11 +335,11 @@ public class SurfaceView extends View {
mFormat = mRequestedFormat;
mType = mRequestedType;
// Scaling window's layout here beause mLayout is not used elsewhere.
mLayout.x = (int) (mLeft * mAppScale);
mLayout.y = (int) (mTop * mAppScale);
mLayout.width = (int) (getWidth() * mAppScale);
mLayout.height = (int) (getHeight() * mAppScale);
// Scaling window's layout here because mLayout is not used elsewhere.
mLayout.x = (int) (mLeft * appScale);
mLayout.y = (int) (mTop * appScale);
mLayout.width = (int) (getWidth() * appScale);
mLayout.height = (int) (getHeight() * appScale);
mLayout.format = mRequestedFormat;
mLayout.flags |=WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_SCALED
@ -367,14 +365,18 @@ public class SurfaceView extends View {
mSurfaceLock.lock();
mDrawingStopped = !visible;
final int relayoutResult = mSession.relayout(
mWindow, mLayout, mWidth, mHeight,
visible ? VISIBLE : GONE, false, mWinFrame, mContentInsets,
mVisibleInsets, mSurface);
mContentInsets.scale(mAppScaleInverted);
mVisibleInsets.scale(mAppScaleInverted);
mWinFrame.scale(mAppScaleInverted);
if (mCompatibilityInfo.mScalingRequired) {
float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
mContentInsets.scale(invertedScale);
mVisibleInsets.scale(invertedScale);
mWinFrame.scale(invertedScale);
}
if (localLOGV) Log.i(TAG, "New surface: " + mSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
@ -444,23 +446,23 @@ public class SurfaceView extends View {
private static class MyWindow extends IWindow.Stub {
private final WeakReference<SurfaceView> mSurfaceView;
private final float mAppScale;
private final float mAppScaleInverted;
private final CompatibilityInfo mCompatibilityInfo;
public MyWindow(SurfaceView surfaceView) {
mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
mAppScale = surfaceView.getContext().getApplicationScale();
mAppScaleInverted = 1.0f / mAppScale;
mCompatibilityInfo = surfaceView.getContext().getResources().getCompatibilityInfo();
}
public void resized(int w, int h, Rect coveredInsets,
Rect visibleInsets, boolean reportDraw) {
SurfaceView surfaceView = mSurfaceView.get();
float scale = mAppScaleInverted;
w *= scale;
h *= scale;
coveredInsets.scale(scale);
visibleInsets.scale(scale);
if (mCompatibilityInfo.mScalingRequired) {
float scale = mCompatibilityInfo.mApplicationInvertedScale;
w *= scale;
h *= scale;
coveredInsets.scale(scale);
visibleInsets.scale(scale);
}
if (surfaceView != null) {
if (localLOGV) Log.v(
@ -624,7 +626,9 @@ public class SurfaceView extends View {
Canvas c = null;
if (!mDrawingStopped && mWindow != null) {
Rect frame = dirty != null ? dirty : mSurfaceFrame;
frame.scale(mAppScale);
if (mCompatibilityInfo.mScalingRequired) {
frame.scale(mCompatibilityInfo.mApplicationScale);
}
try {
c = mSurface.lockCanvas(frame);
} catch (Exception e) {

View File

@ -30,6 +30,7 @@ import android.os.Process;
import android.os.SystemProperties;
import android.util.AndroidRuntimeException;
import android.util.Config;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.EventLog;
import android.util.SparseArray;
@ -40,6 +41,7 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.Context;
import android.app.ActivityManagerNative;
import android.Manifest;
@ -125,9 +127,8 @@ public final class ViewRoot extends Handler implements ViewParent,
int mHeight;
Rect mDirty; // will be a graphics.Region soon
boolean mIsAnimating;
// TODO: change these to scalar class.
private float mAppScale;
private float mAppScaleInverted; // = 1.0f / mAppScale
private CompatibilityInfo mCompatibilityInfo;
private int[] mWindowLayoutParamsBackup = null;
final View.AttachInfo mAttachInfo;
@ -386,12 +387,15 @@ public final class ViewRoot extends Handler implements ViewParent,
synchronized (this) {
if (mView == null) {
mView = view;
mAppScale = mView.getContext().getApplicationScale();
if (mAppScale != 1.0f) {
mWindowAttributes.copyFrom(attrs);
mCompatibilityInfo =
mView.getContext().getResources().getCompatibilityInfo();
if (mCompatibilityInfo.mScalingRequired) {
mWindowLayoutParamsBackup = new int[4];
}
mAppScaleInverted = 1.0f / mAppScale;
mWindowAttributes.copyFrom(attrs);
if (!mCompatibilityInfo.mExpandable) {
adjustWindowAttributesForCompatibleMode(mWindowAttributes);
}
mSoftInputMode = attrs.softInputMode;
mWindowAttributesChanged = true;
mAttachInfo.mRootView = view;
@ -406,9 +410,8 @@ public final class ViewRoot extends Handler implements ViewParent,
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
try {
res = sWindowSession.add(mWindow, attrs,
res = sWindowSession.add(mWindow, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets);
} catch (RemoteException e) {
mAdded = false;
@ -417,7 +420,10 @@ public final class ViewRoot extends Handler implements ViewParent,
unscheduleTraversals();
throw new RuntimeException("Adding window failed", e);
}
mAttachInfo.mContentInsets.scale(mAppScaleInverted);
if (mCompatibilityInfo.mScalingRequired) {
mAttachInfo.mContentInsets.scale(
mCompatibilityInfo.mApplicationInvertedScale);
}
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
if (Config.LOGV) Log.v("ViewRoot", "Added window " + mWindow);
@ -529,13 +535,13 @@ public final class ViewRoot extends Handler implements ViewParent,
public void invalidateChild(View child, Rect dirty) {
checkThread();
if (LOCAL_LOGV) Log.v(TAG, "Invalidate child: " + dirty);
if (mCurScrollY != 0 || mAppScale != 1.0f) {
if (mCurScrollY != 0 || mCompatibilityInfo.mScalingRequired) {
mTempRect.set(dirty);
if (mCurScrollY != 0) {
mTempRect.offset(0, -mCurScrollY);
}
if (mAppScale != 1.0f) {
mTempRect.scale(mAppScale);
if (mCompatibilityInfo.mScalingRequired) {
mTempRect.scale(mCompatibilityInfo.mApplicationScale);
}
dirty = mTempRect;
}
@ -615,6 +621,8 @@ public final class ViewRoot extends Handler implements ViewParent,
boolean viewVisibilityChanged = mViewVisibility != viewVisibility
|| mNewSurfaceNeeded;
float appScale = mCompatibilityInfo.mApplicationScale;
WindowManager.LayoutParams params = null;
if (mWindowAttributesChanged) {
mWindowAttributesChanged = false;
@ -625,9 +633,10 @@ public final class ViewRoot extends Handler implements ViewParent,
fullRedrawNeeded = true;
mLayoutRequested = true;
Display d = new Display(0);
desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
DisplayMetrics packageMetrics =
mView.getContext().getResources().getDisplayMetrics();
desiredWindowWidth = packageMetrics.widthPixels;
desiredWindowHeight = packageMetrics.heightPixels;
// For the very first time, tell the view hierarchy that it
// is attached to the window. Note that at this point the surface
@ -696,9 +705,10 @@ public final class ViewRoot extends Handler implements ViewParent,
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
windowResizesToFitContent = true;
Display d = new Display(0);
desiredWindowWidth = (int) (d.getWidth() * mAppScaleInverted);
desiredWindowHeight = (int) (d.getHeight() * mAppScaleInverted);
DisplayMetrics packageMetrics =
mView.getContext().getResources().getDisplayMetrics();
desiredWindowWidth = packageMetrics.widthPixels;
desiredWindowHeight = packageMetrics.heightPixels;
}
}
@ -878,7 +888,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mHeight = frame.height();
if (initialized) {
mGlCanvas.setViewport((int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
mGlCanvas.setViewport((int) (mWidth * appScale), (int) (mHeight * appScale));
}
boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
@ -968,11 +978,7 @@ public final class ViewRoot extends Handler implements ViewParent,
mTmpLocation[1] + host.mBottom - host.mTop);
host.gatherTransparentRegion(mTransparentRegion);
// TODO: scale the region, like:
// Region uses native methods. We probabl should have ScalableRegion class.
// Region does not have equals method ?
mTransparentRegion.scale(appScale);
if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
mPreviousTransparentRegion.set(mTransparentRegion);
// reconfigure window manager
@ -983,7 +989,6 @@ public final class ViewRoot extends Handler implements ViewParent,
}
}
if (DBG) {
System.out.println("======================================");
System.out.println("performTraversals -- after setFrame");
@ -1003,10 +1008,11 @@ public final class ViewRoot extends Handler implements ViewParent,
givenContent.left = givenContent.top = givenContent.right
= givenContent.bottom = givenVisible.left = givenVisible.top
= givenVisible.right = givenVisible.bottom = 0;
insets.contentInsets.scale(mAppScale);
insets.visibleInsets.scale(mAppScale);
attachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
if (mCompatibilityInfo.mScalingRequired) {
insets.contentInsets.scale(appScale);
insets.visibleInsets.scale(appScale);
}
if (insetsPending || !mLastGivenInsets.equals(insets)) {
mLastGivenInsets.set(insets);
try {
@ -1154,6 +1160,8 @@ public final class ViewRoot extends Handler implements ViewParent,
mCurScrollY = yoff;
fullRedrawNeeded = true;
}
float appScale = mCompatibilityInfo.mApplicationScale;
boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
Rect dirty = mDirty;
if (mUseGL) {
@ -1169,12 +1177,11 @@ public final class ViewRoot extends Handler implements ViewParent,
mAttachInfo.mIgnoreDirtyState = true;
mView.mPrivateFlags |= View.DRAWN;
float scale = mAppScale;
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try {
canvas.translate(0, -yoff);
if (scale != 1.0f) {
canvas.scale(scale, scale);
if (scalingRequired) {
canvas.scale(appScale, appScale);
}
mView.draw(canvas);
if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
@ -1206,8 +1213,8 @@ public final class ViewRoot extends Handler implements ViewParent,
}
if (fullRedrawNeeded) {
mAttachInfo.mIgnoreDirtyState = true;
dirty.union(0, 0, (int) (mWidth * mAppScale), (int) (mHeight * mAppScale));
mAttachInfo.mIgnoreDirtyState = true;
dirty.union(0, 0, (int) (mWidth * appScale), (int) (mHeight * appScale));
}
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
@ -1215,7 +1222,8 @@ public final class ViewRoot extends Handler implements ViewParent,
+ mWindowAttributes.getTitle()
+ ": dirty={" + dirty.left + "," + dirty.top
+ "," + dirty.right + "," + dirty.bottom + "} surface="
+ surface + " surface.isValid()=" + surface.isValid());
+ surface + " surface.isValid()=" + surface.isValid() + ", appScale:" +
appScale + ", width=" + mWidth + ", height=" + mHeight);
}
Canvas canvas;
@ -1272,18 +1280,16 @@ public final class ViewRoot extends Handler implements ViewParent,
mAttachInfo.mDrawingTime = SystemClock.uptimeMillis();
mView.mPrivateFlags |= View.DRAWN;
float scale = mAppScale;
if (DEBUG_DRAW) {
Context cxt = mView.getContext();
Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
", appScale=" + mAppScale);
", metrics=" + mView.getContext().getResources().getDisplayMetrics());
}
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG);
try {
canvas.translate(0, -yoff);
if (scale != 1.0f) {
// re-scale this
canvas.scale(scale, scale);
if (scalingRequired) {
canvas.scale(appScale, appScale);
}
mView.draw(canvas);
} finally {
@ -1586,8 +1592,8 @@ public final class ViewRoot extends Handler implements ViewParent,
} else {
didFinish = event.getAction() == MotionEvent.ACTION_OUTSIDE;
}
if (event != null) {
event.scale(mAppScaleInverted);
if (event != null && mCompatibilityInfo.mScalingRequired) {
event.scale(mCompatibilityInfo.mApplicationInvertedScale);
}
try {
@ -1709,8 +1715,9 @@ public final class ViewRoot extends Handler implements ViewParent,
if (mGlWanted && !mUseGL) {
initializeGL();
if (mGlCanvas != null) {
mGlCanvas.setViewport((int) (mWidth * mAppScale),
(int) (mHeight * mAppScale));
float appScale = mCompatibilityInfo.mApplicationScale;
mGlCanvas.setViewport(
(int) (mWidth * appScale), (int) (mHeight * appScale));
}
}
}
@ -1914,8 +1921,8 @@ public final class ViewRoot extends Handler implements ViewParent,
} else {
didFinish = false;
}
if (event != null) {
event.scale(mAppScaleInverted);
if (event != null && mCompatibilityInfo.mScalingRequired) {
event.scale(mCompatibilityInfo.mApplicationInvertedScale);
}
if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
@ -2345,27 +2352,59 @@ public final class ViewRoot extends Handler implements ViewParent,
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
boolean restore = false;
if (params != null && mAppScale != 1.0f) {
float appScale = mCompatibilityInfo.mApplicationScale;
boolean scalingRequired = mCompatibilityInfo.mScalingRequired;
if (params != null && !mCompatibilityInfo.mExpandable) {
adjustWindowAttributesForCompatibleMode(params);
}
if (params != null && scalingRequired) {
restore = true;
params.scale(mAppScale, mWindowLayoutParamsBackup);
params.scale(appScale, mWindowLayoutParamsBackup);
}
int relayoutResult = sWindowSession.relayout(
mWindow, params,
(int) (mView.mMeasuredWidth * mAppScale),
(int) (mView.mMeasuredHeight * mAppScale),
(int) (mView.mMeasuredWidth * appScale),
(int) (mView.mMeasuredHeight * appScale),
viewVisibility, insetsPending, mWinFrame,
mPendingContentInsets, mPendingVisibleInsets, mSurface);
if (restore) {
params.restore(mWindowLayoutParamsBackup);
}
mPendingContentInsets.scale(mAppScaleInverted);
mPendingVisibleInsets.scale(mAppScaleInverted);
mWinFrame.scale(mAppScaleInverted);
if (scalingRequired) {
float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
mPendingContentInsets.scale(invertedScale);
mPendingVisibleInsets.scale(invertedScale);
mWinFrame.scale(invertedScale);
}
return relayoutResult;
}
/**
* Adjust the window's layout parameter for compatibility mode. It replaces FILL_PARENT
* with the default window size, and centers if the window wanted to fill
* horizontally.
*
* @param attrs the window's layout params to adjust
*/
private void adjustWindowAttributesForCompatibleMode(WindowManager.LayoutParams attrs) {
// fix app windows only
if (attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
DisplayMetrics metrics = mView.getContext().getResources().getDisplayMetrics();
// TODO: improve gravity logic
if (attrs.width == ViewGroup.LayoutParams.FILL_PARENT) {
attrs.width = metrics.widthPixels;
attrs.gravity |= Gravity.CENTER_HORIZONTAL;
}
if (attrs.height == ViewGroup.LayoutParams.FILL_PARENT) {
attrs.height = metrics.heightPixels;
}
if (DEBUG_LAYOUT) {
Log.d(TAG, "Attributes fixed for compatibility : " + attrs);
}
}
}
/**
* {@inheritDoc}
@ -2470,11 +2509,16 @@ public final class ViewRoot extends Handler implements ViewParent,
+ " visibleInsets=" + visibleInsets.toShortString()
+ " reportDraw=" + reportDraw);
Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
coveredInsets.scale(mAppScaleInverted);
visibleInsets.scale(mAppScaleInverted);
msg.arg1 = (int) (w * mAppScaleInverted);
msg.arg2 = (int) (h * mAppScaleInverted);
if (mCompatibilityInfo.mScalingRequired) {
float invertedScale = mCompatibilityInfo.mApplicationInvertedScale;
coveredInsets.scale(invertedScale);
visibleInsets.scale(invertedScale);
msg.arg1 = (int) (w * invertedScale);
msg.arg2 = (int) (h * invertedScale);
} else {
msg.arg1 = w;
msg.arg2 = h;
}
msg.obj = new Rect[] { new Rect(coveredInsets), new Rect(visibleInsets) };
sendMessage(msg);
}

View File

@ -810,12 +810,19 @@
<!-- The <code>supports-density</code> specifies a screen density that this
package supports. Application can specify multiple densities it supports.
<p>This appears as a child tag of the
{@link #AndroidManifestApplication application} tag. -->
<declare-styleable name="AndroidManifestSupportsDensity" parent="AndroidManifestApplication">
{@link #AndroidManifest manifest} tag. -->
<declare-styleable name="AndroidManifestSupportsDensity" parent="AndroidManifest">
<!-- Required value of the density in dip (device independent pixel). -->
<attr name="density" format="integer" />
</declare-styleable>
<!-- The <code>expandable</code> specifies if this package supports screen metrics
other than 320x480 dip.
<p>This appears as a child tag of the
{@link #AndroidManifest manifest} tag. -->
<declare-styleable name="AndroidManifestExpandable" parent="AndroidManifest">
</declare-styleable>
<!-- The <code>provider</code> tag declares a
{@link android.content.ContentProvider} class that is available
as part of the package's application components, supplying structured

View File

@ -183,7 +183,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// The flags that are set for all calls we make to the package manager.
static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
| PackageManager.GET_SUPPORTS_DENSITIES;
| PackageManager.GET_SUPPORTS_DENSITIES | PackageManager.GET_EXPANDABLE;
private static final String SYSTEM_SECURE = "ro.secure";

View File

@ -386,12 +386,4 @@ public class MockContext extends Context {
throws PackageManager.NameNotFoundException {
throw new UnsupportedOperationException();
}
/**
* @hide
*/
@Override
public float getApplicationScale() {
throw new UnsupportedOperationException();
}
}

View File

@ -1145,12 +1145,4 @@ public final class BridgeContext extends Context {
public Context getApplicationContext() {
throw new UnsupportedOperationException();
}
/**
* @hide
*/
@Override
public float getApplicationScale() {
throw new UnsupportedOperationException();
}
}