diff options
9 files changed, 135 insertions, 7 deletions
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java index 815a0ac..64f023f 100644 --- a/cmds/wm/src/com/android/commands/wm/Wm.java +++ b/cmds/wm/src/com/android/commands/wm/Wm.java @@ -24,6 +24,7 @@ import android.graphics.Rect; import android.os.RemoteException; import android.os.ServiceManager; import android.util.AndroidException; +import android.util.DisplayMetrics; import android.view.Display; import android.view.IWindowManager; import com.android.internal.os.BaseCommand; @@ -45,21 +46,27 @@ public class Wm extends BaseCommand { (new Wm()).run(args); } + @Override public void onShowUsage(PrintStream out) { out.println( "usage: wm [subcommand] [options]\n" + - " wm size [reset|WxH]\n" + + " wm size [reset|WxH|WdpxHdp]\n" + " wm density [reset|DENSITY]\n" + " wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" + + " wm scaling [off|auto]\n" + "\n" + "wm size: return or override display size.\n" + + " width and height in pixels unless suffixed with 'dp'.\n" + "\n" + "wm density: override display density.\n" + "\n" + - "wm overscan: set overscan area for display.\n" + "wm overscan: set overscan area for display.\n" + + "\n" + + "wm scaling: set display scaling mode.\n" ); } + @Override public void onRun() throws Exception { mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService( Context.WINDOW_SERVICE)); @@ -76,6 +83,8 @@ public class Wm extends BaseCommand { runDisplayDensity(); } else if (op.equals("overscan")) { runDisplayOverscan(); + } else if (op.equals("scaling")) { + runDisplayScaling(); } else { showError("Error: unknown command '" + op + "'"); return; @@ -85,6 +94,7 @@ public class Wm extends BaseCommand { private void runDisplaySize() throws Exception { String size = nextArg(); int w, h; + boolean scale = true; if (size == null) { Point initialSize = new Point(); Point baseSize = new Point(); @@ -109,8 +119,8 @@ public class Wm extends BaseCommand { String wstr = size.substring(0, div); String hstr = size.substring(div+1); try { - w = Integer.parseInt(wstr); - h = Integer.parseInt(hstr); + w = parseDimension(wstr); + h = parseDimension(hstr); } catch (NumberFormatException e) { System.err.println("Error: bad number " + e); return; @@ -193,4 +203,32 @@ public class Wm extends BaseCommand { } catch (RemoteException e) { } } + + private void runDisplayScaling() throws Exception { + String scalingStr = nextArgRequired(); + if ("auto".equals(scalingStr)) { + mWm.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 0); + } else if ("off".equals(scalingStr)) { + mWm.setForcedDisplayScalingMode(Display.DEFAULT_DISPLAY, 1); + } else { + System.err.println("Error: scaling must be 'auto' or 'off'"); + } + } + + private int parseDimension(String s) throws NumberFormatException { + if (s.endsWith("px")) { + return Integer.parseInt(s.substring(0, s.length() - 2)); + } + if (s.endsWith("dp")) { + int density; + try { + density = mWm.getBaseDisplayDensity(Display.DEFAULT_DISPLAY); + } catch (RemoteException e) { + density = DisplayMetrics.DENSITY_DEFAULT; + } + return Integer.parseInt(s.substring(0, s.length() - 2)) * density / + DisplayMetrics.DENSITY_DEFAULT; + } + return Integer.parseInt(s); + } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 109c23b..cf1a5d1 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6036,6 +6036,13 @@ public final class Settings { public static final String DISPLAY_SIZE_FORCED = "display_size_forced"; /** + * The saved value for WindowManagerService.setForcedDisplayScalingMode(). + * 0 or unset if scaling is automatic, 1 if scaling is disabled. + * @hide + */ + public static final String DISPLAY_SCALING_FORCE = "display_scaling_force"; + + /** * The maximum size, in bytes, of a download that the download manager will transfer over * a non-wifi connection. * @hide diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 71863b7..71e2251 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -170,6 +170,15 @@ public final class Display { public static final int FLAG_PRESENTATION = 1 << 3; /** + * Display flag: Indicates that the contents of the display should not be scaled + * to fit the physical screen dimensions. Used for development only to emulate + * devices with smaller physicals screens while preserving density. + * + * @hide + */ + public static final int FLAG_SCALING_DISABLED = 1 << 30; + + /** * Display type: Unknown display type. * @hide */ diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index ecf45b4..243961c 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -538,6 +538,9 @@ public final class DisplayInfo implements Parcelable { if ((flags & Display.FLAG_PRESENTATION) != 0) { result.append(", FLAG_PRESENTATION"); } + if ((flags & Display.FLAG_SCALING_DISABLED) != 0) { + result.append(", FLAG_SCALING_DISABLED"); + } return result.toString(); } } diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index d6625c8..5994d4f 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -70,6 +70,7 @@ interface IWindowManager int getBaseDisplayDensity(int displayId); void setForcedDisplayDensity(int displayId, int density); void clearForcedDisplayDensity(int displayId); + void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable void setOverscan(int displayId, int left, int top, int right, int bottom); diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 3bb7818..65dc72f 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -302,7 +302,10 @@ final class LogicalDisplay { // multiplying the fractions by the product of their denominators before // comparing them. int displayRectWidth, displayRectHeight; - if (physWidth * displayInfo.logicalHeight + if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0) { + displayRectWidth = displayInfo.logicalWidth; + displayRectHeight = displayInfo.logicalHeight; + } else if (physWidth * displayInfo.logicalHeight < physHeight * displayInfo.logicalWidth) { // Letter box. displayRectWidth = physWidth; diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index f073c23..f914369 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -66,6 +66,7 @@ class DisplayContent { int mBaseDisplayWidth = 0; int mBaseDisplayHeight = 0; int mBaseDisplayDensity = 0; + boolean mDisplayScalingDisabled; private final DisplayInfo mDisplayInfo = new DisplayInfo(); private final Display mDisplay; @@ -360,6 +361,9 @@ class DisplayContent { pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight); pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi"); } + if (mDisplayScalingDisabled) { + pw.println(" noscale"); + } pw.print(" cur="); pw.print(mDisplayInfo.logicalWidth); pw.print("x"); pw.print(mDisplayInfo.logicalHeight); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index e790fb0..04b71a4 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7249,8 +7249,15 @@ public class WindowManagerService extends IWindowManager.Stub displayInfo.getLogicalMetrics(mRealDisplayMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); displayInfo.getAppMetrics(mDisplayMetrics); + if (displayContent.mDisplayScalingDisabled) { + displayInfo.flags |= Display.FLAG_SCALING_DISABLED; + } else { + displayInfo.flags &= ~Display.FLAG_SCALING_DISABLED; + } + mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager( displayContent.getDisplayId(), displayInfo); + displayContent.mBaseDisplayRect.set(0, 0, dw, dh); } if (false) { @@ -7547,7 +7554,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized(mWindowMap) { final DisplayContent displayContent = getDefaultDisplayContentLocked(); - readForcedDisplaySizeAndDensityLocked(displayContent); + readForcedDisplayPropertiesLocked(displayContent); mDisplayReady = true; } @@ -8320,7 +8327,47 @@ public class WindowManagerService extends IWindowManager.Stub } } - private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) { + @Override + public void setForcedDisplayScalingMode(int displayId, int mode) { + 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"); + } + final long ident = Binder.clearCallingIdentity(); + try { + synchronized(mWindowMap) { + final DisplayContent displayContent = getDisplayContentLocked(displayId); + if (displayContent != null) { + if (mode < 0 || mode > 1) { + mode = 0; + } + setForcedDisplayScalingModeLocked(displayContent, mode); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DISPLAY_SCALING_FORCE, mode); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void setForcedDisplayScalingModeLocked(DisplayContent displayContent, + int mode) { + Slog.i(TAG, "Using display scaling mode: " + (mode == 0 ? "auto" : "off")); + + synchronized(displayContent.mDisplaySizeLock) { + displayContent.mDisplayScalingDisabled = (mode != 0); + } + reconfigureDisplayLocked(displayContent); + } + + private void readForcedDisplayPropertiesLocked(final DisplayContent displayContent) { + // Display size. String sizeStr = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.DISPLAY_SIZE_FORCED); if (sizeStr == null || sizeStr.length() == 0) { @@ -8345,6 +8392,8 @@ public class WindowManagerService extends IWindowManager.Stub } } } + + // Display density. String densityStr = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.DISPLAY_DENSITY_FORCED); if (densityStr == null || densityStr.length() == 0) { @@ -8363,6 +8412,16 @@ public class WindowManagerService extends IWindowManager.Stub } catch (NumberFormatException ex) { } } + + // Display scaling mode. + int mode = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DISPLAY_SCALING_FORCE, 0); + if (mode != 0) { + synchronized(displayContent.mDisplaySizeLock) { + Slog.i(TAG, "FORCED DISPLAY SCALING DISABLED"); + displayContent.mDisplayScalingDisabled = true; + } + } } // displayContent must not be null diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 818940d..82012c1 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -376,6 +376,10 @@ public class IWindowManagerImpl implements IWindowManager { } @Override + public void setForcedDisplayScalingMode(int displayId, int mode) { + } + + @Override public void setInTouchMode(boolean arg0) throws RemoteException { // TODO Auto-generated method stub } |