1.Android 4.3引入的wm工具:
a.获取Android设备屏幕分辨率: adb shell wm size
b.获取android设备屏幕密度: adb shell wm density
Wm.java
public class Wm extends BaseCommand {
...
public void onShowUsage(PrintStream out) {
out.println(
"usage: wm [subcommand] [options]
" +
" wm size [reset|WxH]
" +
" wm density [reset|DENSITY]
" +
" wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]
" +
"
" +
"wm size: return or override display size.
" +
"
" +
"wm density: override display density.
" +
"
" +
"wm overscan: set overscan area for display.
"
);
}
public void onRun() throws Exception {
mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService(
Context.WINDOW_SERVICE));
if (mWm == null) {
System.err.println(NO_SYSTEM_ERROR_CODE);
throw new AndroidException("Can't connect to window manager; is the system running?");
}
String op = nextArgRequired();
if (op.equals("size")) {
runDisplaySize();
} else if (op.equals("density")) {
runDisplayDensity();
} else if (op.equals("overscan")) {
runDisplayOverscan();
} else {
showError("Error: unknown command '" + op + "'");
return;
}
}
private void runDisplaySize() throws Exception {
String size = nextArg();
int w, h;
if (size == null) {
Point initialSize = new Point();
Point baseSize = new Point();
try {
mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize);
mWm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize);
System.out.println("Physical size: " + initialSize.x + "x" + initialSize.y);
if (!initialSize.equals(baseSize)) {
System.out.println("Override size: " + baseSize.x + "x" + baseSize.y);
}
} catch (RemoteException e) {
}
return;
} else if ("reset".equals(size)) {
w = h = -1;
} else {
int div = size.indexOf('x');
if (div <= 0 || div >= (size.length()-1)) {
System.err.println("Error: bad size " + size);
return;
}
String wstr = size.substring(0, div);
String hstr = size.substring(div+1);
try {
w = Integer.parseInt(wstr);
h = Integer.parseInt(hstr);
} catch (NumberFormatException e) {
System.err.println("Error: bad number " + e);
return;
}
}
try {
if (w >= 0 && h >= 0) {
// TODO(multidisplay): For now Configuration only applies to main screen.
mWm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h);
} else {
mWm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY);
}
} catch (RemoteException e) {
}
}
private void runDisplayDensity() throws Exception {
String densityStr = nextArg();
int density;
if (densityStr == null) {
try {
int initialDensity = mWm.getInitialDisplayDensity(Display.DEFAULT_DISPLAY);
int baseDensity = mWm.getBaseDisplayDensity(Display.DEFAULT_DISPLAY);
System.out.println("Physical density: " + initialDensity);
if (initialDensity != baseDensity) {
System.out.println("Override density: " + baseDensity);
}
} catch (RemoteException e) {
}
return;
} else if ("reset".equals(densityStr)) {
density = -1;
} else {
try {
density = Integer.parseInt(densityStr);
} catch (NumberFormatException e) {
System.err.println("Error: bad number " + e);
return;
}
if (density < 72) {
System.err.println("Error: density must be >= 72");
return;
}
}
try {
if (density > 0) {
// TODO(multidisplay): For now Configuration only applies to main screen.
mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density);
} else {
mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY);
}
} catch (RemoteException e) {
}
}
...
View Code
WindowManagerService.java
View Code@Override
public void getInitialDisplaySize(int displayId, Point size) {
synchronized (mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
synchronized(displayContent.mDisplaySizeLock) {
size.x = displayContent.mInitialDisplayWidth;
size.y = displayContent.mInitialDisplayHeight;
}
}
}
}
@Override
public void getBaseDisplaySize(int displayId, Point size) {
synchronized (mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
synchronized(displayContent.mDisplaySizeLock) {
size.x = displayContent.mBaseDisplayWidth;
size.y = displayContent.mBaseDisplayHeight;
}
}
}
}
@Override
public int getInitialDisplayDensity(int displayId) {
synchronized (mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
synchronized(displayContent.mDisplaySizeLock) {
return displayContent.mInitialDisplayDensity;
}
}
}
return -1;
}
@Override
public int getBaseDisplayDensity(int displayId) {
synchronized (mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
synchronized(displayContent.mDisplaySizeLock) {
return displayContent.mBaseDisplayDensity;
}
}
}
return -1;
}
@Override
public void setForcedDisplaySize(int displayId, int width, int height) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Must hold permission " +
android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
if (displayId != Display.DEFAULT_DISPLAY) {
throw new IllegalArgumentException("Can only set the default display");
}
synchronized(mWindowMap) {
// Set some sort of reasonable bounds on the size of the display that we
// will try to emulate.
final int MIN_WIDTH = 200;
final int MIN_HEIGHT = 200;
final int MAX_SCALE = 2;
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
width = Math.min(Math.max(width, MIN_WIDTH),
displayContent.mInitialDisplayWidth * MAX_SCALE);
height = Math.min(Math.max(height, MIN_HEIGHT),
displayContent.mInitialDisplayHeight * MAX_SCALE);
setForcedDisplaySizeLocked(displayContent, width, height);
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
}
}
}
@Override
public void setForcedDisplayDensity(int displayId, int density) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Must hold permission " +
android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
if (displayId != Display.DEFAULT_DISPLAY) {
throw new IllegalArgumentException("Can only set the default display");
}
synchronized(mWindowMap) {
final DisplayContent displayContent = getDisplayContentLocked(displayId);
if (displayContent != null) {
setForcedDisplayDensityLocked(displayContent, density);
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
}
}
}
// displayContent must not be null
private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
Slog.i(TAG, "Using new display density: " + density);
synchronized(displayContent.mDisplaySizeLock) {
displayContent.mBaseDisplayDensity = density;
}
reconfigureDisplayLocked(displayContent);
}
private DisplayContent newDisplayContentLocked(final Display display) {
DisplayContent displayContent = new DisplayContent(display);
mDisplayContents.put(display.getDisplayId(), displayContent);
final Rect rect = new Rect();
DisplayInfo info = displayContent.getDisplayInfo();
mDisplaySettings.getOverscanLocked(info.name, rect);
info.overscanLeft = rect.left;
info.overscanTop = rect.top;
info.overscanRight = rect.right;
info.overscanBottom = rect.bottom;
mDisplayManagerService.setOverscan(display.getDisplayId(), rect.left, rect.top,
rect.right, rect.bottom);
mPolicy.setDisplayOverscan(displayContent.getDisplay(), rect.left, rect.top,
rect.right, rect.bottom);
return displayContent;
}
/**
* Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
* there is a Display for the displayId.
* @param displayId The display the caller is interested in.
* @return The DisplayContent associated with displayId or null if there is no Display for it.
*/
public DisplayContent getDisplayContentLocked(final int displayId) {
DisplayContent displayContent = mDisplayContents.get(displayId);
if (displayContent == null) {
final Display display = mDisplayManager.getDisplay(displayId);
if (display != null) {
displayContent = newDisplayContentLocked(display);
}
}
return displayContent;
}
DisplayContent.java
DisplayManager.java
View Code/**
* Gets all currently valid logical displays of the specified category.
* <p>
* When there are multiple displays in a category the returned displays are sorted
* of preference. For example, if the requested category is
* {@link #DISPLAY_CATEGORY_PRESENTATION} and there are multiple presentation displays
* then the displays are sorted so that the first display in the returned array
* is the most preferred presentation display. The application may simply
* use the first display or allow the user to choose.
* </p>
*
* @param category The requested display category or null to return all displays.
* @return An array containing all displays sorted by order of preference.
*
* @see #DISPLAY_CATEGORY_PRESENTATION
*/
public Display[] getDisplays(String category) {
final int[] displayIds = mGlobal.getDisplayIds();
synchronized (mLock) {
try {
if (category == null) {
addMatchingDisplaysLocked(mTempDisplays, displayIds, -1);
} else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_HDMI);
addMatchingDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
}
return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
} finally {
mTempDisplays.clear();
}
}
}
private void addMatchingDisplaysLocked(
ArrayList<Display> displays, int[] displayIds, int matchType) {
for (int i = 0; i < displayIds.length; i++) {
Display display = getOrCreateDisplayLocked(displayIds[i], true /*assumeValid*/);
if (display != null
&& (matchType < 0 || display.getType() == matchType)) {
displays.add(display);
}
}
}
2.显示区域分为应用显示区域和真实显示区域。
a.应用显示区域不包括系统点缀,它可能比真实显示区域小因为系统减掉了点缀元素的空间如导航栏(隐藏/显示导航栏得到的高度不同)
View CodeDisplayMetrics metrics = new DisplayMetrics();
Display displaymetrics = getWindowManager().getDefaultDisplay().getMetrics(metrics);
int width = displaymetrics.widthPixels;
int height = displaymetrics.heightPixels;
float density = displaymetrics.density;
int densityDpi = displaymetrics.densityDpi;
Display.java
View Code/**
* Gets display metrics that describe the size and density of this display.
* <p>
* The size is adjusted based on the current rotation of the display.
* </p><p>
* The size returned by this method does not necessarily represent the
* actual raw size (native resolution) of the display. The returned size may
* be adjusted to exclude certain system decor elements that are always visible.
* It may also be scaled to provide compatibility with older applications that
* were originally designed for smaller displays.
* </p>
*
* @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
*/
public void getMetrics(DisplayMetrics outMetrics) {
synchronized (this) {
updateDisplayInfoLocked();
mDisplayInfo.getAppMetrics(outMetrics, mCompatibilityInfo);
}
}
/**
* Gets display metrics based on the real size of this display.
* <p>
* The size is adjusted based on the current rotation of the display.
* </p><p>
* The real size may be smaller than the physical size of the screen when the
* window manager is emulating a smaller display (using adb shell am display-size).
* </p>
*
* @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
*/
public void getRealMetrics(DisplayMetrics outMetrics) {
synchronized (this) {
updateDisplayInfoLocked();
mDisplayInfo.getLogicalMetrics(outMetrics, null);
}
}
private void updateDisplayInfoLocked() {
// Note: The display manager caches display info objects on our behalf.
DisplayInfo newInfo = mGlobal.getDisplayInfo(mDisplayId);
if (newInfo == null) {
// Preserve the old mDisplayInfo after the display is removed.
if (mIsValid) {
mIsValid = false;
if (DEBUG) {
Log.d(TAG, "Logical display " + mDisplayId + " was removed.");
}
}
} else {
// Use the new display info. (It might be the same object if nothing changed.)
mDisplayInfo = newInfo;
if (!mIsValid) {
mIsValid = true;
if (DEBUG) {
Log.d(TAG, "Logical display " + mDisplayId + " was recreated.");
}
}
}
}
DisplayInfo.java
View Code/**
* Describes the characteristics of a particular logical display.
* @hide
*/
public final class DisplayInfo implements Parcelable {
...
/**
* The width of the portion of the display that is available to applications, in pixels.
* Represents the size of the display minus any system decorations.
*/
public int appWidth;
/**
* The height of the portion of the display that is available to applications, in pixels.
* Represents the size of the display minus any system decorations.
*/
public int appHeight;
...
/**
* The logical width of the display, in pixels.
* Represents the usable size of the display which may be smaller than the
* physical size when the system is emulating a smaller display.
*/
public int logicalWidth;
/**
* The logical height of the display, in pixels.
* Represents the usable size of the display which may be smaller than the
* physical size when the system is emulating a smaller display.
*/
public int logicalHeight;
...
public static final Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
@Override
public DisplayInfo createFromParcel(Parcel source) {
return new DisplayInfo(source);
}
@Override
public DisplayInfo[] newArray(int size) {
return new DisplayInfo[size];
}
};
...
private DisplayInfo(Parcel source) {
readFromParcel(source);
}
...
public void readFromParcel(Parcel source) {
layerStack = source.readInt();
flags = source.readInt();
type = source.readInt();
address = source.readString();
name = source.readString();
appWidth = source.readInt();
appHeight = source.readInt();
smallestNominalAppWidth = source.readInt();
smallestNominalAppHeight = source.readInt();
largestNominalAppWidth = source.readInt();
largestNominalAppHeight = source.readInt();
logicalWidth = source.readInt();
logicalHeight = source.readInt();
overscanLeft = source.readInt();
overscanTop = source.readInt();
overscanRight = source.readInt();
overscanBottom = source.readInt();
rotation = source.readInt();
refreshRate = source.readFloat();
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
}
public void getAppMetrics(DisplayMetrics outMetrics, CompatibilityInfoHolder cih) {
getMetricsWithSize(outMetrics, cih, appWidth, appHeight);
}
public void getLogicalMetrics(DisplayMetrics outMetrics, CompatibilityInfoHolder cih) {
getMetricsWithSize(outMetrics, cih, logicalWidth, logicalHeight);
}
private void getMetricsWithSize(DisplayMetrics outMetrics, CompatibilityInfoHolder cih,
int width, int height) {
outMetrics.densityDpi = outMetrics.noncompatDensityDpi = logicalDensityDpi;
outMetrics.noncompatWidthPixels = outMetrics.widthPixels = width;
outMetrics.noncompatHeightPixels = outMetrics.heightPixels = height;
outMetrics.density = outMetrics.noncompatDensity =
logicalDensityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
outMetrics.scaledDensity = outMetrics.noncompatScaledDensity = outMetrics.density;
outMetrics.xdpi = outMetrics.noncompatXdpi = physicalXDpi;
outMetrics.ydpi = outMetrics.noncompatYdpi = physicalYDpi;
if (cih != null) {
CompatibilityInfo ci = cih.getIfNeeded();
if (ci != null) {
ci.applyToDisplayMetrics(outMetrics);
}
}
}
b.真实显示区域包括系统点缀,但它有可能比物理显示小当窗口管理器模拟更小显示(如使用adb shell am display-size)时
View CodeDisplay d = getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = d.getMetrics(new DisplayMetrics());
int ver = Build.VERSION.SDK_INT;
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
if (Build.VERSION.SDK_INT = 13)
try {
widthPixels = (Integer) Display.class.getMethod("getRealWidth").invoke(d);
heightPixels = (Integer) Display.class.getMethod("getRealHeight").invoke(d);
} catch (Exception ignored) {
}
// includes window decorations (statusbar bar/menu bar)
if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 17)
try {
widthPixels = (Integer) Display.class.getMethod("getRawWidth").invoke(d);
heightPixels = (Integer) Display.class.getMethod("getRawHeight").invoke(d);
} catch (Exception ignored) {
}
// includes window decorations (statusbar bar/menu bar)
if (Build.VERSION.SDK_INT >= 17)
try {
//Point realSize = new Point();
//Display.class.getMethod("getRealSize", Point.class).invoke(d, realSize);
//widthPixels = realSize.x;
//heightPixels = realSize.y;
DisplayMetrics realMetrics = d.getRealMetrics(new DisplayMetrics());
widthPixels = realMetrics.widthPixels;
heightPixels = realMetrics.heightPixels;
} catch (Exception ignored) {
}