1.Android 4.3引入的wm工具:
a.获取Android设备屏幕分辨率: adb shell wm size
b.获取android设备屏幕密度: adb shell wm density
public class Wm extends BaseCommand { ... public void onShowUsage(PrintStream out) { out.println( "usage: wm [subcommand] [options]\n" + " wm size [reset|WxH]\n" + " wm density [reset|DENSITY]\n" + " wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" + "\n" + "wm size: return or override display size.\n" + "\n" + "wm density: override display density.\n" + "\n" + "wm overscan: set overscan area for display.\n" ); } 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@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; }
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;
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."); } } } }
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) { }